OpenTTD Source 20250205-master-gfd85ab1e2c
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
317 enum Refittability : uint8_t {
318 UNSET = 0,
321 };
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, GRFStringID 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(GRFStringID 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(GRFStringID 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.base(), 0xD000, 0xD7FF));
512
513#define TEXTID_TO_STRINGID(begin, end, stringid, stringend) \
514 static_assert(stringend - stringid == end - begin); \
515 if (str.base() >= begin && str.base() <= end) return StringID{str.base() + (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.base() >= 0x004E && str.base() <= 0x006D) return units_volume[str.base() - 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.base()) {
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.base() == 0) 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
561{
562 if (IsInsideMM(str.base(), 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.base(), 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 = GRFStringID(str.base() & ~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}", std::byteswap(source_grfid));
599 } else {
600 _grf_id_overrides[source_grfid] = target_grfid;
601 GrfMsg(5, "SetNewGRFOverride: Added override of 0x{:X} to 0x{:X}", std::byteswap(source_grfid), std::byteswap(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", std::byteswap(file->grfid), std::byteswap(scope_grfid));
640 } else {
641 GrfMsg(5, "Mapping from GRFID {:x} to {:x}", std::byteswap(file->grfid), std::byteswap(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, std::byteswap(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, std::byteswap(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 CargoType cargo = GetCargoTranslation(bit, _cur.grffile, true);
968 if (IsValidCargoType(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
1008using ChangeInfoHandler = ChangeInfoResult(uint first, uint last, 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 = TimerGameCalendar::Year{buf.ReadByte()};
1030 break;
1031
1032 case 0x04: // Model life
1033 ei->base_life = TimerGameCalendar::Year{buf.ReadByte()};
1034 break;
1035
1036 case 0x06: // Climates available
1037 ei->climates = LandscapeTypes{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 first, uint last, int prop, ByteReader &buf)
1061{
1063
1064 for (uint id = first; id < last; ++id) {
1065 Engine *e = GetNewEngine(_cur.grffile, VEH_TRAIN, id);
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 auto mask = ei->callback_mask.base();
1246 SB(mask, 0, 8, buf.ReadByte());
1248 break;
1249 }
1250
1251 case PROP_TRAIN_TRACTIVE_EFFORT: // 0x1F Tractive effort coefficient
1252 rvi->tractive_effort = buf.ReadByte();
1253 break;
1254
1255 case 0x20: // Air drag
1256 rvi->air_drag = buf.ReadByte();
1257 break;
1258
1259 case PROP_TRAIN_SHORTEN_FACTOR: // 0x21 Shorter vehicle
1260 rvi->shorten_factor = buf.ReadByte();
1261 break;
1262
1263 case 0x22: // Visual effect
1264 rvi->visual_effect = buf.ReadByte();
1265 /* Avoid accidentally setting visual_effect to the default value
1266 * Since bit 6 (disable effects) is set anyways, we can safely erase some bits. */
1267 if (rvi->visual_effect == VE_DEFAULT) {
1268 assert(HasBit(rvi->visual_effect, VE_DISABLE_EFFECT));
1270 }
1271 break;
1272
1273 case 0x23: // Powered wagons weight bonus
1274 rvi->pow_wag_weight = buf.ReadByte();
1275 break;
1276
1277 case 0x24: { // High byte of vehicle weight
1278 uint8_t weight = buf.ReadByte();
1279
1280 if (weight > 4) {
1281 GrfMsg(2, "RailVehicleChangeInfo: Nonsensical weight of {} tons, ignoring", weight << 8);
1282 } else {
1283 SB(rvi->weight, 8, 8, weight);
1284 }
1285 break;
1286 }
1287
1288 case PROP_TRAIN_USER_DATA: // 0x25 User-defined bit mask to set when checking veh. var. 42
1289 rvi->user_def_data = buf.ReadByte();
1290 break;
1291
1292 case 0x26: // Retire vehicle early
1293 ei->retire_early = buf.ReadByte();
1294 break;
1295
1296 case 0x27: // Miscellaneous flags
1297 ei->misc_flags = static_cast<EngineMiscFlags>(buf.ReadByte());
1299 break;
1300
1301 case 0x28: // Cargo classes allowed
1302 _gted[e->index].cargo_allowed = buf.ReadWord();
1303 _gted[e->index].UpdateRefittability(_gted[e->index].cargo_allowed != 0);
1304 _gted[e->index].defaultcargo_grf = _cur.grffile;
1305 break;
1306
1307 case 0x29: // Cargo classes disallowed
1308 _gted[e->index].cargo_disallowed = buf.ReadWord();
1309 _gted[e->index].UpdateRefittability(false);
1310 break;
1311
1312 case 0x2A: // Long format introduction date (days since year 0)
1313 ei->base_intro = TimerGameCalendar::Date(buf.ReadDWord());
1314 break;
1315
1316 case PROP_TRAIN_CARGO_AGE_PERIOD: // 0x2B Cargo aging period
1317 ei->cargo_age_period = buf.ReadWord();
1318 break;
1319
1320 case 0x2C: // CTT refit include list
1321 case 0x2D: { // CTT refit exclude list
1322 uint8_t count = buf.ReadByte();
1323 _gted[e->index].UpdateRefittability(prop == 0x2C && count != 0);
1324 if (prop == 0x2C) _gted[e->index].defaultcargo_grf = _cur.grffile;
1325 CargoTypes &ctt = prop == 0x2C ? _gted[e->index].ctt_include_mask : _gted[e->index].ctt_exclude_mask;
1326 ctt = 0;
1327 while (count--) {
1328 CargoType ctype = GetCargoTranslation(buf.ReadByte(), _cur.grffile);
1329 if (IsValidCargoType(ctype)) SetBit(ctt, ctype);
1330 }
1331 break;
1332 }
1333
1334 case PROP_TRAIN_CURVE_SPEED_MOD: // 0x2E Curve speed modifier
1335 rvi->curve_speed_mod = buf.ReadWord();
1336 break;
1337
1338 case 0x2F: // Engine variant
1339 ei->variant_id = buf.ReadWord();
1340 break;
1341
1342 case 0x30: // Extra miscellaneous flags
1343 ei->extra_flags = static_cast<ExtraEngineFlags>(buf.ReadDWord());
1344 break;
1345
1346 case 0x31: { // Callback additional mask
1347 auto mask = ei->callback_mask.base();
1348 SB(mask, 8, 8, buf.ReadByte());
1350 break;
1351 }
1352
1353 case 0x32: // Cargo classes required for a refit.
1354 _gted[e->index].cargo_allowed_required = buf.ReadWord();
1355 break;
1356
1357 default:
1358 ret = CommonVehicleChangeInfo(ei, prop, buf);
1359 break;
1360 }
1361 }
1362
1363 return ret;
1364}
1365
1374static ChangeInfoResult RoadVehicleChangeInfo(uint first, uint last, int prop, ByteReader &buf)
1375{
1377
1378 for (uint id = first; id < last; ++id) {
1379 Engine *e = GetNewEngine(_cur.grffile, VEH_ROAD, id);
1380 if (e == nullptr) return CIR_INVALID_ID; // No engine could be allocated, so neither can any next vehicles
1381
1382 EngineInfo *ei = &e->info;
1383 RoadVehicleInfo *rvi = &e->u.road;
1384
1385 switch (prop) {
1386 case 0x05: // Road/tram type
1387 /* RoadTypeLabel is looked up later after the engine's road/tram
1388 * flag is set, however 0 means the value has not been set. */
1389 _gted[e->index].roadtramtype = buf.ReadByte() + 1;
1390 break;
1391
1392 case 0x08: // Speed (1 unit is 0.5 kmh)
1393 rvi->max_speed = buf.ReadByte();
1394 break;
1395
1396 case PROP_ROADVEH_RUNNING_COST_FACTOR: // 0x09 Running cost factor
1397 rvi->running_cost = buf.ReadByte();
1398 break;
1399
1400 case 0x0A: // Running cost base
1401 ConvertTTDBasePrice(buf.ReadDWord(), "RoadVehicleChangeInfo", &rvi->running_cost_class);
1402 break;
1403
1404 case 0x0E: { // Sprite ID
1405 uint8_t spriteid = buf.ReadByte();
1406 uint8_t orig_spriteid = spriteid;
1407
1408 /* cars have different custom id in the GRF file */
1409 if (spriteid == 0xFF) spriteid = 0xFD;
1410
1411 if (spriteid < 0xFD) spriteid >>= 1;
1412
1413 if (IsValidNewGRFImageIndex<VEH_ROAD>(spriteid)) {
1414 rvi->image_index = spriteid;
1415 } else {
1416 GrfMsg(1, "RoadVehicleChangeInfo: Invalid Sprite {} specified, ignoring", orig_spriteid);
1417 rvi->image_index = 0;
1418 }
1419 break;
1420 }
1421
1422 case PROP_ROADVEH_CARGO_CAPACITY: // 0x0F Cargo capacity
1423 rvi->capacity = buf.ReadByte();
1424 break;
1425
1426 case 0x10: { // Cargo type
1427 _gted[e->index].defaultcargo_grf = _cur.grffile;
1428 uint8_t ctype = buf.ReadByte();
1429
1430 if (ctype == 0xFF) {
1431 /* 0xFF is specified as 'use first refittable' */
1432 ei->cargo_type = INVALID_CARGO;
1433 } else {
1434 /* Use translated cargo. Might result in INVALID_CARGO (first refittable), if cargo is not defined. */
1435 ei->cargo_type = GetCargoTranslation(ctype, _cur.grffile);
1436 if (ei->cargo_type == INVALID_CARGO) GrfMsg(2, "RoadVehicleChangeInfo: Invalid cargo type {}, using first refittable", ctype);
1437 }
1438 ei->cargo_label = CT_INVALID;
1439 break;
1440 }
1441
1442 case PROP_ROADVEH_COST_FACTOR: // 0x11 Cost factor
1443 rvi->cost_factor = buf.ReadByte();
1444 break;
1445
1446 case 0x12: // SFX
1447 rvi->sfx = GetNewGRFSoundID(_cur.grffile, buf.ReadByte());
1448 break;
1449
1450 case PROP_ROADVEH_POWER: // Power in units of 10 HP.
1451 rvi->power = buf.ReadByte();
1452 break;
1453
1454 case PROP_ROADVEH_WEIGHT: // Weight in units of 1/4 tons.
1455 rvi->weight = buf.ReadByte();
1456 break;
1457
1458 case PROP_ROADVEH_SPEED: // Speed in mph/0.8
1459 _gted[e->index].rv_max_speed = buf.ReadByte();
1460 break;
1461
1462 case 0x16: { // Cargoes available for refitting
1463 uint32_t mask = buf.ReadDWord();
1464 _gted[e->index].UpdateRefittability(mask != 0);
1465 ei->refit_mask = TranslateRefitMask(mask);
1466 _gted[e->index].defaultcargo_grf = _cur.grffile;
1467 break;
1468 }
1469
1470 case 0x17: { // Callback mask
1471 auto mask = ei->callback_mask.base();
1472 SB(mask, 0, 8, buf.ReadByte());
1474 break;
1475 }
1476
1477 case PROP_ROADVEH_TRACTIVE_EFFORT: // Tractive effort coefficient in 1/256.
1478 rvi->tractive_effort = buf.ReadByte();
1479 break;
1480
1481 case 0x19: // Air drag
1482 rvi->air_drag = buf.ReadByte();
1483 break;
1484
1485 case 0x1A: // Refit cost
1486 ei->refit_cost = buf.ReadByte();
1487 break;
1488
1489 case 0x1B: // Retire vehicle early
1490 ei->retire_early = buf.ReadByte();
1491 break;
1492
1493 case 0x1C: // Miscellaneous flags
1494 ei->misc_flags = static_cast<EngineMiscFlags>(buf.ReadByte());
1496 break;
1497
1498 case 0x1D: // Cargo classes allowed
1499 _gted[e->index].cargo_allowed = buf.ReadWord();
1500 _gted[e->index].UpdateRefittability(_gted[e->index].cargo_allowed != 0);
1501 _gted[e->index].defaultcargo_grf = _cur.grffile;
1502 break;
1503
1504 case 0x1E: // Cargo classes disallowed
1505 _gted[e->index].cargo_disallowed = buf.ReadWord();
1506 _gted[e->index].UpdateRefittability(false);
1507 break;
1508
1509 case 0x1F: // Long format introduction date (days since year 0)
1510 ei->base_intro = TimerGameCalendar::Date(buf.ReadDWord());
1511 break;
1512
1513 case 0x20: // Alter purchase list sort order
1514 AlterVehicleListOrder(e->index, buf.ReadExtendedByte());
1515 break;
1516
1517 case 0x21: // Visual effect
1518 rvi->visual_effect = buf.ReadByte();
1519 /* Avoid accidentally setting visual_effect to the default value
1520 * Since bit 6 (disable effects) is set anyways, we can safely erase some bits. */
1521 if (rvi->visual_effect == VE_DEFAULT) {
1522 assert(HasBit(rvi->visual_effect, VE_DISABLE_EFFECT));
1524 }
1525 break;
1526
1527 case PROP_ROADVEH_CARGO_AGE_PERIOD: // 0x22 Cargo aging period
1528 ei->cargo_age_period = buf.ReadWord();
1529 break;
1530
1531 case PROP_ROADVEH_SHORTEN_FACTOR: // 0x23 Shorter vehicle
1532 rvi->shorten_factor = buf.ReadByte();
1533 break;
1534
1535 case 0x24: // CTT refit include list
1536 case 0x25: { // CTT refit exclude list
1537 uint8_t count = buf.ReadByte();
1538 _gted[e->index].UpdateRefittability(prop == 0x24 && count != 0);
1539 if (prop == 0x24) _gted[e->index].defaultcargo_grf = _cur.grffile;
1540 CargoTypes &ctt = prop == 0x24 ? _gted[e->index].ctt_include_mask : _gted[e->index].ctt_exclude_mask;
1541 ctt = 0;
1542 while (count--) {
1543 CargoType ctype = GetCargoTranslation(buf.ReadByte(), _cur.grffile);
1544 if (IsValidCargoType(ctype)) SetBit(ctt, ctype);
1545 }
1546 break;
1547 }
1548
1549 case 0x26: // Engine variant
1550 ei->variant_id = buf.ReadWord();
1551 break;
1552
1553 case 0x27: // Extra miscellaneous flags
1554 ei->extra_flags = static_cast<ExtraEngineFlags>(buf.ReadDWord());
1555 break;
1556
1557 case 0x28: { // Callback additional mask
1558 auto mask = ei->callback_mask.base();
1559 SB(mask, 8, 8, buf.ReadByte());
1561 break;
1562 }
1563
1564 case 0x29: // Cargo classes required for a refit.
1565 _gted[e->index].cargo_allowed_required = buf.ReadWord();
1566 break;
1567
1568 default:
1569 ret = CommonVehicleChangeInfo(ei, prop, buf);
1570 break;
1571 }
1572 }
1573
1574 return ret;
1575}
1576
1585static ChangeInfoResult ShipVehicleChangeInfo(uint first, uint last, int prop, ByteReader &buf)
1586{
1588
1589 for (uint id = first; id < last; ++id) {
1590 Engine *e = GetNewEngine(_cur.grffile, VEH_SHIP, id);
1591 if (e == nullptr) return CIR_INVALID_ID; // No engine could be allocated, so neither can any next vehicles
1592
1593 EngineInfo *ei = &e->info;
1594 ShipVehicleInfo *svi = &e->u.ship;
1595
1596 switch (prop) {
1597 case 0x08: { // Sprite ID
1598 uint8_t spriteid = buf.ReadByte();
1599 uint8_t orig_spriteid = spriteid;
1600
1601 /* ships have different custom id in the GRF file */
1602 if (spriteid == 0xFF) spriteid = 0xFD;
1603
1604 if (spriteid < 0xFD) spriteid >>= 1;
1605
1606 if (IsValidNewGRFImageIndex<VEH_SHIP>(spriteid)) {
1607 svi->image_index = spriteid;
1608 } else {
1609 GrfMsg(1, "ShipVehicleChangeInfo: Invalid Sprite {} specified, ignoring", orig_spriteid);
1610 svi->image_index = 0;
1611 }
1612 break;
1613 }
1614
1615 case 0x09: // Refittable
1616 svi->old_refittable = (buf.ReadByte() != 0);
1617 break;
1618
1619 case PROP_SHIP_COST_FACTOR: // 0x0A Cost factor
1620 svi->cost_factor = buf.ReadByte();
1621 break;
1622
1623 case PROP_SHIP_SPEED: // 0x0B Speed (1 unit is 0.5 km-ish/h). Use 0x23 to achieve higher speeds.
1624 svi->max_speed = buf.ReadByte();
1625 break;
1626
1627 case 0x0C: { // Cargo type
1628 _gted[e->index].defaultcargo_grf = _cur.grffile;
1629 uint8_t ctype = buf.ReadByte();
1630
1631 if (ctype == 0xFF) {
1632 /* 0xFF is specified as 'use first refittable' */
1633 ei->cargo_type = INVALID_CARGO;
1634 } else {
1635 /* Use translated cargo. Might result in INVALID_CARGO (first refittable), if cargo is not defined. */
1636 ei->cargo_type = GetCargoTranslation(ctype, _cur.grffile);
1637 if (ei->cargo_type == INVALID_CARGO) GrfMsg(2, "ShipVehicleChangeInfo: Invalid cargo type {}, using first refittable", ctype);
1638 }
1639 ei->cargo_label = CT_INVALID;
1640 break;
1641 }
1642
1643 case PROP_SHIP_CARGO_CAPACITY: // 0x0D Cargo capacity
1644 svi->capacity = buf.ReadWord();
1645 break;
1646
1647 case PROP_SHIP_RUNNING_COST_FACTOR: // 0x0F Running cost factor
1648 svi->running_cost = buf.ReadByte();
1649 break;
1650
1651 case 0x10: // SFX
1652 svi->sfx = GetNewGRFSoundID(_cur.grffile, buf.ReadByte());
1653 break;
1654
1655 case 0x11: { // Cargoes available for refitting
1656 uint32_t mask = buf.ReadDWord();
1657 _gted[e->index].UpdateRefittability(mask != 0);
1658 ei->refit_mask = TranslateRefitMask(mask);
1659 _gted[e->index].defaultcargo_grf = _cur.grffile;
1660 break;
1661 }
1662
1663 case 0x12: { // Callback mask
1664 auto mask = ei->callback_mask.base();
1665 SB(mask, 0, 8, buf.ReadByte());
1667 break;
1668 }
1669
1670 case 0x13: // Refit cost
1671 ei->refit_cost = buf.ReadByte();
1672 break;
1673
1674 case 0x14: // Ocean speed fraction
1675 svi->ocean_speed_frac = buf.ReadByte();
1676 break;
1677
1678 case 0x15: // Canal speed fraction
1679 svi->canal_speed_frac = buf.ReadByte();
1680 break;
1681
1682 case 0x16: // Retire vehicle early
1683 ei->retire_early = buf.ReadByte();
1684 break;
1685
1686 case 0x17: // Miscellaneous flags
1687 ei->misc_flags = static_cast<EngineMiscFlags>(buf.ReadByte());
1689 break;
1690
1691 case 0x18: // Cargo classes allowed
1692 _gted[e->index].cargo_allowed = buf.ReadWord();
1693 _gted[e->index].UpdateRefittability(_gted[e->index].cargo_allowed != 0);
1694 _gted[e->index].defaultcargo_grf = _cur.grffile;
1695 break;
1696
1697 case 0x19: // Cargo classes disallowed
1698 _gted[e->index].cargo_disallowed = buf.ReadWord();
1699 _gted[e->index].UpdateRefittability(false);
1700 break;
1701
1702 case 0x1A: // Long format introduction date (days since year 0)
1703 ei->base_intro = TimerGameCalendar::Date(buf.ReadDWord());
1704 break;
1705
1706 case 0x1B: // Alter purchase list sort order
1707 AlterVehicleListOrder(e->index, buf.ReadExtendedByte());
1708 break;
1709
1710 case 0x1C: // Visual effect
1711 svi->visual_effect = buf.ReadByte();
1712 /* Avoid accidentally setting visual_effect to the default value
1713 * Since bit 6 (disable effects) is set anyways, we can safely erase some bits. */
1714 if (svi->visual_effect == VE_DEFAULT) {
1715 assert(HasBit(svi->visual_effect, VE_DISABLE_EFFECT));
1717 }
1718 break;
1719
1720 case PROP_SHIP_CARGO_AGE_PERIOD: // 0x1D Cargo aging period
1721 ei->cargo_age_period = buf.ReadWord();
1722 break;
1723
1724 case 0x1E: // CTT refit include list
1725 case 0x1F: { // CTT refit exclude list
1726 uint8_t count = buf.ReadByte();
1727 _gted[e->index].UpdateRefittability(prop == 0x1E && count != 0);
1728 if (prop == 0x1E) _gted[e->index].defaultcargo_grf = _cur.grffile;
1729 CargoTypes &ctt = prop == 0x1E ? _gted[e->index].ctt_include_mask : _gted[e->index].ctt_exclude_mask;
1730 ctt = 0;
1731 while (count--) {
1732 CargoType ctype = GetCargoTranslation(buf.ReadByte(), _cur.grffile);
1733 if (IsValidCargoType(ctype)) SetBit(ctt, ctype);
1734 }
1735 break;
1736 }
1737
1738 case 0x20: // Engine variant
1739 ei->variant_id = buf.ReadWord();
1740 break;
1741
1742 case 0x21: // Extra miscellaneous flags
1743 ei->extra_flags = static_cast<ExtraEngineFlags>(buf.ReadDWord());
1744 break;
1745
1746 case 0x22: { // Callback additional mask
1747 auto mask = ei->callback_mask.base();
1748 SB(mask, 8, 8, buf.ReadByte());
1750 break;
1751 }
1752
1753 case 0x23: // Speed (1 unit is 0.5 km-ish/h)
1754 svi->max_speed = buf.ReadWord();
1755 break;
1756
1757 case 0x24: // Acceleration (1 unit is 0.5 km-ish/h per tick)
1758 svi->acceleration = std::max<uint8_t>(1, buf.ReadByte());
1759 break;
1760
1761 case 0x25: // Cargo classes required for a refit.
1762 _gted[e->index].cargo_allowed_required = buf.ReadWord();
1763 break;
1764
1765 default:
1766 ret = CommonVehicleChangeInfo(ei, prop, buf);
1767 break;
1768 }
1769 }
1770
1771 return ret;
1772}
1773
1782static ChangeInfoResult AircraftVehicleChangeInfo(uint first, uint last, int prop, ByteReader &buf)
1783{
1785
1786 for (uint id = first; id < last; ++id) {
1787 Engine *e = GetNewEngine(_cur.grffile, VEH_AIRCRAFT, id);
1788 if (e == nullptr) return CIR_INVALID_ID; // No engine could be allocated, so neither can any next vehicles
1789
1790 EngineInfo *ei = &e->info;
1791 AircraftVehicleInfo *avi = &e->u.air;
1792
1793 switch (prop) {
1794 case 0x08: { // Sprite ID
1795 uint8_t spriteid = buf.ReadByte();
1796 uint8_t orig_spriteid = spriteid;
1797
1798 /* aircraft have different custom id in the GRF file */
1799 if (spriteid == 0xFF) spriteid = 0xFD;
1800
1801 if (spriteid < 0xFD) spriteid >>= 1;
1802
1803 if (IsValidNewGRFImageIndex<VEH_AIRCRAFT>(spriteid)) {
1804 avi->image_index = spriteid;
1805 } else {
1806 GrfMsg(1, "AircraftVehicleChangeInfo: Invalid Sprite {} specified, ignoring", orig_spriteid);
1807 avi->image_index = 0;
1808 }
1809 break;
1810 }
1811
1812 case 0x09: // Helicopter
1813 if (buf.ReadByte() == 0) {
1814 avi->subtype = AIR_HELI;
1815 } else {
1816 SB(avi->subtype, 0, 1, 1); // AIR_CTOL
1817 }
1818 break;
1819
1820 case 0x0A: // Large
1821 AssignBit(avi->subtype, 1, buf.ReadByte() != 0); // AIR_FAST
1822 break;
1823
1824 case PROP_AIRCRAFT_COST_FACTOR: // 0x0B Cost factor
1825 avi->cost_factor = buf.ReadByte();
1826 break;
1827
1828 case PROP_AIRCRAFT_SPEED: // 0x0C Speed (1 unit is 8 mph, we translate to 1 unit is 1 km-ish/h)
1829 avi->max_speed = (buf.ReadByte() * 128) / 10;
1830 break;
1831
1832 case 0x0D: // Acceleration
1833 avi->acceleration = buf.ReadByte();
1834 break;
1835
1836 case PROP_AIRCRAFT_RUNNING_COST_FACTOR: // 0x0E Running cost factor
1837 avi->running_cost = buf.ReadByte();
1838 break;
1839
1840 case PROP_AIRCRAFT_PASSENGER_CAPACITY: // 0x0F Passenger capacity
1841 avi->passenger_capacity = buf.ReadWord();
1842 break;
1843
1844 case PROP_AIRCRAFT_MAIL_CAPACITY: // 0x11 Mail capacity
1845 avi->mail_capacity = buf.ReadByte();
1846 break;
1847
1848 case 0x12: // SFX
1849 avi->sfx = GetNewGRFSoundID(_cur.grffile, buf.ReadByte());
1850 break;
1851
1852 case 0x13: { // Cargoes available for refitting
1853 uint32_t mask = buf.ReadDWord();
1854 _gted[e->index].UpdateRefittability(mask != 0);
1855 ei->refit_mask = TranslateRefitMask(mask);
1856 _gted[e->index].defaultcargo_grf = _cur.grffile;
1857 break;
1858 }
1859
1860 case 0x14: { // Callback mask
1861 auto mask = ei->callback_mask.base();
1862 SB(mask, 0, 8, buf.ReadByte());
1864 break;
1865 }
1866
1867 case 0x15: // Refit cost
1868 ei->refit_cost = buf.ReadByte();
1869 break;
1870
1871 case 0x16: // Retire vehicle early
1872 ei->retire_early = buf.ReadByte();
1873 break;
1874
1875 case 0x17: // Miscellaneous flags
1876 ei->misc_flags = static_cast<EngineMiscFlags>(buf.ReadByte());
1878 break;
1879
1880 case 0x18: // Cargo classes allowed
1881 _gted[e->index].cargo_allowed = buf.ReadWord();
1882 _gted[e->index].UpdateRefittability(_gted[e->index].cargo_allowed != 0);
1883 _gted[e->index].defaultcargo_grf = _cur.grffile;
1884 break;
1885
1886 case 0x19: // Cargo classes disallowed
1887 _gted[e->index].cargo_disallowed = buf.ReadWord();
1888 _gted[e->index].UpdateRefittability(false);
1889 break;
1890
1891 case 0x1A: // Long format introduction date (days since year 0)
1892 ei->base_intro = TimerGameCalendar::Date(buf.ReadDWord());
1893 break;
1894
1895 case 0x1B: // Alter purchase list sort order
1896 AlterVehicleListOrder(e->index, buf.ReadExtendedByte());
1897 break;
1898
1899 case PROP_AIRCRAFT_CARGO_AGE_PERIOD: // 0x1C Cargo aging period
1900 ei->cargo_age_period = buf.ReadWord();
1901 break;
1902
1903 case 0x1D: // CTT refit include list
1904 case 0x1E: { // CTT refit exclude list
1905 uint8_t count = buf.ReadByte();
1906 _gted[e->index].UpdateRefittability(prop == 0x1D && count != 0);
1907 if (prop == 0x1D) _gted[e->index].defaultcargo_grf = _cur.grffile;
1908 CargoTypes &ctt = prop == 0x1D ? _gted[e->index].ctt_include_mask : _gted[e->index].ctt_exclude_mask;
1909 ctt = 0;
1910 while (count--) {
1911 CargoType ctype = GetCargoTranslation(buf.ReadByte(), _cur.grffile);
1912 if (IsValidCargoType(ctype)) SetBit(ctt, ctype);
1913 }
1914 break;
1915 }
1916
1917 case PROP_AIRCRAFT_RANGE: // 0x1F Max aircraft range
1918 avi->max_range = buf.ReadWord();
1919 break;
1920
1921 case 0x20: // Engine variant
1922 ei->variant_id = buf.ReadWord();
1923 break;
1924
1925 case 0x21: // Extra miscellaneous flags
1926 ei->extra_flags = static_cast<ExtraEngineFlags>(buf.ReadDWord());
1927 break;
1928
1929 case 0x22: { // Callback additional mask
1930 auto mask = ei->callback_mask.base();
1931 SB(mask, 8, 8, buf.ReadByte());
1933 break;
1934 }
1935
1936 case 0x23: // Cargo classes required for a refit.
1937 _gted[e->index].cargo_allowed_required = buf.ReadWord();
1938 break;
1939
1940 default:
1941 ret = CommonVehicleChangeInfo(ei, prop, buf);
1942 break;
1943 }
1944 }
1945
1946 return ret;
1947}
1948
1957static ChangeInfoResult StationChangeInfo(uint first, uint last, int prop, ByteReader &buf)
1958{
1960
1961 if (last > NUM_STATIONS_PER_GRF) {
1962 GrfMsg(1, "StationChangeInfo: Station {} is invalid, max {}, ignoring", last, NUM_STATIONS_PER_GRF);
1963 return CIR_INVALID_ID;
1964 }
1965
1966 /* Allocate station specs if necessary */
1967 if (_cur.grffile->stations.size() < last) _cur.grffile->stations.resize(last);
1968
1969 for (uint id = first; id < last; ++id) {
1970 auto &statspec = _cur.grffile->stations[id];
1971
1972 /* Check that the station we are modifying is defined. */
1973 if (statspec == nullptr && prop != 0x08) {
1974 GrfMsg(2, "StationChangeInfo: Attempt to modify undefined station {}, ignoring", id);
1975 return CIR_INVALID_ID;
1976 }
1977
1978 switch (prop) {
1979 case 0x08: { // Class ID
1980 /* Property 0x08 is special; it is where the station is allocated */
1981 if (statspec == nullptr) {
1982 statspec = std::make_unique<StationSpec>();
1983 }
1984
1985 /* Swap classid because we read it in BE meaning WAYP or DFLT */
1986 uint32_t classid = buf.ReadDWord();
1987 statspec->class_index = StationClass::Allocate(std::byteswap(classid));
1988 break;
1989 }
1990
1991 case 0x09: { // Define sprite layout
1992 uint16_t tiles = buf.ReadExtendedByte();
1993 statspec->renderdata.clear(); // delete earlier loaded stuff
1994 statspec->renderdata.reserve(tiles);
1995
1996 for (uint t = 0; t < tiles; t++) {
1997 NewGRFSpriteLayout *dts = &statspec->renderdata.emplace_back();
1998 dts->consistent_max_offset = UINT16_MAX; // Spritesets are unknown, so no limit.
1999
2000 if (buf.HasData(4) && buf.PeekDWord() == 0) {
2001 buf.Skip(4);
2002 extern const DrawTileSprites _station_display_datas_rail[8];
2003 dts->Clone(&_station_display_datas_rail[t % 8]);
2004 continue;
2005 }
2006
2007 ReadSpriteLayoutSprite(buf, false, false, false, GSF_STATIONS, &dts->ground);
2008 /* On error, bail out immediately. Temporary GRF data was already freed */
2009 if (_cur.skip_sprites < 0) return CIR_DISABLED;
2010
2011 static std::vector<DrawTileSeqStruct> tmp_layout;
2012 tmp_layout.clear();
2013 for (;;) {
2014 /* no relative bounding box support */
2015 DrawTileSeqStruct &dtss = tmp_layout.emplace_back();
2016 MemSetT(&dtss, 0);
2017
2018 dtss.delta_x = buf.ReadByte();
2019 if (dtss.IsTerminator()) break;
2020 dtss.delta_y = buf.ReadByte();
2021 dtss.delta_z = buf.ReadByte();
2022 dtss.size_x = buf.ReadByte();
2023 dtss.size_y = buf.ReadByte();
2024 dtss.size_z = buf.ReadByte();
2025
2026 ReadSpriteLayoutSprite(buf, false, true, false, GSF_STATIONS, &dtss.image);
2027 /* On error, bail out immediately. Temporary GRF data was already freed */
2028 if (_cur.skip_sprites < 0) return CIR_DISABLED;
2029 }
2030 dts->Clone(tmp_layout.data());
2031 }
2032
2033 /* Number of layouts must be even, alternating X and Y */
2034 if (statspec->renderdata.size() & 1) {
2035 GrfMsg(1, "StationChangeInfo: Station {} defines an odd number of sprite layouts, dropping the last item", id);
2036 statspec->renderdata.pop_back();
2037 }
2038 break;
2039 }
2040
2041 case 0x0A: { // Copy sprite layout
2042 uint16_t srcid = buf.ReadExtendedByte();
2043 const StationSpec *srcstatspec = srcid >= _cur.grffile->stations.size() ? nullptr : _cur.grffile->stations[srcid].get();
2044
2045 if (srcstatspec == nullptr) {
2046 GrfMsg(1, "StationChangeInfo: Station {} is not defined, cannot copy sprite layout to {}.", srcid, id);
2047 continue;
2048 }
2049
2050 statspec->renderdata.clear(); // delete earlier loaded stuff
2051 statspec->renderdata.reserve(srcstatspec->renderdata.size());
2052
2053 for (const auto &it : srcstatspec->renderdata) {
2054 NewGRFSpriteLayout *dts = &statspec->renderdata.emplace_back();
2055 dts->Clone(&it);
2056 }
2057 break;
2058 }
2059
2060 case 0x0B: // Callback mask
2061 statspec->callback_mask = static_cast<StationCallbackMasks>(buf.ReadByte());
2062 break;
2063
2064 case 0x0C: // Disallowed number of platforms
2065 statspec->disallowed_platforms = buf.ReadByte();
2066 break;
2067
2068 case 0x0D: // Disallowed platform lengths
2069 statspec->disallowed_lengths = buf.ReadByte();
2070 break;
2071
2072 case 0x0E: // Define custom layout
2073 while (buf.HasData()) {
2074 uint8_t length = buf.ReadByte();
2075 uint8_t number = buf.ReadByte();
2076
2077 if (length == 0 || number == 0) break;
2078
2079 const uint8_t *buf_layout = buf.ReadBytes(length * number);
2080
2081 /* Create entry in layouts and assign the layout to it. */
2082 auto &layout = statspec->layouts[GetStationLayoutKey(number, length)];
2083 layout.assign(buf_layout, buf_layout + length * number);
2084
2085 /* Ensure the first bit, axis, is zero. The rest of the value is validated during rendering, as we don't know the range yet. */
2086 for (auto &tile : layout) {
2087 if ((tile & ~1U) != tile) {
2088 GrfMsg(1, "StationChangeInfo: Invalid tile {} in layout {}x{}", tile, length, number);
2089 tile &= ~1U;
2090 }
2091 }
2092 }
2093 break;
2094
2095 case 0x0F: { // Copy custom layout
2096 uint16_t srcid = buf.ReadExtendedByte();
2097 const StationSpec *srcstatspec = srcid >= _cur.grffile->stations.size() ? nullptr : _cur.grffile->stations[srcid].get();
2098
2099 if (srcstatspec == nullptr) {
2100 GrfMsg(1, "StationChangeInfo: Station {} is not defined, cannot copy tile layout to {}.", srcid, id);
2101 continue;
2102 }
2103
2104 statspec->layouts = srcstatspec->layouts;
2105 break;
2106 }
2107
2108 case 0x10: // Little/lots cargo threshold
2109 statspec->cargo_threshold = buf.ReadWord();
2110 break;
2111
2112 case 0x11: { // Pylon placement
2113 uint8_t pylons = buf.ReadByte();
2114 if (statspec->tileflags.size() < 8) statspec->tileflags.resize(8);
2115 for (int j = 0; j < 8; ++j) {
2116 if (HasBit(pylons, j)) {
2117 statspec->tileflags[j].Set(StationSpec::TileFlag::Pylons);
2118 } else {
2119 statspec->tileflags[j].Reset(StationSpec::TileFlag::Pylons);
2120 }
2121 }
2122 break;
2123 }
2124
2125 case 0x12: // Cargo types for random triggers
2126 if (_cur.grffile->grf_version >= 7) {
2127 statspec->cargo_triggers = TranslateRefitMask(buf.ReadDWord());
2128 } else {
2129 statspec->cargo_triggers = (CargoTypes)buf.ReadDWord();
2130 }
2131 break;
2132
2133 case 0x13: // General flags
2134 statspec->flags = StationSpecFlags{buf.ReadByte()};
2135 break;
2136
2137 case 0x14: { // Overhead wire placement
2138 uint8_t wires = buf.ReadByte();
2139 if (statspec->tileflags.size() < 8) statspec->tileflags.resize(8);
2140 for (int j = 0; j < 8; ++j) {
2141 if (HasBit(wires, j)) {
2142 statspec->tileflags[j].Set(StationSpec::TileFlag::NoWires);
2143 } else {
2144 statspec->tileflags[j].Reset(StationSpec::TileFlag::NoWires);
2145 }
2146 }
2147 break;
2148 }
2149
2150 case 0x15: { // Blocked tiles
2151 uint8_t blocked = buf.ReadByte();
2152 if (statspec->tileflags.size() < 8) statspec->tileflags.resize(8);
2153 for (int j = 0; j < 8; ++j) {
2154 if (HasBit(blocked, j)) {
2155 statspec->tileflags[j].Set(StationSpec::TileFlag::Blocked);
2156 } else {
2157 statspec->tileflags[j].Reset(StationSpec::TileFlag::Blocked);
2158 }
2159 }
2160 break;
2161 }
2162
2163 case 0x16: // Animation info
2164 statspec->animation.frames = buf.ReadByte();
2165 statspec->animation.status = buf.ReadByte();
2166 break;
2167
2168 case 0x17: // Animation speed
2169 statspec->animation.speed = buf.ReadByte();
2170 break;
2171
2172 case 0x18: // Animation triggers
2173 statspec->animation.triggers = buf.ReadWord();
2174 break;
2175
2176 /* 0x19 road routing (not implemented) */
2177
2178 case 0x1A: { // Advanced sprite layout
2179 uint16_t tiles = buf.ReadExtendedByte();
2180 statspec->renderdata.clear(); // delete earlier loaded stuff
2181 statspec->renderdata.reserve(tiles);
2182
2183 for (uint t = 0; t < tiles; t++) {
2184 NewGRFSpriteLayout *dts = &statspec->renderdata.emplace_back();
2185 uint num_building_sprites = buf.ReadByte();
2186 /* On error, bail out immediately. Temporary GRF data was already freed */
2187 if (ReadSpriteLayout(buf, num_building_sprites, false, GSF_STATIONS, true, false, dts)) return CIR_DISABLED;
2188 }
2189
2190 /* Number of layouts must be even, alternating X and Y */
2191 if (statspec->renderdata.size() & 1) {
2192 GrfMsg(1, "StationChangeInfo: Station {} defines an odd number of sprite layouts, dropping the last item", id);
2193 statspec->renderdata.pop_back();
2194 }
2195 break;
2196 }
2197
2198 case 0x1B: // Minimum bridge height (not implemented)
2199 buf.ReadWord();
2200 buf.ReadWord();
2201 buf.ReadWord();
2202 buf.ReadWord();
2203 break;
2204
2205 case 0x1C: // Station Name
2206 AddStringForMapping(GRFStringID{buf.ReadWord()}, &statspec->name);
2207 break;
2208
2209 case 0x1D: // Station Class name
2210 AddStringForMapping(GRFStringID{buf.ReadWord()}, [statspec = statspec.get()](StringID str) { StationClass::Get(statspec->class_index)->name = str; });
2211 break;
2212
2213 case 0x1E: { // Extended tile flags (replaces prop 11, 14 and 15)
2214 uint16_t tiles = buf.ReadExtendedByte();
2215 auto flags = reinterpret_cast<const StationSpec::TileFlags *>(buf.ReadBytes(tiles));
2216 statspec->tileflags.assign(flags, flags + tiles);
2217 break;
2218 }
2219
2220 default:
2221 ret = CIR_UNKNOWN;
2222 break;
2223 }
2224 }
2225
2226 return ret;
2227}
2228
2237static ChangeInfoResult CanalChangeInfo(uint first, uint last, int prop, ByteReader &buf)
2238{
2240
2241 if (last > CF_END) {
2242 GrfMsg(1, "CanalChangeInfo: Canal feature 0x{:02X} is invalid, max {}, ignoring", last, CF_END);
2243 return CIR_INVALID_ID;
2244 }
2245
2246 for (uint id = first; id < last; ++id) {
2248
2249 switch (prop) {
2250 case 0x08:
2251 cp->callback_mask = static_cast<CanalCallbackMasks>(buf.ReadByte());
2252 break;
2253
2254 case 0x09:
2255 cp->flags = buf.ReadByte();
2256 break;
2257
2258 default:
2259 ret = CIR_UNKNOWN;
2260 break;
2261 }
2262 }
2263
2264 return ret;
2265}
2266
2275static ChangeInfoResult BridgeChangeInfo(uint first, uint last, int prop, ByteReader &buf)
2276{
2278
2279 if (last > MAX_BRIDGES) {
2280 GrfMsg(1, "BridgeChangeInfo: Bridge {} is invalid, max {}, ignoring", last, MAX_BRIDGES);
2281 return CIR_INVALID_ID;
2282 }
2283
2284 for (uint id = first; id < last; ++id) {
2285 BridgeSpec *bridge = &_bridge[id];
2286
2287 switch (prop) {
2288 case 0x08: { // Year of availability
2289 /* We treat '0' as always available */
2290 uint8_t year = buf.ReadByte();
2292 break;
2293 }
2294
2295 case 0x09: // Minimum length
2296 bridge->min_length = buf.ReadByte();
2297 break;
2298
2299 case 0x0A: // Maximum length
2300 bridge->max_length = buf.ReadByte();
2301 if (bridge->max_length > 16) bridge->max_length = UINT16_MAX;
2302 break;
2303
2304 case 0x0B: // Cost factor
2305 bridge->price = buf.ReadByte();
2306 break;
2307
2308 case 0x0C: // Maximum speed
2309 bridge->speed = buf.ReadWord();
2310 if (bridge->speed == 0) bridge->speed = UINT16_MAX;
2311 break;
2312
2313 case 0x0D: { // Bridge sprite tables
2314 uint8_t tableid = buf.ReadByte();
2315 uint8_t numtables = buf.ReadByte();
2316
2317 if (bridge->sprite_table == nullptr) {
2318 /* Allocate memory for sprite table pointers and zero out */
2319 bridge->sprite_table = CallocT<PalSpriteID*>(NUM_BRIDGE_PIECES);
2320 }
2321
2322 for (; numtables-- != 0; tableid++) {
2323 if (tableid >= NUM_BRIDGE_PIECES) { // skip invalid data
2324 GrfMsg(1, "BridgeChangeInfo: Table {} >= {}, skipping", tableid, NUM_BRIDGE_PIECES);
2325 for (uint8_t sprite = 0; sprite < SPRITES_PER_BRIDGE_PIECE; sprite++) buf.ReadDWord();
2326 continue;
2327 }
2328
2329 if (bridge->sprite_table[tableid] == nullptr) {
2330 bridge->sprite_table[tableid] = MallocT<PalSpriteID>(SPRITES_PER_BRIDGE_PIECE);
2331 }
2332
2333 for (uint8_t sprite = 0; sprite < SPRITES_PER_BRIDGE_PIECE; sprite++) {
2334 SpriteID image = buf.ReadWord();
2335 PaletteID pal = buf.ReadWord();
2336
2337 bridge->sprite_table[tableid][sprite].sprite = image;
2338 bridge->sprite_table[tableid][sprite].pal = pal;
2339
2340 MapSpriteMappingRecolour(&bridge->sprite_table[tableid][sprite]);
2341 }
2342 }
2343 break;
2344 }
2345
2346 case 0x0E: // Flags; bit 0 - disable far pillars
2347 bridge->flags = buf.ReadByte();
2348 break;
2349
2350 case 0x0F: // Long format year of availability (year since year 0)
2352 break;
2353
2354 case 0x10: // purchase string
2355 AddStringForMapping(GRFStringID{buf.ReadWord()}, &bridge->material);
2356 break;
2357
2358 case 0x11: // description of bridge with rails
2359 AddStringForMapping(GRFStringID{buf.ReadWord()}, &bridge->transport_name[0]);
2360 break;
2361
2362 case 0x12: // description of bridge with roads
2363 AddStringForMapping(GRFStringID{buf.ReadWord()}, &bridge->transport_name[1]);
2364 break;
2365
2366 case 0x13: // 16 bits cost multiplier
2367 bridge->price = buf.ReadWord();
2368 break;
2369
2370 default:
2371 ret = CIR_UNKNOWN;
2372 break;
2373 }
2374 }
2375
2376 return ret;
2377}
2378
2386{
2388
2389 switch (prop) {
2390 case 0x09:
2391 case 0x0B:
2392 case 0x0C:
2393 case 0x0D:
2394 case 0x0E:
2395 case 0x0F:
2396 case 0x11:
2397 case 0x14:
2398 case 0x15:
2399 case 0x16:
2400 case 0x18:
2401 case 0x19:
2402 case 0x1A:
2403 case 0x1B:
2404 case 0x1C:
2405 case 0x1D:
2406 case 0x1F:
2407 buf.ReadByte();
2408 break;
2409
2410 case 0x0A:
2411 case 0x10:
2412 case 0x12:
2413 case 0x13:
2414 case 0x21:
2415 case 0x22:
2416 buf.ReadWord();
2417 break;
2418
2419 case 0x1E:
2420 buf.ReadDWord();
2421 break;
2422
2423 case 0x17:
2424 for (uint j = 0; j < 4; j++) buf.ReadByte();
2425 break;
2426
2427 case 0x20: {
2428 uint8_t count = buf.ReadByte();
2429 for (uint8_t j = 0; j < count; j++) buf.ReadByte();
2430 break;
2431 }
2432
2433 case 0x23:
2434 buf.Skip(buf.ReadByte() * 2);
2435 break;
2436
2437 default:
2438 ret = CIR_UNKNOWN;
2439 break;
2440 }
2441 return ret;
2442}
2443
2452static ChangeInfoResult TownHouseChangeInfo(uint first, uint last, int prop, ByteReader &buf)
2453{
2455
2456 if (last > NUM_HOUSES_PER_GRF) {
2457 GrfMsg(1, "TownHouseChangeInfo: Too many houses loaded ({}), max ({}). Ignoring.", last, NUM_HOUSES_PER_GRF);
2458 return CIR_INVALID_ID;
2459 }
2460
2461 /* Allocate house specs if they haven't been allocated already. */
2462 if (_cur.grffile->housespec.size() < last) _cur.grffile->housespec.resize(last);
2463
2464 for (uint id = first; id < last; ++id) {
2465 auto &housespec = _cur.grffile->housespec[id];
2466
2467 if (prop != 0x08 && housespec == nullptr) {
2468 /* If the house property 08 is not yet set, ignore this property */
2470 if (cir > ret) ret = cir;
2471 continue;
2472 }
2473
2474 switch (prop) {
2475 case 0x08: { // Substitute building type, and definition of a new house
2476 uint8_t subs_id = buf.ReadByte();
2477 if (subs_id == 0xFF) {
2478 /* Instead of defining a new house, a substitute house id
2479 * of 0xFF disables the old house with the current id. */
2480 if (id < NEW_HOUSE_OFFSET) HouseSpec::Get(id)->enabled = false;
2481 continue;
2482 } else if (subs_id >= NEW_HOUSE_OFFSET) {
2483 /* The substitute id must be one of the original houses. */
2484 GrfMsg(2, "TownHouseChangeInfo: Attempt to use new house {} as substitute house for {}. Ignoring.", subs_id, id);
2485 continue;
2486 }
2487
2488 /* Allocate space for this house. */
2489 if (housespec == nullptr) {
2490 /* Only the first property 08 setting copies properties; if you later change it, properties will stay. */
2491 housespec = std::make_unique<HouseSpec>(*HouseSpec::Get(subs_id));
2492
2493 housespec->enabled = true;
2494 housespec->grf_prop.local_id = id;
2495 housespec->grf_prop.subst_id = subs_id;
2496 housespec->grf_prop.grfid = _cur.grffile->grfid;
2497 housespec->grf_prop.grffile = _cur.grffile;
2498 /* Set default colours for randomization, used if not overridden. */
2499 housespec->random_colour[0] = COLOUR_RED;
2500 housespec->random_colour[1] = COLOUR_BLUE;
2501 housespec->random_colour[2] = COLOUR_ORANGE;
2502 housespec->random_colour[3] = COLOUR_GREEN;
2503
2504 /* House flags 40 and 80 are exceptions; these flags are never set automatically. */
2505 housespec->building_flags.Reset(BuildingFlag::IsChurch).Reset(BuildingFlag::IsStadium);
2506
2507 /* Make sure that the third cargo type is valid in this
2508 * climate. This can cause problems when copying the properties
2509 * of a house that accepts food, where the new house is valid
2510 * in the temperate climate. */
2511 CargoType cargo_type = housespec->accepts_cargo[2];
2512 if (!IsValidCargoType(cargo_type)) cargo_type = GetCargoTypeByLabel(housespec->accepts_cargo_label[2]);
2513 if (!IsValidCargoType(cargo_type)) {
2514 housespec->cargo_acceptance[2] = 0;
2515 }
2516 }
2517 break;
2518 }
2519
2520 case 0x09: // Building flags
2521 housespec->building_flags = (BuildingFlags)buf.ReadByte();
2522 break;
2523
2524 case 0x0A: { // Availability years
2525 uint16_t years = buf.ReadWord();
2526 housespec->min_year = GB(years, 0, 8) > 150 ? CalendarTime::MAX_YEAR : CalendarTime::ORIGINAL_BASE_YEAR + GB(years, 0, 8);
2527 housespec->max_year = GB(years, 8, 8) > 150 ? CalendarTime::MAX_YEAR : CalendarTime::ORIGINAL_BASE_YEAR + GB(years, 8, 8);
2528 break;
2529 }
2530
2531 case 0x0B: // Population
2532 housespec->population = buf.ReadByte();
2533 break;
2534
2535 case 0x0C: // Mail generation multiplier
2536 housespec->mail_generation = buf.ReadByte();
2537 break;
2538
2539 case 0x0D: // Passenger acceptance
2540 case 0x0E: // Mail acceptance
2541 housespec->cargo_acceptance[prop - 0x0D] = buf.ReadByte();
2542 break;
2543
2544 case 0x0F: { // Goods/candy, food/fizzy drinks acceptance
2545 int8_t goods = buf.ReadByte();
2546
2547 /* If value of goods is negative, it means in fact food or, if in toyland, fizzy_drink acceptance.
2548 * Else, we have "standard" 3rd cargo type, goods or candy, for toyland once more */
2549 CargoType cargo_type = (goods >= 0) ? ((_settings_game.game_creation.landscape == LandscapeType::Toyland) ? GetCargoTypeByLabel(CT_CANDY) : GetCargoTypeByLabel(CT_GOODS)) :
2550 ((_settings_game.game_creation.landscape == LandscapeType::Toyland) ? GetCargoTypeByLabel(CT_FIZZY_DRINKS) : GetCargoTypeByLabel(CT_FOOD));
2551
2552 /* Make sure the cargo type is valid in this climate. */
2553 if (!IsValidCargoType(cargo_type)) goods = 0;
2554
2555 housespec->accepts_cargo[2] = cargo_type;
2556 housespec->accepts_cargo_label[2] = CT_INVALID;
2557 housespec->cargo_acceptance[2] = abs(goods); // but we do need positive value here
2558 break;
2559 }
2560
2561 case 0x10: // Local authority rating decrease on removal
2562 housespec->remove_rating_decrease = buf.ReadWord();
2563 break;
2564
2565 case 0x11: // Removal cost multiplier
2566 housespec->removal_cost = buf.ReadByte();
2567 break;
2568
2569 case 0x12: // Building name ID
2570 AddStringForMapping(GRFStringID{buf.ReadWord()}, &housespec->building_name);
2571 break;
2572
2573 case 0x13: // Building availability mask
2574 housespec->building_availability = (HouseZones)buf.ReadWord();
2575 break;
2576
2577 case 0x14: { // House callback mask
2578 auto mask = housespec->callback_mask.base();
2579 SB(mask, 0, 8, buf.ReadByte());
2580 housespec->callback_mask = HouseCallbackMasks{mask};
2581 break;
2582 }
2583
2584 case 0x15: { // House override byte
2585 uint8_t override = buf.ReadByte();
2586
2587 /* The house being overridden must be an original house. */
2588 if (override >= NEW_HOUSE_OFFSET) {
2589 GrfMsg(2, "TownHouseChangeInfo: Attempt to override new house {} with house id {}. Ignoring.", override, id);
2590 continue;
2591 }
2592
2593 _house_mngr.Add(id, _cur.grffile->grfid, override);
2594 break;
2595 }
2596
2597 case 0x16: // Periodic refresh multiplier
2598 housespec->processing_time = std::min<uint8_t>(buf.ReadByte(), 63u);
2599 break;
2600
2601 case 0x17: // Four random colours to use
2602 for (uint j = 0; j < 4; j++) housespec->random_colour[j] = static_cast<Colours>(GB(buf.ReadByte(), 0, 4));
2603 break;
2604
2605 case 0x18: // Relative probability of appearing
2606 housespec->probability = buf.ReadByte();
2607 break;
2608
2609 case 0x19: // Extra flags
2610 housespec->extra_flags = static_cast<HouseExtraFlags>(buf.ReadByte());
2611 break;
2612
2613 case 0x1A: // Animation frames
2614 housespec->animation.frames = buf.ReadByte();
2615 housespec->animation.status = GB(housespec->animation.frames, 7, 1);
2616 SB(housespec->animation.frames, 7, 1, 0);
2617 break;
2618
2619 case 0x1B: // Animation speed
2620 housespec->animation.speed = Clamp(buf.ReadByte(), 2, 16);
2621 break;
2622
2623 case 0x1C: // Class of the building type
2624 housespec->class_id = AllocateHouseClassID(buf.ReadByte(), _cur.grffile->grfid);
2625 break;
2626
2627 case 0x1D: { // Callback mask part 2
2628 auto mask = housespec->callback_mask.base();
2629 SB(mask, 8, 8, buf.ReadByte());
2630 housespec->callback_mask = HouseCallbackMasks{mask};
2631 break;
2632 }
2633
2634 case 0x1E: { // Accepted cargo types
2635 uint32_t cargotypes = buf.ReadDWord();
2636
2637 /* Check if the cargo types should not be changed */
2638 if (cargotypes == 0xFFFFFFFF) break;
2639
2640 for (uint j = 0; j < HOUSE_ORIGINAL_NUM_ACCEPTS; j++) {
2641 /* Get the cargo number from the 'list' */
2642 uint8_t cargo_part = GB(cargotypes, 8 * j, 8);
2643 CargoType cargo = GetCargoTranslation(cargo_part, _cur.grffile);
2644
2645 if (!IsValidCargoType(cargo)) {
2646 /* Disable acceptance of invalid cargo type */
2647 housespec->cargo_acceptance[j] = 0;
2648 } else {
2649 housespec->accepts_cargo[j] = cargo;
2650 }
2651 housespec->accepts_cargo_label[j] = CT_INVALID;
2652 }
2653 break;
2654 }
2655
2656 case 0x1F: // Minimum life span
2657 housespec->minimum_life = buf.ReadByte();
2658 break;
2659
2660 case 0x20: { // Cargo acceptance watch list
2661 uint8_t count = buf.ReadByte();
2662 for (uint8_t j = 0; j < count; j++) {
2663 CargoType cargo = GetCargoTranslation(buf.ReadByte(), _cur.grffile);
2664 if (IsValidCargoType(cargo)) SetBit(housespec->watched_cargoes, cargo);
2665 }
2666 break;
2667 }
2668
2669 case 0x21: // long introduction year
2670 housespec->min_year = TimerGameCalendar::Year{buf.ReadWord()};
2671 break;
2672
2673 case 0x22: // long maximum year
2674 housespec->max_year = TimerGameCalendar::Year{buf.ReadWord()};
2675 if (housespec->max_year == UINT16_MAX) housespec->max_year = CalendarTime::MAX_YEAR;
2676 break;
2677
2678 case 0x23: { // variable length cargo types accepted
2679 uint count = buf.ReadByte();
2680 if (count > lengthof(housespec->accepts_cargo)) {
2681 GRFError *error = DisableGrf(STR_NEWGRF_ERROR_LIST_PROPERTY_TOO_LONG);
2682 error->param_value[1] = prop;
2683 return CIR_DISABLED;
2684 }
2685 /* Always write the full accepts_cargo array, and check each index for being inside the
2686 * provided data. This ensures all values are properly initialized, and also avoids
2687 * any risks of array overrun. */
2688 for (uint i = 0; i < lengthof(housespec->accepts_cargo); i++) {
2689 if (i < count) {
2690 housespec->accepts_cargo[i] = GetCargoTranslation(buf.ReadByte(), _cur.grffile);
2691 housespec->cargo_acceptance[i] = buf.ReadByte();
2692 } else {
2693 housespec->accepts_cargo[i] = INVALID_CARGO;
2694 housespec->cargo_acceptance[i] = 0;
2695 }
2696 if (i < std::size(housespec->accepts_cargo_label)) housespec->accepts_cargo_label[i] = CT_INVALID;
2697 }
2698 break;
2699 }
2700
2701 default:
2702 ret = CIR_UNKNOWN;
2703 break;
2704 }
2705 }
2706
2707 return ret;
2708}
2709
2716/* static */ const LanguageMap *LanguageMap::GetLanguageMap(uint32_t grfid, uint8_t language_id)
2717{
2718 /* LanguageID "MAX_LANG", i.e. 7F is any. This language can't have a gender/case mapping, but has to be handled gracefully. */
2719 const GRFFile *grffile = GetFileByGRFID(grfid);
2720 if (grffile == nullptr) return nullptr;
2721
2722 auto it = grffile->language_map.find(language_id);
2723 if (it == std::end(grffile->language_map)) return nullptr;
2724
2725 return &it->second;
2726}
2727
2737template <typename T, typename TGetTableFunc>
2738static ChangeInfoResult LoadTranslationTable(uint first, uint last, ByteReader &buf, TGetTableFunc gettable, std::string_view name)
2739{
2740 if (first != 0) {
2741 GrfMsg(1, "LoadTranslationTable: {} translation table must start at zero", name);
2742 return CIR_INVALID_ID;
2743 }
2744
2745 std::vector<T> &translation_table = gettable(*_cur.grffile);
2746 translation_table.clear();
2747 translation_table.reserve(last);
2748 for (uint id = first; id < last; ++id) {
2749 translation_table.push_back(T(std::byteswap(buf.ReadDWord())));
2750 }
2751
2752 GRFFile *grf_override = GetCurrentGRFOverride();
2753 if (grf_override != nullptr) {
2754 /* GRF override is present, copy the translation table to the overridden GRF as well. */
2755 GrfMsg(1, "LoadTranslationTable: Copying {} translation table to override GRFID '{}'", name, std::byteswap(grf_override->grfid));
2756 std::vector<T> &override_table = gettable(*grf_override);
2757 override_table = translation_table;
2758 }
2759
2760 return CIR_SUCCESS;
2761}
2762
2769static std::string ReadDWordAsString(ByteReader &reader)
2770{
2771 std::string output;
2772 for (int i = 0; i < 4; i++) output.push_back(reader.ReadByte());
2773 return StrMakeValid(output);
2774}
2775
2784static ChangeInfoResult GlobalVarChangeInfo(uint first, uint last, int prop, ByteReader &buf)
2785{
2786 /* Properties which are handled as a whole */
2787 switch (prop) {
2788 case 0x09: // Cargo Translation Table; loading during both reservation and activation stage (in case it is selected depending on defined cargos)
2789 return LoadTranslationTable<CargoLabel>(first, last, buf, [](GRFFile &grf) -> std::vector<CargoLabel> & { return grf.cargo_list; }, "Cargo");
2790
2791 case 0x12: // Rail type translation table; loading during both reservation and activation stage (in case it is selected depending on defined railtypes)
2792 return LoadTranslationTable<RailTypeLabel>(first, last, buf, [](GRFFile &grf) -> std::vector<RailTypeLabel> & { return grf.railtype_list; }, "Rail type");
2793
2794 case 0x16: // Road type translation table; loading during both reservation and activation stage (in case it is selected depending on defined roadtypes)
2795 return LoadTranslationTable<RoadTypeLabel>(first, last, buf, [](GRFFile &grf) -> std::vector<RoadTypeLabel> & { return grf.roadtype_list; }, "Road type");
2796
2797 case 0x17: // Tram type translation table; loading during both reservation and activation stage (in case it is selected depending on defined tramtypes)
2798 return LoadTranslationTable<RoadTypeLabel>(first, last, buf, [](GRFFile &grf) -> std::vector<RoadTypeLabel> & { return grf.tramtype_list; }, "Tram type");
2799
2800 default:
2801 break;
2802 }
2803
2804 /* Properties which are handled per item */
2806 for (uint id = first; id < last; ++id) {
2807 switch (prop) {
2808 case 0x08: { // Cost base factor
2809 int factor = buf.ReadByte();
2810
2811 if (id < PR_END) {
2812 _cur.grffile->price_base_multipliers[id] = std::min<int>(factor - 8, MAX_PRICE_MODIFIER);
2813 } else {
2814 GrfMsg(1, "GlobalVarChangeInfo: Price {} out of range, ignoring", id);
2815 }
2816 break;
2817 }
2818
2819 case 0x0A: { // Currency display names
2820 uint curidx = GetNewgrfCurrencyIdConverted(id);
2821 if (curidx < CURRENCY_END) {
2822 AddStringForMapping(GRFStringID{buf.ReadWord()}, [curidx](StringID str) {
2823 _currency_specs[curidx].name = str;
2824 _currency_specs[curidx].code.clear();
2825 });
2826 } else {
2827 buf.ReadWord();
2828 }
2829 break;
2830 }
2831
2832 case 0x0B: { // Currency multipliers
2833 uint curidx = GetNewgrfCurrencyIdConverted(id);
2834 uint32_t rate = buf.ReadDWord();
2835
2836 if (curidx < CURRENCY_END) {
2837 /* TTDPatch uses a multiple of 1000 for its conversion calculations,
2838 * which OTTD does not. For this reason, divide grf value by 1000,
2839 * to be compatible */
2840 _currency_specs[curidx].rate = rate / 1000;
2841 } else {
2842 GrfMsg(1, "GlobalVarChangeInfo: Currency multipliers {} out of range, ignoring", curidx);
2843 }
2844 break;
2845 }
2846
2847 case 0x0C: { // Currency options
2848 uint curidx = GetNewgrfCurrencyIdConverted(id);
2849 uint16_t options = buf.ReadWord();
2850
2851 if (curidx < CURRENCY_END) {
2852 _currency_specs[curidx].separator.clear();
2853 _currency_specs[curidx].separator.push_back(GB(options, 0, 8));
2854 /* By specifying only one bit, we prevent errors,
2855 * since newgrf specs said that only 0 and 1 can be set for symbol_pos */
2856 _currency_specs[curidx].symbol_pos = GB(options, 8, 1);
2857 } else {
2858 GrfMsg(1, "GlobalVarChangeInfo: Currency option {} out of range, ignoring", curidx);
2859 }
2860 break;
2861 }
2862
2863 case 0x0D: { // Currency prefix symbol
2864 uint curidx = GetNewgrfCurrencyIdConverted(id);
2865 std::string prefix = ReadDWordAsString(buf);
2866
2867 if (curidx < CURRENCY_END) {
2868 _currency_specs[curidx].prefix = prefix;
2869 } else {
2870 GrfMsg(1, "GlobalVarChangeInfo: Currency symbol {} out of range, ignoring", curidx);
2871 }
2872 break;
2873 }
2874
2875 case 0x0E: { // Currency suffix symbol
2876 uint curidx = GetNewgrfCurrencyIdConverted(id);
2877 std::string suffix = ReadDWordAsString(buf);
2878
2879 if (curidx < CURRENCY_END) {
2880 _currency_specs[curidx].suffix = suffix;
2881 } else {
2882 GrfMsg(1, "GlobalVarChangeInfo: Currency symbol {} out of range, ignoring", curidx);
2883 }
2884 break;
2885 }
2886
2887 case 0x0F: { // Euro introduction dates
2888 uint curidx = GetNewgrfCurrencyIdConverted(id);
2889 TimerGameCalendar::Year year_euro{buf.ReadWord()};
2890
2891 if (curidx < CURRENCY_END) {
2892 _currency_specs[curidx].to_euro = year_euro;
2893 } else {
2894 GrfMsg(1, "GlobalVarChangeInfo: Euro intro date {} out of range, ignoring", curidx);
2895 }
2896 break;
2897 }
2898
2899 case 0x10: // Snow line height table
2900 if (last > 1 || IsSnowLineSet()) {
2901 GrfMsg(1, "GlobalVarChangeInfo: The snowline can only be set once ({})", last);
2902 } else if (buf.Remaining() < SNOW_LINE_MONTHS * SNOW_LINE_DAYS) {
2903 GrfMsg(1, "GlobalVarChangeInfo: Not enough entries set in the snowline table ({})", buf.Remaining());
2904 } else {
2905 auto snow_line = std::make_unique<SnowLine>();
2906
2907 for (uint i = 0; i < SNOW_LINE_MONTHS; i++) {
2908 for (uint j = 0; j < SNOW_LINE_DAYS; j++) {
2909 uint8_t &level = snow_line->table[i][j];
2910 level = buf.ReadByte();
2911 if (_cur.grffile->grf_version >= 8) {
2912 if (level != 0xFF) level = level * (1 + _settings_game.construction.map_height_limit) / 256;
2913 } else {
2914 if (level >= 128) {
2915 /* no snow */
2916 level = 0xFF;
2917 } else {
2918 level = level * (1 + _settings_game.construction.map_height_limit) / 128;
2919 }
2920 }
2921
2922 snow_line->highest_value = std::max(snow_line->highest_value, level);
2923 snow_line->lowest_value = std::min(snow_line->lowest_value, level);
2924 }
2925 }
2926 SetSnowLine(std::move(snow_line));
2927 }
2928 break;
2929
2930 case 0x11: // GRF match for engine allocation
2931 /* This is loaded during the reservation stage, so just skip it here. */
2932 /* Each entry is 8 bytes. */
2933 buf.Skip(8);
2934 break;
2935
2936 case 0x13: // Gender translation table
2937 case 0x14: // Case translation table
2938 case 0x15: { // Plural form translation
2939 uint curidx = id; // The current index, i.e. language.
2940 const LanguageMetadata *lang = curidx < MAX_LANG ? GetLanguage(curidx) : nullptr;
2941 if (lang == nullptr) {
2942 GrfMsg(1, "GlobalVarChangeInfo: Language {} is not known, ignoring", curidx);
2943 /* Skip over the data. */
2944 if (prop == 0x15) {
2945 buf.ReadByte();
2946 } else {
2947 while (buf.ReadByte() != 0) {
2948 buf.ReadString();
2949 }
2950 }
2951 break;
2952 }
2953
2954 if (prop == 0x15) {
2955 uint plural_form = buf.ReadByte();
2956 if (plural_form >= LANGUAGE_MAX_PLURAL) {
2957 GrfMsg(1, "GlobalVarChanceInfo: Plural form {} is out of range, ignoring", plural_form);
2958 } else {
2959 _cur.grffile->language_map[curidx].plural_form = plural_form;
2960 }
2961 break;
2962 }
2963
2964 uint8_t newgrf_id = buf.ReadByte(); // The NewGRF (custom) identifier.
2965 while (newgrf_id != 0) {
2966 std::string_view name = buf.ReadString(); // The name for the OpenTTD identifier.
2967
2968 /* We'll just ignore the UTF8 identifier character. This is (fairly)
2969 * safe as OpenTTD's strings gender/cases are usually in ASCII which
2970 * is just a subset of UTF8, or they need the bigger UTF8 characters
2971 * such as Cyrillic. Thus we will simply assume they're all UTF8. */
2972 char32_t c;
2973 size_t len = Utf8Decode(&c, name.data());
2974 if (c == NFO_UTF8_IDENTIFIER) name = name.substr(len);
2975
2977 map.newgrf_id = newgrf_id;
2978 if (prop == 0x13) {
2979 map.openttd_id = lang->GetGenderIndex(name.data());
2980 if (map.openttd_id >= MAX_NUM_GENDERS) {
2981 GrfMsg(1, "GlobalVarChangeInfo: Gender name {} is not known, ignoring", StrMakeValid(name));
2982 } else {
2983 _cur.grffile->language_map[curidx].gender_map.push_back(map);
2984 }
2985 } else {
2986 map.openttd_id = lang->GetCaseIndex(name.data());
2987 if (map.openttd_id >= MAX_NUM_CASES) {
2988 GrfMsg(1, "GlobalVarChangeInfo: Case name {} is not known, ignoring", StrMakeValid(name));
2989 } else {
2990 _cur.grffile->language_map[curidx].case_map.push_back(map);
2991 }
2992 }
2993 newgrf_id = buf.ReadByte();
2994 }
2995 break;
2996 }
2997
2998 default:
2999 ret = CIR_UNKNOWN;
3000 break;
3001 }
3002 }
3003
3004 return ret;
3005}
3006
3007static ChangeInfoResult GlobalVarReserveInfo(uint first, uint last, int prop, ByteReader &buf)
3008{
3009 /* Properties which are handled as a whole */
3010 switch (prop) {
3011 case 0x09: // Cargo Translation Table; loading during both reservation and activation stage (in case it is selected depending on defined cargos)
3012 return LoadTranslationTable<CargoLabel>(first, last, buf, [](GRFFile &grf) -> std::vector<CargoLabel> & { return grf.cargo_list; }, "Cargo");
3013
3014 case 0x12: // Rail type translation table; loading during both reservation and activation stage (in case it is selected depending on defined railtypes)
3015 return LoadTranslationTable<RailTypeLabel>(first, last, buf, [](GRFFile &grf) -> std::vector<RailTypeLabel> & { return grf.railtype_list; }, "Rail type");
3016
3017 case 0x16: // Road type translation table; loading during both reservation and activation stage (in case it is selected depending on defined roadtypes)
3018 return LoadTranslationTable<RoadTypeLabel>(first, last, buf, [](GRFFile &grf) -> std::vector<RoadTypeLabel> & { return grf.roadtype_list; }, "Road type");
3019
3020 case 0x17: // Tram type translation table; loading during both reservation and activation stage (in case it is selected depending on defined tramtypes)
3021 return LoadTranslationTable<RoadTypeLabel>(first, last, buf, [](GRFFile &grf) -> std::vector<RoadTypeLabel> & { return grf.tramtype_list; }, "Tram type");
3022
3023 default:
3024 break;
3025 }
3026
3027 /* Properties which are handled per item */
3029
3030 for (uint id = first; id < last; ++id) {
3031 switch (prop) {
3032 case 0x08: // Cost base factor
3033 case 0x15: // Plural form translation
3034 buf.ReadByte();
3035 break;
3036
3037 case 0x0A: // Currency display names
3038 case 0x0C: // Currency options
3039 case 0x0F: // Euro introduction dates
3040 buf.ReadWord();
3041 break;
3042
3043 case 0x0B: // Currency multipliers
3044 case 0x0D: // Currency prefix symbol
3045 case 0x0E: // Currency suffix symbol
3046 buf.ReadDWord();
3047 break;
3048
3049 case 0x10: // Snow line height table
3050 buf.Skip(SNOW_LINE_MONTHS * SNOW_LINE_DAYS);
3051 break;
3052
3053 case 0x11: { // GRF match for engine allocation
3054 uint32_t s = buf.ReadDWord();
3055 uint32_t t = buf.ReadDWord();
3056 SetNewGRFOverride(s, t);
3057 break;
3058 }
3059
3060 case 0x13: // Gender translation table
3061 case 0x14: // Case translation table
3062 while (buf.ReadByte() != 0) {
3063 buf.ReadString();
3064 }
3065 break;
3066
3067 default:
3068 ret = CIR_UNKNOWN;
3069 break;
3070 }
3071 }
3072
3073 return ret;
3074}
3075
3076
3085static ChangeInfoResult CargoChangeInfo(uint first, uint last, int prop, ByteReader &buf)
3086{
3088
3089 if (last > NUM_CARGO) {
3090 GrfMsg(2, "CargoChangeInfo: Cargo type {} out of range (max {})", last, NUM_CARGO - 1);
3091 return CIR_INVALID_ID;
3092 }
3093
3094 for (uint id = first; id < last; ++id) {
3095 CargoSpec *cs = CargoSpec::Get(id);
3096
3097 switch (prop) {
3098 case 0x08: // Bit number of cargo
3099 cs->bitnum = buf.ReadByte();
3100 if (cs->IsValid()) {
3101 cs->grffile = _cur.grffile;
3102 SetBit(_cargo_mask, id);
3103 } else {
3104 ClrBit(_cargo_mask, id);
3105 }
3107 break;
3108
3109 case 0x09: // String ID for cargo type name
3110 AddStringForMapping(GRFStringID{buf.ReadWord()}, &cs->name);
3111 break;
3112
3113 case 0x0A: // String for 1 unit of cargo
3114 AddStringForMapping(GRFStringID{buf.ReadWord()}, &cs->name_single);
3115 break;
3116
3117 case 0x0B: // String for singular quantity of cargo (e.g. 1 tonne of coal)
3118 case 0x1B: // String for cargo units
3119 /* String for units of cargo. This is different in OpenTTD
3120 * (e.g. tonnes) to TTDPatch (e.g. {COMMA} tonne of coal).
3121 * Property 1B is used to set OpenTTD's behaviour. */
3122 AddStringForMapping(GRFStringID{buf.ReadWord()}, &cs->units_volume);
3123 break;
3124
3125 case 0x0C: // String for plural quantity of cargo (e.g. 10 tonnes of coal)
3126 case 0x1C: // String for any amount of cargo
3127 /* Strings for an amount of cargo. This is different in OpenTTD
3128 * (e.g. {WEIGHT} of coal) to TTDPatch (e.g. {COMMA} tonnes of coal).
3129 * Property 1C is used to set OpenTTD's behaviour. */
3130 AddStringForMapping(GRFStringID{buf.ReadWord()}, &cs->quantifier);
3131 break;
3132
3133 case 0x0D: // String for two letter cargo abbreviation
3134 AddStringForMapping(GRFStringID{buf.ReadWord()}, &cs->abbrev);
3135 break;
3136
3137 case 0x0E: // Sprite ID for cargo icon
3138 cs->sprite = buf.ReadWord();
3139 break;
3140
3141 case 0x0F: // Weight of one unit of cargo
3142 cs->weight = buf.ReadByte();
3143 break;
3144
3145 case 0x10: // Used for payment calculation
3146 cs->transit_periods[0] = buf.ReadByte();
3147 break;
3148
3149 case 0x11: // Used for payment calculation
3150 cs->transit_periods[1] = buf.ReadByte();
3151 break;
3152
3153 case 0x12: // Base cargo price
3154 cs->initial_payment = buf.ReadDWord();
3155 break;
3156
3157 case 0x13: // Colour for station rating bars
3158 cs->rating_colour = buf.ReadByte();
3159 break;
3160
3161 case 0x14: // Colour for cargo graph
3162 cs->legend_colour = buf.ReadByte();
3163 break;
3164
3165 case 0x15: // Freight status
3166 cs->is_freight = (buf.ReadByte() != 0);
3167 break;
3168
3169 case 0x16: // Cargo classes
3170 cs->classes = buf.ReadWord();
3171 break;
3172
3173 case 0x17: // Cargo label
3174 cs->label = CargoLabel{std::byteswap(buf.ReadDWord())};
3176 break;
3177
3178 case 0x18: { // Town growth substitute type
3179 uint8_t substitute_type = buf.ReadByte();
3180
3181 switch (substitute_type) {
3182 case 0x00: cs->town_acceptance_effect = TAE_PASSENGERS; break;
3183 case 0x02: cs->town_acceptance_effect = TAE_MAIL; break;
3184 case 0x05: cs->town_acceptance_effect = TAE_GOODS; break;
3185 case 0x09: cs->town_acceptance_effect = TAE_WATER; break;
3186 case 0x0B: cs->town_acceptance_effect = TAE_FOOD; break;
3187 default:
3188 GrfMsg(1, "CargoChangeInfo: Unknown town growth substitute value {}, setting to none.", substitute_type);
3189 [[fallthrough]];
3190 case 0xFF: cs->town_acceptance_effect = TAE_NONE; break;
3191 }
3192 break;
3193 }
3194
3195 case 0x19: // Town growth coefficient
3196 buf.ReadWord();
3197 break;
3198
3199 case 0x1A: // Bitmask of callbacks to use
3200 cs->callback_mask = static_cast<CargoCallbackMasks>(buf.ReadByte());
3201 break;
3202
3203 case 0x1D: // Vehicle capacity muliplier
3204 cs->multiplier = std::max<uint16_t>(1u, buf.ReadWord());
3205 break;
3206
3207 case 0x1E: { // Town production substitute type
3208 uint8_t substitute_type = buf.ReadByte();
3209
3210 switch (substitute_type) {
3211 case 0x00: cs->town_production_effect = TPE_PASSENGERS; break;
3212 case 0x02: cs->town_production_effect = TPE_MAIL; break;
3213 default:
3214 GrfMsg(1, "CargoChangeInfo: Unknown town production substitute value {}, setting to none.", substitute_type);
3215 [[fallthrough]];
3216 case 0xFF: cs->town_production_effect = TPE_NONE; break;
3217 }
3218 break;
3219 }
3220
3221 case 0x1F: // Town production multiplier
3222 cs->town_production_multiplier = std::max<uint16_t>(1U, buf.ReadWord());
3223 break;
3224
3225 default:
3226 ret = CIR_UNKNOWN;
3227 break;
3228 }
3229 }
3230
3231 return ret;
3232}
3233
3234
3243static ChangeInfoResult SoundEffectChangeInfo(uint first, uint last, int prop, ByteReader &buf)
3244{
3246
3247 if (_cur.grffile->sound_offset == 0) {
3248 GrfMsg(1, "SoundEffectChangeInfo: No effects defined, skipping");
3249 return CIR_INVALID_ID;
3250 }
3251
3252 if (last - ORIGINAL_SAMPLE_COUNT > _cur.grffile->num_sounds) {
3253 GrfMsg(1, "SoundEffectChangeInfo: Attempting to change undefined sound effect ({}), max ({}). Ignoring.", last, ORIGINAL_SAMPLE_COUNT + _cur.grffile->num_sounds);
3254 return CIR_INVALID_ID;
3255 }
3256
3257 for (uint id = first; id < last; ++id) {
3258 SoundEntry *sound = GetSound(first + _cur.grffile->sound_offset - ORIGINAL_SAMPLE_COUNT);
3259
3260 switch (prop) {
3261 case 0x08: // Relative volume
3262 sound->volume = Clamp(buf.ReadByte(), 0, SOUND_EFFECT_MAX_VOLUME);
3263 break;
3264
3265 case 0x09: // Priority
3266 sound->priority = buf.ReadByte();
3267 break;
3268
3269 case 0x0A: { // Override old sound
3270 SoundID orig_sound = buf.ReadByte();
3271
3272 if (orig_sound >= ORIGINAL_SAMPLE_COUNT) {
3273 GrfMsg(1, "SoundEffectChangeInfo: Original sound {} not defined (max {})", orig_sound, ORIGINAL_SAMPLE_COUNT);
3274 } else {
3275 SoundEntry *old_sound = GetSound(orig_sound);
3276
3277 /* Literally copy the data of the new sound over the original */
3278 *old_sound = *sound;
3279 }
3280 break;
3281 }
3282
3283 default:
3284 ret = CIR_UNKNOWN;
3285 break;
3286 }
3287 }
3288
3289 return ret;
3290}
3291
3299{
3301
3302 switch (prop) {
3303 case 0x09:
3304 case 0x0D:
3305 case 0x0E:
3306 case 0x10:
3307 case 0x11:
3308 case 0x12:
3309 buf.ReadByte();
3310 break;
3311
3312 case 0x0A:
3313 case 0x0B:
3314 case 0x0C:
3315 case 0x0F:
3316 buf.ReadWord();
3317 break;
3318
3319 case 0x13:
3320 buf.Skip(buf.ReadByte() * 2);
3321 break;
3322
3323 default:
3324 ret = CIR_UNKNOWN;
3325 break;
3326 }
3327 return ret;
3328}
3329
3338static ChangeInfoResult IndustrytilesChangeInfo(uint first, uint last, int prop, ByteReader &buf)
3339{
3341
3342 if (last > NUM_INDUSTRYTILES_PER_GRF) {
3343 GrfMsg(1, "IndustryTilesChangeInfo: Too many industry tiles loaded ({}), max ({}). Ignoring.", last, NUM_INDUSTRYTILES_PER_GRF);
3344 return CIR_INVALID_ID;
3345 }
3346
3347 /* Allocate industry tile specs if they haven't been allocated already. */
3348 if (_cur.grffile->indtspec.size() < last) _cur.grffile->indtspec.resize(last);
3349
3350 for (uint id = first; id < last; ++id) {
3351 auto &tsp = _cur.grffile->indtspec[id];
3352
3353 if (prop != 0x08 && tsp == nullptr) {
3355 if (cir > ret) ret = cir;
3356 continue;
3357 }
3358
3359 switch (prop) {
3360 case 0x08: { // Substitute industry tile type
3361 uint8_t subs_id = buf.ReadByte();
3362 if (subs_id >= NEW_INDUSTRYTILEOFFSET) {
3363 /* The substitute id must be one of the original industry tile. */
3364 GrfMsg(2, "IndustryTilesChangeInfo: Attempt to use new industry tile {} as substitute industry tile for {}. Ignoring.", subs_id, id);
3365 continue;
3366 }
3367
3368 /* Allocate space for this industry. */
3369 if (tsp == nullptr) {
3370 tsp = std::make_unique<IndustryTileSpec>(_industry_tile_specs[subs_id]);
3371
3372 tsp->enabled = true;
3373
3374 /* A copied tile should not have the animation infos copied too.
3375 * The anim_state should be left untouched, though
3376 * It is up to the author to animate them */
3377 tsp->anim_production = INDUSTRYTILE_NOANIM;
3378 tsp->anim_next = INDUSTRYTILE_NOANIM;
3379
3380 tsp->grf_prop.local_id = id;
3381 tsp->grf_prop.subst_id = subs_id;
3382 tsp->grf_prop.grfid = _cur.grffile->grfid;
3383 tsp->grf_prop.grffile = _cur.grffile;
3384 _industile_mngr.AddEntityID(id, _cur.grffile->grfid, subs_id); // pre-reserve the tile slot
3385 }
3386 break;
3387 }
3388
3389 case 0x09: { // Industry tile override
3390 uint8_t ovrid = buf.ReadByte();
3391
3392 /* The industry being overridden must be an original industry. */
3393 if (ovrid >= NEW_INDUSTRYTILEOFFSET) {
3394 GrfMsg(2, "IndustryTilesChangeInfo: Attempt to override new industry tile {} with industry tile id {}. Ignoring.", ovrid, id);
3395 continue;
3396 }
3397
3398 _industile_mngr.Add(id, _cur.grffile->grfid, ovrid);
3399 break;
3400 }
3401
3402 case 0x0A: // Tile acceptance
3403 case 0x0B:
3404 case 0x0C: {
3405 uint16_t acctp = buf.ReadWord();
3406 tsp->accepts_cargo[prop - 0x0A] = GetCargoTranslation(GB(acctp, 0, 8), _cur.grffile);
3407 tsp->acceptance[prop - 0x0A] = Clamp(GB(acctp, 8, 8), 0, 16);
3408 tsp->accepts_cargo_label[prop - 0x0A] = CT_INVALID;
3409 break;
3410 }
3411
3412 case 0x0D: // Land shape flags
3413 tsp->slopes_refused = (Slope)buf.ReadByte();
3414 break;
3415
3416 case 0x0E: // Callback mask
3417 tsp->callback_mask = static_cast<IndustryTileCallbackMasks>(buf.ReadByte());
3418 break;
3419
3420 case 0x0F: // Animation information
3421 tsp->animation.frames = buf.ReadByte();
3422 tsp->animation.status = buf.ReadByte();
3423 break;
3424
3425 case 0x10: // Animation speed
3426 tsp->animation.speed = buf.ReadByte();
3427 break;
3428
3429 case 0x11: // Triggers for callback 25
3430 tsp->animation.triggers = buf.ReadByte();
3431 break;
3432
3433 case 0x12: // Special flags
3434 tsp->special_flags = (IndustryTileSpecialFlags)buf.ReadByte();
3435 break;
3436
3437 case 0x13: { // variable length cargo acceptance
3438 uint8_t num_cargoes = buf.ReadByte();
3439 if (num_cargoes > std::size(tsp->acceptance)) {
3440 GRFError *error = DisableGrf(STR_NEWGRF_ERROR_LIST_PROPERTY_TOO_LONG);
3441 error->param_value[1] = prop;
3442 return CIR_DISABLED;
3443 }
3444 for (uint i = 0; i < std::size(tsp->acceptance); i++) {
3445 if (i < num_cargoes) {
3446 tsp->accepts_cargo[i] = GetCargoTranslation(buf.ReadByte(), _cur.grffile);
3447 /* Tile acceptance can be negative to counteract the INDTILE_SPECIAL_ACCEPTS_ALL_CARGO flag */
3448 tsp->acceptance[i] = (int8_t)buf.ReadByte();
3449 } else {
3450 tsp->accepts_cargo[i] = INVALID_CARGO;
3451 tsp->acceptance[i] = 0;
3452 }
3453 if (i < std::size(tsp->accepts_cargo_label)) tsp->accepts_cargo_label[i] = CT_INVALID;
3454 }
3455 break;
3456 }
3457
3458 default:
3459 ret = CIR_UNKNOWN;
3460 break;
3461 }
3462 }
3463
3464 return ret;
3465}
3466
3474{
3476
3477 switch (prop) {
3478 case 0x09:
3479 case 0x0B:
3480 case 0x0F:
3481 case 0x12:
3482 case 0x13:
3483 case 0x14:
3484 case 0x17:
3485 case 0x18:
3486 case 0x19:
3487 case 0x21:
3488 case 0x22:
3489 buf.ReadByte();
3490 break;
3491
3492 case 0x0C:
3493 case 0x0D:
3494 case 0x0E:
3495 case 0x10: // INDUSTRY_ORIGINAL_NUM_OUTPUTS bytes
3496 case 0x1B:
3497 case 0x1F:
3498 case 0x24:
3499 buf.ReadWord();
3500 break;
3501
3502 case 0x11: // INDUSTRY_ORIGINAL_NUM_INPUTS bytes + 1
3503 case 0x1A:
3504 case 0x1C:
3505 case 0x1D:
3506 case 0x1E:
3507 case 0x20:
3508 case 0x23:
3509 buf.ReadDWord();
3510 break;
3511
3512 case 0x0A: {
3513 uint8_t num_table = buf.ReadByte();
3514 for (uint8_t j = 0; j < num_table; j++) {
3515 for (uint k = 0;; k++) {
3516 uint8_t x = buf.ReadByte();
3517 if (x == 0xFE && k == 0) {
3518 buf.ReadByte();
3519 buf.ReadByte();
3520 break;
3521 }
3522
3523 uint8_t y = buf.ReadByte();
3524 if (x == 0 && y == 0x80) break;
3525
3526 uint8_t gfx = buf.ReadByte();
3527 if (gfx == 0xFE) buf.ReadWord();
3528 }
3529 }
3530 break;
3531 }
3532
3533 case 0x16:
3534 for (uint8_t j = 0; j < INDUSTRY_ORIGINAL_NUM_INPUTS; j++) buf.ReadByte();
3535 break;
3536
3537 case 0x15:
3538 case 0x25:
3539 case 0x26:
3540 case 0x27:
3541 buf.Skip(buf.ReadByte());
3542 break;
3543
3544 case 0x28: {
3545 int num_inputs = buf.ReadByte();
3546 int num_outputs = buf.ReadByte();
3547 buf.Skip(num_inputs * num_outputs * 2);
3548 break;
3549 }
3550
3551 default:
3552 ret = CIR_UNKNOWN;
3553 break;
3554 }
3555 return ret;
3556}
3557
3564{
3565 const size_t size = layout.size();
3566 if (size == 0) return false;
3567
3568 for (size_t i = 0; i < size - 1; i++) {
3569 for (size_t j = i + 1; j < size; j++) {
3570 if (layout[i].ti.x == layout[j].ti.x &&
3571 layout[i].ti.y == layout[j].ti.y) {
3572 return false;
3573 }
3574 }
3575 }
3576
3577 bool have_regular_tile = false;
3578 for (const auto &tilelayout : layout) {
3579 if (tilelayout.gfx != GFX_WATERTILE_SPECIALCHECK) {
3580 have_regular_tile = true;
3581 break;
3582 }
3583 }
3584
3585 return have_regular_tile;
3586}
3587
3596static ChangeInfoResult IndustriesChangeInfo(uint first, uint last, int prop, ByteReader &buf)
3597{
3599
3600 if (last > NUM_INDUSTRYTYPES_PER_GRF) {
3601 GrfMsg(1, "IndustriesChangeInfo: Too many industries loaded ({}), max ({}). Ignoring.", last, NUM_INDUSTRYTYPES_PER_GRF);
3602 return CIR_INVALID_ID;
3603 }
3604
3605 /* Allocate industry specs if they haven't been allocated already. */
3606 if (_cur.grffile->industryspec.size() < last) _cur.grffile->industryspec.resize(last);
3607
3608 for (uint id = first; id < last; ++id) {
3609 auto &indsp = _cur.grffile->industryspec[id];
3610
3611 if (prop != 0x08 && indsp == nullptr) {
3613 if (cir > ret) ret = cir;
3614 continue;
3615 }
3616
3617 switch (prop) {
3618 case 0x08: { // Substitute industry type
3619 uint8_t subs_id = buf.ReadByte();
3620 if (subs_id == 0xFF) {
3621 /* Instead of defining a new industry, a substitute industry id
3622 * of 0xFF disables the old industry with the current id. */
3623 _industry_specs[id].enabled = false;
3624 continue;
3625 } else if (subs_id >= NEW_INDUSTRYOFFSET) {
3626 /* The substitute id must be one of the original industry. */
3627 GrfMsg(2, "_industry_specs: Attempt to use new industry {} as substitute industry for {}. Ignoring.", subs_id, id);
3628 continue;
3629 }
3630
3631 /* Allocate space for this industry.
3632 * Only need to do it once. If ever it is called again, it should not
3633 * do anything */
3634 if (indsp == nullptr) {
3635 indsp = std::make_unique<IndustrySpec>(_origin_industry_specs[subs_id]);
3636
3637 indsp->enabled = true;
3638 indsp->grf_prop.local_id = id;
3639 indsp->grf_prop.subst_id = subs_id;
3640 indsp->grf_prop.grfid = _cur.grffile->grfid;
3641 indsp->grf_prop.grffile = _cur.grffile;
3642 /* If the grf industry needs to check its surrounding upon creation, it should
3643 * rely on callbacks, not on the original placement functions */
3644 indsp->check_proc = CHECK_NOTHING;
3645 }
3646 break;
3647 }
3648
3649 case 0x09: { // Industry type override
3650 uint8_t ovrid = buf.ReadByte();
3651
3652 /* The industry being overridden must be an original industry. */
3653 if (ovrid >= NEW_INDUSTRYOFFSET) {
3654 GrfMsg(2, "IndustriesChangeInfo: Attempt to override new industry {} with industry id {}. Ignoring.", ovrid, id);
3655 continue;
3656 }
3657 indsp->grf_prop.override = ovrid;
3658 _industry_mngr.Add(id, _cur.grffile->grfid, ovrid);
3659 break;
3660 }
3661
3662 case 0x0A: { // Set industry layout(s)
3663 uint8_t new_num_layouts = buf.ReadByte();
3664 uint32_t definition_size = buf.ReadDWord();
3665 uint32_t bytes_read = 0;
3666 std::vector<IndustryTileLayout> new_layouts;
3667 IndustryTileLayout layout;
3668
3669 for (uint8_t j = 0; j < new_num_layouts; j++) {
3670 layout.clear();
3671 layout.reserve(new_num_layouts);
3672
3673 for (uint k = 0;; k++) {
3674 if (bytes_read >= definition_size) {
3675 GrfMsg(3, "IndustriesChangeInfo: Incorrect size for industry tile layout definition for industry {}.", id);
3676 /* Avoid warning twice */
3677 definition_size = UINT32_MAX;
3678 }
3679
3680 IndustryTileLayoutTile &it = layout.emplace_back();
3681
3682 it.ti.x = buf.ReadByte(); // Offsets from northermost tile
3683 ++bytes_read;
3684
3685 if (it.ti.x == 0xFE && k == 0) {
3686 /* This means we have to borrow the layout from an old industry */
3687 IndustryType type = buf.ReadByte();
3688 uint8_t laynbr = buf.ReadByte();
3689 bytes_read += 2;
3690
3691 if (type >= lengthof(_origin_industry_specs)) {
3692 GrfMsg(1, "IndustriesChangeInfo: Invalid original industry number for layout import, industry {}", id);
3693 DisableGrf(STR_NEWGRF_ERROR_INVALID_ID);
3694 return CIR_DISABLED;
3695 }
3696 if (laynbr >= _origin_industry_specs[type].layouts.size()) {
3697 GrfMsg(1, "IndustriesChangeInfo: Invalid original industry layout index for layout import, industry {}", id);
3698 DisableGrf(STR_NEWGRF_ERROR_INVALID_ID);
3699 return CIR_DISABLED;
3700 }
3701 layout = _origin_industry_specs[type].layouts[laynbr];
3702 break;
3703 }
3704
3705 it.ti.y = buf.ReadByte(); // Or table definition finalisation
3706 ++bytes_read;
3707
3708 if (it.ti.x == 0 && it.ti.y == 0x80) {
3709 /* Terminator, remove and finish up */
3710 layout.pop_back();
3711 break;
3712 }
3713
3714 it.gfx = buf.ReadByte();
3715 ++bytes_read;
3716
3717 if (it.gfx == 0xFE) {
3718 /* Use a new tile from this GRF */
3719 int local_tile_id = buf.ReadWord();
3720 bytes_read += 2;
3721
3722 /* Read the ID from the _industile_mngr. */
3723 int tempid = _industile_mngr.GetID(local_tile_id, _cur.grffile->grfid);
3724
3725 if (tempid == INVALID_INDUSTRYTILE) {
3726 GrfMsg(2, "IndustriesChangeInfo: Attempt to use industry tile {} with industry id {}, not yet defined. Ignoring.", local_tile_id, id);
3727 } else {
3728 /* Declared as been valid, can be used */
3729 it.gfx = tempid;
3730 }
3731 } else if (it.gfx == GFX_WATERTILE_SPECIALCHECK) {
3732 it.ti.x = (int8_t)GB(it.ti.x, 0, 8);
3733 it.ti.y = (int8_t)GB(it.ti.y, 0, 8);
3734
3735 /* When there were only 256x256 maps, TileIndex was a uint16_t and
3736 * it.ti was just a TileIndexDiff that was added to it.
3737 * As such negative "x" values were shifted into the "y" position.
3738 * x = -1, y = 1 -> x = 255, y = 0
3739 * Since GRF version 8 the position is interpreted as pair of independent int8.
3740 * For GRF version < 8 we need to emulate the old shifting behaviour.
3741 */
3742 if (_cur.grffile->grf_version < 8 && it.ti.x < 0) it.ti.y += 1;
3743 }
3744 }
3745
3746 if (!ValidateIndustryLayout(layout)) {
3747 /* The industry layout was not valid, so skip this one. */
3748 GrfMsg(1, "IndustriesChangeInfo: Invalid industry layout for industry id {}. Ignoring", id);
3749 new_num_layouts--;
3750 j--;
3751 } else {
3752 new_layouts.push_back(layout);
3753 }
3754 }
3755
3756 /* Install final layout construction in the industry spec */
3757 indsp->layouts = new_layouts;
3758 break;
3759 }
3760
3761 case 0x0B: // Industry production flags
3762 indsp->life_type = (IndustryLifeType)buf.ReadByte();
3763 break;
3764
3765 case 0x0C: // Industry closure message
3766 AddStringForMapping(GRFStringID{buf.ReadWord()}, &indsp->closure_text);
3767 break;
3768
3769 case 0x0D: // Production increase message
3770 AddStringForMapping(GRFStringID{buf.ReadWord()}, &indsp->production_up_text);
3771 break;
3772
3773 case 0x0E: // Production decrease message
3774 AddStringForMapping(GRFStringID{buf.ReadWord()}, &indsp->production_down_text);
3775 break;
3776
3777 case 0x0F: // Fund cost multiplier
3778 indsp->cost_multiplier = buf.ReadByte();
3779 break;
3780
3781 case 0x10: // Production cargo types
3782 for (uint8_t j = 0; j < INDUSTRY_ORIGINAL_NUM_OUTPUTS; j++) {
3783 indsp->produced_cargo[j] = GetCargoTranslation(buf.ReadByte(), _cur.grffile);
3784 indsp->produced_cargo_label[j] = CT_INVALID;
3785 }
3786 break;
3787
3788 case 0x11: // Acceptance cargo types
3789 for (uint8_t j = 0; j < INDUSTRY_ORIGINAL_NUM_INPUTS; j++) {
3790 indsp->accepts_cargo[j] = GetCargoTranslation(buf.ReadByte(), _cur.grffile);
3791 indsp->accepts_cargo_label[j] = CT_INVALID;
3792 }
3793 buf.ReadByte(); // Unnused, eat it up
3794 break;
3795
3796 case 0x12: // Production multipliers
3797 case 0x13:
3798 indsp->production_rate[prop - 0x12] = buf.ReadByte();
3799 break;
3800
3801 case 0x14: // Minimal amount of cargo distributed
3802 indsp->minimal_cargo = buf.ReadByte();
3803 break;
3804
3805 case 0x15: { // Random sound effects
3806 uint8_t num_sounds = buf.ReadByte();
3807
3808 std::vector<uint8_t> sounds;
3809 sounds.reserve(num_sounds);
3810 for (uint8_t j = 0; j < num_sounds; ++j) {
3811 sounds.push_back(buf.ReadByte());
3812 }
3813
3814 indsp->random_sounds = std::move(sounds);
3815 break;
3816 }
3817
3818 case 0x16: // Conflicting industry types
3819 for (uint8_t j = 0; j < 3; j++) indsp->conflicting[j] = buf.ReadByte();
3820 break;
3821
3822 case 0x17: // Probability in random game
3823 indsp->appear_creation[to_underlying(_settings_game.game_creation.landscape)] = buf.ReadByte();
3824 break;
3825
3826 case 0x18: // Probability during gameplay
3827 indsp->appear_ingame[to_underlying(_settings_game.game_creation.landscape)] = buf.ReadByte();
3828 break;
3829
3830 case 0x19: // Map colour
3831 indsp->map_colour = buf.ReadByte();
3832 break;
3833
3834 case 0x1A: // Special industry flags to define special behavior
3835 indsp->behaviour = (IndustryBehaviour)buf.ReadDWord();
3836 break;
3837
3838 case 0x1B: // New industry text ID
3839 AddStringForMapping(GRFStringID{buf.ReadWord()}, &indsp->new_industry_text);
3840 break;
3841
3842 case 0x1C: // Input cargo multipliers for the three input cargo types
3843 case 0x1D:
3844 case 0x1E: {
3845 uint32_t multiples = buf.ReadDWord();
3846 indsp->input_cargo_multiplier[prop - 0x1C][0] = GB(multiples, 0, 16);
3847 indsp->input_cargo_multiplier[prop - 0x1C][1] = GB(multiples, 16, 16);
3848 break;
3849 }
3850
3851 case 0x1F: // Industry name
3852 AddStringForMapping(GRFStringID{buf.ReadWord()}, &indsp->name);
3853 break;
3854
3855 case 0x20: // Prospecting success chance
3856 indsp->prospecting_chance = buf.ReadDWord();
3857 break;
3858
3859 case 0x21: // Callback mask
3860 case 0x22: { // Callback additional mask
3861 auto mask = indsp->callback_mask.base();
3862 SB(mask, (prop - 0x21) * 8, 8, buf.ReadByte());
3863 indsp->callback_mask = IndustryCallbackMasks{mask};
3864 break;
3865 }
3866
3867 case 0x23: // removal cost multiplier
3868 indsp->removal_cost_multiplier = buf.ReadDWord();
3869 break;
3870
3871 case 0x24: { // name for nearby station
3872 GRFStringID str{buf.ReadWord()};
3873 if (str == 0) {
3874 indsp->station_name = STR_NULL;
3875 } else {
3876 AddStringForMapping(str, &indsp->station_name);
3877 }
3878 break;
3879 }
3880
3881 case 0x25: { // variable length produced cargoes
3882 uint8_t num_cargoes = buf.ReadByte();
3883 if (num_cargoes > std::size(indsp->produced_cargo)) {
3884 GRFError *error = DisableGrf(STR_NEWGRF_ERROR_LIST_PROPERTY_TOO_LONG);
3885 error->param_value[1] = prop;
3886 return CIR_DISABLED;
3887 }
3888 for (size_t i = 0; i < std::size(indsp->produced_cargo); i++) {
3889 if (i < num_cargoes) {
3890 CargoType cargo = GetCargoTranslation(buf.ReadByte(), _cur.grffile);
3891 indsp->produced_cargo[i] = cargo;
3892 } else {
3893 indsp->produced_cargo[i] = INVALID_CARGO;
3894 }
3895 if (i < std::size(indsp->produced_cargo_label)) indsp->produced_cargo_label[i] = CT_INVALID;
3896 }
3897 break;
3898 }
3899
3900 case 0x26: { // variable length accepted cargoes
3901 uint8_t num_cargoes = buf.ReadByte();
3902 if (num_cargoes > std::size(indsp->accepts_cargo)) {
3903 GRFError *error = DisableGrf(STR_NEWGRF_ERROR_LIST_PROPERTY_TOO_LONG);
3904 error->param_value[1] = prop;
3905 return CIR_DISABLED;
3906 }
3907 for (size_t i = 0; i < std::size(indsp->accepts_cargo); i++) {
3908 if (i < num_cargoes) {
3909 CargoType cargo = GetCargoTranslation(buf.ReadByte(), _cur.grffile);
3910 indsp->accepts_cargo[i] = cargo;
3911 } else {
3912 indsp->accepts_cargo[i] = INVALID_CARGO;
3913 }
3914 if (i < std::size(indsp->accepts_cargo_label)) indsp->accepts_cargo_label[i] = CT_INVALID;
3915 }
3916 break;
3917 }
3918
3919 case 0x27: { // variable length production rates
3920 uint8_t num_cargoes = buf.ReadByte();
3921 if (num_cargoes > lengthof(indsp->production_rate)) {
3922 GRFError *error = DisableGrf(STR_NEWGRF_ERROR_LIST_PROPERTY_TOO_LONG);
3923 error->param_value[1] = prop;
3924 return CIR_DISABLED;
3925 }
3926 for (uint i = 0; i < lengthof(indsp->production_rate); i++) {
3927 if (i < num_cargoes) {
3928 indsp->production_rate[i] = buf.ReadByte();
3929 } else {
3930 indsp->production_rate[i] = 0;
3931 }
3932 }
3933 break;
3934 }
3935
3936 case 0x28: { // variable size input/output production multiplier table
3937 uint8_t num_inputs = buf.ReadByte();
3938 uint8_t num_outputs = buf.ReadByte();
3939 if (num_inputs > std::size(indsp->accepts_cargo) || num_outputs > std::size(indsp->produced_cargo)) {
3940 GRFError *error = DisableGrf(STR_NEWGRF_ERROR_LIST_PROPERTY_TOO_LONG);
3941 error->param_value[1] = prop;
3942 return CIR_DISABLED;
3943 }
3944 for (size_t i = 0; i < std::size(indsp->accepts_cargo); i++) {
3945 for (size_t j = 0; j < std::size(indsp->produced_cargo); j++) {
3946 uint16_t mult = 0;
3947 if (i < num_inputs && j < num_outputs) mult = buf.ReadWord();
3948 indsp->input_cargo_multiplier[i][j] = mult;
3949 }
3950 }
3951 break;
3952 }
3953
3954 default:
3955 ret = CIR_UNKNOWN;
3956 break;
3957 }
3958 }
3959
3960 return ret;
3961}
3962
3971static ChangeInfoResult AirportChangeInfo(uint first, uint last, int prop, ByteReader &buf)
3972{
3974
3975 if (last > NUM_AIRPORTS_PER_GRF) {
3976 GrfMsg(1, "AirportChangeInfo: Too many airports, trying id ({}), max ({}). Ignoring.", last, NUM_AIRPORTS_PER_GRF);
3977 return CIR_INVALID_ID;
3978 }
3979
3980 /* Allocate industry specs if they haven't been allocated already. */
3981 if (_cur.grffile->airportspec.size() < last) _cur.grffile->airportspec.resize(last);
3982
3983 for (uint id = first; id < last; ++id) {
3984 auto &as = _cur.grffile->airportspec[id];
3985
3986 if (as == nullptr && prop != 0x08 && prop != 0x09) {
3987 GrfMsg(2, "AirportChangeInfo: Attempt to modify undefined airport {}, ignoring", id);
3988 return CIR_INVALID_ID;
3989 }
3990
3991 switch (prop) {
3992 case 0x08: { // Modify original airport
3993 uint8_t subs_id = buf.ReadByte();
3994 if (subs_id == 0xFF) {
3995 /* Instead of defining a new airport, an airport id
3996 * of 0xFF disables the old airport with the current id. */
3998 continue;
3999 } else if (subs_id >= NEW_AIRPORT_OFFSET) {
4000 /* The substitute id must be one of the original airports. */
4001 GrfMsg(2, "AirportChangeInfo: Attempt to use new airport {} as substitute airport for {}. Ignoring.", subs_id, id);
4002 continue;
4003 }
4004
4005 /* Allocate space for this airport.
4006 * Only need to do it once. If ever it is called again, it should not
4007 * do anything */
4008 if (as == nullptr) {
4009 as = std::make_unique<AirportSpec>(*AirportSpec::GetWithoutOverride(subs_id));
4010
4011 as->enabled = true;
4012 as->grf_prop.local_id = id;
4013 as->grf_prop.subst_id = subs_id;
4014 as->grf_prop.grfid = _cur.grffile->grfid;
4015 as->grf_prop.grffile = _cur.grffile;
4016 /* override the default airport */
4017 _airport_mngr.Add(id, _cur.grffile->grfid, subs_id);
4018 }
4019 break;
4020 }
4021
4022 case 0x0A: { // Set airport layout
4023 uint8_t num_layouts = buf.ReadByte();
4024 buf.ReadDWord(); // Total size of definition, unneeded.
4025 uint8_t size_x = 0;
4026 uint8_t size_y = 0;
4027
4028 std::vector<AirportTileLayout> layouts;
4029 layouts.reserve(num_layouts);
4030
4031 for (uint8_t j = 0; j != num_layouts; ++j) {
4032 auto &layout = layouts.emplace_back();
4033 layout.rotation = static_cast<Direction>(buf.ReadByte() & 6); // Rotation can only be DIR_NORTH, DIR_EAST, DIR_SOUTH or DIR_WEST.
4034
4035 for (;;) {
4036 auto &tile = layout.tiles.emplace_back();
4037 tile.ti.x = buf.ReadByte();
4038 tile.ti.y = buf.ReadByte();
4039 if (tile.ti.x == 0 && tile.ti.y == 0x80) {
4040 /* Convert terminator to our own. */
4041 tile.ti.x = -0x80;
4042 tile.ti.y = 0;
4043 tile.gfx = 0;
4044 break;
4045 }
4046
4047 tile.gfx = buf.ReadByte();
4048
4049 if (tile.gfx == 0xFE) {
4050 /* Use a new tile from this GRF */
4051 int local_tile_id = buf.ReadWord();
4052
4053 /* Read the ID from the _airporttile_mngr. */
4054 uint16_t tempid = _airporttile_mngr.GetID(local_tile_id, _cur.grffile->grfid);
4055
4056 if (tempid == INVALID_AIRPORTTILE) {
4057 GrfMsg(2, "AirportChangeInfo: Attempt to use airport tile {} with airport id {}, not yet defined. Ignoring.", local_tile_id, id);
4058 } else {
4059 /* Declared as been valid, can be used */
4060 tile.gfx = tempid;
4061 }
4062 } else if (tile.gfx == 0xFF) {
4063 tile.ti.x = static_cast<int8_t>(GB(tile.ti.x, 0, 8));
4064 tile.ti.y = static_cast<int8_t>(GB(tile.ti.y, 0, 8));
4065 }
4066
4067 /* Determine largest size. */
4068 if (layout.rotation == DIR_E || layout.rotation == DIR_W) {
4069 size_x = std::max<uint8_t>(size_x, tile.ti.y + 1);
4070 size_y = std::max<uint8_t>(size_y, tile.ti.x + 1);
4071 } else {
4072 size_x = std::max<uint8_t>(size_x, tile.ti.x + 1);
4073 size_y = std::max<uint8_t>(size_y, tile.ti.y + 1);
4074 }
4075 }
4076 }
4077 as->layouts = std::move(layouts);
4078 as->size_x = size_x;
4079 as->size_y = size_y;
4080 break;
4081 }
4082
4083 case 0x0C:
4084 as->min_year = TimerGameCalendar::Year{buf.ReadWord()};
4085 as->max_year = TimerGameCalendar::Year{buf.ReadWord()};
4086 if (as->max_year == 0xFFFF) as->max_year = CalendarTime::MAX_YEAR;
4087 break;
4088
4089 case 0x0D:
4090 as->ttd_airport_type = (TTDPAirportType)buf.ReadByte();
4091 break;
4092
4093 case 0x0E:
4094 as->catchment = Clamp(buf.ReadByte(), 1, MAX_CATCHMENT);
4095 break;
4096
4097 case 0x0F:
4098 as->noise_level = buf.ReadByte();
4099 break;
4100
4101 case 0x10:
4102 AddStringForMapping(GRFStringID{buf.ReadWord()}, &as->name);
4103 break;
4104
4105 case 0x11: // Maintenance cost factor
4106 as->maintenance_cost = buf.ReadWord();
4107 break;
4108
4109 default:
4110 ret = CIR_UNKNOWN;
4111 break;
4112 }
4113 }
4114
4115 return ret;
4116}
4117
4125{
4127
4128 switch (prop) {
4129 case 0x0B:
4130 case 0x0C:
4131 case 0x0D:
4132 case 0x12:
4133 case 0x14:
4134 case 0x16:
4135 case 0x17:
4136 case 0x18:
4137 buf.ReadByte();
4138 break;
4139
4140 case 0x09:
4141 case 0x0A:
4142 case 0x10:
4143 case 0x11:
4144 case 0x13:
4145 case 0x15:
4146 buf.ReadWord();
4147 break;
4148
4149 case 0x08:
4150 case 0x0E:
4151 case 0x0F:
4152 buf.ReadDWord();
4153 break;
4154
4155 default:
4156 ret = CIR_UNKNOWN;
4157 break;
4158 }
4159
4160 return ret;
4161}
4162
4171static ChangeInfoResult ObjectChangeInfo(uint first, uint last, int prop, ByteReader &buf)
4172{
4174
4175 if (last > NUM_OBJECTS_PER_GRF) {
4176 GrfMsg(1, "ObjectChangeInfo: Too many objects loaded ({}), max ({}). Ignoring.", last, NUM_OBJECTS_PER_GRF);
4177 return CIR_INVALID_ID;
4178 }
4179
4180 /* Allocate object specs if they haven't been allocated already. */
4181 if (_cur.grffile->objectspec.size() < last) _cur.grffile->objectspec.resize(last);
4182
4183 for (uint id = first; id < last; ++id) {
4184 auto &spec = _cur.grffile->objectspec[id];
4185
4186 if (prop != 0x08 && spec == nullptr) {
4187 /* If the object property 08 is not yet set, ignore this property */
4188 ChangeInfoResult cir = IgnoreObjectProperty(prop, buf);
4189 if (cir > ret) ret = cir;
4190 continue;
4191 }
4192
4193 switch (prop) {
4194 case 0x08: { // Class ID
4195 /* Allocate space for this object. */
4196 if (spec == nullptr) {
4197 spec = std::make_unique<ObjectSpec>();
4198 spec->views = 1; // Default for NewGRFs that don't set it.
4199 spec->size = OBJECT_SIZE_1X1; // Default for NewGRFs that manage to not set it (1x1)
4200 }
4201
4202 /* Swap classid because we read it in BE. */
4203 uint32_t classid = buf.ReadDWord();
4204 spec->class_index = ObjectClass::Allocate(std::byteswap(classid));
4205 break;
4206 }
4207
4208 case 0x09: { // Class name
4209 AddStringForMapping(GRFStringID{buf.ReadWord()}, [spec = spec.get()](StringID str) { ObjectClass::Get(spec->class_index)->name = str; });
4210 break;
4211 }
4212
4213 case 0x0A: // Object name
4214 AddStringForMapping(GRFStringID{buf.ReadWord()}, &spec->name);
4215 break;
4216
4217 case 0x0B: // Climate mask
4218 spec->climate = LandscapeTypes{buf.ReadByte()};
4219 break;
4220
4221 case 0x0C: // Size
4222 spec->size = buf.ReadByte();
4223 if (GB(spec->size, 0, 4) == 0 || GB(spec->size, 4, 4) == 0) {
4224 GrfMsg(0, "ObjectChangeInfo: Invalid object size requested (0x{:X}) for object id {}. Ignoring.", spec->size, id);
4225 spec->size = OBJECT_SIZE_1X1;
4226 }
4227 break;
4228
4229 case 0x0D: // Build cost multipler
4230 spec->build_cost_multiplier = buf.ReadByte();
4231 spec->clear_cost_multiplier = spec->build_cost_multiplier;
4232 break;
4233
4234 case 0x0E: // Introduction date
4235 spec->introduction_date = TimerGameCalendar::Date(buf.ReadDWord());
4236 break;
4237
4238 case 0x0F: // End of life
4239 spec->end_of_life_date = TimerGameCalendar::Date(buf.ReadDWord());
4240 break;
4241
4242 case 0x10: // Flags
4243 spec->flags = (ObjectFlags)buf.ReadWord();
4245 break;
4246
4247 case 0x11: // Animation info
4248 spec->animation.frames = buf.ReadByte();
4249 spec->animation.status = buf.ReadByte();
4250 break;
4251
4252 case 0x12: // Animation speed
4253 spec->animation.speed = buf.ReadByte();
4254 break;
4255
4256 case 0x13: // Animation triggers
4257 spec->animation.triggers = buf.ReadWord();
4258 break;
4259
4260 case 0x14: // Removal cost multiplier
4261 spec->clear_cost_multiplier = buf.ReadByte();
4262 break;
4263
4264 case 0x15: // Callback mask
4265 spec->callback_mask = static_cast<ObjectCallbackMasks>(buf.ReadWord());
4266 break;
4267
4268 case 0x16: // Building height
4269 spec->height = buf.ReadByte();
4270 break;
4271
4272 case 0x17: // Views
4273 spec->views = buf.ReadByte();
4274 if (spec->views != 1 && spec->views != 2 && spec->views != 4) {
4275 GrfMsg(2, "ObjectChangeInfo: Invalid number of views ({}) for object id {}. Ignoring.", spec->views, id);
4276 spec->views = 1;
4277 }
4278 break;
4279
4280 case 0x18: // Amount placed on 256^2 map on map creation
4281 spec->generate_amount = buf.ReadByte();
4282 break;
4283
4284 default:
4285 ret = CIR_UNKNOWN;
4286 break;
4287 }
4288 }
4289
4290 return ret;
4291}
4292
4301static ChangeInfoResult RailTypeChangeInfo(uint first, uint last, int prop, ByteReader &buf)
4302{
4304
4305 extern RailTypeInfo _railtypes[RAILTYPE_END];
4306
4307 if (last > RAILTYPE_END) {
4308 GrfMsg(1, "RailTypeChangeInfo: Rail type {} is invalid, max {}, ignoring", last, RAILTYPE_END);
4309 return CIR_INVALID_ID;
4310 }
4311
4312 for (uint id = first; id < last; ++id) {
4313 RailType rt = _cur.grffile->railtype_map[id];
4314 if (rt == INVALID_RAILTYPE) return CIR_INVALID_ID;
4315
4316 RailTypeInfo *rti = &_railtypes[rt];
4317
4318 switch (prop) {
4319 case 0x08: // Label of rail type
4320 /* Skipped here as this is loaded during reservation stage. */
4321 buf.ReadDWord();
4322 break;
4323
4324 case 0x09: { // Toolbar caption of railtype (sets name as well for backwards compatibility for grf ver < 8)
4325 GRFStringID str{buf.ReadWord()};
4327 if (_cur.grffile->grf_version < 8) {
4328 AddStringForMapping(str, &rti->strings.name);
4329 }
4330 break;
4331 }
4332
4333 case 0x0A: // Menu text of railtype
4334 AddStringForMapping(GRFStringID{buf.ReadWord()}, &rti->strings.menu_text);
4335 break;
4336
4337 case 0x0B: // Build window caption
4338 AddStringForMapping(GRFStringID{buf.ReadWord()}, &rti->strings.build_caption);
4339 break;
4340
4341 case 0x0C: // Autoreplace text
4342 AddStringForMapping(GRFStringID{buf.ReadWord()}, &rti->strings.replace_text);
4343 break;
4344
4345 case 0x0D: // New locomotive text
4346 AddStringForMapping(GRFStringID{buf.ReadWord()}, &rti->strings.new_loco);
4347 break;
4348
4349 case 0x0E: // Compatible railtype list
4350 case 0x0F: // Powered railtype list
4351 case 0x18: // Railtype list required for date introduction
4352 case 0x19: // Introduced railtype list
4353 {
4354 /* Rail type compatibility bits are added to the existing bits
4355 * to allow multiple GRFs to modify compatibility with the
4356 * default rail types. */
4357 int n = buf.ReadByte();
4358 for (int j = 0; j != n; j++) {
4359 RailTypeLabel label = buf.ReadDWord();
4360 RailType resolved_rt = GetRailTypeByLabel(std::byteswap(label), false);
4361 if (resolved_rt != INVALID_RAILTYPE) {
4362 switch (prop) {
4363 case 0x0F: SetBit(rti->powered_railtypes, resolved_rt); [[fallthrough]]; // Powered implies compatible.
4364 case 0x0E: SetBit(rti->compatible_railtypes, resolved_rt); break;
4365 case 0x18: SetBit(rti->introduction_required_railtypes, resolved_rt); break;
4366 case 0x19: SetBit(rti->introduces_railtypes, resolved_rt); break;
4367 }
4368 }
4369 }
4370 break;
4371 }
4372
4373 case 0x10: // Rail Type flags
4374 rti->flags = static_cast<RailTypeFlags>(buf.ReadByte());
4375 break;
4376
4377 case 0x11: // Curve speed advantage
4378 rti->curve_speed = buf.ReadByte();
4379 break;
4380
4381 case 0x12: // Station graphic
4382 rti->fallback_railtype = Clamp(buf.ReadByte(), 0, 2);
4383 break;
4384
4385 case 0x13: // Construction cost factor
4386 rti->cost_multiplier = buf.ReadWord();
4387 break;
4388
4389 case 0x14: // Speed limit
4390 rti->max_speed = buf.ReadWord();
4391 break;
4392
4393 case 0x15: // Acceleration model
4394 rti->acceleration_type = Clamp(buf.ReadByte(), 0, 2);
4395 break;
4396
4397 case 0x16: // Map colour
4398 rti->map_colour = buf.ReadByte();
4399 break;
4400
4401 case 0x17: // Introduction date
4402 rti->introduction_date = TimerGameCalendar::Date(buf.ReadDWord());
4403 break;
4404
4405 case 0x1A: // Sort order
4406 rti->sorting_order = buf.ReadByte();
4407 break;
4408
4409 case 0x1B: // Name of railtype (overridden by prop 09 for grf ver < 8)
4410 AddStringForMapping(GRFStringID{buf.ReadWord()}, &rti->strings.name);
4411 break;
4412
4413 case 0x1C: // Maintenance cost factor
4414 rti->maintenance_multiplier = buf.ReadWord();
4415 break;
4416
4417 case 0x1D: // Alternate rail type label list
4418 /* Skipped here as this is loaded during reservation stage. */
4419 for (int j = buf.ReadByte(); j != 0; j--) buf.ReadDWord();
4420 break;
4421
4422 default:
4423 ret = CIR_UNKNOWN;
4424 break;
4425 }
4426 }
4427
4428 return ret;
4429}
4430
4431static ChangeInfoResult RailTypeReserveInfo(uint first, uint last, int prop, ByteReader &buf)
4432{
4434
4435 extern RailTypeInfo _railtypes[RAILTYPE_END];
4436
4437 if (last > RAILTYPE_END) {
4438 GrfMsg(1, "RailTypeReserveInfo: Rail type {} is invalid, max {}, ignoring", last, RAILTYPE_END);
4439 return CIR_INVALID_ID;
4440 }
4441
4442 for (uint id = first; id < last; ++id) {
4443 switch (prop) {
4444 case 0x08: // Label of rail type
4445 {
4446 RailTypeLabel rtl = buf.ReadDWord();
4447 rtl = std::byteswap(rtl);
4448
4449 RailType rt = GetRailTypeByLabel(rtl, false);
4450 if (rt == INVALID_RAILTYPE) {
4451 /* Set up new rail type */
4452 rt = AllocateRailType(rtl);
4453 }
4454
4455 _cur.grffile->railtype_map[id] = rt;
4456 break;
4457 }
4458
4459 case 0x09: // Toolbar caption of railtype
4460 case 0x0A: // Menu text
4461 case 0x0B: // Build window caption
4462 case 0x0C: // Autoreplace text
4463 case 0x0D: // New loco
4464 case 0x13: // Construction cost
4465 case 0x14: // Speed limit
4466 case 0x1B: // Name of railtype
4467 case 0x1C: // Maintenance cost factor
4468 buf.ReadWord();
4469 break;
4470
4471 case 0x1D: // Alternate rail type label list
4472 if (_cur.grffile->railtype_map[id] != INVALID_RAILTYPE) {
4473 int n = buf.ReadByte();
4474 for (int j = 0; j != n; j++) {
4475 _railtypes[_cur.grffile->railtype_map[id]].alternate_labels.push_back(std::byteswap(buf.ReadDWord()));
4476 }
4477 break;
4478 }
4479 GrfMsg(1, "RailTypeReserveInfo: Ignoring property 1D for rail type {} because no label was set", id);
4480 [[fallthrough]];
4481
4482 case 0x0E: // Compatible railtype list
4483 case 0x0F: // Powered railtype list
4484 case 0x18: // Railtype list required for date introduction
4485 case 0x19: // Introduced railtype list
4486 for (int j = buf.ReadByte(); j != 0; j--) buf.ReadDWord();
4487 break;
4488
4489 case 0x10: // Rail Type flags
4490 case 0x11: // Curve speed advantage
4491 case 0x12: // Station graphic
4492 case 0x15: // Acceleration model
4493 case 0x16: // Map colour
4494 case 0x1A: // Sort order
4495 buf.ReadByte();
4496 break;
4497
4498 case 0x17: // Introduction date
4499 buf.ReadDWord();
4500 break;
4501
4502 default:
4503 ret = CIR_UNKNOWN;
4504 break;
4505 }
4506 }
4507
4508 return ret;
4509}
4510
4519static ChangeInfoResult RoadTypeChangeInfo(uint first, uint last, int prop, ByteReader &buf, RoadTramType rtt)
4520{
4522
4523 extern RoadTypeInfo _roadtypes[ROADTYPE_END];
4524 std::array<RoadType, ROADTYPE_END> &type_map = (rtt == RTT_TRAM) ? _cur.grffile->tramtype_map : _cur.grffile->roadtype_map;
4525
4526 if (last > ROADTYPE_END) {
4527 GrfMsg(1, "RoadTypeChangeInfo: Road type {} is invalid, max {}, ignoring", last, ROADTYPE_END);
4528 return CIR_INVALID_ID;
4529 }
4530
4531 for (uint id = first; id < last; ++id) {
4532 RoadType rt = type_map[id];
4533 if (rt == INVALID_ROADTYPE) return CIR_INVALID_ID;
4534
4535 RoadTypeInfo *rti = &_roadtypes[rt];
4536
4537 switch (prop) {
4538 case 0x08: // Label of road type
4539 /* Skipped here as this is loaded during reservation stage. */
4540 buf.ReadDWord();
4541 break;
4542
4543 case 0x09: // Toolbar caption of roadtype
4545 break;
4546
4547 case 0x0A: // Menu text of roadtype
4548 AddStringForMapping(GRFStringID{buf.ReadWord()}, &rti->strings.menu_text);
4549 break;
4550
4551 case 0x0B: // Build window caption
4552 AddStringForMapping(GRFStringID{buf.ReadWord()}, &rti->strings.build_caption);
4553 break;
4554
4555 case 0x0C: // Autoreplace text
4556 AddStringForMapping(GRFStringID{buf.ReadWord()}, &rti->strings.replace_text);
4557 break;
4558
4559 case 0x0D: // New engine text
4560 AddStringForMapping(GRFStringID{buf.ReadWord()}, &rti->strings.new_engine);
4561 break;
4562
4563 case 0x0F: // Powered roadtype list
4564 case 0x18: // Roadtype list required for date introduction
4565 case 0x19: { // Introduced roadtype list
4566 /* Road type compatibility bits are added to the existing bits
4567 * to allow multiple GRFs to modify compatibility with the
4568 * default road types. */
4569 int n = buf.ReadByte();
4570 for (int j = 0; j != n; j++) {
4571 RoadTypeLabel label = buf.ReadDWord();
4572 RoadType resolved_rt = GetRoadTypeByLabel(std::byteswap(label), false);
4573 if (resolved_rt != INVALID_ROADTYPE) {
4574 switch (prop) {
4575 case 0x0F:
4576 if (GetRoadTramType(resolved_rt) == rtt) {
4577 SetBit(rti->powered_roadtypes, resolved_rt);
4578 } else {
4579 GrfMsg(1, "RoadTypeChangeInfo: Powered road type list: Road type {} road/tram type does not match road type {}, ignoring", resolved_rt, rt);
4580 }
4581 break;
4582 case 0x18: SetBit(rti->introduction_required_roadtypes, resolved_rt); break;
4583 case 0x19: SetBit(rti->introduces_roadtypes, resolved_rt); break;
4584 }
4585 }
4586 }
4587 break;
4588 }
4589
4590 case 0x10: // Road Type flags
4591 rti->flags = static_cast<RoadTypeFlags>(buf.ReadByte());
4592 break;
4593
4594 case 0x13: // Construction cost factor
4595 rti->cost_multiplier = buf.ReadWord();
4596 break;
4597
4598 case 0x14: // Speed limit
4599 rti->max_speed = buf.ReadWord();
4600 break;
4601
4602 case 0x16: // Map colour
4603 rti->map_colour = buf.ReadByte();
4604 break;
4605
4606 case 0x17: // Introduction date
4607 rti->introduction_date = TimerGameCalendar::Date(buf.ReadDWord());
4608 break;
4609
4610 case 0x1A: // Sort order
4611 rti->sorting_order = buf.ReadByte();
4612 break;
4613
4614 case 0x1B: // Name of roadtype
4615 AddStringForMapping(GRFStringID{buf.ReadWord()}, &rti->strings.name);
4616 break;
4617
4618 case 0x1C: // Maintenance cost factor
4619 rti->maintenance_multiplier = buf.ReadWord();
4620 break;
4621
4622 case 0x1D: // Alternate road type label list
4623 /* Skipped here as this is loaded during reservation stage. */
4624 for (int j = buf.ReadByte(); j != 0; j--) buf.ReadDWord();
4625 break;
4626
4627 default:
4628 ret = CIR_UNKNOWN;
4629 break;
4630 }
4631 }
4632
4633 return ret;
4634}
4635
4636static ChangeInfoResult RoadTypeChangeInfo(uint first, uint last, int prop, ByteReader &buf)
4637{
4638 return RoadTypeChangeInfo(first, last, prop, buf, RTT_ROAD);
4639}
4640
4641static ChangeInfoResult TramTypeChangeInfo(uint first, uint last, int prop, ByteReader &buf)
4642{
4643 return RoadTypeChangeInfo(first, last, prop, buf, RTT_TRAM);
4644}
4645
4646
4647static ChangeInfoResult RoadTypeReserveInfo(uint first, uint last, int prop, ByteReader &buf, RoadTramType rtt)
4648{
4650
4651 extern RoadTypeInfo _roadtypes[ROADTYPE_END];
4652 std::array<RoadType, ROADTYPE_END> &type_map = (rtt == RTT_TRAM) ? _cur.grffile->tramtype_map : _cur.grffile->roadtype_map;
4653
4654 if (last > ROADTYPE_END) {
4655 GrfMsg(1, "RoadTypeReserveInfo: Road type {} is invalid, max {}, ignoring", last, ROADTYPE_END);
4656 return CIR_INVALID_ID;
4657 }
4658
4659 for (uint id = first; id < last; ++id) {
4660 switch (prop) {
4661 case 0x08: { // Label of road type
4662 RoadTypeLabel rtl = buf.ReadDWord();
4663 rtl = std::byteswap(rtl);
4664
4665 RoadType rt = GetRoadTypeByLabel(rtl, false);
4666 if (rt == INVALID_ROADTYPE) {
4667 /* Set up new road type */
4668 rt = AllocateRoadType(rtl, rtt);
4669 } else if (GetRoadTramType(rt) != rtt) {
4670 GrfMsg(1, "RoadTypeReserveInfo: Road type {} is invalid type (road/tram), ignoring", id);
4671 return CIR_INVALID_ID;
4672 }
4673
4674 type_map[id] = rt;
4675 break;
4676 }
4677 case 0x09: // Toolbar caption of roadtype
4678 case 0x0A: // Menu text
4679 case 0x0B: // Build window caption
4680 case 0x0C: // Autoreplace text
4681 case 0x0D: // New loco
4682 case 0x13: // Construction cost
4683 case 0x14: // Speed limit
4684 case 0x1B: // Name of roadtype
4685 case 0x1C: // Maintenance cost factor
4686 buf.ReadWord();
4687 break;
4688
4689 case 0x1D: // Alternate road type label list
4690 if (type_map[id] != INVALID_ROADTYPE) {
4691 int n = buf.ReadByte();
4692 for (int j = 0; j != n; j++) {
4693 _roadtypes[type_map[id]].alternate_labels.push_back(std::byteswap(buf.ReadDWord()));
4694 }
4695 break;
4696 }
4697 GrfMsg(1, "RoadTypeReserveInfo: Ignoring property 1D for road type {} because no label was set", id);
4698 /* FALL THROUGH */
4699
4700 case 0x0F: // Powered roadtype list
4701 case 0x18: // Roadtype list required for date introduction
4702 case 0x19: // Introduced roadtype list
4703 for (int j = buf.ReadByte(); j != 0; j--) buf.ReadDWord();
4704 break;
4705
4706 case 0x10: // Road Type flags
4707 case 0x16: // Map colour
4708 case 0x1A: // Sort order
4709 buf.ReadByte();
4710 break;
4711
4712 case 0x17: // Introduction date
4713 buf.ReadDWord();
4714 break;
4715
4716 default:
4717 ret = CIR_UNKNOWN;
4718 break;
4719 }
4720 }
4721
4722 return ret;
4723}
4724
4725static ChangeInfoResult RoadTypeReserveInfo(uint first, uint last, int prop, ByteReader &buf)
4726{
4727 return RoadTypeReserveInfo(first, last, prop, buf, RTT_ROAD);
4728}
4729
4730static ChangeInfoResult TramTypeReserveInfo(uint first, uint last, int prop, ByteReader &buf)
4731{
4732 return RoadTypeReserveInfo(first, last, prop, buf, RTT_TRAM);
4733}
4734
4735static ChangeInfoResult AirportTilesChangeInfo(uint first, uint last, int prop, ByteReader &buf)
4736{
4738
4739 if (last > NUM_AIRPORTTILES_PER_GRF) {
4740 GrfMsg(1, "AirportTileChangeInfo: Too many airport tiles loaded ({}), max ({}). Ignoring.", last, NUM_AIRPORTTILES_PER_GRF);
4741 return CIR_INVALID_ID;
4742 }
4743
4744 /* Allocate airport tile specs if they haven't been allocated already. */
4745 if (_cur.grffile->airtspec.size() < last) _cur.grffile->airtspec.resize(last);
4746
4747 for (uint id = first; id < last; ++id) {
4748 auto &tsp = _cur.grffile->airtspec[id];
4749
4750 if (prop != 0x08 && tsp == nullptr) {
4751 GrfMsg(2, "AirportTileChangeInfo: Attempt to modify undefined airport tile {}. Ignoring.", id);
4752 return CIR_INVALID_ID;
4753 }
4754
4755 switch (prop) {
4756 case 0x08: { // Substitute airport tile type
4757 uint8_t subs_id = buf.ReadByte();
4758 if (subs_id >= NEW_AIRPORTTILE_OFFSET) {
4759 /* The substitute id must be one of the original airport tiles. */
4760 GrfMsg(2, "AirportTileChangeInfo: Attempt to use new airport tile {} as substitute airport tile for {}. Ignoring.", subs_id, id);
4761 continue;
4762 }
4763
4764 /* Allocate space for this airport tile. */
4765 if (tsp == nullptr) {
4766 tsp = std::make_unique<AirportTileSpec>(*AirportTileSpec::Get(subs_id));
4767
4768 tsp->enabled = true;
4769
4770 tsp->animation.status = ANIM_STATUS_NO_ANIMATION;
4771
4772 tsp->grf_prop.local_id = id;
4773 tsp->grf_prop.subst_id = subs_id;
4774 tsp->grf_prop.grfid = _cur.grffile->grfid;
4775 tsp->grf_prop.grffile = _cur.grffile;
4776 _airporttile_mngr.AddEntityID(id, _cur.grffile->grfid, subs_id); // pre-reserve the tile slot
4777 }
4778 break;
4779 }
4780
4781 case 0x09: { // Airport tile override
4782 uint8_t override = buf.ReadByte();
4783
4784 /* The airport tile being overridden must be an original airport tile. */
4785 if (override >= NEW_AIRPORTTILE_OFFSET) {
4786 GrfMsg(2, "AirportTileChangeInfo: Attempt to override new airport tile {} with airport tile id {}. Ignoring.", override, id);
4787 continue;
4788 }
4789
4790 _airporttile_mngr.Add(id, _cur.grffile->grfid, override);
4791 break;
4792 }
4793
4794 case 0x0E: // Callback mask
4795 tsp->callback_mask = static_cast<AirportTileCallbackMasks>(buf.ReadByte());
4796 break;
4797
4798 case 0x0F: // Animation information
4799 tsp->animation.frames = buf.ReadByte();
4800 tsp->animation.status = buf.ReadByte();
4801 break;
4802
4803 case 0x10: // Animation speed
4804 tsp->animation.speed = buf.ReadByte();
4805 break;
4806
4807 case 0x11: // Animation triggers
4808 tsp->animation.triggers = buf.ReadByte();
4809 break;
4810
4811 default:
4812 ret = CIR_UNKNOWN;
4813 break;
4814 }
4815 }
4816
4817 return ret;
4818}
4819
4827{
4829
4830 switch (prop) {
4831 case 0x09:
4832 case 0x0C:
4833 case 0x0F:
4834 case 0x11:
4835 buf.ReadByte();
4836 break;
4837
4838 case 0x0A:
4839 case 0x0B:
4840 case 0x0E:
4841 case 0x10:
4842 case 0x15:
4843 buf.ReadWord();
4844 break;
4845
4846 case 0x08:
4847 case 0x0D:
4848 case 0x12:
4849 buf.ReadDWord();
4850 break;
4851
4852 default:
4853 ret = CIR_UNKNOWN;
4854 break;
4855 }
4856
4857 return ret;
4858}
4859
4860static ChangeInfoResult RoadStopChangeInfo(uint first, uint last, int prop, ByteReader &buf)
4861{
4863
4864 if (last > NUM_ROADSTOPS_PER_GRF) {
4865 GrfMsg(1, "RoadStopChangeInfo: RoadStop {} is invalid, max {}, ignoring", last, NUM_ROADSTOPS_PER_GRF);
4866 return CIR_INVALID_ID;
4867 }
4868
4869 if (_cur.grffile->roadstops.size() < last) _cur.grffile->roadstops.resize(last);
4870
4871 for (uint id = first; id < last; ++id) {
4872 auto &rs = _cur.grffile->roadstops[id];
4873
4874 if (rs == nullptr && prop != 0x08) {
4875 GrfMsg(1, "RoadStopChangeInfo: Attempt to modify undefined road stop {}, ignoring", id);
4877 if (cir > ret) ret = cir;
4878 continue;
4879 }
4880
4881 switch (prop) {
4882 case 0x08: { // Road Stop Class ID
4883 if (rs == nullptr) {
4884 rs = std::make_unique<RoadStopSpec>();
4885 }
4886
4887 uint32_t classid = buf.ReadDWord();
4888 rs->class_index = RoadStopClass::Allocate(std::byteswap(classid));
4889 break;
4890 }
4891
4892 case 0x09: // Road stop type
4893 rs->stop_type = (RoadStopAvailabilityType)buf.ReadByte();
4894 break;
4895
4896 case 0x0A: // Road Stop Name
4897 AddStringForMapping(GRFStringID{buf.ReadWord()}, &rs->name);
4898 break;
4899
4900 case 0x0B: // Road Stop Class name
4901 AddStringForMapping(GRFStringID{buf.ReadWord()}, [rs = rs.get()](StringID str) { RoadStopClass::Get(rs->class_index)->name = str; });
4902 break;
4903
4904 case 0x0C: // The draw mode
4905 rs->draw_mode = static_cast<RoadStopDrawMode>(buf.ReadByte());
4906 break;
4907
4908 case 0x0D: // Cargo types for random triggers
4909 rs->cargo_triggers = TranslateRefitMask(buf.ReadDWord());
4910 break;
4911
4912 case 0x0E: // Animation info
4913 rs->animation.frames = buf.ReadByte();
4914 rs->animation.status = buf.ReadByte();
4915 break;
4916
4917 case 0x0F: // Animation speed
4918 rs->animation.speed = buf.ReadByte();
4919 break;
4920
4921 case 0x10: // Animation triggers
4922 rs->animation.triggers = buf.ReadWord();
4923 break;
4924
4925 case 0x11: // Callback mask
4926 rs->callback_mask = static_cast<RoadStopCallbackMasks>(buf.ReadByte());
4927 break;
4928
4929 case 0x12: // General flags
4930 rs->flags = static_cast<RoadStopSpecFlags>(buf.ReadDWord()); // Future-proofing, size this as 4 bytes, but we only need two byte's worth of flags at present
4931 break;
4932
4933 case 0x15: // Cost multipliers
4934 rs->build_cost_multiplier = buf.ReadByte();
4935 rs->clear_cost_multiplier = buf.ReadByte();
4936 break;
4937
4938 default:
4939 ret = CIR_UNKNOWN;
4940 break;
4941 }
4942 }
4943
4944 return ret;
4945}
4946
4947static bool HandleChangeInfoResult(const char *caller, ChangeInfoResult cir, uint8_t feature, uint8_t property)
4948{
4949 switch (cir) {
4950 default: NOT_REACHED();
4951
4952 case CIR_DISABLED:
4953 /* Error has already been printed; just stop parsing */
4954 return true;
4955
4956 case CIR_SUCCESS:
4957 return false;
4958
4959 case CIR_UNHANDLED:
4960 GrfMsg(1, "{}: Ignoring property 0x{:02X} of feature 0x{:02X} (not implemented)", caller, property, feature);
4961 return false;
4962
4963 case CIR_UNKNOWN:
4964 GrfMsg(0, "{}: Unknown property 0x{:02X} of feature 0x{:02X}, disabling", caller, property, feature);
4965 [[fallthrough]];
4966
4967 case CIR_INVALID_ID: {
4968 /* No debug message for an invalid ID, as it has already been output */
4969 GRFError *error = DisableGrf(cir == CIR_INVALID_ID ? STR_NEWGRF_ERROR_INVALID_ID : STR_NEWGRF_ERROR_UNKNOWN_PROPERTY);
4970 if (cir != CIR_INVALID_ID) error->param_value[1] = property;
4971 return true;
4972 }
4973 }
4974}
4975
4976/* Action 0x00 */
4977static void FeatureChangeInfo(ByteReader &buf)
4978{
4979 /* <00> <feature> <num-props> <num-info> <id> (<property <new-info>)...
4980 *
4981 * B feature
4982 * B num-props how many properties to change per vehicle/station
4983 * B num-info how many vehicles/stations to change
4984 * E id ID of first vehicle/station to change, if num-info is
4985 * greater than one, this one and the following
4986 * vehicles/stations will be changed
4987 * B property what property to change, depends on the feature
4988 * V new-info new bytes of info (variable size; depends on properties) */
4989
4990 static ChangeInfoHandler * const handler[] = {
4991 /* GSF_TRAINS */ RailVehicleChangeInfo,
4992 /* GSF_ROADVEHICLES */ RoadVehicleChangeInfo,
4993 /* GSF_SHIPS */ ShipVehicleChangeInfo,
4994 /* GSF_AIRCRAFT */ AircraftVehicleChangeInfo,
4995 /* GSF_STATIONS */ StationChangeInfo,
4996 /* GSF_CANALS */ CanalChangeInfo,
4997 /* GSF_BRIDGES */ BridgeChangeInfo,
4998 /* GSF_HOUSES */ TownHouseChangeInfo,
4999 /* GSF_GLOBALVAR */ GlobalVarChangeInfo,
5000 /* GSF_INDUSTRYTILES */ IndustrytilesChangeInfo,
5001 /* GSF_INDUSTRIES */ IndustriesChangeInfo,
5002 /* GSF_CARGOES */ nullptr, // Cargo is handled during reservation
5003 /* GSF_SOUNDFX */ SoundEffectChangeInfo,
5004 /* GSF_AIRPORTS */ AirportChangeInfo,
5005 /* GSF_SIGNALS */ nullptr,
5006 /* GSF_OBJECTS */ ObjectChangeInfo,
5007 /* GSF_RAILTYPES */ RailTypeChangeInfo,
5008 /* GSF_AIRPORTTILES */ AirportTilesChangeInfo,
5009 /* GSF_ROADTYPES */ RoadTypeChangeInfo,
5010 /* GSF_TRAMTYPES */ TramTypeChangeInfo,
5011 /* GSF_ROADSTOPS */ RoadStopChangeInfo,
5012 };
5013 static_assert(GSF_END == std::size(handler));
5014
5015 uint8_t feature = buf.ReadByte();
5016 uint8_t numprops = buf.ReadByte();
5017 uint numinfo = buf.ReadByte();
5018 uint engine = buf.ReadExtendedByte();
5019
5020 if (feature >= GSF_END) {
5021 GrfMsg(1, "FeatureChangeInfo: Unsupported feature 0x{:02X}, skipping", feature);
5022 return;
5023 }
5024
5025 GrfMsg(6, "FeatureChangeInfo: Feature 0x{:02X}, {} properties, to apply to {}+{}",
5026 feature, numprops, engine, numinfo);
5027
5028 if (handler[feature] == nullptr) {
5029 if (feature != GSF_CARGOES) GrfMsg(1, "FeatureChangeInfo: Unsupported feature 0x{:02X}, skipping", feature);
5030 return;
5031 }
5032
5033 /* Mark the feature as used by the grf */
5034 SetBit(_cur.grffile->grf_features, feature);
5035
5036 while (numprops-- && buf.HasData()) {
5037 uint8_t prop = buf.ReadByte();
5038
5039 ChangeInfoResult cir = handler[feature](engine, engine + numinfo, prop, buf);
5040 if (HandleChangeInfoResult("FeatureChangeInfo", cir, feature, prop)) return;
5041 }
5042}
5043
5044/* Action 0x00 (GLS_SAFETYSCAN) */
5045static void SafeChangeInfo(ByteReader &buf)
5046{
5047 uint8_t feature = buf.ReadByte();
5048 uint8_t numprops = buf.ReadByte();
5049 uint numinfo = buf.ReadByte();
5050 buf.ReadExtendedByte(); // id
5051
5052 if (feature == GSF_BRIDGES && numprops == 1) {
5053 uint8_t prop = buf.ReadByte();
5054 /* Bridge property 0x0D is redefinition of sprite layout tables, which
5055 * is considered safe. */
5056 if (prop == 0x0D) return;
5057 } else if (feature == GSF_GLOBALVAR && numprops == 1) {
5058 uint8_t prop = buf.ReadByte();
5059 /* Engine ID Mappings are safe, if the source is static */
5060 if (prop == 0x11) {
5061 bool is_safe = true;
5062 for (uint i = 0; i < numinfo; i++) {
5063 uint32_t s = buf.ReadDWord();
5064 buf.ReadDWord(); // dest
5065 const GRFConfig *grfconfig = GetGRFConfig(s);
5066 if (grfconfig != nullptr && !grfconfig->flags.Test(GRFConfigFlag::Static)) {
5067 is_safe = false;
5068 break;
5069 }
5070 }
5071 if (is_safe) return;
5072 }
5073 }
5074
5076
5077 /* Skip remainder of GRF */
5078 _cur.skip_sprites = -1;
5079}
5080
5081/* Action 0x00 (GLS_RESERVE) */
5082static void ReserveChangeInfo(ByteReader &buf)
5083{
5084 uint8_t feature = buf.ReadByte();
5085
5086 if (feature != GSF_CARGOES && feature != GSF_GLOBALVAR && feature != GSF_RAILTYPES && feature != GSF_ROADTYPES && feature != GSF_TRAMTYPES) return;
5087
5088 uint8_t numprops = buf.ReadByte();
5089 uint8_t numinfo = buf.ReadByte();
5090 uint16_t index = buf.ReadExtendedByte();
5091
5092 while (numprops-- && buf.HasData()) {
5093 uint8_t prop = buf.ReadByte();
5095
5096 switch (feature) {
5097 default: NOT_REACHED();
5098 case GSF_CARGOES:
5099 cir = CargoChangeInfo(index, index + numinfo, prop, buf);
5100 break;
5101
5102 case GSF_GLOBALVAR:
5103 cir = GlobalVarReserveInfo(index, index + numinfo, prop, buf);
5104 break;
5105
5106 case GSF_RAILTYPES:
5107 cir = RailTypeReserveInfo(index, index + numinfo, prop, buf);
5108 break;
5109
5110 case GSF_ROADTYPES:
5111 cir = RoadTypeReserveInfo(index, index + numinfo, prop, buf);
5112 break;
5113
5114 case GSF_TRAMTYPES:
5115 cir = TramTypeReserveInfo(index, index + numinfo, prop, buf);
5116 break;
5117 }
5118
5119 if (HandleChangeInfoResult("ReserveChangeInfo", cir, feature, prop)) return;
5120 }
5121}
5122
5123/* Action 0x01 */
5124static void NewSpriteSet(ByteReader &buf)
5125{
5126 /* Basic format: <01> <feature> <num-sets> <num-ent>
5127 * Extended format: <01> <feature> 00 <first-set> <num-sets> <num-ent>
5128 *
5129 * B feature feature to define sprites for
5130 * 0, 1, 2, 3: veh-type, 4: train stations
5131 * E first-set first sprite set to define
5132 * B num-sets number of sprite sets (extended byte in extended format)
5133 * E num-ent how many entries per sprite set
5134 * For vehicles, this is the number of different
5135 * vehicle directions in each sprite set
5136 * Set num-dirs=8, unless your sprites are symmetric.
5137 * In that case, use num-dirs=4.
5138 */
5139
5140 uint8_t feature = buf.ReadByte();
5141 uint16_t num_sets = buf.ReadByte();
5142 uint16_t first_set = 0;
5143
5144 if (num_sets == 0 && buf.HasData(3)) {
5145 /* Extended Action1 format.
5146 * Some GRFs define zero sets of zero sprites, though there is actually no use in that. Ignore them. */
5147 first_set = buf.ReadExtendedByte();
5148 num_sets = buf.ReadExtendedByte();
5149 }
5150 uint16_t num_ents = buf.ReadExtendedByte();
5151
5152 if (feature >= GSF_END) {
5153 _cur.skip_sprites = num_sets * num_ents;
5154 GrfMsg(1, "NewSpriteSet: Unsupported feature 0x{:02X}, skipping {} sprites", feature, _cur.skip_sprites);
5155 return;
5156 }
5157
5158 _cur.AddSpriteSets(feature, _cur.spriteid, first_set, num_sets, num_ents);
5159
5160 GrfMsg(7, "New sprite set at {} of feature 0x{:02X}, consisting of {} sets with {} views each (total {})",
5161 _cur.spriteid, feature, num_sets, num_ents, num_sets * num_ents
5162 );
5163
5164 for (int i = 0; i < num_sets * num_ents; i++) {
5165 _cur.nfo_line++;
5166 LoadNextSprite(_cur.spriteid++, *_cur.file, _cur.nfo_line);
5167 }
5168}
5169
5170/* Action 0x01 (SKIP) */
5171static void SkipAct1(ByteReader &buf)
5172{
5173 buf.ReadByte();
5174 uint16_t num_sets = buf.ReadByte();
5175
5176 if (num_sets == 0 && buf.HasData(3)) {
5177 /* Extended Action1 format.
5178 * Some GRFs define zero sets of zero sprites, though there is actually no use in that. Ignore them. */
5179 buf.ReadExtendedByte(); // first_set
5180 num_sets = buf.ReadExtendedByte();
5181 }
5182 uint16_t num_ents = buf.ReadExtendedByte();
5183
5184 _cur.skip_sprites = num_sets * num_ents;
5185
5186 GrfMsg(3, "SkipAct1: Skipping {} sprites", _cur.skip_sprites);
5187}
5188
5189using CachedCallback = std::pair<uint16_t, SpriteGroupID>;
5190static std::vector<CachedCallback> _cached_callback_groups;
5191
5192static const SpriteGroup *GetCallbackResultGroup(uint16_t value)
5193{
5194 /* Old style callback results (only valid for version < 8) have the highest byte 0xFF to signify it is a callback result.
5195 * New style ones only have the highest bit set (allows 15-bit results, instead of just 8) */
5196 if (_cur.grffile->grf_version < 8 && GB(value, 8, 8) == 0xFF) {
5197 value &= ~0xFF00;
5198 } else {
5199 value &= ~0x8000;
5200 }
5201
5202 /* Find position for value within the cached callback list. */
5203 auto it = std::ranges::lower_bound(_cached_callback_groups, value, std::less{}, &CachedCallback::first);
5204 if (it != std::end(_cached_callback_groups) && it->first == value) return SpriteGroup::Get(it->second);
5205
5206 /* Result value is not present, so make it and add to cache. */
5208 const SpriteGroup *group = new CallbackResultSpriteGroup(value);
5209 it = _cached_callback_groups.emplace(it, value, group->index);
5210 return group;
5211}
5212
5213/* Helper function to either create a callback or link to a previously
5214 * defined spritegroup. */
5215static const SpriteGroup *GetGroupFromGroupID(uint8_t setid, uint8_t type, uint16_t groupid)
5216{
5217 if (HasBit(groupid, 15)) return GetCallbackResultGroup(groupid);
5218
5219 if (groupid > MAX_SPRITEGROUP || _cur.spritegroups[groupid] == nullptr) {
5220 GrfMsg(1, "GetGroupFromGroupID(0x{:02X}:0x{:02X}): Groupid 0x{:04X} does not exist, leaving empty", setid, type, groupid);
5221 return nullptr;
5222 }
5223
5224 return _cur.spritegroups[groupid];
5225}
5226
5235static const SpriteGroup *CreateGroupFromGroupID(uint8_t feature, uint8_t setid, uint8_t type, uint16_t spriteid)
5236{
5237 if (HasBit(spriteid, 15)) return GetCallbackResultGroup(spriteid);
5238
5239 if (!_cur.IsValidSpriteSet(feature, spriteid)) {
5240 GrfMsg(1, "CreateGroupFromGroupID(0x{:02X}:0x{:02X}): Sprite set {} invalid", setid, type, spriteid);
5241 return nullptr;
5242 }
5243
5244 SpriteID spriteset_start = _cur.GetSprite(feature, spriteid);
5245 uint num_sprites = _cur.GetNumEnts(feature, spriteid);
5246
5247 /* Ensure that the sprites are loeded */
5248 assert(spriteset_start + num_sprites <= _cur.spriteid);
5249
5251 return new ResultSpriteGroup(spriteset_start, num_sprites);
5252}
5253
5254/* Action 0x02 */
5255static void NewSpriteGroup(ByteReader &buf)
5256{
5257 /* <02> <feature> <set-id> <type/num-entries> <feature-specific-data...>
5258 *
5259 * B feature see action 1
5260 * B set-id ID of this particular definition
5261 * B type/num-entries
5262 * if 80 or greater, this is a randomized or variational
5263 * list definition, see below
5264 * otherwise it specifies a number of entries, the exact
5265 * meaning depends on the feature
5266 * V feature-specific-data (huge mess, don't even look it up --pasky) */
5267 const SpriteGroup *act_group = nullptr;
5268
5269 uint8_t feature = buf.ReadByte();
5270 if (feature >= GSF_END) {
5271 GrfMsg(1, "NewSpriteGroup: Unsupported feature 0x{:02X}, skipping", feature);
5272 return;
5273 }
5274
5275 uint8_t setid = buf.ReadByte();
5276 uint8_t type = buf.ReadByte();
5277
5278 /* Sprite Groups are created here but they are allocated from a pool, so
5279 * we do not need to delete anything if there is an exception from the
5280 * ByteReader. */
5281
5282 switch (type) {
5283 /* Deterministic Sprite Group */
5284 case 0x81: // Self scope, byte
5285 case 0x82: // Parent scope, byte
5286 case 0x85: // Self scope, word
5287 case 0x86: // Parent scope, word
5288 case 0x89: // Self scope, dword
5289 case 0x8A: // Parent scope, dword
5290 {
5291 uint8_t varadjust;
5292 uint8_t varsize;
5293
5296 group->nfo_line = _cur.nfo_line;
5297 act_group = group;
5298 group->var_scope = HasBit(type, 1) ? VSG_SCOPE_PARENT : VSG_SCOPE_SELF;
5299
5300 switch (GB(type, 2, 2)) {
5301 default: NOT_REACHED();
5302 case 0: group->size = DSG_SIZE_BYTE; varsize = 1; break;
5303 case 1: group->size = DSG_SIZE_WORD; varsize = 2; break;
5304 case 2: group->size = DSG_SIZE_DWORD; varsize = 4; break;
5305 }
5306
5307 /* Loop through the var adjusts. Unfortunately we don't know how many we have
5308 * from the outset, so we shall have to keep reallocing. */
5309 do {
5310 DeterministicSpriteGroupAdjust &adjust = group->adjusts.emplace_back();
5311
5312 /* The first var adjust doesn't have an operation specified, so we set it to add. */
5313 adjust.operation = group->adjusts.size() == 1 ? DSGA_OP_ADD : (DeterministicSpriteGroupAdjustOperation)buf.ReadByte();
5314 adjust.variable = buf.ReadByte();
5315 if (adjust.variable == 0x7E) {
5316 /* Link subroutine group */
5317 adjust.subroutine = GetGroupFromGroupID(setid, type, buf.ReadByte());
5318 } else {
5319 adjust.parameter = IsInsideMM(adjust.variable, 0x60, 0x80) ? buf.ReadByte() : 0;
5320 }
5321
5322 varadjust = buf.ReadByte();
5323 adjust.shift_num = GB(varadjust, 0, 5);
5324 adjust.type = (DeterministicSpriteGroupAdjustType)GB(varadjust, 6, 2);
5325 adjust.and_mask = buf.ReadVarSize(varsize);
5326
5327 if (adjust.type != DSGA_TYPE_NONE) {
5328 adjust.add_val = buf.ReadVarSize(varsize);
5329 adjust.divmod_val = buf.ReadVarSize(varsize);
5330 if (adjust.divmod_val == 0) adjust.divmod_val = 1; // Ensure that divide by zero cannot occur
5331 } else {
5332 adjust.add_val = 0;
5333 adjust.divmod_val = 0;
5334 }
5335
5336 /* Continue reading var adjusts while bit 5 is set. */
5337 } while (HasBit(varadjust, 5));
5338
5339 std::vector<DeterministicSpriteGroupRange> ranges;
5340 ranges.resize(buf.ReadByte());
5341 for (auto &range : ranges) {
5342 range.group = GetGroupFromGroupID(setid, type, buf.ReadWord());
5343 range.low = buf.ReadVarSize(varsize);
5344 range.high = buf.ReadVarSize(varsize);
5345 }
5346
5347 group->default_group = GetGroupFromGroupID(setid, type, buf.ReadWord());
5348 group->error_group = ranges.empty() ? group->default_group : ranges[0].group;
5349 /* nvar == 0 is a special case -- we turn our value into a callback result */
5350 group->calculated_result = ranges.empty();
5351
5352 /* Sort ranges ascending. When ranges overlap, this may required clamping or splitting them */
5353 std::vector<uint32_t> bounds;
5354 bounds.reserve(ranges.size());
5355 for (const auto &range : ranges) {
5356 bounds.push_back(range.low);
5357 if (range.high != UINT32_MAX) bounds.push_back(range.high + 1);
5358 }
5359 std::sort(bounds.begin(), bounds.end());
5360 bounds.erase(std::unique(bounds.begin(), bounds.end()), bounds.end());
5361
5362 std::vector<const SpriteGroup *> target;
5363 target.reserve(bounds.size());
5364 for (const auto &bound : bounds) {
5365 const SpriteGroup *t = group->default_group;
5366 for (const auto &range : ranges) {
5367 if (range.low <= bound && bound <= range.high) {
5368 t = range.group;
5369 break;
5370 }
5371 }
5372 target.push_back(t);
5373 }
5374 assert(target.size() == bounds.size());
5375
5376 for (uint j = 0; j < bounds.size(); ) {
5377 if (target[j] != group->default_group) {
5378 DeterministicSpriteGroupRange &r = group->ranges.emplace_back();
5379 r.group = target[j];
5380 r.low = bounds[j];
5381 while (j < bounds.size() && target[j] == r.group) {
5382 j++;
5383 }
5384 r.high = j < bounds.size() ? bounds[j] - 1 : UINT32_MAX;
5385 } else {
5386 j++;
5387 }
5388 }
5389
5390 break;
5391 }
5392
5393 /* Randomized Sprite Group */
5394 case 0x80: // Self scope
5395 case 0x83: // Parent scope
5396 case 0x84: // Relative scope
5397 {
5400 group->nfo_line = _cur.nfo_line;
5401 act_group = group;
5402 group->var_scope = HasBit(type, 1) ? VSG_SCOPE_PARENT : VSG_SCOPE_SELF;
5403
5404 if (HasBit(type, 2)) {
5405 if (feature <= GSF_AIRCRAFT) group->var_scope = VSG_SCOPE_RELATIVE;
5406 group->count = buf.ReadByte();
5407 }
5408
5409 uint8_t triggers = buf.ReadByte();
5410 group->triggers = GB(triggers, 0, 7);
5411 group->cmp_mode = HasBit(triggers, 7) ? RSG_CMP_ALL : RSG_CMP_ANY;
5412 group->lowest_randbit = buf.ReadByte();
5413
5414 uint8_t num_groups = buf.ReadByte();
5415 if (!HasExactlyOneBit(num_groups)) {
5416 GrfMsg(1, "NewSpriteGroup: Random Action 2 nrand should be power of 2");
5417 }
5418
5419 group->groups.reserve(num_groups);
5420 for (uint i = 0; i < num_groups; i++) {
5421 group->groups.push_back(GetGroupFromGroupID(setid, type, buf.ReadWord()));
5422 }
5423
5424 break;
5425 }
5426
5427 /* Neither a variable or randomized sprite group... must be a real group */
5428 default:
5429 {
5430 switch (feature) {
5431 case GSF_TRAINS:
5432 case GSF_ROADVEHICLES:
5433 case GSF_SHIPS:
5434 case GSF_AIRCRAFT:
5435 case GSF_STATIONS:
5436 case GSF_CANALS:
5437 case GSF_CARGOES:
5438 case GSF_AIRPORTS:
5439 case GSF_RAILTYPES:
5440 case GSF_ROADTYPES:
5441 case GSF_TRAMTYPES:
5442 {
5443 uint8_t num_loaded = type;
5444 uint8_t num_loading = buf.ReadByte();
5445
5446 if (!_cur.HasValidSpriteSets(feature)) {
5447 GrfMsg(0, "NewSpriteGroup: No sprite set to work on! Skipping");
5448 return;
5449 }
5450
5451 GrfMsg(6, "NewSpriteGroup: New SpriteGroup 0x{:02X}, {} loaded, {} loading",
5452 setid, num_loaded, num_loading);
5453
5454 if (num_loaded + num_loading == 0) {
5455 GrfMsg(1, "NewSpriteGroup: no result, skipping invalid RealSpriteGroup");
5456 break;
5457 }
5458
5459 if (num_loaded + num_loading == 1) {
5460 /* Avoid creating 'Real' sprite group if only one option. */
5461 uint16_t spriteid = buf.ReadWord();
5462 act_group = CreateGroupFromGroupID(feature, setid, type, spriteid);
5463 GrfMsg(8, "NewSpriteGroup: one result, skipping RealSpriteGroup = subset {}", spriteid);
5464 break;
5465 }
5466
5467 std::vector<uint16_t> loaded;
5468 std::vector<uint16_t> loading;
5469
5470 loaded.reserve(num_loaded);
5471 for (uint i = 0; i < num_loaded; i++) {
5472 loaded.push_back(buf.ReadWord());
5473 GrfMsg(8, "NewSpriteGroup: + rg->loaded[{}] = subset {}", i, loaded[i]);
5474 }
5475
5476 loading.reserve(num_loading);
5477 for (uint i = 0; i < num_loading; i++) {
5478 loading.push_back(buf.ReadWord());
5479 GrfMsg(8, "NewSpriteGroup: + rg->loading[{}] = subset {}", i, loading[i]);
5480 }
5481
5482 bool loaded_same = !loaded.empty() && std::adjacent_find(loaded.begin(), loaded.end(), std::not_equal_to<>()) == loaded.end();
5483 bool loading_same = !loading.empty() && std::adjacent_find(loading.begin(), loading.end(), std::not_equal_to<>()) == loading.end();
5484 if (loaded_same && loading_same && loaded[0] == loading[0]) {
5485 /* Both lists only contain the same value, so don't create 'Real' sprite group */
5486 act_group = CreateGroupFromGroupID(feature, setid, type, loaded[0]);
5487 GrfMsg(8, "NewSpriteGroup: same result, skipping RealSpriteGroup = subset {}", loaded[0]);
5488 break;
5489 }
5490
5492 RealSpriteGroup *group = new RealSpriteGroup();
5493 group->nfo_line = _cur.nfo_line;
5494 act_group = group;
5495
5496 if (loaded_same && loaded.size() > 1) loaded.resize(1);
5497 group->loaded.reserve(loaded.size());
5498 for (uint16_t spriteid : loaded) {
5499 const SpriteGroup *t = CreateGroupFromGroupID(feature, setid, type, spriteid);
5500 group->loaded.push_back(t);
5501 }
5502
5503 if (loading_same && loading.size() > 1) loading.resize(1);
5504 group->loading.reserve(loading.size());
5505 for (uint16_t spriteid : loading) {
5506 const SpriteGroup *t = CreateGroupFromGroupID(feature, setid, type, spriteid);
5507 group->loading.push_back(t);
5508 }
5509
5510 break;
5511 }
5512
5513 case GSF_HOUSES:
5514 case GSF_AIRPORTTILES:
5515 case GSF_OBJECTS:
5516 case GSF_INDUSTRYTILES:
5517 case GSF_ROADSTOPS: {
5518 uint8_t num_building_sprites = std::max((uint8_t)1, type);
5519
5522 group->nfo_line = _cur.nfo_line;
5523 act_group = group;
5524
5525 /* On error, bail out immediately. Temporary GRF data was already freed */
5526 if (ReadSpriteLayout(buf, num_building_sprites, true, feature, false, type == 0, &group->dts)) return;
5527 break;
5528 }
5529
5530 case GSF_INDUSTRIES: {
5531 if (type > 2) {
5532 GrfMsg(1, "NewSpriteGroup: Unsupported industry production version {}, skipping", type);
5533 break;
5534 }
5535
5538 group->nfo_line = _cur.nfo_line;
5539 act_group = group;
5540 group->version = type;
5541 if (type == 0) {
5543 for (uint i = 0; i < INDUSTRY_ORIGINAL_NUM_INPUTS; i++) {
5544 group->subtract_input[i] = (int16_t)buf.ReadWord(); // signed
5545 }
5547 for (uint i = 0; i < INDUSTRY_ORIGINAL_NUM_OUTPUTS; i++) {
5548 group->add_output[i] = buf.ReadWord(); // unsigned
5549 }
5550 group->again = buf.ReadByte();
5551 } else if (type == 1) {
5553 for (uint i = 0; i < INDUSTRY_ORIGINAL_NUM_INPUTS; i++) {
5554 group->subtract_input[i] = buf.ReadByte();
5555 }
5557 for (uint i = 0; i < INDUSTRY_ORIGINAL_NUM_OUTPUTS; i++) {
5558 group->add_output[i] = buf.ReadByte();
5559 }
5560 group->again = buf.ReadByte();
5561 } else if (type == 2) {
5562 group->num_input = buf.ReadByte();
5563 if (group->num_input > lengthof(group->subtract_input)) {
5564 GRFError *error = DisableGrf(STR_NEWGRF_ERROR_INDPROD_CALLBACK);
5565 error->data = "too many inputs (max 16)";
5566 return;
5567 }
5568 for (uint i = 0; i < group->num_input; i++) {
5569 uint8_t rawcargo = buf.ReadByte();
5570 CargoType cargo = GetCargoTranslation(rawcargo, _cur.grffile);
5571 if (!IsValidCargoType(cargo)) {
5572 /* The mapped cargo is invalid. This is permitted at this point,
5573 * as long as the result is not used. Mark it invalid so this
5574 * can be tested later. */
5575 group->version = 0xFF;
5576 } else if (std::find(group->cargo_input, group->cargo_input + i, cargo) != group->cargo_input + i) {
5577 GRFError *error = DisableGrf(STR_NEWGRF_ERROR_INDPROD_CALLBACK);
5578 error->data = "duplicate input cargo";
5579 return;
5580 }
5581 group->cargo_input[i] = cargo;
5582 group->subtract_input[i] = buf.ReadByte();
5583 }
5584 group->num_output = buf.ReadByte();
5585 if (group->num_output > lengthof(group->add_output)) {
5586 GRFError *error = DisableGrf(STR_NEWGRF_ERROR_INDPROD_CALLBACK);
5587 error->data = "too many outputs (max 16)";
5588 return;
5589 }
5590 for (uint i = 0; i < group->num_output; i++) {
5591 uint8_t rawcargo = buf.ReadByte();
5592 CargoType cargo = GetCargoTranslation(rawcargo, _cur.grffile);
5593 if (!IsValidCargoType(cargo)) {
5594 /* Mark this result as invalid to use */
5595 group->version = 0xFF;
5596 } else if (std::find(group->cargo_output, group->cargo_output + i, cargo) != group->cargo_output + i) {
5597 GRFError *error = DisableGrf(STR_NEWGRF_ERROR_INDPROD_CALLBACK);
5598 error->data = "duplicate output cargo";
5599 return;
5600 }
5601 group->cargo_output[i] = cargo;
5602 group->add_output[i] = buf.ReadByte();
5603 }
5604 group->again = buf.ReadByte();
5605 } else {
5606 NOT_REACHED();
5607 }
5608 break;
5609 }
5610
5611 /* Loading of Tile Layout and Production Callback groups would happen here */
5612 default: GrfMsg(1, "NewSpriteGroup: Unsupported feature 0x{:02X}, skipping", feature);
5613 }
5614 }
5615 }
5616
5617 _cur.spritegroups[setid] = act_group;
5618}
5619
5625std::span<const CargoLabel> GetCargoTranslationTable(const GRFFile &grffile)
5626{
5627 /* Always use the translation table if it's installed. */
5628 if (!grffile.cargo_list.empty()) return grffile.cargo_list;
5629
5630 /* Pre-v7 use climate-dependent "slot" table. */
5631 if (grffile.grf_version < 7) return GetClimateDependentCargoTranslationTable();
5632
5633 /* Otherwise use climate-independent "bitnum" table. */
5635}
5636
5637static CargoType TranslateCargo(uint8_t feature, uint8_t ctype)
5638{
5639 /* Special cargo types for purchase list and stations */
5640 if ((feature == GSF_STATIONS || feature == GSF_ROADSTOPS) && ctype == 0xFE) return SpriteGroupCargo::SG_DEFAULT_NA;
5641 if (ctype == 0xFF) return SpriteGroupCargo::SG_PURCHASE;
5642
5643 auto cargo_list = GetCargoTranslationTable(*_cur.grffile);
5644
5645 /* Check if the cargo type is out of bounds of the cargo translation table */
5646 if (ctype >= cargo_list.size()) {
5647 GrfMsg(1, "TranslateCargo: Cargo type {} out of range (max {}), skipping.", ctype, (unsigned int)_cur.grffile->cargo_list.size() - 1);
5648 return INVALID_CARGO;
5649 }
5650
5651 /* Look up the cargo label from the translation table */
5652 CargoLabel cl = cargo_list[ctype];
5653 if (cl == CT_INVALID) {
5654 GrfMsg(5, "TranslateCargo: Cargo type {} not available in this climate, skipping.", ctype);
5655 return INVALID_CARGO;
5656 }
5657
5658 CargoType cargo_type = GetCargoTypeByLabel(cl);
5659 if (!IsValidCargoType(cargo_type)) {
5660 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));
5661 return INVALID_CARGO;
5662 }
5663
5664 GrfMsg(6, "TranslateCargo: Cargo '{:c}{:c}{:c}{:c}' mapped to cargo type {}.", GB(cl.base(), 24, 8), GB(cl.base(), 16, 8), GB(cl.base(), 8, 8), GB(cl.base(), 0, 8), cargo_type);
5665 return cargo_type;
5666}
5667
5668
5669static bool IsValidGroupID(uint16_t groupid, const char *function)
5670{
5671 if (groupid > MAX_SPRITEGROUP || _cur.spritegroups[groupid] == nullptr) {
5672 GrfMsg(1, "{}: Spritegroup 0x{:04X} out of range or empty, skipping.", function, groupid);
5673 return false;
5674 }
5675
5676 return true;
5677}
5678
5679static void VehicleMapSpriteGroup(ByteReader &buf, uint8_t feature, uint8_t idcount)
5680{
5681 static std::vector<EngineID> last_engines; // Engine IDs are remembered in case the next action is a wagon override.
5682 bool wagover = false;
5683
5684 /* Test for 'wagon override' flag */
5685 if (HasBit(idcount, 7)) {
5686 wagover = true;
5687 /* Strip off the flag */
5688 idcount = GB(idcount, 0, 7);
5689
5690 if (last_engines.empty()) {
5691 GrfMsg(0, "VehicleMapSpriteGroup: WagonOverride: No engine to do override with");
5692 return;
5693 }
5694
5695 GrfMsg(6, "VehicleMapSpriteGroup: WagonOverride: {} engines, {} wagons", last_engines.size(), idcount);
5696 } else {
5697 last_engines.resize(idcount);
5698 }
5699
5700 std::vector<EngineID> engines;
5701 engines.reserve(idcount);
5702 for (uint i = 0; i < idcount; i++) {
5703 Engine *e = GetNewEngine(_cur.grffile, (VehicleType)feature, buf.ReadExtendedByte());
5704 if (e == nullptr) {
5705 /* No engine could be allocated?!? Deal with it. Okay,
5706 * this might look bad. Also make sure this NewGRF
5707 * gets disabled, as a half loaded one is bad. */
5708 HandleChangeInfoResult("VehicleMapSpriteGroup", CIR_INVALID_ID, 0, 0);
5709 return;
5710 }
5711
5712 engines.push_back(e->index);
5713 if (!wagover) last_engines[i] = engines[i];
5714 }
5715
5716 uint8_t cidcount = buf.ReadByte();
5717 for (uint c = 0; c < cidcount; c++) {
5718 uint8_t ctype = buf.ReadByte();
5719 uint16_t groupid = buf.ReadWord();
5720 if (!IsValidGroupID(groupid, "VehicleMapSpriteGroup")) continue;
5721
5722 GrfMsg(8, "VehicleMapSpriteGroup: * [{}] Cargo type 0x{:X}, group id 0x{:02X}", c, ctype, groupid);
5723
5724 CargoType cargo_type = TranslateCargo(feature, ctype);
5725 if (!IsValidCargoType(cargo_type)) continue;
5726
5727 for (uint i = 0; i < idcount; i++) {
5728 EngineID engine = engines[i];
5729
5730 GrfMsg(7, "VehicleMapSpriteGroup: [{}] Engine {}...", i, engine);
5731
5732 if (wagover) {
5733 SetWagonOverrideSprites(engine, cargo_type, _cur.spritegroups[groupid], last_engines);
5734 } else {
5735 SetCustomEngineSprites(engine, cargo_type, _cur.spritegroups[groupid]);
5736 }
5737 }
5738 }
5739
5740 uint16_t groupid = buf.ReadWord();
5741 if (!IsValidGroupID(groupid, "VehicleMapSpriteGroup")) return;
5742
5743 GrfMsg(8, "-- Default group id 0x{:04X}", groupid);
5744
5745 for (uint i = 0; i < idcount; i++) {
5746 EngineID engine = engines[i];
5747
5748 if (wagover) {
5749 SetWagonOverrideSprites(engine, SpriteGroupCargo::SG_DEFAULT, _cur.spritegroups[groupid], last_engines);
5750 } else {
5751 SetCustomEngineSprites(engine, SpriteGroupCargo::SG_DEFAULT, _cur.spritegroups[groupid]);
5752 SetEngineGRF(engine, _cur.grffile);
5753 }
5754 }
5755}
5756
5757
5758static void CanalMapSpriteGroup(ByteReader &buf, uint8_t idcount)
5759{
5760 std::vector<uint16_t> cfs;
5761 cfs.reserve(idcount);
5762 for (uint i = 0; i < idcount; i++) {
5763 cfs.push_back(buf.ReadExtendedByte());
5764 }
5765
5766 uint8_t cidcount = buf.ReadByte();
5767 buf.Skip(cidcount * 3);
5768
5769 uint16_t groupid = buf.ReadWord();
5770 if (!IsValidGroupID(groupid, "CanalMapSpriteGroup")) return;
5771
5772 for (auto &cf : cfs) {
5773 if (cf >= CF_END) {
5774 GrfMsg(1, "CanalMapSpriteGroup: Canal subset {} out of range, skipping", cf);
5775 continue;
5776 }
5777
5778 _water_feature[cf].grffile = _cur.grffile;
5779 _water_feature[cf].group = _cur.spritegroups[groupid];
5780 }
5781}
5782
5783
5784static void StationMapSpriteGroup(ByteReader &buf, uint8_t idcount)
5785{
5786 if (_cur.grffile->stations.empty()) {
5787 GrfMsg(1, "StationMapSpriteGroup: No stations defined, skipping");
5788 return;
5789 }
5790
5791 std::vector<uint16_t> stations;
5792 stations.reserve(idcount);
5793 for (uint i = 0; i < idcount; i++) {
5794 stations.push_back(buf.ReadExtendedByte());
5795 }
5796
5797 uint8_t cidcount = buf.ReadByte();
5798 for (uint c = 0; c < cidcount; c++) {
5799 uint8_t ctype = buf.ReadByte();
5800 uint16_t groupid = buf.ReadWord();
5801 if (!IsValidGroupID(groupid, "StationMapSpriteGroup")) continue;
5802
5803 ctype = TranslateCargo(GSF_STATIONS, ctype);
5804 if (!IsValidCargoType(ctype)) continue;
5805
5806 for (auto &station : stations) {
5807 StationSpec *statspec = station >= _cur.grffile->stations.size() ? nullptr : _cur.grffile->stations[station].get();
5808
5809 if (statspec == nullptr) {
5810 GrfMsg(1, "StationMapSpriteGroup: Station {} undefined, skipping", station);
5811 continue;
5812 }
5813
5814 statspec->grf_prop.spritegroup[ctype] = _cur.spritegroups[groupid];
5815 }
5816 }
5817
5818 uint16_t groupid = buf.ReadWord();
5819 if (!IsValidGroupID(groupid, "StationMapSpriteGroup")) return;
5820
5821 for (auto &station : stations) {
5822 StationSpec *statspec = station >= _cur.grffile->stations.size() ? nullptr : _cur.grffile->stations[station].get();
5823
5824 if (statspec == nullptr) {
5825 GrfMsg(1, "StationMapSpriteGroup: Station {} undefined, skipping", station);
5826 continue;
5827 }
5828
5829 if (statspec->grf_prop.HasGrfFile()) {
5830 GrfMsg(1, "StationMapSpriteGroup: Station {} mapped multiple times, skipping", station);
5831 continue;
5832 }
5833
5834 statspec->grf_prop.spritegroup[SpriteGroupCargo::SG_DEFAULT] = _cur.spritegroups[groupid];
5835 statspec->grf_prop.grfid = _cur.grffile->grfid;
5836 statspec->grf_prop.grffile = _cur.grffile;
5837 statspec->grf_prop.local_id = station;
5838 StationClass::Assign(statspec);
5839 }
5840}
5841
5842
5843static void TownHouseMapSpriteGroup(ByteReader &buf, uint8_t idcount)
5844{
5845 if (_cur.grffile->housespec.empty()) {
5846 GrfMsg(1, "TownHouseMapSpriteGroup: No houses defined, skipping");
5847 return;
5848 }
5849
5850 std::vector<uint16_t> houses;
5851 houses.reserve(idcount);
5852 for (uint i = 0; i < idcount; i++) {
5853 houses.push_back(buf.ReadExtendedByte());
5854 }
5855
5856 /* Skip the cargo type section, we only care about the default group */
5857 uint8_t cidcount = buf.ReadByte();
5858 buf.Skip(cidcount * 3);
5859
5860 uint16_t groupid = buf.ReadWord();
5861 if (!IsValidGroupID(groupid, "TownHouseMapSpriteGroup")) return;
5862
5863 for (auto &house : houses) {
5864 HouseSpec *hs = house >= _cur.grffile->housespec.size() ? nullptr : _cur.grffile->housespec[house].get();
5865
5866 if (hs == nullptr) {
5867 GrfMsg(1, "TownHouseMapSpriteGroup: House {} undefined, skipping.", house);
5868 continue;
5869 }
5870
5871 hs->grf_prop.spritegroup[0] = _cur.spritegroups[groupid];
5872 }
5873}
5874
5875static void IndustryMapSpriteGroup(ByteReader &buf, uint8_t idcount)
5876{
5877 if (_cur.grffile->industryspec.empty()) {
5878 GrfMsg(1, "IndustryMapSpriteGroup: No industries defined, skipping");
5879 return;
5880 }
5881
5882 std::vector<uint16_t> industries;
5883 industries.reserve(idcount);
5884 for (uint i = 0; i < idcount; i++) {
5885 industries.push_back(buf.ReadExtendedByte());
5886 }
5887
5888 /* Skip the cargo type section, we only care about the default group */
5889 uint8_t cidcount = buf.ReadByte();
5890 buf.Skip(cidcount * 3);
5891
5892 uint16_t groupid = buf.ReadWord();
5893 if (!IsValidGroupID(groupid, "IndustryMapSpriteGroup")) return;
5894
5895 for (auto &industry : industries) {
5896 IndustrySpec *indsp = industry >= _cur.grffile->industryspec.size() ? nullptr : _cur.grffile->industryspec[industry].get();
5897
5898 if (indsp == nullptr) {
5899 GrfMsg(1, "IndustryMapSpriteGroup: Industry {} undefined, skipping", industry);
5900 continue;
5901 }
5902
5903 indsp->grf_prop.spritegroup[0] = _cur.spritegroups[groupid];
5904 }
5905}
5906
5907static void IndustrytileMapSpriteGroup(ByteReader &buf, uint8_t idcount)
5908{
5909 if (_cur.grffile->indtspec.empty()) {
5910 GrfMsg(1, "IndustrytileMapSpriteGroup: No industry tiles defined, skipping");
5911 return;
5912 }
5913
5914 std::vector<uint16_t> indtiles;
5915 indtiles.reserve(idcount);
5916 for (uint i = 0; i < idcount; i++) {
5917 indtiles.push_back(buf.ReadExtendedByte());
5918 }
5919
5920 /* Skip the cargo type section, we only care about the default group */
5921 uint8_t cidcount = buf.ReadByte();
5922 buf.Skip(cidcount * 3);
5923
5924 uint16_t groupid = buf.ReadWord();
5925 if (!IsValidGroupID(groupid, "IndustrytileMapSpriteGroup")) return;
5926
5927 for (auto &indtile : indtiles) {
5928 IndustryTileSpec *indtsp = indtile >= _cur.grffile->indtspec.size() ? nullptr : _cur.grffile->indtspec[indtile].get();
5929
5930 if (indtsp == nullptr) {
5931 GrfMsg(1, "IndustrytileMapSpriteGroup: Industry tile {} undefined, skipping", indtile);
5932 continue;
5933 }
5934
5935 indtsp->grf_prop.spritegroup[0] = _cur.spritegroups[groupid];
5936 }
5937}
5938
5939static void CargoMapSpriteGroup(ByteReader &buf, uint8_t idcount)
5940{
5941 std::vector<uint16_t> cargoes;
5942 cargoes.reserve(idcount);
5943 for (uint i = 0; i < idcount; i++) {
5944 cargoes.push_back(buf.ReadExtendedByte());
5945 }
5946
5947 /* Skip the cargo type section, we only care about the default group */
5948 uint8_t cidcount = buf.ReadByte();
5949 buf.Skip(cidcount * 3);
5950
5951 uint16_t groupid = buf.ReadWord();
5952 if (!IsValidGroupID(groupid, "CargoMapSpriteGroup")) return;
5953
5954 for (auto &cargo_type : cargoes) {
5955 if (cargo_type >= NUM_CARGO) {
5956 GrfMsg(1, "CargoMapSpriteGroup: Cargo type {} out of range, skipping", cargo_type);
5957 continue;
5958 }
5959
5960 CargoSpec *cs = CargoSpec::Get(cargo_type);
5961 cs->grffile = _cur.grffile;
5962 cs->group = _cur.spritegroups[groupid];
5963 }
5964}
5965
5966static void ObjectMapSpriteGroup(ByteReader &buf, uint8_t idcount)
5967{
5968 if (_cur.grffile->objectspec.empty()) {
5969 GrfMsg(1, "ObjectMapSpriteGroup: No object tiles defined, skipping");
5970 return;
5971 }
5972
5973 std::vector<uint16_t> objects;
5974 objects.reserve(idcount);
5975 for (uint i = 0; i < idcount; i++) {
5976 objects.push_back(buf.ReadExtendedByte());
5977 }
5978
5979 uint8_t cidcount = buf.ReadByte();
5980 for (uint c = 0; c < cidcount; c++) {
5981 uint8_t ctype = buf.ReadByte();
5982 uint16_t groupid = buf.ReadWord();
5983 if (!IsValidGroupID(groupid, "ObjectMapSpriteGroup")) continue;
5984
5985 /* The only valid option here is purchase list sprite groups. */
5986 if (ctype != 0xFF) {
5987 GrfMsg(1, "ObjectMapSpriteGroup: Invalid cargo bitnum {} for objects, skipping.", ctype);
5988 continue;
5989 }
5990
5991 for (auto &object : objects) {
5992 ObjectSpec *spec = object >= _cur.grffile->objectspec.size() ? nullptr : _cur.grffile->objectspec[object].get();
5993
5994 if (spec == nullptr) {
5995 GrfMsg(1, "ObjectMapSpriteGroup: Object {} undefined, skipping", object);
5996 continue;
5997 }
5998
5999 spec->grf_prop.spritegroup[OBJECT_SPRITE_GROUP_PURCHASE] = _cur.spritegroups[groupid];
6000 }
6001 }
6002
6003 uint16_t groupid = buf.ReadWord();
6004 if (!IsValidGroupID(groupid, "ObjectMapSpriteGroup")) return;
6005
6006 for (auto &object : objects) {
6007 ObjectSpec *spec = object >= _cur.grffile->objectspec.size() ? nullptr : _cur.grffile->objectspec[object].get();
6008
6009 if (spec == nullptr) {
6010 GrfMsg(1, "ObjectMapSpriteGroup: Object {} undefined, skipping", object);
6011 continue;
6012 }
6013
6014 if (spec->grf_prop.HasGrfFile()) {
6015 GrfMsg(1, "ObjectMapSpriteGroup: Object {} mapped multiple times, skipping", object);
6016 continue;
6017 }
6018
6019 spec->grf_prop.spritegroup[OBJECT_SPRITE_GROUP_DEFAULT] = _cur.spritegroups[groupid];
6020 spec->grf_prop.grfid = _cur.grffile->grfid;
6021 spec->grf_prop.grffile = _cur.grffile;
6022 spec->grf_prop.local_id = object;
6023 }
6024}
6025
6026static void RailTypeMapSpriteGroup(ByteReader &buf, uint8_t idcount)
6027{
6028 std::vector<uint8_t> railtypes;
6029 railtypes.reserve(idcount);
6030 for (uint i = 0; i < idcount; i++) {
6031 uint16_t id = buf.ReadExtendedByte();
6032 railtypes.push_back(id < RAILTYPE_END ? _cur.grffile->railtype_map[id] : INVALID_RAILTYPE);
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, "RailTypeMapSpriteGroup")) continue;
6040
6041 if (ctype >= RTSG_END) continue;
6042
6043 extern RailTypeInfo _railtypes[RAILTYPE_END];
6044 for (auto &railtype : railtypes) {
6045 if (railtype != INVALID_RAILTYPE) {
6046 RailTypeInfo *rti = &_railtypes[railtype];
6047
6048 rti->grffile[ctype] = _cur.grffile;
6049 rti->group[ctype] = _cur.spritegroups[groupid];
6050 }
6051 }
6052 }
6053
6054 /* Railtypes do not use the default group. */
6055 buf.ReadWord();
6056}
6057
6058static void RoadTypeMapSpriteGroup(ByteReader &buf, uint8_t idcount, RoadTramType rtt)
6059{
6060 std::array<RoadType, ROADTYPE_END> &type_map = (rtt == RTT_TRAM) ? _cur.grffile->tramtype_map : _cur.grffile->roadtype_map;
6061
6062 std::vector<uint8_t> roadtypes;
6063 roadtypes.reserve(idcount);
6064 for (uint i = 0; i < idcount; i++) {
6065 uint16_t id = buf.ReadExtendedByte();
6066 roadtypes.push_back(id < ROADTYPE_END ? type_map[id] : INVALID_ROADTYPE);
6067 }
6068
6069 uint8_t cidcount = buf.ReadByte();
6070 for (uint c = 0; c < cidcount; c++) {
6071 uint8_t ctype = buf.ReadByte();
6072 uint16_t groupid = buf.ReadWord();
6073 if (!IsValidGroupID(groupid, "RoadTypeMapSpriteGroup")) continue;
6074
6075 if (ctype >= ROTSG_END) continue;
6076
6077 extern RoadTypeInfo _roadtypes[ROADTYPE_END];
6078 for (auto &roadtype : roadtypes) {
6079 if (roadtype != INVALID_ROADTYPE) {
6080 RoadTypeInfo *rti = &_roadtypes[roadtype];
6081
6082 rti->grffile[ctype] = _cur.grffile;
6083 rti->group[ctype] = _cur.spritegroups[groupid];
6084 }
6085 }
6086 }
6087
6088 /* Roadtypes do not use the default group. */
6089 buf.ReadWord();
6090}
6091
6092static void AirportMapSpriteGroup(ByteReader &buf, uint8_t idcount)
6093{
6094 if (_cur.grffile->airportspec.empty()) {
6095 GrfMsg(1, "AirportMapSpriteGroup: No airports defined, skipping");
6096 return;
6097 }
6098
6099 std::vector<uint16_t> airports;
6100 airports.reserve(idcount);
6101 for (uint i = 0; i < idcount; i++) {
6102 airports.push_back(buf.ReadExtendedByte());
6103 }
6104
6105 /* Skip the cargo type section, we only care about the default group */
6106 uint8_t cidcount = buf.ReadByte();
6107 buf.Skip(cidcount * 3);
6108
6109 uint16_t groupid = buf.ReadWord();
6110 if (!IsValidGroupID(groupid, "AirportMapSpriteGroup")) return;
6111
6112 for (auto &airport : airports) {
6113 AirportSpec *as = airport >= _cur.grffile->airportspec.size() ? nullptr : _cur.grffile->airportspec[airport].get();
6114
6115 if (as == nullptr) {
6116 GrfMsg(1, "AirportMapSpriteGroup: Airport {} undefined, skipping", airport);
6117 continue;
6118 }
6119
6120 as->grf_prop.spritegroup[0] = _cur.spritegroups[groupid];
6121 }
6122}
6123
6124static void AirportTileMapSpriteGroup(ByteReader &buf, uint8_t idcount)
6125{
6126 if (_cur.grffile->airtspec.empty()) {
6127 GrfMsg(1, "AirportTileMapSpriteGroup: No airport tiles defined, skipping");
6128 return;
6129 }
6130
6131 std::vector<uint16_t> airptiles;
6132 airptiles.reserve(idcount);
6133 for (uint i = 0; i < idcount; i++) {
6134 airptiles.push_back(buf.ReadExtendedByte());
6135 }
6136
6137 /* Skip the cargo type section, we only care about the default group */
6138 uint8_t cidcount = buf.ReadByte();
6139 buf.Skip(cidcount * 3);
6140
6141 uint16_t groupid = buf.ReadWord();
6142 if (!IsValidGroupID(groupid, "AirportTileMapSpriteGroup")) return;
6143
6144 for (auto &airptile : airptiles) {
6145 AirportTileSpec *airtsp = airptile >= _cur.grffile->airtspec.size() ? nullptr : _cur.grffile->airtspec[airptile].get();
6146
6147 if (airtsp == nullptr) {
6148 GrfMsg(1, "AirportTileMapSpriteGroup: Airport tile {} undefined, skipping", airptile);
6149 continue;
6150 }
6151
6152 airtsp->grf_prop.spritegroup[0] = _cur.spritegroups[groupid];
6153 }
6154}
6155
6156static void RoadStopMapSpriteGroup(ByteReader &buf, uint8_t idcount)
6157{
6158 if (_cur.grffile->roadstops.empty()) {
6159 GrfMsg(1, "RoadStopMapSpriteGroup: No roadstops defined, skipping");
6160 return;
6161 }
6162
6163 std::vector<uint16_t> roadstops;
6164 roadstops.reserve(idcount);
6165 for (uint i = 0; i < idcount; i++) {
6166 roadstops.push_back(buf.ReadExtendedByte());
6167 }
6168
6169 uint8_t cidcount = buf.ReadByte();
6170 for (uint c = 0; c < cidcount; c++) {
6171 uint8_t ctype = buf.ReadByte();
6172 uint16_t groupid = buf.ReadWord();
6173 if (!IsValidGroupID(groupid, "RoadStopMapSpriteGroup")) continue;
6174
6175 ctype = TranslateCargo(GSF_ROADSTOPS, ctype);
6176 if (!IsValidCargoType(ctype)) continue;
6177
6178 for (auto &roadstop : roadstops) {
6179 RoadStopSpec *roadstopspec = roadstop >= _cur.grffile->roadstops.size() ? nullptr : _cur.grffile->roadstops[roadstop].get();
6180
6181 if (roadstopspec == nullptr) {
6182 GrfMsg(1, "RoadStopMapSpriteGroup: Road stop {} undefined, skipping", roadstop);
6183 continue;
6184 }
6185
6186 roadstopspec->grf_prop.spritegroup[ctype] = _cur.spritegroups[groupid];
6187 }
6188 }
6189
6190 uint16_t groupid = buf.ReadWord();
6191 if (!IsValidGroupID(groupid, "RoadStopMapSpriteGroup")) return;
6192
6193 for (auto &roadstop : roadstops) {
6194 RoadStopSpec *roadstopspec = roadstop >= _cur.grffile->roadstops.size() ? nullptr : _cur.grffile->roadstops[roadstop].get();
6195
6196 if (roadstopspec == nullptr) {
6197 GrfMsg(1, "RoadStopMapSpriteGroup: Road stop {} undefined, skipping.", roadstop);
6198 continue;
6199 }
6200
6201 if (roadstopspec->grf_prop.HasGrfFile()) {
6202 GrfMsg(1, "RoadStopMapSpriteGroup: Road stop {} mapped multiple times, skipping", roadstop);
6203 continue;
6204 }
6205
6206 roadstopspec->grf_prop.spritegroup[SpriteGroupCargo::SG_DEFAULT] = _cur.spritegroups[groupid];
6207 roadstopspec->grf_prop.grfid = _cur.grffile->grfid;
6208 roadstopspec->grf_prop.grffile = _cur.grffile;
6209 roadstopspec->grf_prop.local_id = roadstop;
6210 RoadStopClass::Assign(roadstopspec);
6211 }
6212}
6213
6214/* Action 0x03 */
6215static void FeatureMapSpriteGroup(ByteReader &buf)
6216{
6217 /* <03> <feature> <n-id> <ids>... <num-cid> [<cargo-type> <cid>]... <def-cid>
6218 * id-list := [<id>] [id-list]
6219 * cargo-list := <cargo-type> <cid> [cargo-list]
6220 *
6221 * B feature see action 0
6222 * B n-id bits 0-6: how many IDs this definition applies to
6223 * bit 7: if set, this is a wagon override definition (see below)
6224 * E ids the IDs for which this definition applies
6225 * B num-cid number of cargo IDs (sprite group IDs) in this definition
6226 * can be zero, in that case the def-cid is used always
6227 * B cargo-type type of this cargo type (e.g. mail=2, wood=7, see below)
6228 * W cid cargo ID (sprite group ID) for this type of cargo
6229 * W def-cid default cargo ID (sprite group ID) */
6230
6231 uint8_t feature = buf.ReadByte();
6232 uint8_t idcount = buf.ReadByte();
6233
6234 if (feature >= GSF_END) {
6235 GrfMsg(1, "FeatureMapSpriteGroup: Unsupported feature 0x{:02X}, skipping", feature);
6236 return;
6237 }
6238
6239 /* If idcount is zero, this is a feature callback */
6240 if (idcount == 0) {
6241 /* Skip number of cargo ids? */
6242 buf.ReadByte();
6243 uint16_t groupid = buf.ReadWord();
6244 if (!IsValidGroupID(groupid, "FeatureMapSpriteGroup")) return;
6245
6246 GrfMsg(6, "FeatureMapSpriteGroup: Adding generic feature callback for feature 0x{:02X}", feature);
6247
6248 AddGenericCallback(feature, _cur.grffile, _cur.spritegroups[groupid]);
6249 return;
6250 }
6251
6252 /* Mark the feature as used by the grf (generic callbacks do not count) */
6253 SetBit(_cur.grffile->grf_features, feature);
6254
6255 GrfMsg(6, "FeatureMapSpriteGroup: Feature 0x{:02X}, {} ids", feature, idcount);
6256
6257 switch (feature) {
6258 case GSF_TRAINS:
6259 case GSF_ROADVEHICLES:
6260 case GSF_SHIPS:
6261 case GSF_AIRCRAFT:
6262 VehicleMapSpriteGroup(buf, feature, idcount);
6263 return;
6264
6265 case GSF_CANALS:
6266 CanalMapSpriteGroup(buf, idcount);
6267 return;
6268
6269 case GSF_STATIONS:
6270 StationMapSpriteGroup(buf, idcount);
6271 return;
6272
6273 case GSF_HOUSES:
6274 TownHouseMapSpriteGroup(buf, idcount);
6275 return;
6276
6277 case GSF_INDUSTRIES:
6278 IndustryMapSpriteGroup(buf, idcount);
6279 return;
6280
6281 case GSF_INDUSTRYTILES:
6282 IndustrytileMapSpriteGroup(buf, idcount);
6283 return;
6284
6285 case GSF_CARGOES:
6286 CargoMapSpriteGroup(buf, idcount);
6287 return;
6288
6289 case GSF_AIRPORTS:
6290 AirportMapSpriteGroup(buf, idcount);
6291 return;
6292
6293 case GSF_OBJECTS:
6294 ObjectMapSpriteGroup(buf, idcount);
6295 break;
6296
6297 case GSF_RAILTYPES:
6298 RailTypeMapSpriteGroup(buf, idcount);
6299 break;
6300
6301 case GSF_ROADTYPES:
6302 RoadTypeMapSpriteGroup(buf, idcount, RTT_ROAD);
6303 break;
6304
6305 case GSF_TRAMTYPES:
6306 RoadTypeMapSpriteGroup(buf, idcount, RTT_TRAM);
6307 break;
6308
6309 case GSF_AIRPORTTILES:
6310 AirportTileMapSpriteGroup(buf, idcount);
6311 return;
6312
6313 case GSF_ROADSTOPS:
6314 RoadStopMapSpriteGroup(buf, idcount);
6315 return;
6316
6317 default:
6318 GrfMsg(1, "FeatureMapSpriteGroup: Unsupported feature 0x{:02X}, skipping", feature);
6319 return;
6320 }
6321}
6322
6323/* Action 0x04 */
6324static void FeatureNewName(ByteReader &buf)
6325{
6326 /* <04> <veh-type> <language-id> <num-veh> <offset> <data...>
6327 *
6328 * B veh-type see action 0 (as 00..07, + 0A
6329 * But IF veh-type = 48, then generic text
6330 * B language-id If bit 6 is set, This is the extended language scheme,
6331 * with up to 64 language.
6332 * Otherwise, it is a mapping where set bits have meaning
6333 * 0 = american, 1 = english, 2 = german, 3 = french, 4 = spanish
6334 * Bit 7 set means this is a generic text, not a vehicle one (or else)
6335 * B num-veh number of vehicles which are getting a new name
6336 * B/W offset number of the first vehicle that gets a new name
6337 * Byte : ID of vehicle to change
6338 * Word : ID of string to change/add
6339 * S data new texts, each of them zero-terminated, after
6340 * which the next name begins. */
6341
6342 bool new_scheme = _cur.grffile->grf_version >= 7;
6343
6344 uint8_t feature = buf.ReadByte();
6345 if (feature >= GSF_END && feature != 0x48) {
6346 GrfMsg(1, "FeatureNewName: Unsupported feature 0x{:02X}, skipping", feature);
6347 return;
6348 }
6349
6350 uint8_t lang = buf.ReadByte();
6351 uint8_t num = buf.ReadByte();
6352 bool generic = HasBit(lang, 7);
6353 uint16_t id;
6354 if (generic) {
6355 id = buf.ReadWord();
6356 } else if (feature <= GSF_AIRCRAFT) {
6357 id = buf.ReadExtendedByte();
6358 } else {
6359 id = buf.ReadByte();
6360 }
6361
6362 ClrBit(lang, 7);
6363
6364 uint16_t endid = id + num;
6365
6366 GrfMsg(6, "FeatureNewName: About to rename engines {}..{} (feature 0x{:02X}) in language 0x{:02X}",
6367 id, endid, feature, lang);
6368
6369 for (; id < endid && buf.HasData(); id++) {
6370 const std::string_view name = buf.ReadString();
6371 GrfMsg(8, "FeatureNewName: 0x{:04X} <- {}", id, StrMakeValid(name));
6372
6373 switch (feature) {
6374 case GSF_TRAINS:
6375 case GSF_ROADVEHICLES:
6376 case GSF_SHIPS:
6377 case GSF_AIRCRAFT:
6378 if (!generic) {
6380 if (e == nullptr) break;
6381 StringID string = AddGRFString(_cur.grffile->grfid, GRFStringID{e->index}, lang, new_scheme, false, name, e->info.string_id);
6382 e->info.string_id = string;
6383 } else {
6384 AddGRFString(_cur.grffile->grfid, GRFStringID{id}, lang, new_scheme, true, name, STR_UNDEFINED);
6385 }
6386 break;
6387
6388 default:
6389 if (IsInsideMM(id, 0xD000, 0xD400) || IsInsideMM(id, 0xD800, 0x10000)) {
6390 AddGRFString(_cur.grffile->grfid, GRFStringID{id}, lang, new_scheme, true, name, STR_UNDEFINED);
6391 break;
6392 }
6393
6394 switch (GB(id, 8, 8)) {
6395 case 0xC4: // Station class name
6396 if (GB(id, 0, 8) >= _cur.grffile->stations.size() || _cur.grffile->stations[GB(id, 0, 8)] == nullptr) {
6397 GrfMsg(1, "FeatureNewName: Attempt to name undefined station 0x{:X}, ignoring", GB(id, 0, 8));
6398 } else {
6399 StationClassID class_index = _cur.grffile->stations[GB(id, 0, 8)]->class_index;
6400 StationClass::Get(class_index)->name = AddGRFString(_cur.grffile->grfid, GRFStringID{id}, lang, new_scheme, false, name, STR_UNDEFINED);
6401 }
6402 break;
6403
6404 case 0xC5: // Station name
6405 if (GB(id, 0, 8) >= _cur.grffile->stations.size() || _cur.grffile->stations[GB(id, 0, 8)] == nullptr) {
6406 GrfMsg(1, "FeatureNewName: Attempt to name undefined station 0x{:X}, ignoring", GB(id, 0, 8));
6407 } else {
6408 _cur.grffile->stations[GB(id, 0, 8)]->name = AddGRFString(_cur.grffile->grfid, GRFStringID{id}, lang, new_scheme, false, name, STR_UNDEFINED);
6409 }
6410 break;
6411
6412 case 0xC7: // Airporttile name
6413 if (GB(id, 0, 8) >= _cur.grffile->airtspec.size() || _cur.grffile->airtspec[GB(id, 0, 8)] == nullptr) {
6414 GrfMsg(1, "FeatureNewName: Attempt to name undefined airport tile 0x{:X}, ignoring", GB(id, 0, 8));
6415 } else {
6416 _cur.grffile->airtspec[GB(id, 0, 8)]->name = AddGRFString(_cur.grffile->grfid, GRFStringID{id}, lang, new_scheme, false, name, STR_UNDEFINED);
6417 }
6418 break;
6419
6420 case 0xC9: // House name
6421 if (GB(id, 0, 8) >= _cur.grffile->housespec.size() || _cur.grffile->housespec[GB(id, 0, 8)] == nullptr) {
6422 GrfMsg(1, "FeatureNewName: Attempt to name undefined house 0x{:X}, ignoring.", GB(id, 0, 8));
6423 } else {
6424 _cur.grffile->housespec[GB(id, 0, 8)]->building_name = AddGRFString(_cur.grffile->grfid, GRFStringID{id}, lang, new_scheme, false, name, STR_UNDEFINED);
6425 }
6426 break;
6427
6428 default:
6429 GrfMsg(7, "FeatureNewName: Unsupported ID (0x{:04X})", id);
6430 break;
6431 }
6432 break;
6433 }
6434 }
6435}
6436
6445static uint16_t SanitizeSpriteOffset(uint16_t &num, uint16_t offset, int max_sprites, const std::string_view name)
6446{
6447
6448 if (offset >= max_sprites) {
6449 GrfMsg(1, "GraphicsNew: {} sprite offset must be less than {}, skipping", name, max_sprites);
6450 uint orig_num = num;
6451 num = 0;
6452 return orig_num;
6453 }
6454
6455 if (offset + num > max_sprites) {
6456 GrfMsg(4, "GraphicsNew: {} sprite overflow, truncating...", name);
6457 uint orig_num = num;
6458 num = std::max(max_sprites - offset, 0);
6459 return orig_num - num;
6460 }
6461
6462 return 0;
6463}
6464
6465
6467static constexpr auto _action5_types = std::to_array<Action5Type>({
6468 /* Note: min_sprites should not be changed. Therefore these constants are directly here and not in sprites.h */
6469 /* 0x00 */ { A5BLOCK_INVALID, 0, 0, 0, "Type 0x00" },
6470 /* 0x01 */ { A5BLOCK_INVALID, 0, 0, 0, "Type 0x01" },
6471 /* 0x02 */ { A5BLOCK_INVALID, 0, 0, 0, "Type 0x02" },
6472 /* 0x03 */ { A5BLOCK_INVALID, 0, 0, 0, "Type 0x03" },
6473 /* 0x04 */ { A5BLOCK_ALLOW_OFFSET, SPR_SIGNALS_BASE, 1, PRESIGNAL_SEMAPHORE_AND_PBS_SPRITE_COUNT, "Signal graphics" },
6474 /* 0x05 */ { A5BLOCK_ALLOW_OFFSET, SPR_ELRAIL_BASE, 1, ELRAIL_SPRITE_COUNT, "Rail catenary graphics" },
6475 /* 0x06 */ { A5BLOCK_ALLOW_OFFSET, SPR_SLOPES_BASE, 1, NORMAL_AND_HALFTILE_FOUNDATION_SPRITE_COUNT, "Foundation graphics" },
6476 /* 0x07 */ { A5BLOCK_INVALID, 0, 75, 0, "TTDP GUI graphics" }, // Not used by OTTD.
6477 /* 0x08 */ { A5BLOCK_ALLOW_OFFSET, SPR_CANALS_BASE, 1, CANALS_SPRITE_COUNT, "Canal graphics" },
6478 /* 0x09 */ { A5BLOCK_ALLOW_OFFSET, SPR_ONEWAY_BASE, 1, ONEWAY_SPRITE_COUNT, "One way road graphics" },
6479 /* 0x0A */ { A5BLOCK_ALLOW_OFFSET, SPR_2CCMAP_BASE, 1, TWOCCMAP_SPRITE_COUNT, "2CC colour maps" },
6480 /* 0x0B */ { A5BLOCK_ALLOW_OFFSET, SPR_TRAMWAY_BASE, 1, TRAMWAY_SPRITE_COUNT, "Tramway graphics" },
6481 /* 0x0C */ { A5BLOCK_INVALID, 0, 133, 0, "Snowy temperate tree" }, // Not yet used by OTTD.
6482 /* 0x0D */ { A5BLOCK_FIXED, SPR_SHORE_BASE, 16, SHORE_SPRITE_COUNT, "Shore graphics" },
6483 /* 0x0E */ { A5BLOCK_INVALID, 0, 0, 0, "New Signals graphics" }, // Not yet used by OTTD.
6484 /* 0x0F */ { A5BLOCK_ALLOW_OFFSET, SPR_TRACKS_FOR_SLOPES_BASE, 1, TRACKS_FOR_SLOPES_SPRITE_COUNT, "Sloped rail track" },
6485 /* 0x10 */ { A5BLOCK_ALLOW_OFFSET, SPR_AIRPORTX_BASE, 1, AIRPORTX_SPRITE_COUNT, "Airport graphics" },
6486 /* 0x11 */ { A5BLOCK_ALLOW_OFFSET, SPR_ROADSTOP_BASE, 1, ROADSTOP_SPRITE_COUNT, "Road stop graphics" },
6487 /* 0x12 */ { A5BLOCK_ALLOW_OFFSET, SPR_AQUEDUCT_BASE, 1, AQUEDUCT_SPRITE_COUNT, "Aqueduct graphics" },
6488 /* 0x13 */ { A5BLOCK_ALLOW_OFFSET, SPR_AUTORAIL_BASE, 1, AUTORAIL_SPRITE_COUNT, "Autorail graphics" },
6489 /* 0x14 */ { A5BLOCK_INVALID, 0, 1, 0, "Flag graphics" }, // deprecated, no longer used.
6490 /* 0x15 */ { A5BLOCK_ALLOW_OFFSET, SPR_OPENTTD_BASE, 1, OPENTTD_SPRITE_COUNT, "OpenTTD GUI graphics" },
6491 /* 0x16 */ { A5BLOCK_ALLOW_OFFSET, SPR_AIRPORT_PREVIEW_BASE, 1, AIRPORT_PREVIEW_SPRITE_COUNT, "Airport preview graphics" },
6492 /* 0x17 */ { A5BLOCK_ALLOW_OFFSET, SPR_RAILTYPE_TUNNEL_BASE, 1, RAILTYPE_TUNNEL_BASE_COUNT, "Railtype tunnel base" },
6493 /* 0x18 */ { A5BLOCK_ALLOW_OFFSET, SPR_PALETTE_BASE, 1, PALETTE_SPRITE_COUNT, "Palette" },
6494 /* 0x19 */ { A5BLOCK_ALLOW_OFFSET, SPR_ROAD_WAYPOINTS_BASE, 1, ROAD_WAYPOINTS_SPRITE_COUNT, "Road waypoints" },
6495});
6496
6501std::span<const Action5Type> GetAction5Types()
6502{
6503 return _action5_types;
6504}
6505
6506/* Action 0x05 */
6507static void GraphicsNew(ByteReader &buf)
6508{
6509 /* <05> <graphics-type> <num-sprites> <other data...>
6510 *
6511 * B graphics-type What set of graphics the sprites define.
6512 * E num-sprites How many sprites are in this set?
6513 * V other data Graphics type specific data. Currently unused. */
6514
6515 uint8_t type = buf.ReadByte();
6516 uint16_t num = buf.ReadExtendedByte();
6517 uint16_t offset = HasBit(type, 7) ? buf.ReadExtendedByte() : 0;
6518 ClrBit(type, 7); // Clear the high bit as that only indicates whether there is an offset.
6519
6520 if ((type == 0x0D) && (num == 10) && _cur.grfconfig->flags.Test(GRFConfigFlag::System)) {
6521 /* Special not-TTDP-compatible case used in openttd.grf
6522 * Missing shore sprites and initialisation of SPR_SHORE_BASE */
6523 GrfMsg(2, "GraphicsNew: Loading 10 missing shore sprites from extra grf.");
6524 LoadNextSprite(SPR_SHORE_BASE + 0, *_cur.file, _cur.nfo_line++); // SLOPE_STEEP_S
6525 LoadNextSprite(SPR_SHORE_BASE + 5, *_cur.file, _cur.nfo_line++); // SLOPE_STEEP_W
6526 LoadNextSprite(SPR_SHORE_BASE + 7, *_cur.file, _cur.nfo_line++); // SLOPE_WSE
6527 LoadNextSprite(SPR_SHORE_BASE + 10, *_cur.file, _cur.nfo_line++); // SLOPE_STEEP_N
6528 LoadNextSprite(SPR_SHORE_BASE + 11, *_cur.file, _cur.nfo_line++); // SLOPE_NWS
6529 LoadNextSprite(SPR_SHORE_BASE + 13, *_cur.file, _cur.nfo_line++); // SLOPE_ENW
6530 LoadNextSprite(SPR_SHORE_BASE + 14, *_cur.file, _cur.nfo_line++); // SLOPE_SEN
6531 LoadNextSprite(SPR_SHORE_BASE + 15, *_cur.file, _cur.nfo_line++); // SLOPE_STEEP_E
6532 LoadNextSprite(SPR_SHORE_BASE + 16, *_cur.file, _cur.nfo_line++); // SLOPE_EW
6533 LoadNextSprite(SPR_SHORE_BASE + 17, *_cur.file, _cur.nfo_line++); // SLOPE_NS
6535 return;
6536 }
6537
6538 /* Supported type? */
6539 if ((type >= std::size(_action5_types)) || (_action5_types[type].block_type == A5BLOCK_INVALID)) {
6540 GrfMsg(2, "GraphicsNew: Custom graphics (type 0x{:02X}) sprite block of length {} (unimplemented, ignoring)", type, num);
6541 _cur.skip_sprites = num;
6542 return;
6543 }
6544
6545 const Action5Type *action5_type = &_action5_types[type];
6546
6547 /* Contrary to TTDP we allow always to specify too few sprites as we allow always an offset,
6548 * except for the long version of the shore type:
6549 * Ignore offset if not allowed */
6550 if ((action5_type->block_type != A5BLOCK_ALLOW_OFFSET) && (offset != 0)) {
6551 GrfMsg(1, "GraphicsNew: {} (type 0x{:02X}) do not allow an <offset> field. Ignoring offset.", action5_type->name, type);
6552 offset = 0;
6553 }
6554
6555 /* Ignore action5 if too few sprites are specified. (for TTDP compatibility)
6556 * This does not make sense, if <offset> is allowed */
6557 if ((action5_type->block_type == A5BLOCK_FIXED) && (num < action5_type->min_sprites)) {
6558 GrfMsg(1, "GraphicsNew: {} (type 0x{:02X}) count must be at least {}. Only {} were specified. Skipping.", action5_type->name, type, action5_type->min_sprites, num);
6559 _cur.skip_sprites = num;
6560 return;
6561 }
6562
6563 /* Load at most max_sprites sprites. Skip remaining sprites. (for compatibility with TTDP and future extensions) */
6564 uint16_t skip_num = SanitizeSpriteOffset(num, offset, action5_type->max_sprites, action5_type->name);
6565 SpriteID replace = action5_type->sprite_base + offset;
6566
6567 /* Load <num> sprites starting from <replace>, then skip <skip_num> sprites. */
6568 GrfMsg(2, "GraphicsNew: Replacing sprites {} to {} of {} (type 0x{:02X}) at SpriteID 0x{:04X}", offset, offset + num - 1, action5_type->name, type, replace);
6569
6571
6572 if (type == 0x0B) {
6573 static const SpriteID depot_with_track_offset = SPR_TRAMWAY_DEPOT_WITH_TRACK - SPR_TRAMWAY_BASE;
6574 static const SpriteID depot_no_track_offset = SPR_TRAMWAY_DEPOT_NO_TRACK - SPR_TRAMWAY_BASE;
6575 if (offset <= depot_with_track_offset && offset + num > depot_with_track_offset) _loaded_newgrf_features.tram = TRAMWAY_REPLACE_DEPOT_WITH_TRACK;
6576 if (offset <= depot_no_track_offset && offset + num > depot_no_track_offset) _loaded_newgrf_features.tram = TRAMWAY_REPLACE_DEPOT_NO_TRACK;
6577 }
6578
6579 /* If the baseset or grf only provides sprites for flat tiles (pre #10282), duplicate those for use on slopes. */
6580 bool dup_oneway_sprites = ((type == 0x09) && (offset + num <= ONEWAY_SLOPE_N_OFFSET));
6581
6582 for (; num > 0; num--) {
6583 _cur.nfo_line++;
6584 SpriteID load_index = (replace == 0 ? _cur.spriteid++ : replace++);
6585 LoadNextSprite(load_index, *_cur.file, _cur.nfo_line);
6586 if (dup_oneway_sprites) {
6587 DupSprite(load_index, load_index + ONEWAY_SLOPE_N_OFFSET);
6588 DupSprite(load_index, load_index + ONEWAY_SLOPE_S_OFFSET);
6589 }
6590 }
6591
6592 _cur.skip_sprites = skip_num;
6593}
6594
6595/* Action 0x05 (SKIP) */
6596static void SkipAct5(ByteReader &buf)
6597{
6598 /* Ignore type byte */
6599 buf.ReadByte();
6600
6601 /* Skip the sprites of this action */
6602 _cur.skip_sprites = buf.ReadExtendedByte();
6603
6604 GrfMsg(3, "SkipAct5: Skipping {} sprites", _cur.skip_sprites);
6605}
6606
6618bool GetGlobalVariable(uint8_t param, uint32_t *value, const GRFFile *grffile)
6619{
6620 switch (param) {
6621 case 0x00: // current date
6622 *value = std::max(TimerGameCalendar::date - CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR, TimerGameCalendar::Date(0)).base();
6623 return true;
6624
6625 case 0x01: // current year
6627 return true;
6628
6629 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)
6630 TimerGameCalendar::YearMonthDay ymd = TimerGameCalendar::ConvertDateToYMD(TimerGameCalendar::date);
6631 TimerGameCalendar::Date start_of_year = TimerGameCalendar::ConvertYMDToDate(ymd.year, 0, 1);
6632 *value = ymd.month | (ymd.day - 1) << 8 | (TimerGameCalendar::IsLeapYear(ymd.year) ? 1 << 15 : 0) | (TimerGameCalendar::date - start_of_year).base() << 16;
6633 return true;
6634 }
6635
6636 case 0x03: // current climate, 0=temp, 1=arctic, 2=trop, 3=toyland
6638 return true;
6639
6640 case 0x06: // road traffic side, bit 4 clear=left, set=right
6641 *value = _settings_game.vehicle.road_side << 4;
6642 return true;
6643
6644 case 0x09: // date fraction
6645 *value = TimerGameCalendar::date_fract * 885;
6646 return true;
6647
6648 case 0x0A: // animation counter
6649 *value = GB(TimerGameTick::counter, 0, 16);
6650 return true;
6651
6652 case 0x0B: { // TTDPatch version
6653 uint major = 2;
6654 uint minor = 6;
6655 uint revision = 1; // special case: 2.0.1 is 2.0.10
6656 uint build = 1382;
6657 *value = (major << 24) | (minor << 20) | (revision << 16) | build;
6658 return true;
6659 }
6660
6661 case 0x0D: // TTD Version, 00=DOS, 01=Windows
6662 *value = _cur.grfconfig->palette & GRFP_USE_MASK;
6663 return true;
6664
6665 case 0x0E: // Y-offset for train sprites
6666 *value = _cur.grffile->traininfo_vehicle_pitch;
6667 return true;
6668
6669 case 0x0F: // Rail track type cost factors
6670 *value = 0;
6671 SB(*value, 0, 8, GetRailTypeInfo(RAILTYPE_RAIL)->cost_multiplier); // normal rail
6673 /* skip elrail multiplier - disabled */
6674 SB(*value, 8, 8, GetRailTypeInfo(RAILTYPE_MONO)->cost_multiplier); // monorail
6675 } else {
6676 SB(*value, 8, 8, GetRailTypeInfo(RAILTYPE_ELECTRIC)->cost_multiplier); // electified railway
6677 /* Skip monorail multiplier - no space in result */
6678 }
6679 SB(*value, 16, 8, GetRailTypeInfo(RAILTYPE_MAGLEV)->cost_multiplier); // maglev
6680 return true;
6681
6682 case 0x11: // current rail tool type
6683 *value = 0; // constant fake value to avoid desync
6684 return true;
6685
6686 case 0x12: // Game mode
6687 *value = _game_mode;
6688 return true;
6689
6690 /* case 0x13: // Tile refresh offset to left not implemented */
6691 /* case 0x14: // Tile refresh offset to right not implemented */
6692 /* case 0x15: // Tile refresh offset upwards not implemented */
6693 /* case 0x16: // Tile refresh offset downwards not implemented */
6694 /* case 0x17: // temperate snow line not implemented */
6695
6696 case 0x1A: // Always -1
6697 *value = UINT_MAX;
6698 return true;
6699
6700 case 0x1B: // Display options
6701 *value = 0x3F; // constant fake value to avoid desync
6702 return true;
6703
6704 case 0x1D: // TTD Platform, 00=TTDPatch, 01=OpenTTD
6705 *value = 1;
6706 return true;
6707
6708 case 0x1E: // Miscellaneous GRF features
6709 *value = _misc_grf_features;
6710
6711 /* Add the local flags */
6712 assert(!HasBit(*value, GMB_TRAIN_WIDTH_32_PIXELS));
6713 if (_cur.grffile->traininfo_vehicle_width == VEHICLEINFO_FULL_VEHICLE_WIDTH) SetBit(*value, GMB_TRAIN_WIDTH_32_PIXELS);
6714 return true;
6715
6716 /* case 0x1F: // locale dependent settings not implemented to avoid desync */
6717
6718 case 0x20: { // snow line height
6719 uint8_t snowline = GetSnowLine();
6720 if (_settings_game.game_creation.landscape == LandscapeType::Arctic && snowline <= _settings_game.construction.map_height_limit) {
6721 *value = Clamp(snowline * (grffile->grf_version >= 8 ? 1 : TILE_HEIGHT), 0, 0xFE);
6722 } else {
6723 /* No snow */
6724 *value = 0xFF;
6725 }
6726 return true;
6727 }
6728
6729 case 0x21: // OpenTTD version
6730 *value = _openttd_newgrf_version;
6731 return true;
6732
6733 case 0x22: // difficulty level
6734 *value = SP_CUSTOM;
6735 return true;
6736
6737 case 0x23: // long format date
6738 *value = TimerGameCalendar::date.base();
6739 return true;
6740
6741 case 0x24: // long format year
6742 *value = TimerGameCalendar::year.base();
6743 return true;
6744
6745 default: return false;
6746 }
6747}
6748
6749static uint32_t GetParamVal(uint8_t param, uint32_t *cond_val)
6750{
6751 /* First handle variable common with VarAction2 */
6752 uint32_t value;
6753 if (GetGlobalVariable(param - 0x80, &value, _cur.grffile)) return value;
6754
6755
6756 /* Non-common variable */
6757 switch (param) {
6758 case 0x84: { // GRF loading stage
6759 uint32_t res = 0;
6760
6761 if (_cur.stage > GLS_INIT) SetBit(res, 0);
6762 if (_cur.stage == GLS_RESERVE) SetBit(res, 8);
6763 if (_cur.stage == GLS_ACTIVATION) SetBit(res, 9);
6764 return res;
6765 }
6766
6767 case 0x85: // TTDPatch flags, only for bit tests
6768 if (cond_val == nullptr) {
6769 /* Supported in Action 0x07 and 0x09, not 0x0D */
6770 return 0;
6771 } else {
6772 uint32_t index = *cond_val / 0x20;
6773 uint32_t param_val = index < lengthof(_ttdpatch_flags) ? _ttdpatch_flags[index] : 0;
6774 *cond_val %= 0x20;
6775 return param_val;
6776 }
6777
6778 case 0x88: // GRF ID check
6779 return 0;
6780
6781 /* case 0x99: Global ID offset not implemented */
6782
6783 default:
6784 /* GRF Parameter */
6785 if (param < 0x80) return _cur.grffile->GetParam(param);
6786
6787 /* In-game variable. */
6788 GrfMsg(1, "Unsupported in-game variable 0x{:02X}", param);
6789 return UINT_MAX;
6790 }
6791}
6792
6793/* Action 0x06 */
6794static void CfgApply(ByteReader &buf)
6795{
6796 /* <06> <param-num> <param-size> <offset> ... <FF>
6797 *
6798 * B param-num Number of parameter to substitute (First = "zero")
6799 * Ignored if that parameter was not specified in newgrf.cfg
6800 * B param-size How many bytes to replace. If larger than 4, the
6801 * bytes of the following parameter are used. In that
6802 * case, nothing is applied unless *all* parameters
6803 * were specified.
6804 * B offset Offset into data from beginning of next sprite
6805 * to place where parameter is to be stored. */
6806
6807 /* Preload the next sprite */
6808 SpriteFile &file = *_cur.file;
6809 size_t pos = file.GetPos();
6810 uint32_t num = file.GetContainerVersion() >= 2 ? file.ReadDword() : file.ReadWord();
6811 uint8_t type = file.ReadByte();
6812
6813 /* Check if the sprite is a pseudo sprite. We can't operate on real sprites. */
6814 if (type != 0xFF) {
6815 GrfMsg(2, "CfgApply: Ignoring (next sprite is real, unsupported)");
6816
6817 /* Reset the file position to the start of the next sprite */
6818 file.SeekTo(pos, SEEK_SET);
6819 return;
6820 }
6821
6822 /* Get (or create) the override for the next sprite. */
6823 GRFLocation location(_cur.grfconfig->ident.grfid, _cur.nfo_line + 1);
6824 std::vector<uint8_t> &preload_sprite = _grf_line_to_action6_sprite_override[location];
6825
6826 /* Load new sprite data if it hasn't already been loaded. */
6827 if (preload_sprite.empty()) {
6828 preload_sprite.resize(num);
6829 file.ReadBlock(preload_sprite.data(), num);
6830 }
6831
6832 /* Reset the file position to the start of the next sprite */
6833 file.SeekTo(pos, SEEK_SET);
6834
6835 /* Now perform the Action 0x06 on our data. */
6836 for (;;) {
6837 uint i;
6838 uint param_num;
6839 uint param_size;
6840 uint offset;
6841 bool add_value;
6842
6843 /* Read the parameter to apply. 0xFF indicates no more data to change. */
6844 param_num = buf.ReadByte();
6845 if (param_num == 0xFF) break;
6846
6847 /* Get the size of the parameter to use. If the size covers multiple
6848 * double words, sequential parameter values are used. */
6849 param_size = buf.ReadByte();
6850
6851 /* Bit 7 of param_size indicates we should add to the original value
6852 * instead of replacing it. */
6853 add_value = HasBit(param_size, 7);
6854 param_size = GB(param_size, 0, 7);
6855
6856 /* Where to apply the data to within the pseudo sprite data. */
6857 offset = buf.ReadExtendedByte();
6858
6859 /* If the parameter is a GRF parameter (not an internal variable) check
6860 * if it (and all further sequential parameters) has been defined. */
6861 if (param_num < 0x80 && (param_num + (param_size - 1) / 4) >= std::size(_cur.grffile->param)) {
6862 GrfMsg(2, "CfgApply: Ignoring (param {} not set)", (param_num + (param_size - 1) / 4));
6863 break;
6864 }
6865
6866 GrfMsg(8, "CfgApply: Applying {} bytes from parameter 0x{:02X} at offset 0x{:04X}", param_size, param_num, offset);
6867
6868 bool carry = false;
6869 for (i = 0; i < param_size && offset + i < num; i++) {
6870 uint32_t value = GetParamVal(param_num + i / 4, nullptr);
6871 /* Reset carry flag for each iteration of the variable (only really
6872 * matters if param_size is greater than 4) */
6873 if (i % 4 == 0) carry = false;
6874
6875 if (add_value) {
6876 uint new_value = preload_sprite[offset + i] + GB(value, (i % 4) * 8, 8) + (carry ? 1 : 0);
6877 preload_sprite[offset + i] = GB(new_value, 0, 8);
6878 /* Check if the addition overflowed */
6879 carry = new_value >= 256;
6880 } else {
6881 preload_sprite[offset + i] = GB(value, (i % 4) * 8, 8);
6882 }
6883 }
6884 }
6885}
6886
6897{
6898 GRFError *error = DisableGrf(STR_NEWGRF_ERROR_STATIC_GRF_CAUSES_DESYNC, &c);
6899 error->data = _cur.grfconfig->GetName();
6900}
6901
6902/* Action 0x07
6903 * Action 0x09 */
6904static void SkipIf(ByteReader &buf)
6905{
6906 /* <07/09> <param-num> <param-size> <condition-type> <value> <num-sprites>
6907 *
6908 * B param-num
6909 * B param-size
6910 * B condition-type
6911 * V value
6912 * B num-sprites */
6913 uint32_t cond_val = 0;
6914 uint32_t mask = 0;
6915 bool result;
6916
6917 uint8_t param = buf.ReadByte();
6918 uint8_t paramsize = buf.ReadByte();
6919 uint8_t condtype = buf.ReadByte();
6920
6921 if (condtype < 2) {
6922 /* Always 1 for bit tests, the given value should be ignored. */
6923 paramsize = 1;
6924 }
6925
6926 switch (paramsize) {
6927 case 8: cond_val = buf.ReadDWord(); mask = buf.ReadDWord(); break;
6928 case 4: cond_val = buf.ReadDWord(); mask = 0xFFFFFFFF; break;
6929 case 2: cond_val = buf.ReadWord(); mask = 0x0000FFFF; break;
6930 case 1: cond_val = buf.ReadByte(); mask = 0x000000FF; break;
6931 default: break;
6932 }
6933
6934 if (param < 0x80 && std::size(_cur.grffile->param) <= param) {
6935 GrfMsg(7, "SkipIf: Param {} undefined, skipping test", param);
6936 return;
6937 }
6938
6939 GrfMsg(7, "SkipIf: Test condtype {}, param 0x{:02X}, condval 0x{:08X}", condtype, param, cond_val);
6940
6941 /* condtypes that do not use 'param' are always valid.
6942 * condtypes that use 'param' are either not valid for param 0x88, or they are only valid for param 0x88.
6943 */
6944 if (condtype >= 0x0B) {
6945 /* Tests that ignore 'param' */
6946 switch (condtype) {
6947 case 0x0B: result = !IsValidCargoType(GetCargoTypeByLabel(CargoLabel(std::byteswap(cond_val))));
6948 break;
6949 case 0x0C: result = IsValidCargoType(GetCargoTypeByLabel(CargoLabel(std::byteswap(cond_val))));
6950 break;
6951 case 0x0D: result = GetRailTypeByLabel(std::byteswap(cond_val)) == INVALID_RAILTYPE;
6952 break;
6953 case 0x0E: result = GetRailTypeByLabel(std::byteswap(cond_val)) != INVALID_RAILTYPE;
6954 break;
6955 case 0x0F: {
6956 RoadType rt = GetRoadTypeByLabel(std::byteswap(cond_val));
6957 result = rt == INVALID_ROADTYPE || !RoadTypeIsRoad(rt);
6958 break;
6959 }
6960 case 0x10: {
6961 RoadType rt = GetRoadTypeByLabel(std::byteswap(cond_val));
6962 result = rt != INVALID_ROADTYPE && RoadTypeIsRoad(rt);
6963 break;
6964 }
6965 case 0x11: {
6966 RoadType rt = GetRoadTypeByLabel(std::byteswap(cond_val));
6967 result = rt == INVALID_ROADTYPE || !RoadTypeIsTram(rt);
6968 break;
6969 }
6970 case 0x12: {
6971 RoadType rt = GetRoadTypeByLabel(std::byteswap(cond_val));
6972 result = rt != INVALID_ROADTYPE && RoadTypeIsTram(rt);
6973 break;
6974 }
6975 default: GrfMsg(1, "SkipIf: Unsupported condition type {:02X}. Ignoring", condtype); return;
6976 }
6977 } else if (param == 0x88) {
6978 /* GRF ID checks */
6979
6980 GRFConfig *c = GetGRFConfig(cond_val, mask);
6981
6982 if (c != nullptr && c->flags.Test(GRFConfigFlag::Static) && !_cur.grfconfig->flags.Test(GRFConfigFlag::Static) && _networking) {
6984 c = nullptr;
6985 }
6986
6987 if (condtype != 10 && c == nullptr) {
6988 GrfMsg(7, "SkipIf: GRFID 0x{:08X} unknown, skipping test", std::byteswap(cond_val));
6989 return;
6990 }
6991
6992 switch (condtype) {
6993 /* Tests 0x06 to 0x0A are only for param 0x88, GRFID checks */
6994 case 0x06: // Is GRFID active?
6995 result = c->status == GCS_ACTIVATED;
6996 break;
6997
6998 case 0x07: // Is GRFID non-active?
6999 result = c->status != GCS_ACTIVATED;
7000 break;
7001
7002 case 0x08: // GRFID is not but will be active?
7003 result = c->status == GCS_INITIALISED;
7004 break;
7005
7006 case 0x09: // GRFID is or will be active?
7007 result = c->status == GCS_ACTIVATED || c->status == GCS_INITIALISED;
7008 break;
7009
7010 case 0x0A: // GRFID is not nor will be active
7011 /* This is the only condtype that doesn't get ignored if the GRFID is not found */
7012 result = c == nullptr || c->status == GCS_DISABLED || c->status == GCS_NOT_FOUND;
7013 break;
7014
7015 default: GrfMsg(1, "SkipIf: Unsupported GRF condition type {:02X}. Ignoring", condtype); return;
7016 }
7017 } else {
7018 /* Tests that use 'param' and are not GRF ID checks. */
7019 uint32_t param_val = GetParamVal(param, &cond_val); // cond_val is modified for param == 0x85
7020 switch (condtype) {
7021 case 0x00: result = !!(param_val & (1 << cond_val));
7022 break;
7023 case 0x01: result = !(param_val & (1 << cond_val));
7024 break;
7025 case 0x02: result = (param_val & mask) == cond_val;
7026 break;
7027 case 0x03: result = (param_val & mask) != cond_val;
7028 break;
7029 case 0x04: result = (param_val & mask) < cond_val;
7030 break;
7031 case 0x05: result = (param_val & mask) > cond_val;
7032 break;
7033 default: GrfMsg(1, "SkipIf: Unsupported condition type {:02X}. Ignoring", condtype); return;
7034 }
7035 }
7036
7037 if (!result) {
7038 GrfMsg(2, "SkipIf: Not skipping sprites, test was false");
7039 return;
7040 }
7041
7042 uint8_t numsprites = buf.ReadByte();
7043
7044 /* numsprites can be a GOTO label if it has been defined in the GRF
7045 * file. The jump will always be the first matching label that follows
7046 * the current nfo_line. If no matching label is found, the first matching
7047 * label in the file is used. */
7048 const GRFLabel *choice = nullptr;
7049 for (const auto &label : _cur.grffile->labels) {
7050 if (label.label != numsprites) continue;
7051
7052 /* Remember a goto before the current line */
7053 if (choice == nullptr) choice = &label;
7054 /* If we find a label here, this is definitely good */
7055 if (label.nfo_line > _cur.nfo_line) {
7056 choice = &label;
7057 break;
7058 }
7059 }
7060
7061 if (choice != nullptr) {
7062 GrfMsg(2, "SkipIf: Jumping to label 0x{:X} at line {}, test was true", choice->label, choice->nfo_line);
7063 _cur.file->SeekTo(choice->pos, SEEK_SET);
7064 _cur.nfo_line = choice->nfo_line;
7065 return;
7066 }
7067
7068 GrfMsg(2, "SkipIf: Skipping {} sprites, test was true", numsprites);
7069 _cur.skip_sprites = numsprites;
7070 if (_cur.skip_sprites == 0) {
7071 /* Zero means there are no sprites to skip, so
7072 * we use -1 to indicate that all further
7073 * sprites should be skipped. */
7074 _cur.skip_sprites = -1;
7075
7076 /* If an action 8 hasn't been encountered yet, disable the grf. */
7077 if (_cur.grfconfig->status != (_cur.stage < GLS_RESERVE ? GCS_INITIALISED : GCS_ACTIVATED)) {
7078 DisableGrf();
7079 }
7080 }
7081}
7082
7083
7084/* Action 0x08 (GLS_FILESCAN) */
7085static void ScanInfo(ByteReader &buf)
7086{
7087 uint8_t grf_version = buf.ReadByte();
7088 uint32_t grfid = buf.ReadDWord();
7089 std::string_view name = buf.ReadString();
7090
7091 _cur.grfconfig->ident.grfid = grfid;
7092
7093 if (grf_version < 2 || grf_version > 8) {
7095 Debug(grf, 0, "{}: NewGRF \"{}\" (GRFID {:08X}) uses GRF version {}, which is incompatible with this version of OpenTTD.", _cur.grfconfig->filename, StrMakeValid(name), std::byteswap(grfid), grf_version);
7096 }
7097
7098 /* GRF IDs starting with 0xFF are reserved for internal TTDPatch use */
7099 if (GB(grfid, 0, 8) == 0xFF) _cur.grfconfig->flags.Set(GRFConfigFlag::System);
7100
7101 AddGRFTextToList(_cur.grfconfig->name, 0x7F, grfid, false, name);
7102
7103 if (buf.HasData()) {
7104 std::string_view info = buf.ReadString();
7105 AddGRFTextToList(_cur.grfconfig->info, 0x7F, grfid, true, info);
7106 }
7107
7108 /* GLS_INFOSCAN only looks for the action 8, so we can skip the rest of the file */
7109 _cur.skip_sprites = -1;
7110}
7111
7112/* Action 0x08 */
7113static void GRFInfo(ByteReader &buf)
7114{
7115 /* <08> <version> <grf-id> <name> <info>
7116 *
7117 * B version newgrf version, currently 06
7118 * 4*B grf-id globally unique ID of this .grf file
7119 * S name name of this .grf set
7120 * S info string describing the set, and e.g. author and copyright */
7121
7122 uint8_t version = buf.ReadByte();
7123 uint32_t grfid = buf.ReadDWord();
7124 std::string_view name = buf.ReadString();
7125
7126 if (_cur.stage < GLS_RESERVE && _cur.grfconfig->status != GCS_UNKNOWN) {
7127 DisableGrf(STR_NEWGRF_ERROR_MULTIPLE_ACTION_8);
7128 return;
7129 }
7130
7131 if (_cur.grffile->grfid != grfid) {
7132 Debug(grf, 0, "GRFInfo: GRFID {:08X} in FILESCAN stage does not match GRFID {:08X} in INIT/RESERVE/ACTIVATION stage", std::byteswap(_cur.grffile->grfid), std::byteswap(grfid));
7133 _cur.grffile->grfid = grfid;
7134 }
7135
7136 _cur.grffile->grf_version = version;
7137 _cur.grfconfig->status = _cur.stage < GLS_RESERVE ? GCS_INITIALISED : GCS_ACTIVATED;
7138
7139 /* Do swap the GRFID for displaying purposes since people expect that */
7140 Debug(grf, 1, "GRFInfo: Loaded GRFv{} set {:08X} - {} (palette: {}, version: {})", version, std::byteswap(grfid), StrMakeValid(name), (_cur.grfconfig->palette & GRFP_USE_MASK) ? "Windows" : "DOS", _cur.grfconfig->version);
7141}
7142
7149static bool IsGRMReservedSprite(SpriteID first_sprite, uint16_t num_sprites)
7150{
7151 for (const auto &grm_sprite : _grm_sprites) {
7152 if (grm_sprite.first.grfid != _cur.grffile->grfid) continue;
7153 if (grm_sprite.second.first <= first_sprite && grm_sprite.second.first + grm_sprite.second.second >= first_sprite + num_sprites) return true;
7154 }
7155 return false;
7156}
7157
7158/* Action 0x0A */
7159static void SpriteReplace(ByteReader &buf)
7160{
7161 /* <0A> <num-sets> <set1> [<set2> ...]
7162 * <set>: <num-sprites> <first-sprite>
7163 *
7164 * B num-sets How many sets of sprites to replace.
7165 * Each set:
7166 * B num-sprites How many sprites are in this set
7167 * W first-sprite First sprite number to replace */
7168
7169 uint8_t num_sets = buf.ReadByte();
7170
7171 for (uint i = 0; i < num_sets; i++) {
7172 uint8_t num_sprites = buf.ReadByte();
7173 uint16_t first_sprite = buf.ReadWord();
7174
7175 GrfMsg(2, "SpriteReplace: [Set {}] Changing {} sprites, beginning with {}",
7176 i, num_sprites, first_sprite
7177 );
7178
7179 if (first_sprite + num_sprites >= SPR_OPENTTD_BASE) {
7180 /* Outside allowed range, check for GRM sprite reservations. */
7181 if (!IsGRMReservedSprite(first_sprite, num_sprites)) {
7182 GrfMsg(0, "SpriteReplace: [Set {}] Changing {} sprites, beginning with {}, above limit of {} and not within reserved range, ignoring.",
7183 i, num_sprites, first_sprite, SPR_OPENTTD_BASE);
7184
7185 /* Load the sprites at the current location so they will do nothing instead of appearing to work. */
7186 first_sprite = _cur.spriteid;
7187 _cur.spriteid += num_sprites;
7188 }
7189 }
7190
7191 for (uint j = 0; j < num_sprites; j++) {
7192 SpriteID load_index = first_sprite + j;
7193 _cur.nfo_line++;
7194 LoadNextSprite(load_index, *_cur.file, _cur.nfo_line); // XXX
7195
7196 /* Shore sprites now located at different addresses.
7197 * So detect when the old ones get replaced. */
7198 if (IsInsideMM(load_index, SPR_ORIGINALSHORE_START, SPR_ORIGINALSHORE_END + 1)) {
7200 }
7201 }
7202 }
7203}
7204
7205/* Action 0x0A (SKIP) */
7206static void SkipActA(ByteReader &buf)
7207{
7208 uint8_t num_sets = buf.ReadByte();
7209
7210 for (uint i = 0; i < num_sets; i++) {
7211 /* Skip the sprites this replaces */
7212 _cur.skip_sprites += buf.ReadByte();
7213 /* But ignore where they go */
7214 buf.ReadWord();
7215 }
7216
7217 GrfMsg(3, "SkipActA: Skipping {} sprites", _cur.skip_sprites);
7218}
7219
7220/* Action 0x0B */
7221static void GRFLoadError(ByteReader &buf)
7222{
7223 /* <0B> <severity> <language-id> <message-id> [<message...> 00] [<data...>] 00 [<parnum>]
7224 *
7225 * B severity 00: notice, continue loading grf file
7226 * 01: warning, continue loading grf file
7227 * 02: error, but continue loading grf file, and attempt
7228 * loading grf again when loading or starting next game
7229 * 03: error, abort loading and prevent loading again in
7230 * the future (only when restarting the patch)
7231 * B language-id see action 4, use 1F for built-in error messages
7232 * B message-id message to show, see below
7233 * S message for custom messages (message-id FF), text of the message
7234 * not present for built-in messages.
7235 * V data additional data for built-in (or custom) messages
7236 * B parnum parameter numbers to be shown in the message (maximum of 2) */
7237
7238 static const StringID msgstr[] = {
7239 STR_NEWGRF_ERROR_VERSION_NUMBER,
7240 STR_NEWGRF_ERROR_DOS_OR_WINDOWS,
7241 STR_NEWGRF_ERROR_UNSET_SWITCH,
7242 STR_NEWGRF_ERROR_INVALID_PARAMETER,
7243 STR_NEWGRF_ERROR_LOAD_BEFORE,
7244 STR_NEWGRF_ERROR_LOAD_AFTER,
7245 STR_NEWGRF_ERROR_OTTD_VERSION_NUMBER,
7246 };
7247
7248 static const StringID sevstr[] = {
7249 STR_NEWGRF_ERROR_MSG_INFO,
7250 STR_NEWGRF_ERROR_MSG_WARNING,
7251 STR_NEWGRF_ERROR_MSG_ERROR,
7252 STR_NEWGRF_ERROR_MSG_FATAL
7253 };
7254
7255 uint8_t severity = buf.ReadByte();
7256 uint8_t lang = buf.ReadByte();
7257 uint8_t message_id = buf.ReadByte();
7258
7259 /* Skip the error if it isn't valid for the current language. */
7260 if (!CheckGrfLangID(lang, _cur.grffile->grf_version)) return;
7261
7262 /* Skip the error until the activation stage unless bit 7 of the severity
7263 * is set. */
7264 if (!HasBit(severity, 7) && _cur.stage == GLS_INIT) {
7265 GrfMsg(7, "GRFLoadError: Skipping non-fatal GRFLoadError in stage {}", _cur.stage);
7266 return;
7267 }
7268 ClrBit(severity, 7);
7269
7270 if (severity >= lengthof(sevstr)) {
7271 GrfMsg(7, "GRFLoadError: Invalid severity id {}. Setting to 2 (non-fatal error).", severity);
7272 severity = 2;
7273 } else if (severity == 3) {
7274 /* This is a fatal error, so make sure the GRF is deactivated and no
7275 * more of it gets loaded. */
7276 DisableGrf();
7277
7278 /* Make sure we show fatal errors, instead of silly infos from before */
7279 _cur.grfconfig->error.reset();
7280 }
7281
7282 if (message_id >= lengthof(msgstr) && message_id != 0xFF) {
7283 GrfMsg(7, "GRFLoadError: Invalid message id.");
7284 return;
7285 }
7286
7287 if (buf.Remaining() <= 1) {
7288 GrfMsg(7, "GRFLoadError: No message data supplied.");
7289 return;
7290 }
7291
7292 /* For now we can only show one message per newgrf file. */
7293 if (_cur.grfconfig->error.has_value()) return;
7294
7295 _cur.grfconfig->error = {sevstr[severity]};
7296 GRFError *error = &_cur.grfconfig->error.value();
7297
7298 if (message_id == 0xFF) {
7299 /* This is a custom error message. */
7300 if (buf.HasData()) {
7301 std::string_view message = buf.ReadString();
7302
7303 error->custom_message = TranslateTTDPatchCodes(_cur.grffile->grfid, lang, true, message, SCC_RAW_STRING_POINTER);
7304 } else {
7305 GrfMsg(7, "GRFLoadError: No custom message supplied.");
7306 error->custom_message.clear();
7307 }
7308 } else {
7309 error->message = msgstr[message_id];
7310 }
7311
7312 if (buf.HasData()) {
7313 std::string_view data = buf.ReadString();
7314
7315 error->data = TranslateTTDPatchCodes(_cur.grffile->grfid, lang, true, data);
7316 } else {
7317 GrfMsg(7, "GRFLoadError: No message data supplied.");
7318 error->data.clear();
7319 }
7320
7321 /* Only two parameter numbers can be used in the string. */
7322 for (uint i = 0; i < error->param_value.size() && buf.HasData(); i++) {
7323 uint param_number = buf.ReadByte();
7324 error->param_value[i] = _cur.grffile->GetParam(param_number);
7325 }
7326}
7327
7328/* Action 0x0C */
7329static void GRFComment(ByteReader &buf)
7330{
7331 /* <0C> [<ignored...>]
7332 *
7333 * V ignored Anything following the 0C is ignored */
7334
7335 if (!buf.HasData()) return;
7336
7337 std::string_view text = buf.ReadString();
7338 GrfMsg(2, "GRFComment: {}", StrMakeValid(text));
7339}
7340
7341/* Action 0x0D (GLS_SAFETYSCAN) */
7342static void SafeParamSet(ByteReader &buf)
7343{
7344 uint8_t target = buf.ReadByte();
7345
7346 /* Writing GRF parameters and some bits of 'misc GRF features' are safe. */
7347 if (target < 0x80 || target == 0x9E) return;
7348
7349 /* GRM could be unsafe, but as here it can only happen after other GRFs
7350 * are loaded, it should be okay. If the GRF tried to use the slots it
7351 * reserved, it would be marked unsafe anyway. GRM for (e.g. bridge)
7352 * sprites is considered safe. */
7353
7355
7356 /* Skip remainder of GRF */
7357 _cur.skip_sprites = -1;
7358}
7359
7360
7361static uint32_t GetPatchVariable(uint8_t param)
7362{
7363 switch (param) {
7364 /* start year - 1920 */
7366
7367 /* freight trains weight factor */
7368 case 0x0E: return _settings_game.vehicle.freight_trains;
7369
7370 /* empty wagon speed increase */
7371 case 0x0F: return 0;
7372
7373 /* plane speed factor; our patch option is reversed from TTDPatch's,
7374 * the following is good for 1x, 2x and 4x (most common?) and...
7375 * well not really for 3x. */
7376 case 0x10:
7378 default:
7379 case 4: return 1;
7380 case 3: return 2;
7381 case 2: return 2;
7382 case 1: return 4;
7383 }
7384
7385
7386 /* 2CC colourmap base sprite */
7387 case 0x11: return SPR_2CCMAP_BASE;
7388
7389 /* map size: format = -MABXYSS
7390 * M : the type of map
7391 * bit 0 : set : squared map. Bit 1 is now not relevant
7392 * clear : rectangle map. Bit 1 will indicate the bigger edge of the map
7393 * bit 1 : set : Y is the bigger edge. Bit 0 is clear
7394 * clear : X is the bigger edge.
7395 * A : minimum edge(log2) of the map
7396 * B : maximum edge(log2) of the map
7397 * XY : edges(log2) of each side of the map.
7398 * SS : combination of both X and Y, thus giving the size(log2) of the map
7399 */
7400 case 0x13: {
7401 uint8_t map_bits = 0;
7402 uint8_t log_X = Map::LogX() - 6; // subtraction is required to make the minimal size (64) zero based
7403 uint8_t log_Y = Map::LogY() - 6;
7404 uint8_t max_edge = std::max(log_X, log_Y);
7405
7406 if (log_X == log_Y) { // we have a squared map, since both edges are identical
7407 SetBit(map_bits, 0);
7408 } else {
7409 if (max_edge == log_Y) SetBit(map_bits, 1); // edge Y been the biggest, mark it
7410 }
7411
7412 return (map_bits << 24) | (std::min(log_X, log_Y) << 20) | (max_edge << 16) |
7413 (log_X << 12) | (log_Y << 8) | (log_X + log_Y);
7414 }
7415
7416 /* The maximum height of the map. */
7417 case 0x14:
7419
7420 /* Extra foundations base sprite */
7421 case 0x15:
7422 return SPR_SLOPES_BASE;
7423
7424 /* Shore base sprite */
7425 case 0x16:
7426 return SPR_SHORE_BASE;
7427
7428 /* Game map seed */
7429 case 0x17:
7431
7432 default:
7433 GrfMsg(2, "ParamSet: Unknown Patch variable 0x{:02X}.", param);
7434 return 0;
7435 }
7436}
7437
7438
7439static uint32_t PerformGRM(uint32_t *grm, uint16_t num_ids, uint16_t count, uint8_t op, uint8_t target, const char *type)
7440{
7441 uint start = 0;
7442 uint size = 0;
7443
7444 if (op == 6) {
7445 /* Return GRFID of set that reserved ID */
7446 return grm[_cur.grffile->GetParam(target)];
7447 }
7448
7449 /* With an operation of 2 or 3, we want to reserve a specific block of IDs */
7450 if (op == 2 || op == 3) start = _cur.grffile->GetParam(target);
7451
7452 for (uint i = start; i < num_ids; i++) {
7453 if (grm[i] == 0) {
7454 size++;
7455 } else {
7456 if (op == 2 || op == 3) break;
7457 start = i + 1;
7458 size = 0;
7459 }
7460
7461 if (size == count) break;
7462 }
7463
7464 if (size == count) {
7465 /* Got the slot... */
7466 if (op == 0 || op == 3) {
7467 GrfMsg(2, "ParamSet: GRM: Reserving {} {} at {}", count, type, start);
7468 for (uint i = 0; i < count; i++) grm[start + i] = _cur.grffile->grfid;
7469 }
7470 return start;
7471 }
7472
7473 /* Unable to allocate */
7474 if (op != 4 && op != 5) {
7475 /* Deactivate GRF */
7476 GrfMsg(0, "ParamSet: GRM: Unable to allocate {} {}, deactivating", count, type);
7477 DisableGrf(STR_NEWGRF_ERROR_GRM_FAILED);
7478 return UINT_MAX;
7479 }
7480
7481 GrfMsg(1, "ParamSet: GRM: Unable to allocate {} {}", count, type);
7482 return UINT_MAX;
7483}
7484
7485
7487static void ParamSet(ByteReader &buf)
7488{
7489 /* <0D> <target> <operation> <source1> <source2> [<data>]
7490 *
7491 * B target parameter number where result is stored
7492 * B operation operation to perform, see below
7493 * B source1 first source operand
7494 * B source2 second source operand
7495 * D data data to use in the calculation, not necessary
7496 * if both source1 and source2 refer to actual parameters
7497 *
7498 * Operations
7499 * 00 Set parameter equal to source1
7500 * 01 Addition, source1 + source2
7501 * 02 Subtraction, source1 - source2
7502 * 03 Unsigned multiplication, source1 * source2 (both unsigned)
7503 * 04 Signed multiplication, source1 * source2 (both signed)
7504 * 05 Unsigned bit shift, source1 by source2 (source2 taken to be a
7505 * signed quantity; left shift if positive and right shift if
7506 * negative, source1 is unsigned)
7507 * 06 Signed bit shift, source1 by source2
7508 * (source2 like in 05, and source1 as well)
7509 */
7510
7511 uint8_t target = buf.ReadByte();
7512 uint8_t oper = buf.ReadByte();
7513 uint32_t src1 = buf.ReadByte();
7514 uint32_t src2 = buf.ReadByte();
7515
7516 uint32_t data = 0;
7517 if (buf.Remaining() >= 4) data = buf.ReadDWord();
7518
7519 /* You can add 80 to the operation to make it apply only if the target
7520 * is not defined yet. In this respect, a parameter is taken to be
7521 * defined if any of the following applies:
7522 * - it has been set to any value in the newgrf(w).cfg parameter list
7523 * - it OR A PARAMETER WITH HIGHER NUMBER has been set to any value by
7524 * an earlier action D */
7525 if (HasBit(oper, 7)) {
7526 if (target < 0x80 && target < std::size(_cur.grffile->param)) {
7527 GrfMsg(7, "ParamSet: Param {} already defined, skipping", target);
7528 return;
7529 }
7530
7531 oper = GB(oper, 0, 7);
7532 }
7533
7534 if (src2 == 0xFE) {
7535 if (GB(data, 0, 8) == 0xFF) {
7536 if (data == 0x0000FFFF) {
7537 /* Patch variables */
7538 src1 = GetPatchVariable(src1);
7539 } else {
7540 /* GRF Resource Management */
7541 uint8_t op = src1;
7542 uint8_t feature = GB(data, 8, 8);
7543 uint16_t count = GB(data, 16, 16);
7544
7545 if (_cur.stage == GLS_RESERVE) {
7546 if (feature == 0x08) {
7547 /* General sprites */
7548 if (op == 0) {
7549 /* Check if the allocated sprites will fit below the original sprite limit */
7550 if (_cur.spriteid + count >= 16384) {
7551 GrfMsg(0, "ParamSet: GRM: Unable to allocate {} sprites; try changing NewGRF order", count);
7552 DisableGrf(STR_NEWGRF_ERROR_GRM_FAILED);
7553 return;
7554 }
7555
7556 /* Reserve space at the current sprite ID */
7557 GrfMsg(4, "ParamSet: GRM: Allocated {} sprites at {}", count, _cur.spriteid);
7558 _grm_sprites[GRFLocation(_cur.grffile->grfid, _cur.nfo_line)] = std::make_pair(_cur.spriteid, count);
7559 _cur.spriteid += count;
7560 }
7561 }
7562 /* Ignore GRM result during reservation */
7563 src1 = 0;
7564 } else if (_cur.stage == GLS_ACTIVATION) {
7565 switch (feature) {
7566 case 0x00: // Trains
7567 case 0x01: // Road Vehicles
7568 case 0x02: // Ships
7569 case 0x03: // Aircraft
7571 src1 = PerformGRM(&_grm_engines[_engine_offsets[feature]], _engine_counts[feature], count, op, target, "vehicles");
7572 if (_cur.skip_sprites == -1) return;
7573 } else {
7574 /* GRM does not apply for dynamic engine allocation. */
7575 switch (op) {
7576 case 2:
7577 case 3:
7578 src1 = _cur.grffile->GetParam(target);
7579 break;
7580
7581 default:
7582 src1 = 0;
7583 break;
7584 }
7585 }
7586 break;
7587
7588 case 0x08: // General sprites
7589 switch (op) {
7590 case 0:
7591 /* Return space reserved during reservation stage */
7592 src1 = _grm_sprites[GRFLocation(_cur.grffile->grfid, _cur.nfo_line)].first;
7593 GrfMsg(4, "ParamSet: GRM: Using pre-allocated sprites at {}", src1);
7594 break;
7595
7596 case 1:
7597 src1 = _cur.spriteid;
7598 break;
7599
7600 default:
7601 GrfMsg(1, "ParamSet: GRM: Unsupported operation {} for general sprites", op);
7602 return;
7603 }
7604 break;
7605
7606 case 0x0B: // Cargo
7607 /* There are two ranges: one for cargo IDs and one for cargo bitmasks */
7608 src1 = PerformGRM(_grm_cargoes, NUM_CARGO * 2, count, op, target, "cargoes");
7609 if (_cur.skip_sprites == -1) return;
7610 break;
7611
7612 default: GrfMsg(1, "ParamSet: GRM: Unsupported feature 0x{:X}", feature); return;
7613 }
7614 } else {
7615 /* Ignore GRM during initialization */
7616 src1 = 0;
7617 }
7618 }
7619 } else {
7620 /* Read another GRF File's parameter */
7621 const GRFFile *file = GetFileByGRFID(data);
7622 GRFConfig *c = GetGRFConfig(data);
7623 if (c != nullptr && c->flags.Test(GRFConfigFlag::Static) && !_cur.grfconfig->flags.Test(GRFConfigFlag::Static) && _networking) {
7624 /* Disable the read GRF if it is a static NewGRF. */
7626 src1 = 0;
7627 } else if (file == nullptr || c == nullptr || c->status == GCS_DISABLED) {
7628 src1 = 0;
7629 } else if (src1 == 0xFE) {
7630 src1 = c->version;
7631 } else {
7632 src1 = file->GetParam(src1);
7633 }
7634 }
7635 } else {
7636 /* The source1 and source2 operands refer to the grf parameter number
7637 * like in action 6 and 7. In addition, they can refer to the special
7638 * variables available in action 7, or they can be FF to use the value
7639 * of <data>. If referring to parameters that are undefined, a value
7640 * of 0 is used instead. */
7641 src1 = (src1 == 0xFF) ? data : GetParamVal(src1, nullptr);
7642 src2 = (src2 == 0xFF) ? data : GetParamVal(src2, nullptr);
7643 }
7644
7645 uint32_t res;
7646 switch (oper) {
7647 case 0x00:
7648 res = src1;
7649 break;
7650
7651 case 0x01:
7652 res = src1 + src2;
7653 break;
7654
7655 case 0x02:
7656 res = src1 - src2;
7657 break;
7658
7659 case 0x03:
7660 res = src1 * src2;
7661 break;
7662
7663 case 0x04:
7664 res = (int32_t)src1 * (int32_t)src2;
7665 break;
7666
7667 case 0x05:
7668 if ((int32_t)src2 < 0) {
7669 res = src1 >> -(int32_t)src2;
7670 } else {
7671 res = src1 << (src2 & 0x1F); // Same behaviour as in EvalAdjustT, mask 'value' to 5 bits, which should behave the same on all architectures.
7672 }
7673 break;
7674
7675 case 0x06:
7676 if ((int32_t)src2 < 0) {
7677 res = (int32_t)src1 >> -(int32_t)src2;
7678 } else {
7679 res = (int32_t)src1 << (src2 & 0x1F); // Same behaviour as in EvalAdjustT, mask 'value' to 5 bits, which should behave the same on all architectures.
7680 }
7681 break;
7682
7683 case 0x07: // Bitwise AND
7684 res = src1 & src2;
7685 break;
7686
7687 case 0x08: // Bitwise OR
7688 res = src1 | src2;
7689 break;
7690
7691 case 0x09: // Unsigned division
7692 if (src2 == 0) {
7693 res = src1;
7694 } else {
7695 res = src1 / src2;
7696 }
7697 break;
7698
7699 case 0x0A: // Signed division
7700 if (src2 == 0) {
7701 res = src1;
7702 } else {
7703 res = (int32_t)src1 / (int32_t)src2;
7704 }
7705 break;
7706
7707 case 0x0B: // Unsigned modulo
7708 if (src2 == 0) {
7709 res = src1;
7710 } else {
7711 res = src1 % src2;
7712 }
7713 break;
7714
7715 case 0x0C: // Signed modulo
7716 if (src2 == 0) {
7717 res = src1;
7718 } else {
7719 res = (int32_t)src1 % (int32_t)src2;
7720 }
7721 break;
7722
7723 default: GrfMsg(0, "ParamSet: Unknown operation {}, skipping", oper); return;
7724 }
7725
7726 switch (target) {
7727 case 0x8E: // Y-Offset for train sprites
7728 _cur.grffile->traininfo_vehicle_pitch = res;
7729 break;
7730
7731 case 0x8F: { // Rail track type cost factors
7732 extern RailTypeInfo _railtypes[RAILTYPE_END];
7733 _railtypes[RAILTYPE_RAIL].cost_multiplier = GB(res, 0, 8);
7735 _railtypes[RAILTYPE_ELECTRIC].cost_multiplier = GB(res, 0, 8);
7736 _railtypes[RAILTYPE_MONO].cost_multiplier = GB(res, 8, 8);
7737 } else {
7738 _railtypes[RAILTYPE_ELECTRIC].cost_multiplier = GB(res, 8, 8);
7739 _railtypes[RAILTYPE_MONO].cost_multiplier = GB(res, 16, 8);
7740 }
7741 _railtypes[RAILTYPE_MAGLEV].cost_multiplier = GB(res, 16, 8);
7742 break;
7743 }
7744
7745 /* not implemented */
7746 case 0x93: // Tile refresh offset to left -- Intended to allow support for larger sprites, not necessary for OTTD
7747 case 0x94: // Tile refresh offset to right
7748 case 0x95: // Tile refresh offset upwards
7749 case 0x96: // Tile refresh offset downwards
7750 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
7751 case 0x99: // Global ID offset -- Not necessary since IDs are remapped automatically
7752 GrfMsg(7, "ParamSet: Skipping unimplemented target 0x{:02X}", target);
7753 break;
7754
7755 case 0x9E: // Miscellaneous GRF features
7756 /* Set train list engine width */
7757 _cur.grffile->traininfo_vehicle_width = HasBit(res, GMB_TRAIN_WIDTH_32_PIXELS) ? VEHICLEINFO_FULL_VEHICLE_WIDTH : TRAININFO_DEFAULT_VEHICLE_WIDTH;
7758 /* Remove the local flags from the global flags */
7760
7761 /* Only copy safe bits for static grfs */
7763 uint32_t safe_bits = 0;
7764 SetBit(safe_bits, GMB_SECOND_ROCKY_TILE_SET);
7765
7766 _misc_grf_features = (_misc_grf_features & ~safe_bits) | (res & safe_bits);
7767 } else {
7768 _misc_grf_features = res;
7769 }
7770 break;
7771
7772 case 0x9F: // locale-dependent settings
7773 GrfMsg(7, "ParamSet: Skipping unimplemented target 0x{:02X}", target);
7774 break;
7775
7776 default:
7777 if (target < 0x80) {
7778 /* Resize (and fill with zeroes) if needed. */
7779 if (target >= std::size(_cur.grffile->param)) _cur.grffile->param.resize(target + 1);
7780 _cur.grffile->param[target] = res;
7781 } else {
7782 GrfMsg(7, "ParamSet: Skipping unknown target 0x{:02X}", target);
7783 }
7784 break;
7785 }
7786}
7787
7788/* Action 0x0E (GLS_SAFETYSCAN) */
7789static void SafeGRFInhibit(ByteReader &buf)
7790{
7791 /* <0E> <num> <grfids...>
7792 *
7793 * B num Number of GRFIDs that follow
7794 * D grfids GRFIDs of the files to deactivate */
7795
7796 uint8_t num = buf.ReadByte();
7797
7798 for (uint i = 0; i < num; i++) {
7799 uint32_t grfid = buf.ReadDWord();
7800
7801 /* GRF is unsafe it if tries to deactivate other GRFs */
7802 if (grfid != _cur.grfconfig->ident.grfid) {
7804
7805 /* Skip remainder of GRF */
7806 _cur.skip_sprites = -1;
7807
7808 return;
7809 }
7810 }
7811}
7812
7813/* Action 0x0E */
7814static void GRFInhibit(ByteReader &buf)
7815{
7816 /* <0E> <num> <grfids...>
7817 *
7818 * B num Number of GRFIDs that follow
7819 * D grfids GRFIDs of the files to deactivate */
7820
7821 uint8_t num = buf.ReadByte();
7822
7823 for (uint i = 0; i < num; i++) {
7824 uint32_t grfid = buf.ReadDWord();
7825 GRFConfig *file = GetGRFConfig(grfid);
7826
7827 /* Unset activation flag */
7828 if (file != nullptr && file != _cur.grfconfig) {
7829 GrfMsg(2, "GRFInhibit: Deactivating file '{}'", file->filename);
7830 GRFError *error = DisableGrf(STR_NEWGRF_ERROR_FORCEFULLY_DISABLED, file);
7831 error->data = _cur.grfconfig->GetName();
7832 }
7833 }
7834}
7835
7838{
7839 /* <0F> <id> <style-name> <num-parts> <parts>
7840 *
7841 * B id ID of this definition in bottom 7 bits (final definition if bit 7 set)
7842 * V style-name Name of the style (only for final definition)
7843 * B num-parts Number of parts in this definition
7844 * V parts The parts */
7845
7846 uint32_t grfid = _cur.grffile->grfid;
7847
7848 GRFTownName *townname = AddGRFTownName(grfid);
7849
7850 uint8_t id = buf.ReadByte();
7851 GrfMsg(6, "FeatureTownName: definition 0x{:02X}", id & 0x7F);
7852
7853 if (HasBit(id, 7)) {
7854 /* Final definition */
7855 ClrBit(id, 7);
7856 bool new_scheme = _cur.grffile->grf_version >= 7;
7857
7858 uint8_t lang = buf.ReadByte();
7859 StringID style = STR_UNDEFINED;
7860
7861 do {
7862 ClrBit(lang, 7);
7863
7864 std::string_view name = buf.ReadString();
7865
7866 std::string lang_name = TranslateTTDPatchCodes(grfid, lang, false, name);
7867 GrfMsg(6, "FeatureTownName: lang 0x{:X} -> '{}'", lang, lang_name);
7868
7869 style = AddGRFString(grfid, GRFStringID{id}, lang, new_scheme, false, name, STR_UNDEFINED);
7870
7871 lang = buf.ReadByte();
7872 } while (lang != 0);
7873 townname->styles.emplace_back(style, id);
7874 }
7875
7876 uint8_t parts = buf.ReadByte();
7877 GrfMsg(6, "FeatureTownName: {} parts", parts);
7878
7879 townname->partlists[id].reserve(parts);
7880 for (uint partnum = 0; partnum < parts; partnum++) {
7881 NamePartList &partlist = townname->partlists[id].emplace_back();
7882 uint8_t texts = buf.ReadByte();
7883 partlist.bitstart = buf.ReadByte();
7884 partlist.bitcount = buf.ReadByte();
7885 partlist.maxprob = 0;
7886 GrfMsg(6, "FeatureTownName: part {} contains {} texts and will use GB(seed, {}, {})", partnum, texts, partlist.bitstart, partlist.bitcount);
7887
7888 partlist.parts.reserve(texts);
7889 for (uint textnum = 0; textnum < texts; textnum++) {
7890 NamePart &part = partlist.parts.emplace_back();
7891 part.prob = buf.ReadByte();
7892
7893 if (HasBit(part.prob, 7)) {
7894 uint8_t ref_id = buf.ReadByte();
7895 if (ref_id >= GRFTownName::MAX_LISTS || townname->partlists[ref_id].empty()) {
7896 GrfMsg(0, "FeatureTownName: definition 0x{:02X} doesn't exist, deactivating", ref_id);
7897 DelGRFTownName(grfid);
7898 DisableGrf(STR_NEWGRF_ERROR_INVALID_ID);
7899 return;
7900 }
7901 part.id = ref_id;
7902 GrfMsg(6, "FeatureTownName: part {}, text {}, uses intermediate definition 0x{:02X} (with probability {})", partnum, textnum, ref_id, part.prob & 0x7F);
7903 } else {
7904 std::string_view text = buf.ReadString();
7905 part.text = TranslateTTDPatchCodes(grfid, 0, false, text);
7906 GrfMsg(6, "FeatureTownName: part {}, text {}, '{}' (with probability {})", partnum, textnum, part.text, part.prob);
7907 }
7908 partlist.maxprob += GB(part.prob, 0, 7);
7909 }
7910 GrfMsg(6, "FeatureTownName: part {}, total probability {}", partnum, partlist.maxprob);
7911 }
7912}
7913
7916{
7917 /* <10> <label> [<comment>]
7918 *
7919 * B label The label to define
7920 * V comment Optional comment - ignored */
7921
7922 uint8_t nfo_label = buf.ReadByte();
7923
7924 _cur.grffile->labels.emplace_back(nfo_label, _cur.nfo_line, _cur.file->GetPos());
7925
7926 GrfMsg(2, "DefineGotoLabel: GOTO target with label 0x{:02X}", nfo_label);
7927}
7928
7933static void ImportGRFSound(SoundEntry *sound)
7934{
7935 const GRFFile *file;
7936 uint32_t grfid = _cur.file->ReadDword();
7937 SoundID sound_id = _cur.file->ReadWord();
7938
7939 file = GetFileByGRFID(grfid);
7940 if (file == nullptr || file->sound_offset == 0) {
7941 GrfMsg(1, "ImportGRFSound: Source file not available");
7942 return;
7943 }
7944
7945 if (sound_id >= file->num_sounds) {
7946 GrfMsg(1, "ImportGRFSound: Sound effect {} is invalid", sound_id);
7947 return;
7948 }
7949
7950 GrfMsg(2, "ImportGRFSound: Copying sound {} ({}) from file {:x}", sound_id, file->sound_offset + sound_id, grfid);
7951
7952 *sound = *GetSound(file->sound_offset + sound_id);
7953
7954 /* Reset volume and priority, which TTDPatch doesn't copy */
7955 sound->volume = SOUND_EFFECT_MAX_VOLUME;
7956 sound->priority = 0;
7957}
7958
7964static void LoadGRFSound(size_t offs, SoundEntry *sound)
7965{
7966 /* Set default volume and priority */
7967 sound->volume = SOUND_EFFECT_MAX_VOLUME;
7968 sound->priority = 0;
7969
7970 if (offs != SIZE_MAX) {
7971 /* Sound is present in the NewGRF. */
7972 sound->file = _cur.file;
7973 sound->file_offset = offs;
7974 sound->source = SoundSource::NewGRF;
7976 }
7977}
7978
7979/* Action 0x11 */
7980static void GRFSound(ByteReader &buf)
7981{
7982 /* <11> <num>
7983 *
7984 * W num Number of sound files that follow */
7985
7986 uint16_t num = buf.ReadWord();
7987 if (num == 0) return;
7988
7989 SoundEntry *sound;
7990 if (_cur.grffile->sound_offset == 0) {
7991 _cur.grffile->sound_offset = GetNumSounds();
7992 _cur.grffile->num_sounds = num;
7993 sound = AllocateSound(num);
7994 } else {
7995 sound = GetSound(_cur.grffile->sound_offset);
7996 }
7997
7998 SpriteFile &file = *_cur.file;
7999 uint8_t grf_container_version = file.GetContainerVersion();
8000 for (int i = 0; i < num; i++) {
8001 _cur.nfo_line++;
8002
8003 /* Check whether the index is in range. This might happen if multiple action 11 are present.
8004 * While this is invalid, we do not check for this. But we should prevent it from causing bigger trouble */
8005 bool invalid = i >= _cur.grffile->num_sounds;
8006
8007 size_t offs = file.GetPos();
8008
8009 uint32_t len = grf_container_version >= 2 ? file.ReadDword() : file.ReadWord();
8010 uint8_t type = file.ReadByte();
8011
8012 if (grf_container_version >= 2 && type == 0xFD) {
8013 /* Reference to sprite section. */
8014 if (invalid) {
8015 GrfMsg(1, "GRFSound: Sound index out of range (multiple Action 11?)");
8016 file.SkipBytes(len);
8017 } else if (len != 4) {
8018 GrfMsg(1, "GRFSound: Invalid sprite section import");
8019 file.SkipBytes(len);
8020 } else {
8021 uint32_t id = file.ReadDword();
8022 if (_cur.stage == GLS_INIT) LoadGRFSound(GetGRFSpriteOffset(id), sound + i);
8023 }
8024 continue;
8025 }
8026
8027 if (type != 0xFF) {
8028 GrfMsg(1, "GRFSound: Unexpected RealSprite found, skipping");
8029 file.SkipBytes(7);
8030 SkipSpriteData(*_cur.file, type, len - 8);
8031 continue;
8032 }
8033
8034 if (invalid) {
8035 GrfMsg(1, "GRFSound: Sound index out of range (multiple Action 11?)");
8036 file.SkipBytes(len);
8037 }
8038
8039 uint8_t action = file.ReadByte();
8040 switch (action) {
8041 case 0xFF:
8042 /* Allocate sound only in init stage. */
8043 if (_cur.stage == GLS_INIT) {
8044 if (grf_container_version >= 2) {
8045 GrfMsg(1, "GRFSound: Inline sounds are not supported for container version >= 2");
8046 } else {
8047 LoadGRFSound(offs, sound + i);
8048 }
8049 }
8050 file.SkipBytes(len - 1); // already read <action>
8051 break;
8052
8053 case 0xFE:
8054 if (_cur.stage == GLS_ACTIVATION) {
8055 /* XXX 'Action 0xFE' isn't really specified. It is only mentioned for
8056 * importing sounds, so this is probably all wrong... */
8057 if (file.ReadByte() != 0) GrfMsg(1, "GRFSound: Import type mismatch");
8058 ImportGRFSound(sound + i);
8059 } else {
8060 file.SkipBytes(len - 1); // already read <action>
8061 }
8062 break;
8063
8064 default:
8065 GrfMsg(1, "GRFSound: Unexpected Action {:x} found, skipping", action);
8066 file.SkipBytes(len - 1); // already read <action>
8067 break;
8068 }
8069 }
8070}
8071
8072/* Action 0x11 (SKIP) */
8073static void SkipAct11(ByteReader &buf)
8074{
8075 /* <11> <num>
8076 *
8077 * W num Number of sound files that follow */
8078
8079 _cur.skip_sprites = buf.ReadWord();
8080
8081 GrfMsg(3, "SkipAct11: Skipping {} sprites", _cur.skip_sprites);
8082}
8083
8085static void LoadFontGlyph(ByteReader &buf)
8086{
8087 /* <12> <num_def> <font_size> <num_char> <base_char>
8088 *
8089 * B num_def Number of definitions
8090 * B font_size Size of font (0 = normal, 1 = small, 2 = large, 3 = mono)
8091 * B num_char Number of consecutive glyphs
8092 * W base_char First character index */
8093
8094 uint8_t num_def = buf.ReadByte();
8095
8096 for (uint i = 0; i < num_def; i++) {
8097 FontSize size = (FontSize)buf.ReadByte();
8098 uint8_t num_char = buf.ReadByte();
8099 uint16_t base_char = buf.ReadWord();
8100
8101 if (size >= FS_END) {
8102 GrfMsg(1, "LoadFontGlyph: Size {} is not supported, ignoring", size);
8103 }
8104
8105 GrfMsg(7, "LoadFontGlyph: Loading {} glyph(s) at 0x{:04X} for size {}", num_char, base_char, size);
8106
8107 for (uint c = 0; c < num_char; c++) {
8108 if (size < FS_END) SetUnicodeGlyph(size, base_char + c, _cur.spriteid);
8109 _cur.nfo_line++;
8110 LoadNextSprite(_cur.spriteid++, *_cur.file, _cur.nfo_line);
8111 }
8112 }
8113}
8114
8116static void SkipAct12(ByteReader &buf)
8117{
8118 /* <12> <num_def> <font_size> <num_char> <base_char>
8119 *
8120 * B num_def Number of definitions
8121 * B font_size Size of font (0 = normal, 1 = small, 2 = large)
8122 * B num_char Number of consecutive glyphs
8123 * W base_char First character index */
8124
8125 uint8_t num_def = buf.ReadByte();
8126
8127 for (uint i = 0; i < num_def; i++) {
8128 /* Ignore 'size' byte */
8129 buf.ReadByte();
8130
8131 /* Sum up number of characters */
8132 _cur.skip_sprites += buf.ReadByte();
8133
8134 /* Ignore 'base_char' word */
8135 buf.ReadWord();
8136 }
8137
8138 GrfMsg(3, "SkipAct12: Skipping {} sprites", _cur.skip_sprites);
8139}
8140
8143{
8144 /* <13> <grfid> <num-ent> <offset> <text...>
8145 *
8146 * 4*B grfid The GRFID of the file whose texts are to be translated
8147 * B num-ent Number of strings
8148 * W offset First text ID
8149 * S text... Zero-terminated strings */
8150
8151 uint32_t grfid = buf.ReadDWord();
8152 const GRFConfig *c = GetGRFConfig(grfid);
8153 if (c == nullptr || (c->status != GCS_INITIALISED && c->status != GCS_ACTIVATED)) {
8154 GrfMsg(7, "TranslateGRFStrings: GRFID 0x{:08X} unknown, skipping action 13", std::byteswap(grfid));
8155 return;
8156 }
8157
8158 if (c->status == GCS_INITIALISED) {
8159 /* If the file is not active but will be activated later, give an error
8160 * and disable this file. */
8161 GRFError *error = DisableGrf(STR_NEWGRF_ERROR_LOAD_AFTER);
8162
8163 error->data = GetString(STR_NEWGRF_ERROR_AFTER_TRANSLATED_FILE);
8164
8165 return;
8166 }
8167
8168 /* Since no language id is supplied for with version 7 and lower NewGRFs, this string has
8169 * to be added as a generic string, thus the language id of 0x7F. For this to work
8170 * new_scheme has to be true as well, which will also be implicitly the case for version 8
8171 * and higher. A language id of 0x7F will be overridden by a non-generic id, so this will
8172 * not change anything if a string has been provided specifically for this language. */
8173 uint8_t language = _cur.grffile->grf_version >= 8 ? buf.ReadByte() : 0x7F;
8174 uint8_t num_strings = buf.ReadByte();
8175 uint16_t first_id = buf.ReadWord();
8176
8177 if (!((first_id >= 0xD000 && first_id + num_strings <= 0xD400) || (first_id >= 0xD800 && first_id + num_strings <= 0xE000))) {
8178 GrfMsg(7, "TranslateGRFStrings: Attempting to set out-of-range string IDs in action 13 (first: 0x{:04X}, number: 0x{:02X})", first_id, num_strings);
8179 return;
8180 }
8181
8182 for (uint i = 0; i < num_strings && buf.HasData(); i++) {
8183 std::string_view string = buf.ReadString();
8184
8185 if (string.empty()) {
8186 GrfMsg(7, "TranslateGRFString: Ignoring empty string.");
8187 continue;
8188 }
8189
8190 AddGRFString(grfid, GRFStringID(first_id + i), language, true, true, string, STR_UNDEFINED);
8191 }
8192}
8193
8195static bool ChangeGRFName(uint8_t langid, std::string_view str)
8196{
8197 AddGRFTextToList(_cur.grfconfig->name, langid, _cur.grfconfig->ident.grfid, false, str);
8198 return true;
8199}
8200
8202static bool ChangeGRFDescription(uint8_t langid, std::string_view str)
8203{
8204 AddGRFTextToList(_cur.grfconfig->info, langid, _cur.grfconfig->ident.grfid, true, str);
8205 return true;
8206}
8207
8209static bool ChangeGRFURL(uint8_t langid, std::string_view str)
8210{
8211 AddGRFTextToList(_cur.grfconfig->url, langid, _cur.grfconfig->ident.grfid, false, str);
8212 return true;
8213}
8214
8216static bool ChangeGRFNumUsedParams(size_t len, ByteReader &buf)
8217{
8218 if (len != 1) {
8219 GrfMsg(2, "StaticGRFInfo: expected only 1 byte for 'INFO'->'NPAR' but got {}, ignoring this field", len);
8220 buf.Skip(len);
8221 } else {
8222 _cur.grfconfig->num_valid_params = std::min(buf.ReadByte(), GRFConfig::MAX_NUM_PARAMS);
8223 }
8224 return true;
8225}
8226
8228static bool ChangeGRFPalette(size_t len, ByteReader &buf)
8229{
8230 if (len != 1) {
8231 GrfMsg(2, "StaticGRFInfo: expected only 1 byte for 'INFO'->'PALS' but got {}, ignoring this field", len);
8232 buf.Skip(len);
8233 } else {
8234 char data = buf.ReadByte();
8236 switch (data) {
8237 case '*':
8238 case 'A': pal = GRFP_GRF_ANY; break;
8239 case 'W': pal = GRFP_GRF_WINDOWS; break;
8240 case 'D': pal = GRFP_GRF_DOS; break;
8241 default:
8242 GrfMsg(2, "StaticGRFInfo: unexpected value '{:02X}' for 'INFO'->'PALS', ignoring this field", data);
8243 break;
8244 }
8245 if (pal != GRFP_GRF_UNSET) {
8246 _cur.grfconfig->palette &= ~GRFP_GRF_MASK;
8247 _cur.grfconfig->palette |= pal;
8248 }
8249 }
8250 return true;
8251}
8252
8254static bool ChangeGRFBlitter(size_t len, ByteReader &buf)
8255{
8256 if (len != 1) {
8257 GrfMsg(2, "StaticGRFInfo: expected only 1 byte for 'INFO'->'BLTR' but got {}, ignoring this field", len);
8258 buf.Skip(len);
8259 } else {
8260 char data = buf.ReadByte();
8262 switch (data) {
8263 case '8': pal = GRFP_BLT_UNSET; break;
8264 case '3': pal = GRFP_BLT_32BPP; break;
8265 default:
8266 GrfMsg(2, "StaticGRFInfo: unexpected value '{:02X}' for 'INFO'->'BLTR', ignoring this field", data);
8267 return true;
8268 }
8269 _cur.grfconfig->palette &= ~GRFP_BLT_MASK;
8270 _cur.grfconfig->palette |= pal;
8271 }
8272 return true;
8273}
8274
8276static bool ChangeGRFVersion(size_t len, ByteReader &buf)
8277{
8278 if (len != 4) {
8279 GrfMsg(2, "StaticGRFInfo: expected 4 bytes for 'INFO'->'VRSN' but got {}, ignoring this field", len);
8280 buf.Skip(len);
8281 } else {
8282 /* Set min_loadable_version as well (default to minimal compatibility) */
8283 _cur.grfconfig->version = _cur.grfconfig->min_loadable_version = buf.ReadDWord();
8284 }
8285 return true;
8286}
8287
8289static bool ChangeGRFMinVersion(size_t len, ByteReader &buf)
8290{
8291 if (len != 4) {
8292 GrfMsg(2, "StaticGRFInfo: expected 4 bytes for 'INFO'->'MINV' but got {}, ignoring this field", len);
8293 buf.Skip(len);
8294 } else {
8295 _cur.grfconfig->min_loadable_version = buf.ReadDWord();
8296 if (_cur.grfconfig->version == 0) {
8297 GrfMsg(2, "StaticGRFInfo: 'MINV' defined before 'VRSN' or 'VRSN' set to 0, ignoring this field");
8299 }
8300 if (_cur.grfconfig->version < _cur.grfconfig->min_loadable_version) {
8301 GrfMsg(2, "StaticGRFInfo: 'MINV' defined as {}, limiting it to 'VRSN'", _cur.grfconfig->min_loadable_version);
8303 }
8304 }
8305 return true;
8306}
8307
8309
8311static bool ChangeGRFParamName(uint8_t langid, std::string_view str)
8312{
8313 AddGRFTextToList(_cur_parameter->name, langid, _cur.grfconfig->ident.grfid, false, str);
8314 return true;
8315}
8316
8318static bool ChangeGRFParamDescription(uint8_t langid, std::string_view str)
8319{
8320 AddGRFTextToList(_cur_parameter->desc, langid, _cur.grfconfig->ident.grfid, true, str);
8321 return true;
8322}
8323
8325static bool ChangeGRFParamType(size_t len, ByteReader &buf)
8326{
8327 if (len != 1) {
8328 GrfMsg(2, "StaticGRFInfo: expected 1 byte for 'INFO'->'PARA'->'TYPE' but got {}, ignoring this field", len);
8329 buf.Skip(len);
8330 } else {
8331 GRFParameterType type = (GRFParameterType)buf.ReadByte();
8332 if (type < PTYPE_END) {
8333 _cur_parameter->type = type;
8334 } else {
8335 GrfMsg(3, "StaticGRFInfo: unknown parameter type {}, ignoring this field", type);
8336 }
8337 }
8338 return true;
8339}
8340
8342static bool ChangeGRFParamLimits(size_t len, ByteReader &buf)
8343{
8345 GrfMsg(2, "StaticGRFInfo: 'INFO'->'PARA'->'LIMI' is only valid for parameters with type uint/enum, ignoring this field");
8346 buf.Skip(len);
8347 } else if (len != 8) {
8348 GrfMsg(2, "StaticGRFInfo: expected 8 bytes for 'INFO'->'PARA'->'LIMI' but got {}, ignoring this field", len);
8349 buf.Skip(len);
8350 } else {
8351 uint32_t min_value = buf.ReadDWord();
8352 uint32_t max_value = buf.ReadDWord();
8353 if (min_value <= max_value) {
8354 _cur_parameter->min_value = min_value;
8355 _cur_parameter->max_value = max_value;
8356 } else {
8357 GrfMsg(2, "StaticGRFInfo: 'INFO'->'PARA'->'LIMI' values are incoherent, ignoring this field");
8358 }
8359 }
8360 return true;
8361}
8362
8364static bool ChangeGRFParamMask(size_t len, ByteReader &buf)
8365{
8366 if (len < 1 || len > 3) {
8367 GrfMsg(2, "StaticGRFInfo: expected 1 to 3 bytes for 'INFO'->'PARA'->'MASK' but got {}, ignoring this field", len);
8368 buf.Skip(len);
8369 } else {
8370 uint8_t param_nr = buf.ReadByte();
8371 if (param_nr >= GRFConfig::MAX_NUM_PARAMS) {
8372 GrfMsg(2, "StaticGRFInfo: invalid parameter number in 'INFO'->'PARA'->'MASK', param {}, ignoring this field", param_nr);
8373 buf.Skip(len - 1);
8374 } else {
8375 _cur_parameter->param_nr = param_nr;
8376 if (len >= 2) _cur_parameter->first_bit = std::min<uint8_t>(buf.ReadByte(), 31);
8377 if (len >= 3) _cur_parameter->num_bit = std::min<uint8_t>(buf.ReadByte(), 32 - _cur_parameter->first_bit);
8378 }
8379 }
8380
8381 return true;
8382}
8383
8385static bool ChangeGRFParamDefault(size_t len, ByteReader &buf)
8386{
8387 if (len != 4) {
8388 GrfMsg(2, "StaticGRFInfo: expected 4 bytes for 'INFO'->'PARA'->'DEFA' but got {}, ignoring this field", len);
8389 buf.Skip(len);
8390 } else {
8391 _cur_parameter->def_value = buf.ReadDWord();
8392 }
8393 _cur.grfconfig->has_param_defaults = true;
8394 return true;
8395}
8396
8397typedef bool (*DataHandler)(size_t, ByteReader &);
8398typedef bool (*TextHandler)(uint8_t, std::string_view str);
8399typedef bool (*BranchHandler)(ByteReader &);
8400
8410 using Span = std::pair<const AllowedSubtags *, const AllowedSubtags *>;
8411
8412 uint32_t id;
8413 std::variant<DataHandler, TextHandler, BranchHandler, Span> handler;
8414};
8415
8416static bool SkipUnknownInfo(ByteReader &buf, uint8_t type);
8417static bool HandleNodes(ByteReader &buf, std::span<const AllowedSubtags> tags);
8418
8426{
8427 uint8_t type = buf.ReadByte();
8428 while (type != 0) {
8429 uint32_t id = buf.ReadDWord();
8430 if (type != 'T' || id > _cur_parameter->max_value) {
8431 GrfMsg(2, "StaticGRFInfo: all child nodes of 'INFO'->'PARA'->param_num->'VALU' should have type 't' and the value/bit number as id");
8432 if (!SkipUnknownInfo(buf, type)) return false;
8433 type = buf.ReadByte();
8434 continue;
8435 }
8436
8437 uint8_t langid = buf.ReadByte();
8438 std::string_view name_string = buf.ReadString();
8439
8440 auto it = std::ranges::lower_bound(_cur_parameter->value_names, id, std::less{}, &GRFParameterInfo::ValueName::first);
8441 if (it == std::end(_cur_parameter->value_names) || it->first != id) {
8442 it = _cur_parameter->value_names.emplace(it, id, GRFTextList{});
8443 }
8444 AddGRFTextToList(it->second, langid, _cur.grfconfig->ident.grfid, false, name_string);
8445
8446 type = buf.ReadByte();
8447 }
8448 return true;
8449}
8450
8461
8469{
8470 uint8_t type = buf.ReadByte();
8471 while (type != 0) {
8472 uint32_t id = buf.ReadDWord();
8473 if (type != 'C' || id >= _cur.grfconfig->num_valid_params) {
8474 GrfMsg(2, "StaticGRFInfo: all child nodes of 'INFO'->'PARA' should have type 'C' and their parameter number as id");
8475 if (!SkipUnknownInfo(buf, type)) return false;
8476 type = buf.ReadByte();
8477 continue;
8478 }
8479
8480 if (id >= _cur.grfconfig->param_info.size()) {
8481 _cur.grfconfig->param_info.resize(id + 1);
8482 }
8483 if (!_cur.grfconfig->param_info[id].has_value()) {
8484 _cur.grfconfig->param_info[id] = GRFParameterInfo(id);
8485 }
8486 _cur_parameter = &_cur.grfconfig->param_info[id].value();
8487 /* Read all parameter-data and process each node. */
8488 if (!HandleNodes(buf, _tags_parameters)) return false;
8489 type = buf.ReadByte();
8490 }
8491 return true;
8492}
8493
8506
8508static constexpr AllowedSubtags _tags_root[] = {
8509 AllowedSubtags{'INFO', std::make_pair(std::begin(_tags_info), std::end(_tags_info))},
8510};
8511
8512
8519static bool SkipUnknownInfo(ByteReader &buf, uint8_t type)
8520{
8521 /* type and id are already read */
8522 switch (type) {
8523 case 'C': {
8524 uint8_t new_type = buf.ReadByte();
8525 while (new_type != 0) {
8526 buf.ReadDWord(); // skip the id
8527 if (!SkipUnknownInfo(buf, new_type)) return false;
8528 new_type = buf.ReadByte();
8529 }
8530 break;
8531 }
8532
8533 case 'T':
8534 buf.ReadByte(); // lang
8535 buf.ReadString(); // actual text
8536 break;
8537
8538 case 'B': {
8539 uint16_t size = buf.ReadWord();
8540 buf.Skip(size);
8541 break;
8542 }
8543
8544 default:
8545 return false;
8546 }
8547
8548 return true;
8549}
8550
8559static bool HandleNode(uint8_t type, uint32_t id, ByteReader &buf, std::span<const AllowedSubtags> subtags)
8560{
8561 /* Visitor to get a subtag handler's type. */
8562 struct type_visitor {
8563 char operator()(const DataHandler &) { return 'B'; }
8564 char operator()(const TextHandler &) { return 'T'; }
8565 char operator()(const BranchHandler &) { return 'C'; }
8566 char operator()(const AllowedSubtags::Span &) { return 'C'; }
8567 };
8568
8569 /* Visitor to evaluate a subtag handler. */
8570 struct evaluate_visitor {
8571 ByteReader &buf;
8572
8573 bool operator()(const DataHandler &handler)
8574 {
8575 size_t len = buf.ReadWord();
8576 if (buf.Remaining() < len) return false;
8577 return handler(len, buf);
8578 }
8579
8580 bool operator()(const TextHandler &handler)
8581 {
8582 uint8_t langid = buf.ReadByte();
8583 return handler(langid, buf.ReadString());
8584 }
8585
8586 bool operator()(const BranchHandler &handler)
8587 {
8588 return handler(buf);
8589 }
8590
8591 bool operator()(const AllowedSubtags::Span &subtags)
8592 {
8593 return HandleNodes(buf, {subtags.first, subtags.second});
8594 }
8595 };
8596
8597 for (const auto &tag : subtags) {
8598 if (tag.id != std::byteswap(id) || std::visit(type_visitor{}, tag.handler) != type) continue;
8599 return std::visit(evaluate_visitor{buf}, tag.handler);
8600 }
8601
8602 GrfMsg(2, "StaticGRFInfo: unknown type/id combination found, type={:c}, id={:x}", type, id);
8603 return SkipUnknownInfo(buf, type);
8604}
8605
8612static bool HandleNodes(ByteReader &buf, std::span<const AllowedSubtags> subtags)
8613{
8614 uint8_t type = buf.ReadByte();
8615 while (type != 0) {
8616 uint32_t id = buf.ReadDWord();
8617 if (!HandleNode(type, id, buf, subtags)) return false;
8618 type = buf.ReadByte();
8619 }
8620 return true;
8621}
8622
8627static void StaticGRFInfo(ByteReader &buf)
8628{
8629 /* <14> <type> <id> <text/data...> */
8630 HandleNodes(buf, _tags_root);
8631}
8632
8637static void GRFUnsafe(ByteReader &)
8638{
8640
8641 /* Skip remainder of GRF */
8642 _cur.skip_sprites = -1;
8643}
8644
8645
8648{
8649 _ttdpatch_flags[0] = ((_settings_game.station.never_expire_airports ? 1U : 0U) << 0x0C) // keepsmallairport
8650 | (1U << 0x0D) // newairports
8651 | (1U << 0x0E) // largestations
8652 | ((_settings_game.construction.max_bridge_length > 16 ? 1U : 0U) << 0x0F) // longbridges
8653 | (0U << 0x10) // loadtime
8654 | (1U << 0x12) // presignals
8655 | (1U << 0x13) // extpresignals
8656 | ((_settings_game.vehicle.never_expire_vehicles ? 1U : 0U) << 0x16) // enginespersist
8657 | (1U << 0x1B) // multihead
8658 | (1U << 0x1D) // lowmemory
8659 | (1U << 0x1E); // generalfixes
8660
8661 _ttdpatch_flags[1] = ((_settings_game.economy.station_noise_level ? 1U : 0U) << 0x07) // moreairports - based on units of noise
8662 | (1U << 0x08) // mammothtrains
8663 | (1U << 0x09) // trainrefit
8664 | (0U << 0x0B) // subsidiaries
8665 | ((_settings_game.order.gradual_loading ? 1U : 0U) << 0x0C) // gradualloading
8666 | (1U << 0x12) // unifiedmaglevmode - set bit 0 mode. Not revelant to OTTD
8667 | (1U << 0x13) // unifiedmaglevmode - set bit 1 mode
8668 | (1U << 0x14) // bridgespeedlimits
8669 | (1U << 0x16) // eternalgame
8670 | (1U << 0x17) // newtrains
8671 | (1U << 0x18) // newrvs
8672 | (1U << 0x19) // newships
8673 | (1U << 0x1A) // newplanes
8674 | ((_settings_game.construction.train_signal_side == 1 ? 1U : 0U) << 0x1B) // signalsontrafficside
8675 | ((_settings_game.vehicle.disable_elrails ? 0U : 1U) << 0x1C); // electrifiedrailway
8676
8677 _ttdpatch_flags[2] = (1U << 0x01) // loadallgraphics - obsolote
8678 | (1U << 0x03) // semaphores
8679 | (1U << 0x0A) // newobjects
8680 | (0U << 0x0B) // enhancedgui
8681 | (0U << 0x0C) // newagerating
8682 | ((_settings_game.construction.build_on_slopes ? 1U : 0U) << 0x0D) // buildonslopes
8683 | (1U << 0x0E) // fullloadany
8684 | (1U << 0x0F) // planespeed
8685 | (0U << 0x10) // moreindustriesperclimate - obsolete
8686 | (0U << 0x11) // moretoylandfeatures
8687 | (1U << 0x12) // newstations
8688 | (1U << 0x13) // tracktypecostdiff
8689 | (1U << 0x14) // manualconvert
8690 | ((_settings_game.construction.build_on_slopes ? 1U : 0U) << 0x15) // buildoncoasts
8691 | (1U << 0x16) // canals
8692 | (1U << 0x17) // newstartyear
8693 | ((_settings_game.vehicle.freight_trains > 1 ? 1U : 0U) << 0x18) // freighttrains
8694 | (1U << 0x19) // newhouses
8695 | (1U << 0x1A) // newbridges
8696 | (1U << 0x1B) // newtownnames
8697 | (1U << 0x1C) // moreanimation
8698 | ((_settings_game.vehicle.wagon_speed_limits ? 1U : 0U) << 0x1D) // wagonspeedlimits
8699 | (1U << 0x1E) // newshistory
8700 | (0U << 0x1F); // custombridgeheads
8701
8702 _ttdpatch_flags[3] = (0U << 0x00) // newcargodistribution
8703 | (1U << 0x01) // windowsnap
8704 | ((_settings_game.economy.allow_town_roads || _generating_world ? 0U : 1U) << 0x02) // townbuildnoroad
8705 | (1U << 0x03) // pathbasedsignalling
8706 | (0U << 0x04) // aichoosechance
8707 | (1U << 0x05) // resolutionwidth
8708 | (1U << 0x06) // resolutionheight
8709 | (1U << 0x07) // newindustries
8710 | ((_settings_game.order.improved_load ? 1U : 0U) << 0x08) // fifoloading
8711 | (0U << 0x09) // townroadbranchprob
8712 | (0U << 0x0A) // tempsnowline
8713 | (1U << 0x0B) // newcargo
8714 | (1U << 0x0C) // enhancemultiplayer
8715 | (1U << 0x0D) // onewayroads
8716 | (1U << 0x0E) // irregularstations
8717 | (1U << 0x0F) // statistics
8718 | (1U << 0x10) // newsounds
8719 | (1U << 0x11) // autoreplace
8720 | (1U << 0x12) // autoslope
8721 | (0U << 0x13) // followvehicle
8722 | (1U << 0x14) // trams
8723 | (0U << 0x15) // enhancetunnels
8724 | (1U << 0x16) // shortrvs
8725 | (1U << 0x17) // articulatedrvs
8726 | ((_settings_game.vehicle.dynamic_engines ? 1U : 0U) << 0x18) // dynamic engines
8727 | (1U << 0x1E) // variablerunningcosts
8728 | (1U << 0x1F); // any switch is on
8729
8730 _ttdpatch_flags[4] = (1U << 0x00) // larger persistent storage
8731 | ((_settings_game.economy.inflation ? 1U : 0U) << 0x01) // inflation is on
8732 | (1U << 0x02); // extended string range
8733}
8734
8737{
8738 for (GRFFile * const file : _grf_files) {
8739 file->stations.clear();
8740 }
8741}
8742
8745{
8746 for (GRFFile * const file : _grf_files) {
8747 file->housespec.clear();
8748 }
8749}
8750
8753{
8754 for (GRFFile * const file : _grf_files) {
8755 file->airportspec.clear();
8756 file->airtspec.clear();
8757 }
8758}
8759
8762{
8763 for (GRFFile * const file : _grf_files) {
8764 file->industryspec.clear();
8765 file->indtspec.clear();
8766 }
8767}
8768
8771{
8772 for (GRFFile * const file : _grf_files) {
8773 file->objectspec.clear();
8774 }
8775}
8776
8777static void ResetCustomRoadStops()
8778{
8779 for (auto file : _grf_files) {
8780 file->roadstops.clear();
8781 }
8782}
8783
8785static void ResetNewGRF()
8786{
8787 for (GRFFile * const file : _grf_files) {
8788 delete file;
8789 }
8790
8791 _grf_files.clear();
8792 _cur.grffile = nullptr;
8793}
8794
8797{
8798 for (const auto &c : _grfconfig) {
8799 c->error.reset();
8800 }
8801}
8802
8807{
8809 CleanUpGRFTownNames();
8810
8811 /* Copy/reset original engine info data */
8812 SetupEngines();
8813
8814 /* Copy/reset original bridge info data */
8815 ResetBridges();
8816
8817 /* Reset rail type information */
8819
8820 /* Copy/reset original road type info data */
8822
8823 /* Allocate temporary refit/cargo class data */
8824 _gted.resize(Engine::GetPoolSize());
8825
8826 /* Fill rail type label temporary data for default trains */
8827 for (const Engine *e : Engine::IterateType(VEH_TRAIN)) {
8828 _gted[e->index].railtypelabel = GetRailTypeInfo(e->u.rail.railtype)->label;
8829 }
8830
8831 /* Reset GRM reservations */
8832 memset(&_grm_engines, 0, sizeof(_grm_engines));
8833 memset(&_grm_cargoes, 0, sizeof(_grm_cargoes));
8834
8835 /* Reset generic feature callback lists */
8837
8838 /* Reset price base data */
8840
8841 /* Reset the curencies array */
8843
8844 /* Reset the house array */
8846 ResetHouses();
8847
8848 /* Reset the industries structures*/
8851
8852 /* Reset the objects. */
8855 ResetObjects();
8856
8857 /* Reset station classes */
8860
8861 /* Reset airport-related structures */
8866
8867 /* Reset road stop classes */
8869 ResetCustomRoadStops();
8870
8871 /* Reset canal sprite groups and flags */
8872 _water_feature.fill({});
8873
8874 /* Reset the snowline table. */
8875 ClearSnowLine();
8876
8877 /* Reset NewGRF files */
8878 ResetNewGRF();
8879
8880 /* Reset NewGRF errors. */
8882
8883 /* Set up the default cargo types */
8885
8886 /* Reset misc GRF features and train list display variables */
8888
8890 _loaded_newgrf_features.used_liveries = 1 << LS_DEFAULT;
8893
8894 /* Clear all GRF overrides */
8895 _grf_id_overrides.clear();
8896
8897 InitializeSoundPool();
8898 _spritegroup_pool.CleanPool();
8900}
8901
8906{
8907 /* Reset override managers */
8908 _engine_mngr.ResetToDefaultMapping();
8909 _house_mngr.ResetMapping();
8910 _industry_mngr.ResetMapping();
8911 _industile_mngr.ResetMapping();
8912 _airport_mngr.ResetMapping();
8913 _airporttile_mngr.ResetMapping();
8914}
8915
8921{
8922 _cur.grffile->cargo_map.fill(UINT8_MAX);
8923
8924 auto cargo_list = GetCargoTranslationTable(*_cur.grffile);
8925
8926 for (const CargoSpec *cs : CargoSpec::Iterate()) {
8927 if (!cs->IsValid()) continue;
8928
8929 /* Check the translation table for this cargo's label */
8930 int idx = find_index(cargo_list, cs->label);
8931 if (idx >= 0) _cur.grffile->cargo_map[cs->Index()] = idx;
8932 }
8933}
8934
8939static void InitNewGRFFile(const GRFConfig &config)
8940{
8941 GRFFile *newfile = GetFileByFilename(config.filename);
8942 if (newfile != nullptr) {
8943 /* We already loaded it once. */
8944 _cur.grffile = newfile;
8945 return;
8946 }
8947
8948 newfile = new GRFFile(config);
8949 _grf_files.push_back(_cur.grffile = newfile);
8950}
8951
8957{
8958 this->filename = config.filename;
8959 this->grfid = config.ident.grfid;
8960
8961 /* Initialise local settings to defaults */
8962 this->traininfo_vehicle_pitch = 0;
8963 this->traininfo_vehicle_width = TRAININFO_DEFAULT_VEHICLE_WIDTH;
8964
8965 /* Mark price_base_multipliers as 'not set' */
8966 for (Price i = PR_BEGIN; i < PR_END; i++) {
8967 this->price_base_multipliers[i] = INVALID_PRICE_MODIFIER;
8968 }
8969
8970 /* Initialise rail type map with default rail types */
8971 this->railtype_map.fill(INVALID_RAILTYPE);
8972 this->railtype_map[0] = RAILTYPE_RAIL;
8973 this->railtype_map[1] = RAILTYPE_ELECTRIC;
8974 this->railtype_map[2] = RAILTYPE_MONO;
8975 this->railtype_map[3] = RAILTYPE_MAGLEV;
8976
8977 /* Initialise road type map with default road types */
8978 this->roadtype_map.fill(INVALID_ROADTYPE);
8979 this->roadtype_map[0] = ROADTYPE_ROAD;
8980
8981 /* Initialise tram type map with default tram types */
8982 this->tramtype_map.fill(INVALID_ROADTYPE);
8983 this->tramtype_map[0] = ROADTYPE_TRAM;
8984
8985 /* Copy the initial parameter list */
8986 this->param = config.param;
8987}
8988
8994static CargoLabel GetActiveCargoLabel(const std::initializer_list<CargoLabel> &labels)
8995{
8996 for (const CargoLabel &label : labels) {
8997 CargoType cargo_type = GetCargoTypeByLabel(label);
8998 if (cargo_type != INVALID_CARGO) return label;
8999 }
9000 return CT_INVALID;
9001}
9002
9008static CargoLabel GetActiveCargoLabel(const std::variant<CargoLabel, MixedCargoType> &label)
9009{
9010 struct visitor {
9011 CargoLabel operator()(const CargoLabel &label) { return label; }
9012 CargoLabel operator()(const MixedCargoType &mixed)
9013 {
9014 switch (mixed) {
9015 case MCT_LIVESTOCK_FRUIT: return GetActiveCargoLabel({CT_LIVESTOCK, CT_FRUIT});
9016 case MCT_GRAIN_WHEAT_MAIZE: return GetActiveCargoLabel({CT_GRAIN, CT_WHEAT, CT_MAIZE});
9017 case MCT_VALUABLES_GOLD_DIAMONDS: return GetActiveCargoLabel({CT_VALUABLES, CT_GOLD, CT_DIAMONDS});
9018 default: NOT_REACHED();
9019 }
9020 }
9021 };
9022
9023 return std::visit(visitor{}, label);
9024}
9025
9030{
9031 CargoTypes original_known_cargoes = 0;
9032 for (CargoType cargo_type = 0; cargo_type != NUM_CARGO; ++cargo_type) {
9033 if (IsDefaultCargo(cargo_type)) SetBit(original_known_cargoes, cargo_type);
9034 }
9035
9036 for (Engine *e : Engine::Iterate()) {
9037 EngineID engine = e->index;
9038 EngineInfo *ei = &e->info;
9039 bool only_defaultcargo;
9040
9041 /* Apply default cargo translation map if cargo type hasn't been set, either explicitly or by aircraft cargo handling. */
9042 if (!IsValidCargoType(e->info.cargo_type)) {
9043 e->info.cargo_type = GetCargoTypeByLabel(GetActiveCargoLabel(e->info.cargo_label));
9044 }
9045
9046 /* If the NewGRF did not set any cargo properties, we apply default values. */
9047 if (_gted[engine].defaultcargo_grf == nullptr) {
9048 /* If the vehicle has any capacity, apply the default refit masks */
9049 if (e->type != VEH_TRAIN || e->u.rail.capacity != 0) {
9050 static constexpr LandscapeType T = LandscapeType::Temperate;
9051 static constexpr LandscapeType A = LandscapeType::Arctic;
9052 static constexpr LandscapeType S = LandscapeType::Tropic;
9053 static constexpr LandscapeType Y = LandscapeType::Toyland;
9054 static const struct DefaultRefitMasks {
9055 LandscapeTypes climate;
9056 CargoLabel cargo_label;
9057 CargoClasses cargo_allowed;
9058 CargoClasses cargo_disallowed;
9059 } _default_refit_masks[] = {
9060 {{T, A, S, Y}, CT_PASSENGERS, CC_PASSENGERS, 0},
9061 {{T, A, S }, CT_MAIL, CC_MAIL, 0},
9062 {{T, A, S }, CT_VALUABLES, CC_ARMOURED, CC_LIQUID},
9063 {{ Y}, CT_MAIL, CC_MAIL | CC_ARMOURED, CC_LIQUID},
9064 {{T, A }, CT_COAL, CC_BULK, 0},
9065 {{ S }, CT_COPPER_ORE, CC_BULK, 0},
9066 {{ Y}, CT_SUGAR, CC_BULK, 0},
9067 {{T, A, S }, CT_OIL, CC_LIQUID, 0},
9068 {{ Y}, CT_COLA, CC_LIQUID, 0},
9069 {{T }, CT_GOODS, CC_PIECE_GOODS | CC_EXPRESS, CC_LIQUID | CC_PASSENGERS},
9071 {{ A, S }, CT_FOOD, CC_REFRIGERATED, 0},
9072 {{ Y}, CT_CANDY, CC_PIECE_GOODS | CC_EXPRESS, CC_LIQUID | CC_PASSENGERS},
9073 };
9074
9075 if (e->type == VEH_AIRCRAFT) {
9076 /* Aircraft default to "light" cargoes */
9077 _gted[engine].cargo_allowed = CC_PASSENGERS | CC_MAIL | CC_ARMOURED | CC_EXPRESS;
9078 _gted[engine].cargo_disallowed = CC_LIQUID;
9079 } else if (e->type == VEH_SHIP) {
9080 CargoLabel label = GetActiveCargoLabel(ei->cargo_label);
9081 switch (label.base()) {
9082 case CT_PASSENGERS.base():
9083 /* Ferries */
9084 _gted[engine].cargo_allowed = CC_PASSENGERS;
9085 _gted[engine].cargo_disallowed = 0;
9086 break;
9087 case CT_OIL.base():
9088 /* Tankers */
9089 _gted[engine].cargo_allowed = CC_LIQUID;
9090 _gted[engine].cargo_disallowed = 0;
9091 break;
9092 default:
9093 /* Cargo ships */
9094 if (_settings_game.game_creation.landscape == LandscapeType::Toyland) {
9095 /* No tanker in toyland :( */
9096 _gted[engine].cargo_allowed = CC_MAIL | CC_ARMOURED | CC_EXPRESS | CC_BULK | CC_PIECE_GOODS | CC_LIQUID;
9097 _gted[engine].cargo_disallowed = CC_PASSENGERS;
9098 } else {
9099 _gted[engine].cargo_allowed = CC_MAIL | CC_ARMOURED | CC_EXPRESS | CC_BULK | CC_PIECE_GOODS;
9100 _gted[engine].cargo_disallowed = CC_LIQUID | CC_PASSENGERS;
9101 }
9102 break;
9103 }
9104 e->u.ship.old_refittable = true;
9105 } else if (e->type == VEH_TRAIN && e->u.rail.railveh_type != RAILVEH_WAGON) {
9106 /* Train engines default to all cargoes, so you can build single-cargo consists with fast engines.
9107 * Trains loading multiple cargoes may start stations accepting unwanted cargoes. */
9109 _gted[engine].cargo_disallowed = 0;
9110 } else {
9111 /* Train wagons and road vehicles are classified by their default cargo type */
9112 CargoLabel label = GetActiveCargoLabel(ei->cargo_label);
9113 for (const auto &drm : _default_refit_masks) {
9114 if (!drm.climate.Test(_settings_game.game_creation.landscape)) continue;
9115 if (drm.cargo_label != label) continue;
9116
9117 _gted[engine].cargo_allowed = drm.cargo_allowed;
9118 _gted[engine].cargo_disallowed = drm.cargo_disallowed;
9119 break;
9120 }
9121
9122 /* All original cargoes have specialised vehicles, so exclude them */
9123 _gted[engine].ctt_exclude_mask = original_known_cargoes;
9124 }
9125 }
9126 _gted[engine].UpdateRefittability(_gted[engine].cargo_allowed != 0);
9127
9128 if (IsValidCargoType(ei->cargo_type)) ClrBit(_gted[engine].ctt_exclude_mask, ei->cargo_type);
9129 }
9130
9131 /* Compute refittability */
9132 {
9133 CargoTypes mask = 0;
9134 CargoTypes not_mask = 0;
9135 CargoTypes xor_mask = ei->refit_mask;
9136
9137 /* If the original masks set by the grf are zero, the vehicle shall only carry the default cargo.
9138 * Note: After applying the translations, the vehicle may end up carrying no defined cargo. It becomes unavailable in that case. */
9139 only_defaultcargo = _gted[engine].refittability != GRFTempEngineData::NONEMPTY;
9140
9141 if (_gted[engine].cargo_allowed != 0) {
9142 /* Build up the list of cargo types from the set cargo classes. */
9143 for (const CargoSpec *cs : CargoSpec::Iterate()) {
9144 if ((_gted[engine].cargo_allowed & cs->classes) != 0 && (_gted[engine].cargo_allowed_required & cs->classes) == _gted[engine].cargo_allowed_required) SetBit(mask, cs->Index());
9145 if (_gted[engine].cargo_disallowed & cs->classes) SetBit(not_mask, cs->Index());
9146 }
9147 }
9148
9149 ei->refit_mask = ((mask & ~not_mask) ^ xor_mask) & _cargo_mask;
9150
9151 /* Apply explicit refit includes/excludes. */
9152 ei->refit_mask |= _gted[engine].ctt_include_mask;
9153 ei->refit_mask &= ~_gted[engine].ctt_exclude_mask;
9154
9155 /* Custom refit mask callback. */
9156 const GRFFile *file = _gted[e->index].defaultcargo_grf;
9157 if (file == nullptr) file = e->GetGRF();
9158 if (file != nullptr && e->info.callback_mask.Test(VehicleCallbackMask::CustomRefit)) {
9159 for (const CargoSpec *cs : CargoSpec::Iterate()) {
9160 uint8_t local_slot = file->cargo_map[cs->Index()];
9161 uint16_t callback = GetVehicleCallback(CBID_VEHICLE_CUSTOM_REFIT, cs->classes, local_slot, engine, nullptr);
9162 switch (callback) {
9163 case CALLBACK_FAILED:
9164 case 0:
9165 break; // Do nothing.
9166 case 1: SetBit(ei->refit_mask, cs->Index()); break;
9167 case 2: ClrBit(ei->refit_mask, cs->Index()); break;
9168
9169 default: ErrorUnknownCallbackResult(file->grfid, CBID_VEHICLE_CUSTOM_REFIT, callback);
9170 }
9171 }
9172 }
9173 }
9174
9175 /* Clear invalid cargoslots (from default vehicles or pre-NewCargo GRFs) */
9176 if (IsValidCargoType(ei->cargo_type) && !HasBit(_cargo_mask, ei->cargo_type)) ei->cargo_type = INVALID_CARGO;
9177
9178 /* Ensure that the vehicle is either not refittable, or that the default cargo is one of the refittable cargoes.
9179 * Note: Vehicles refittable to no cargo are handle differently to vehicle refittable to a single cargo. The latter might have subtypes. */
9180 if (!only_defaultcargo && (e->type != VEH_SHIP || e->u.ship.old_refittable) && IsValidCargoType(ei->cargo_type) && !HasBit(ei->refit_mask, ei->cargo_type)) {
9181 ei->cargo_type = INVALID_CARGO;
9182 }
9183
9184 /* Check if this engine's cargo type is valid. If not, set to the first refittable
9185 * cargo type. Finally disable the vehicle, if there is still no cargo. */
9186 if (!IsValidCargoType(ei->cargo_type) && ei->refit_mask != 0) {
9187 /* Figure out which CTT to use for the default cargo, if it is 'first refittable'. */
9188 const GRFFile *file = _gted[engine].defaultcargo_grf;
9189 if (file == nullptr) file = e->GetGRF();
9190 if (file != nullptr && file->grf_version >= 8 && !file->cargo_list.empty()) {
9191 /* Use first refittable cargo from cargo translation table */
9192 uint8_t best_local_slot = UINT8_MAX;
9193 for (CargoType cargo_type : SetCargoBitIterator(ei->refit_mask)) {
9194 uint8_t local_slot = file->cargo_map[cargo_type];
9195 if (local_slot < best_local_slot) {
9196 best_local_slot = local_slot;
9197 ei->cargo_type = cargo_type;
9198 }
9199 }
9200 }
9201
9202 if (!IsValidCargoType(ei->cargo_type)) {
9203 /* Use first refittable cargo slot */
9204 ei->cargo_type = (CargoType)FindFirstBit(ei->refit_mask);
9205 }
9206 }
9207 if (!IsValidCargoType(ei->cargo_type) && e->type == VEH_TRAIN && e->u.rail.railveh_type != RAILVEH_WAGON && e->u.rail.capacity == 0) {
9208 /* For train engines which do not carry cargo it does not matter if their cargo type is invalid.
9209 * Fallback to the first available instead, if the cargo type has not been changed (as indicated by
9210 * cargo_label not being CT_INVALID). */
9211 if (GetActiveCargoLabel(ei->cargo_label) != CT_INVALID) {
9212 ei->cargo_type = static_cast<CargoType>(FindFirstBit(_standard_cargo_mask));
9213 }
9214 }
9215 if (!IsValidCargoType(ei->cargo_type)) ei->climates = {};
9216
9217 /* Clear refit_mask for not refittable ships */
9218 if (e->type == VEH_SHIP && !e->u.ship.old_refittable) {
9219 ei->refit_mask = 0;
9220 }
9221 }
9222}
9223
9225static void FinaliseCanals()
9226{
9227 for (uint i = 0; i < CF_END; i++) {
9228 if (_water_feature[i].grffile != nullptr) {
9229 _water_feature[i].callback_mask = _water_feature[i].grffile->canal_local_properties[i].callback_mask;
9230 _water_feature[i].flags = _water_feature[i].grffile->canal_local_properties[i].flags;
9231 }
9232 }
9233}
9234
9237{
9238 for (Engine *e : Engine::Iterate()) {
9239 if (e->GetGRF() == nullptr) {
9240 auto found = std::ranges::find(_engine_mngr.mappings[e->type], e->index, &EngineIDMapping::engine);
9241 if (found == std::end(_engine_mngr.mappings[e->type]) || found->grfid != INVALID_GRFID || found->internal_id != found->substitute_id) {
9242 e->info.string_id = STR_NEWGRF_INVALID_ENGINE;
9243 }
9244 }
9245
9246 /* Do final mapping on variant engine ID. */
9247 if (e->info.variant_id != INVALID_ENGINE) {
9248 e->info.variant_id = GetNewEngineID(e->grf_prop.grffile, e->type, e->info.variant_id);
9249 }
9250
9251 if (!e->info.climates.Test(_settings_game.game_creation.landscape)) continue;
9252
9253 /* Skip wagons, there livery is defined via the engine */
9254 if (e->type != VEH_TRAIN || e->u.rail.railveh_type != RAILVEH_WAGON) {
9257 /* Note: For ships and roadvehicles we assume that they cannot be refitted between passenger and freight */
9258
9259 if (e->type == VEH_TRAIN) {
9260 SetBit(_loaded_newgrf_features.used_liveries, LS_FREIGHT_WAGON);
9261 switch (ls) {
9262 case LS_STEAM:
9263 case LS_DIESEL:
9264 case LS_ELECTRIC:
9265 case LS_MONORAIL:
9266 case LS_MAGLEV:
9267 SetBit(_loaded_newgrf_features.used_liveries, LS_PASSENGER_WAGON_STEAM + ls - LS_STEAM);
9268 break;
9269
9270 case LS_DMU:
9271 case LS_EMU:
9272 SetBit(_loaded_newgrf_features.used_liveries, LS_PASSENGER_WAGON_DIESEL + ls - LS_DMU);
9273 break;
9274
9275 default: NOT_REACHED();
9276 }
9277 }
9278 }
9279 }
9280
9281 /* Check engine variants don't point back on themselves (either directly or via a loop) then set appropriate flags
9282 * on variant engine. This is performed separately as all variant engines need to have been resolved. */
9283 for (Engine *e : Engine::Iterate()) {
9284 EngineID parent = e->info.variant_id;
9285 while (parent != INVALID_ENGINE) {
9286 parent = Engine::Get(parent)->info.variant_id;
9287 if (parent != e->index) continue;
9288
9289 /* Engine looped back on itself, so clear the variant. */
9290 e->info.variant_id = INVALID_ENGINE;
9291
9292 GrfMsg(1, "FinaliseEngineArray: Variant of engine {:x} in '{}' loops back on itself", e->grf_prop.local_id, e->GetGRF()->filename);
9293 break;
9294 }
9295
9296 if (e->info.variant_id != INVALID_ENGINE) {
9298 }
9299 }
9300}
9301
9304{
9305 for (CargoSpec &cs : CargoSpec::array) {
9306 if (cs.town_production_effect == INVALID_TPE) {
9307 /* Set default town production effect by cargo label. */
9308 switch (cs.label.base()) {
9309 case CT_PASSENGERS.base(): cs.town_production_effect = TPE_PASSENGERS; break;
9310 case CT_MAIL.base(): cs.town_production_effect = TPE_MAIL; break;
9311 default: cs.town_production_effect = TPE_NONE; break;
9312 }
9313 }
9314 if (!cs.IsValid()) {
9315 cs.name = cs.name_single = cs.units_volume = STR_NEWGRF_INVALID_CARGO;
9316 cs.quantifier = STR_NEWGRF_INVALID_CARGO_QUANTITY;
9317 cs.abbrev = STR_NEWGRF_INVALID_CARGO_ABBREV;
9318 }
9319 }
9320}
9321
9333static bool IsHouseSpecValid(HouseSpec *hs, const HouseSpec *next1, const HouseSpec *next2, const HouseSpec *next3, const std::string &filename)
9334{
9335 if ((hs->building_flags.Any(BUILDING_HAS_2_TILES) &&
9336 (next1 == nullptr || !next1->enabled || next1->building_flags.Any(BUILDING_HAS_1_TILE))) ||
9337 (hs->building_flags.Any(BUILDING_HAS_4_TILES) &&
9338 (next2 == nullptr || !next2->enabled || next2->building_flags.Any(BUILDING_HAS_1_TILE) ||
9339 next3 == nullptr || !next3->enabled || next3->building_flags.Any(BUILDING_HAS_1_TILE)))) {
9340 hs->enabled = false;
9341 if (!filename.empty()) Debug(grf, 1, "FinaliseHouseArray: {} defines house {} as multitile, but no suitable tiles follow. Disabling house.", filename, hs->grf_prop.local_id);
9342 return false;
9343 }
9344
9345 /* Some places sum population by only counting north tiles. Other places use all tiles causing desyncs.
9346 * As the newgrf specs define population to be zero for non-north tiles, we just disable the offending house.
9347 * If you want to allow non-zero populations somewhen, make sure to sum the population of all tiles in all places. */
9348 if ((hs->building_flags.Any(BUILDING_HAS_2_TILES) && next1->population != 0) ||
9349 (hs->building_flags.Any(BUILDING_HAS_4_TILES) && (next2->population != 0 || next3->population != 0))) {
9350 hs->enabled = false;
9351 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);
9352 return false;
9353 }
9354
9355 /* Substitute type is also used for override, and having an override with a different size causes crashes.
9356 * This check should only be done for NewGRF houses because grf_prop.subst_id is not set for original houses.*/
9357 if (!filename.empty() && (hs->building_flags & BUILDING_HAS_1_TILE) != (HouseSpec::Get(hs->grf_prop.subst_id)->building_flags & BUILDING_HAS_1_TILE)) {
9358 hs->enabled = false;
9359 Debug(grf, 1, "FinaliseHouseArray: {} defines house {} with different house size then it's substitute type. Disabling house.", filename, hs->grf_prop.local_id);
9360 return false;
9361 }
9362
9363 /* Make sure that additional parts of multitile houses are not available. */
9364 if (!hs->building_flags.Any(BUILDING_HAS_1_TILE) && (hs->building_availability & HZ_ZONALL) != 0 && (hs->building_availability & HZ_CLIMALL) != 0) {
9365 hs->enabled = false;
9366 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);
9367 return false;
9368 }
9369
9370 return true;
9371}
9372
9379static void EnsureEarlyHouse(HouseZones bitmask)
9380{
9382
9383 for (const auto &hs : HouseSpec::Specs()) {
9384 if (!hs.enabled) continue;
9385 if ((hs.building_availability & bitmask) != bitmask) continue;
9386 if (hs.min_year < min_year) min_year = hs.min_year;
9387 }
9388
9389 if (min_year == 0) return;
9390
9391 for (auto &hs : HouseSpec::Specs()) {
9392 if (!hs.enabled) continue;
9393 if ((hs.building_availability & bitmask) != bitmask) continue;
9394 if (hs.min_year == min_year) hs.min_year = CalendarTime::MIN_YEAR;
9395 }
9396}
9397
9405{
9406 /* If there are no houses with start dates before 1930, then all houses
9407 * with start dates of 1930 have them reset to 0. This is in order to be
9408 * compatible with TTDPatch, where if no houses have start dates before
9409 * 1930 and the date is before 1930, the game pretends that this is 1930.
9410 * If there have been any houses defined with start dates before 1930 then
9411 * the dates are left alone.
9412 * On the other hand, why 1930? Just 'fix' the houses with the lowest
9413 * minimum introduction date to 0.
9414 */
9415 for (GRFFile * const file : _grf_files) {
9416 if (file->housespec.empty()) continue;
9417
9418 size_t num_houses = file->housespec.size();
9419 for (size_t i = 0; i < num_houses; i++) {
9420 HouseSpec *hs = file->housespec[i].get();
9421
9422 if (hs == nullptr) continue;
9423
9424 const HouseSpec *next1 = (i + 1 < num_houses ? file->housespec[i + 1].get() : nullptr);
9425 const HouseSpec *next2 = (i + 2 < num_houses ? file->housespec[i + 2].get() : nullptr);
9426 const HouseSpec *next3 = (i + 3 < num_houses ? file->housespec[i + 3].get() : nullptr);
9427
9428 if (!IsHouseSpecValid(hs, next1, next2, next3, file->filename)) continue;
9429
9430 _house_mngr.SetEntitySpec(hs);
9431 }
9432 }
9433
9434 for (size_t i = 0; i < HouseSpec::Specs().size(); i++) {
9435 HouseSpec *hs = HouseSpec::Get(i);
9436 const HouseSpec *next1 = (i + 1 < NUM_HOUSES ? HouseSpec::Get(i + 1) : nullptr);
9437 const HouseSpec *next2 = (i + 2 < NUM_HOUSES ? HouseSpec::Get(i + 2) : nullptr);
9438 const HouseSpec *next3 = (i + 3 < NUM_HOUSES ? HouseSpec::Get(i + 3) : nullptr);
9439
9440 /* We need to check all houses again to we are sure that multitile houses
9441 * did get consecutive IDs and none of the parts are missing. */
9442 if (!IsHouseSpecValid(hs, next1, next2, next3, std::string{})) {
9443 /* GetHouseNorthPart checks 3 houses that are directly before
9444 * it in the house pool. If any of those houses have multi-tile
9445 * flags set it assumes it's part of a multitile house. Since
9446 * we can have invalid houses in the pool marked as disabled, we
9447 * don't want to have them influencing valid tiles. As such set
9448 * building_flags to zero here to make sure any house following
9449 * this one in the pool is properly handled as 1x1 house. */
9450 hs->building_flags = {};
9451 }
9452
9453 /* Apply default cargo translation map for unset cargo slots */
9454 for (uint i = 0; i < lengthof(hs->accepts_cargo_label); ++i) {
9455 if (!IsValidCargoType(hs->accepts_cargo[i])) hs->accepts_cargo[i] = GetCargoTypeByLabel(hs->accepts_cargo_label[i]);
9456 /* Disable acceptance if cargo type is invalid. */
9457 if (!IsValidCargoType(hs->accepts_cargo[i])) hs->cargo_acceptance[i] = 0;
9458 }
9459 }
9460
9462 EnsureEarlyHouse(HZ_ZON1 | climate_mask);
9463 EnsureEarlyHouse(HZ_ZON2 | climate_mask);
9464 EnsureEarlyHouse(HZ_ZON3 | climate_mask);
9465 EnsureEarlyHouse(HZ_ZON4 | climate_mask);
9466 EnsureEarlyHouse(HZ_ZON5 | climate_mask);
9467
9468 if (_settings_game.game_creation.landscape == LandscapeType::Arctic) {
9474 }
9475}
9476
9483{
9484 for (GRFFile * const file : _grf_files) {
9485 for (const auto &indsp : file->industryspec) {
9486 if (indsp == nullptr || !indsp->enabled) continue;
9487
9488 _industry_mngr.SetEntitySpec(indsp.get());
9489 }
9490
9491 for (const auto &indtsp : file->indtspec) {
9492 if (indtsp != nullptr) {
9493 _industile_mngr.SetEntitySpec(indtsp.get());
9494 }
9495 }
9496 }
9497
9498 for (auto &indsp : _industry_specs) {
9499 if (indsp.enabled && indsp.grf_prop.HasGrfFile()) {
9500 for (auto &conflicting : indsp.conflicting) {
9501 conflicting = MapNewGRFIndustryType(conflicting, indsp.grf_prop.grfid);
9502 }
9503 }
9504 if (!indsp.enabled) {
9505 indsp.name = STR_NEWGRF_INVALID_INDUSTRYTYPE;
9506 }
9507
9508 /* Apply default cargo translation map for unset cargo slots */
9509 for (size_t i = 0; i < std::size(indsp.produced_cargo_label); ++i) {
9510 if (!IsValidCargoType(indsp.produced_cargo[i])) indsp.produced_cargo[i] = GetCargoTypeByLabel(GetActiveCargoLabel(indsp.produced_cargo_label[i]));
9511 }
9512 for (size_t i = 0; i < std::size(indsp.accepts_cargo_label); ++i) {
9513 if (!IsValidCargoType(indsp.accepts_cargo[i])) indsp.accepts_cargo[i] = GetCargoTypeByLabel(GetActiveCargoLabel(indsp.accepts_cargo_label[i]));
9514 }
9515 }
9516
9517 for (auto &indtsp : _industry_tile_specs) {
9518 /* Apply default cargo translation map for unset cargo slots */
9519 for (size_t i = 0; i < std::size(indtsp.accepts_cargo_label); ++i) {
9520 if (!IsValidCargoType(indtsp.accepts_cargo[i])) indtsp.accepts_cargo[i] = GetCargoTypeByLabel(GetActiveCargoLabel(indtsp.accepts_cargo_label[i]));
9521 }
9522 }
9523}
9524
9531{
9532 for (GRFFile * const file : _grf_files) {
9533 for (auto &objectspec : file->objectspec) {
9534 if (objectspec != nullptr && objectspec->grf_prop.HasGrfFile() && objectspec->IsEnabled()) {
9535 _object_mngr.SetEntitySpec(objectspec.get());
9536 }
9537 }
9538 }
9539
9541}
9542
9549{
9550 for (GRFFile * const file : _grf_files) {
9551 for (auto &as : file->airportspec) {
9552 if (as != nullptr && as->enabled) {
9553 _airport_mngr.SetEntitySpec(as.get());
9554 }
9555 }
9556
9557 for (auto &ats : file->airtspec) {
9558 if (ats != nullptr && ats->enabled) {
9559 _airporttile_mngr.SetEntitySpec(ats.get());
9560 }
9561 }
9562 }
9563}
9564
9565/* Here we perform initial decoding of some special sprites (as are they
9566 * described at http://www.ttdpatch.net/src/newgrf.txt, but this is only a very
9567 * partial implementation yet).
9568 * XXX: We consider GRF files trusted. It would be trivial to exploit OTTD by
9569 * a crafted invalid GRF file. We should tell that to the user somehow, or
9570 * better make this more robust in the future. */
9571static void DecodeSpecialSprite(uint8_t *buf, uint num, GrfLoadingStage stage)
9572{
9573 /* XXX: There is a difference between staged loading in TTDPatch and
9574 * here. In TTDPatch, for some reason actions 1 and 2 are carried out
9575 * during stage 1, whilst action 3 is carried out during stage 2 (to
9576 * "resolve" cargo IDs... wtf). This is a little problem, because cargo
9577 * IDs are valid only within a given set (action 1) block, and may be
9578 * overwritten after action 3 associates them. But overwriting happens
9579 * in an earlier stage than associating, so... We just process actions
9580 * 1 and 2 in stage 2 now, let's hope that won't get us into problems.
9581 * --pasky
9582 * We need a pre-stage to set up GOTO labels of Action 0x10 because the grf
9583 * is not in memory and scanning the file every time would be too expensive.
9584 * In other stages we skip action 0x10 since it's already dealt with. */
9585 static const SpecialSpriteHandler handlers[][GLS_END] = {
9586 /* 0x00 */ { nullptr, SafeChangeInfo, nullptr, nullptr, ReserveChangeInfo, FeatureChangeInfo, },
9587 /* 0x01 */ { SkipAct1, SkipAct1, SkipAct1, SkipAct1, SkipAct1, NewSpriteSet, },
9588 /* 0x02 */ { nullptr, nullptr, nullptr, nullptr, nullptr, NewSpriteGroup, },
9589 /* 0x03 */ { nullptr, GRFUnsafe, nullptr, nullptr, nullptr, FeatureMapSpriteGroup, },
9590 /* 0x04 */ { nullptr, nullptr, nullptr, nullptr, nullptr, FeatureNewName, },
9591 /* 0x05 */ { SkipAct5, SkipAct5, SkipAct5, SkipAct5, SkipAct5, GraphicsNew, },
9592 /* 0x06 */ { nullptr, nullptr, nullptr, CfgApply, CfgApply, CfgApply, },
9593 /* 0x07 */ { nullptr, nullptr, nullptr, nullptr, SkipIf, SkipIf, },
9594 /* 0x08 */ { ScanInfo, nullptr, nullptr, GRFInfo, GRFInfo, GRFInfo, },
9595 /* 0x09 */ { nullptr, nullptr, nullptr, SkipIf, SkipIf, SkipIf, },
9596 /* 0x0A */ { SkipActA, SkipActA, SkipActA, SkipActA, SkipActA, SpriteReplace, },
9597 /* 0x0B */ { nullptr, nullptr, nullptr, GRFLoadError, GRFLoadError, GRFLoadError, },
9598 /* 0x0C */ { nullptr, nullptr, nullptr, GRFComment, nullptr, GRFComment, },
9599 /* 0x0D */ { nullptr, SafeParamSet, nullptr, ParamSet, ParamSet, ParamSet, },
9600 /* 0x0E */ { nullptr, SafeGRFInhibit, nullptr, GRFInhibit, GRFInhibit, GRFInhibit, },
9601 /* 0x0F */ { nullptr, GRFUnsafe, nullptr, FeatureTownName, nullptr, nullptr, },
9602 /* 0x10 */ { nullptr, nullptr, DefineGotoLabel, nullptr, nullptr, nullptr, },
9603 /* 0x11 */ { SkipAct11, GRFUnsafe, SkipAct11, GRFSound, SkipAct11, GRFSound, },
9605 /* 0x13 */ { nullptr, nullptr, nullptr, nullptr, nullptr, TranslateGRFStrings, },
9606 /* 0x14 */ { StaticGRFInfo, nullptr, nullptr, nullptr, nullptr, nullptr, },
9607 };
9608
9609 GRFLocation location(_cur.grfconfig->ident.grfid, _cur.nfo_line);
9610
9611 GRFLineToSpriteOverride::iterator it = _grf_line_to_action6_sprite_override.find(location);
9612 if (it == _grf_line_to_action6_sprite_override.end()) {
9613 /* No preloaded sprite to work with; read the
9614 * pseudo sprite content. */
9615 _cur.file->ReadBlock(buf, num);
9616 } else {
9617 /* Use the preloaded sprite data. */
9618 buf = _grf_line_to_action6_sprite_override[location].data();
9619 GrfMsg(7, "DecodeSpecialSprite: Using preloaded pseudo sprite data");
9620
9621 /* Skip the real (original) content of this action. */
9622 _cur.file->SeekTo(num, SEEK_CUR);
9623 }
9624
9625 ByteReader br(buf, buf + num);
9626
9627 try {
9628 uint8_t action = br.ReadByte();
9629
9630 if (action == 0xFF) {
9631 GrfMsg(2, "DecodeSpecialSprite: Unexpected data block, skipping");
9632 } else if (action == 0xFE) {
9633 GrfMsg(2, "DecodeSpecialSprite: Unexpected import block, skipping");
9634 } else if (action >= lengthof(handlers)) {
9635 GrfMsg(7, "DecodeSpecialSprite: Skipping unknown action 0x{:02X}", action);
9636 } else if (handlers[action][stage] == nullptr) {
9637 GrfMsg(7, "DecodeSpecialSprite: Skipping action 0x{:02X} in stage {}", action, stage);
9638 } else {
9639 GrfMsg(7, "DecodeSpecialSprite: Handling action 0x{:02X} in stage {}", action, stage);
9640 handlers[action][stage](br);
9641 }
9642 } catch (...) {
9643 GrfMsg(1, "DecodeSpecialSprite: Tried to read past end of pseudo-sprite data");
9644 DisableGrf(STR_NEWGRF_ERROR_READ_BOUNDS);
9645 }
9646}
9647
9654static void LoadNewGRFFileFromFile(GRFConfig &config, GrfLoadingStage stage, SpriteFile &file)
9655{
9656 _cur.file = &file;
9657 _cur.grfconfig = &config;
9658
9659 Debug(grf, 2, "LoadNewGRFFile: Reading NewGRF-file '{}'", config.filename);
9660
9661 uint8_t grf_container_version = file.GetContainerVersion();
9662 if (grf_container_version == 0) {
9663 Debug(grf, 7, "LoadNewGRFFile: Custom .grf has invalid format");
9664 return;
9665 }
9666
9667 if (stage == GLS_INIT || stage == GLS_ACTIVATION) {
9668 /* We need the sprite offsets in the init stage for NewGRF sounds
9669 * and in the activation stage for real sprites. */
9671 } else {
9672 /* Skip sprite section offset if present. */
9673 if (grf_container_version >= 2) file.ReadDword();
9674 }
9675
9676 if (grf_container_version >= 2) {
9677 /* Read compression value. */
9678 uint8_t compression = file.ReadByte();
9679 if (compression != 0) {
9680 Debug(grf, 7, "LoadNewGRFFile: Unsupported compression format");
9681 return;
9682 }
9683 }
9684
9685 /* Skip the first sprite; we don't care about how many sprites this
9686 * does contain; newest TTDPatches and George's longvehicles don't
9687 * neither, apparently. */
9688 uint32_t num = grf_container_version >= 2 ? file.ReadDword() : file.ReadWord();
9689 if (num == 4 && file.ReadByte() == 0xFF) {
9690 file.ReadDword();
9691 } else {
9692 Debug(grf, 7, "LoadNewGRFFile: Custom .grf has invalid format");
9693 return;
9694 }
9695
9696 _cur.ClearDataForNextFile();
9697
9699
9700 while ((num = (grf_container_version >= 2 ? file.ReadDword() : file.ReadWord())) != 0) {
9701 uint8_t type = file.ReadByte();
9702 _cur.nfo_line++;
9703
9704 if (type == 0xFF) {
9705 if (_cur.skip_sprites == 0) {
9706 DecodeSpecialSprite(buf.Allocate(num), num, stage);
9707
9708 /* Stop all processing if we are to skip the remaining sprites */
9709 if (_cur.skip_sprites == -1) break;
9710
9711 continue;
9712 } else {
9713 file.SkipBytes(num);
9714 }
9715 } else {
9716 if (_cur.skip_sprites == 0) {
9717 GrfMsg(0, "LoadNewGRFFile: Unexpected sprite, disabling");
9718 DisableGrf(STR_NEWGRF_ERROR_UNEXPECTED_SPRITE);
9719 break;
9720 }
9721
9722 if (grf_container_version >= 2 && type == 0xFD) {
9723 /* Reference to data section. Container version >= 2 only. */
9724 file.SkipBytes(num);
9725 } else {
9726 file.SkipBytes(7);
9727 SkipSpriteData(file, type, num - 8);
9728 }
9729 }
9730
9731 if (_cur.skip_sprites > 0) _cur.skip_sprites--;
9732 }
9733}
9734
9743void LoadNewGRFFile(GRFConfig &config, GrfLoadingStage stage, Subdirectory subdir, bool temporary)
9744{
9745 const std::string &filename = config.filename;
9746
9747 /* A .grf file is activated only if it was active when the game was
9748 * started. If a game is loaded, only its active .grfs will be
9749 * reactivated, unless "loadallgraphics on" is used. A .grf file is
9750 * considered active if its action 8 has been processed, i.e. its
9751 * action 8 hasn't been skipped using an action 7.
9752 *
9753 * During activation, only actions 0, 1, 2, 3, 4, 5, 7, 8, 9, 0A and 0B are
9754 * carried out. All others are ignored, because they only need to be
9755 * processed once at initialization. */
9756 if (stage != GLS_FILESCAN && stage != GLS_SAFETYSCAN && stage != GLS_LABELSCAN) {
9757 _cur.grffile = GetFileByFilename(filename);
9758 if (_cur.grffile == nullptr) UserError("File '{}' lost in cache.\n", filename);
9759 if (stage == GLS_RESERVE && config.status != GCS_INITIALISED) return;
9760 if (stage == GLS_ACTIVATION && !config.flags.Test(GRFConfigFlag::Reserved)) return;
9761 }
9762
9763 bool needs_palette_remap = config.palette & GRFP_USE_MASK;
9764 if (temporary) {
9765 SpriteFile temporarySpriteFile(filename, subdir, needs_palette_remap);
9766 LoadNewGRFFileFromFile(config, stage, temporarySpriteFile);
9767 } else {
9768 LoadNewGRFFileFromFile(config, stage, OpenCachedSpriteFile(filename, subdir, needs_palette_remap));
9769 }
9770}
9771
9779static void ActivateOldShore()
9780{
9781 /* Use default graphics, if no shore sprites were loaded.
9782 * Should not happen, as the base set's extra grf should include some. */
9784
9786 DupSprite(SPR_ORIGINALSHORE_START + 1, SPR_SHORE_BASE + 1); // SLOPE_W
9787 DupSprite(SPR_ORIGINALSHORE_START + 2, SPR_SHORE_BASE + 2); // SLOPE_S
9788 DupSprite(SPR_ORIGINALSHORE_START + 6, SPR_SHORE_BASE + 3); // SLOPE_SW
9789 DupSprite(SPR_ORIGINALSHORE_START + 0, SPR_SHORE_BASE + 4); // SLOPE_E
9790 DupSprite(SPR_ORIGINALSHORE_START + 4, SPR_SHORE_BASE + 6); // SLOPE_SE
9791 DupSprite(SPR_ORIGINALSHORE_START + 3, SPR_SHORE_BASE + 8); // SLOPE_N
9792 DupSprite(SPR_ORIGINALSHORE_START + 7, SPR_SHORE_BASE + 9); // SLOPE_NW
9793 DupSprite(SPR_ORIGINALSHORE_START + 5, SPR_SHORE_BASE + 12); // SLOPE_NE
9794 }
9795
9797 DupSprite(SPR_FLAT_GRASS_TILE + 16, SPR_SHORE_BASE + 0); // SLOPE_STEEP_S
9798 DupSprite(SPR_FLAT_GRASS_TILE + 17, SPR_SHORE_BASE + 5); // SLOPE_STEEP_W
9799 DupSprite(SPR_FLAT_GRASS_TILE + 7, SPR_SHORE_BASE + 7); // SLOPE_WSE
9800 DupSprite(SPR_FLAT_GRASS_TILE + 15, SPR_SHORE_BASE + 10); // SLOPE_STEEP_N
9801 DupSprite(SPR_FLAT_GRASS_TILE + 11, SPR_SHORE_BASE + 11); // SLOPE_NWS
9802 DupSprite(SPR_FLAT_GRASS_TILE + 13, SPR_SHORE_BASE + 13); // SLOPE_ENW
9803 DupSprite(SPR_FLAT_GRASS_TILE + 14, SPR_SHORE_BASE + 14); // SLOPE_SEN
9804 DupSprite(SPR_FLAT_GRASS_TILE + 18, SPR_SHORE_BASE + 15); // SLOPE_STEEP_E
9805
9806 /* XXX - SLOPE_EW, SLOPE_NS are currently not used.
9807 * If they would be used somewhen, then these grass tiles will most like not look as needed */
9808 DupSprite(SPR_FLAT_GRASS_TILE + 5, SPR_SHORE_BASE + 16); // SLOPE_EW
9809 DupSprite(SPR_FLAT_GRASS_TILE + 10, SPR_SHORE_BASE + 17); // SLOPE_NS
9810 }
9811}
9812
9817{
9819 DupSprite(SPR_ROAD_DEPOT + 0, SPR_TRAMWAY_DEPOT_NO_TRACK + 0); // use road depot graphics for "no tracks"
9820 DupSprite(SPR_TRAMWAY_DEPOT_WITH_TRACK + 1, SPR_TRAMWAY_DEPOT_NO_TRACK + 1);
9821 DupSprite(SPR_ROAD_DEPOT + 2, SPR_TRAMWAY_DEPOT_NO_TRACK + 2); // use road depot graphics for "no tracks"
9822 DupSprite(SPR_TRAMWAY_DEPOT_WITH_TRACK + 3, SPR_TRAMWAY_DEPOT_NO_TRACK + 3);
9823 DupSprite(SPR_TRAMWAY_DEPOT_WITH_TRACK + 4, SPR_TRAMWAY_DEPOT_NO_TRACK + 4);
9824 DupSprite(SPR_TRAMWAY_DEPOT_WITH_TRACK + 5, SPR_TRAMWAY_DEPOT_NO_TRACK + 5);
9825 }
9826}
9827
9832{
9833 extern const PriceBaseSpec _price_base_specs[];
9835 static const uint32_t override_features = (1 << GSF_TRAINS) | (1 << GSF_ROADVEHICLES) | (1 << GSF_SHIPS) | (1 << GSF_AIRCRAFT);
9836
9837 /* Evaluate grf overrides */
9838 int num_grfs = (uint)_grf_files.size();
9839 std::vector<int> grf_overrides(num_grfs, -1);
9840 for (int i = 0; i < num_grfs; i++) {
9841 GRFFile *source = _grf_files[i];
9842 auto it = _grf_id_overrides.find(source->grfid);
9843 if (it == std::end(_grf_id_overrides)) continue;
9844 uint32_t override = it->second;
9845
9846 GRFFile *dest = GetFileByGRFID(override);
9847 if (dest == nullptr) continue;
9848
9849 grf_overrides[i] = find_index(_grf_files, dest);
9850 assert(grf_overrides[i] >= 0);
9851 }
9852
9853 /* Override features and price base multipliers of earlier loaded grfs */
9854 for (int i = 0; i < num_grfs; i++) {
9855 if (grf_overrides[i] < 0 || grf_overrides[i] >= i) continue;
9856 GRFFile *source = _grf_files[i];
9857 GRFFile *dest = _grf_files[grf_overrides[i]];
9858
9859 uint32_t features = (source->grf_features | dest->grf_features) & override_features;
9860 source->grf_features |= features;
9861 dest->grf_features |= features;
9862
9863 for (Price p = PR_BEGIN; p < PR_END; p++) {
9864 /* No price defined -> nothing to do */
9865 if (!HasBit(features, _price_base_specs[p].grf_feature) || source->price_base_multipliers[p] == INVALID_PRICE_MODIFIER) continue;
9866 Debug(grf, 3, "'{}' overrides price base multiplier {} of '{}'", source->filename, p, dest->filename);
9867 dest->price_base_multipliers[p] = source->price_base_multipliers[p];
9868 }
9869 }
9870
9871 /* Propagate features and price base multipliers of afterwards loaded grfs, if none is present yet */
9872 for (int i = num_grfs - 1; i >= 0; i--) {
9873 if (grf_overrides[i] < 0 || grf_overrides[i] <= i) continue;
9874 GRFFile *source = _grf_files[i];
9875 GRFFile *dest = _grf_files[grf_overrides[i]];
9876
9877 uint32_t features = (source->grf_features | dest->grf_features) & override_features;
9878 source->grf_features |= features;
9879 dest->grf_features |= features;
9880
9881 for (Price p = PR_BEGIN; p < PR_END; p++) {
9882 /* Already a price defined -> nothing to do */
9883 if (!HasBit(features, _price_base_specs[p].grf_feature) || dest->price_base_multipliers[p] != INVALID_PRICE_MODIFIER) continue;
9884 Debug(grf, 3, "Price base multiplier {} from '{}' propagated to '{}'", p, source->filename, dest->filename);
9885 dest->price_base_multipliers[p] = source->price_base_multipliers[p];
9886 }
9887 }
9888
9889 /* The 'master grf' now have the correct multipliers. Assign them to the 'addon grfs' to make everything consistent. */
9890 for (int i = 0; i < num_grfs; i++) {
9891 if (grf_overrides[i] < 0) continue;
9892 GRFFile *source = _grf_files[i];
9893 GRFFile *dest = _grf_files[grf_overrides[i]];
9894
9895 uint32_t features = (source->grf_features | dest->grf_features) & override_features;
9896 source->grf_features |= features;
9897 dest->grf_features |= features;
9898
9899 for (Price p = PR_BEGIN; p < PR_END; p++) {
9900 if (!HasBit(features, _price_base_specs[p].grf_feature)) continue;
9901 if (source->price_base_multipliers[p] != dest->price_base_multipliers[p]) {
9902 Debug(grf, 3, "Price base multiplier {} from '{}' propagated to '{}'", p, dest->filename, source->filename);
9903 }
9904 source->price_base_multipliers[p] = dest->price_base_multipliers[p];
9905 }
9906 }
9907
9908 /* Apply fallback prices for grf version < 8 */
9909 for (GRFFile * const file : _grf_files) {
9910 if (file->grf_version >= 8) continue;
9911 PriceMultipliers &price_base_multipliers = file->price_base_multipliers;
9912 for (Price p = PR_BEGIN; p < PR_END; p++) {
9913 Price fallback_price = _price_base_specs[p].fallback_price;
9914 if (fallback_price != INVALID_PRICE && price_base_multipliers[p] == INVALID_PRICE_MODIFIER) {
9915 /* No price multiplier has been set.
9916 * So copy the multiplier from the fallback price, maybe a multiplier was set there. */
9917 price_base_multipliers[p] = price_base_multipliers[fallback_price];
9918 }
9919 }
9920 }
9921
9922 /* Decide local/global scope of price base multipliers */
9923 for (GRFFile * const file : _grf_files) {
9924 PriceMultipliers &price_base_multipliers = file->price_base_multipliers;
9925 for (Price p = PR_BEGIN; p < PR_END; p++) {
9926 if (price_base_multipliers[p] == INVALID_PRICE_MODIFIER) {
9927 /* No multiplier was set; set it to a neutral value */
9928 price_base_multipliers[p] = 0;
9929 } else {
9930 if (!HasBit(file->grf_features, _price_base_specs[p].grf_feature)) {
9931 /* The grf does not define any objects of the feature,
9932 * so it must be a difficulty setting. Apply it globally */
9933 Debug(grf, 3, "'{}' sets global price base multiplier {}", file->filename, p);
9934 SetPriceBaseMultiplier(p, price_base_multipliers[p]);
9935 price_base_multipliers[p] = 0;
9936 } else {
9937 Debug(grf, 3, "'{}' sets local price base multiplier {}", file->filename, p);
9938 }
9939 }
9940 }
9941 }
9942}
9943
9944extern void InitGRFTownGeneratorNames();
9945
9947static void AfterLoadGRFs()
9948{
9949 /* Cached callback groups are no longer needed. */
9951 _cached_callback_groups.shrink_to_fit();
9952
9954 it.func(MapGRFStringID(it.grfid, it.source));
9955 }
9956 _string_to_grf_mapping.clear();
9957
9958 /* Clear the action 6 override sprites. */
9959 _grf_line_to_action6_sprite_override.clear();
9960
9961 /* Polish cargoes */
9963
9964 /* Pre-calculate all refit masks after loading GRF files. */
9966
9967 /* Polish engines */
9969
9970 /* Set the actually used Canal properties */
9972
9973 /* Add all new houses to the house array. */
9975
9976 /* Add all new industries to the industry array. */
9978
9979 /* Add all new objects to the object array. */
9981
9983
9984 /* Sort the list of industry types. */
9986
9987 /* Create dynamic list of industry legends for smallmap_gui.cpp */
9989
9990 /* Build the routemap legend, based on the available cargos */
9992
9993 /* Add all new airports to the airports array. */
9996
9997 /* Update the townname generators list */
9999
10000 /* Run all queued vehicle list order changes */
10002
10003 /* Load old shore sprites in new position, if they were replaced by ActionA */
10005
10006 /* Load old tram depot sprites in new position, if no new ones are present */
10008
10009 /* Set up custom rail types */
10010 InitRailTypes();
10011 InitRoadTypes();
10012
10013 for (Engine *e : Engine::IterateType(VEH_ROAD)) {
10014 if (_gted[e->index].rv_max_speed != 0) {
10015 /* Set RV maximum speed from the mph/0.8 unit value */
10016 e->u.road.max_speed = _gted[e->index].rv_max_speed * 4;
10017 }
10018
10019 RoadTramType rtt = e->info.misc_flags.Test(EngineMiscFlag::RoadIsTram) ? RTT_TRAM : RTT_ROAD;
10020
10021 const GRFFile *file = e->GetGRF();
10022 if (file == nullptr || _gted[e->index].roadtramtype == 0) {
10023 e->u.road.roadtype = (rtt == RTT_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD;
10024 continue;
10025 }
10026
10027 /* Remove +1 offset. */
10028 _gted[e->index].roadtramtype--;
10029
10030 const std::vector<RoadTypeLabel> *list = (rtt == RTT_TRAM) ? &file->tramtype_list : &file->roadtype_list;
10031 if (_gted[e->index].roadtramtype < list->size())
10032 {
10033 RoadTypeLabel rtl = (*list)[_gted[e->index].roadtramtype];
10034 RoadType rt = GetRoadTypeByLabel(rtl);
10035 if (rt != INVALID_ROADTYPE && GetRoadTramType(rt) == rtt) {
10036 e->u.road.roadtype = rt;
10037 continue;
10038 }
10039 }
10040
10041 /* Road type is not available, so disable this engine */
10042 e->info.climates = {};
10043 }
10044
10046 RailType railtype = GetRailTypeByLabel(_gted[e->index].railtypelabel);
10047 if (railtype == INVALID_RAILTYPE) {
10048 /* Rail type is not available, so disable this engine */
10049 e->info.climates = {};
10050 } else {
10051 e->u.rail.railtype = railtype;
10052 e->u.rail.intended_railtype = railtype;
10053 }
10054 }
10055
10057
10059
10060 /* Deallocate temporary loading data */
10061 _gted.clear();
10062 _grm_sprites.clear();
10063}
10064
10070void LoadNewGRF(SpriteID load_index, uint num_baseset)
10071{
10072 /* In case of networking we need to "sync" the start values
10073 * so all NewGRFs are loaded equally. For this we use the
10074 * start date of the game and we set the counters, etc. to
10075 * 0 so they're the same too. */
10076 TimerGameCalendar::Date date = TimerGameCalendar::date;
10079
10080 TimerGameEconomy::Date economy_date = TimerGameEconomy::date;
10081 TimerGameEconomy::Year economy_year = TimerGameEconomy::year;
10083
10084 uint64_t tick_counter = TimerGameTick::counter;
10085 uint8_t display_opt = _display_opt;
10086
10087 if (_networking) {
10091
10092 TimerGameEconomy::year = TimerGameEconomy::Year{_settings_game.game_creation.starting_year.base()};
10095
10097 _display_opt = 0;
10098 }
10099
10101
10103
10104 /*
10105 * Reset the status of all files, so we can 'retry' to load them.
10106 * This is needed when one for example rearranges the NewGRFs in-game
10107 * and a previously disabled NewGRF becomes usable. If it would not
10108 * be reset, the NewGRF would remain disabled even though it should
10109 * have been enabled.
10110 */
10111 for (const auto &c : _grfconfig) {
10112 if (c->status != GCS_NOT_FOUND) c->status = GCS_UNKNOWN;
10113 }
10114
10115 _cur.spriteid = load_index;
10116
10117 /* Load newgrf sprites
10118 * in each loading stage, (try to) open each file specified in the config
10119 * and load information from it. */
10120 for (GrfLoadingStage stage = GLS_LABELSCAN; stage <= GLS_ACTIVATION; stage++) {
10121 /* Set activated grfs back to will-be-activated between reservation- and activation-stage.
10122 * This ensures that action7/9 conditions 0x06 - 0x0A work correctly. */
10123 for (const auto &c : _grfconfig) {
10125 }
10126
10127 if (stage == GLS_RESERVE) {
10128 static const std::pair<uint32_t, uint32_t> default_grf_overrides[] = {
10129 { std::byteswap(0x44442202), std::byteswap(0x44440111) }, // UKRS addons modifies UKRS
10130 { std::byteswap(0x6D620402), std::byteswap(0x6D620401) }, // DBSetXL ECS extension modifies DBSetXL
10131 { std::byteswap(0x4D656f20), std::byteswap(0x4D656F17) }, // LV4cut modifies LV4
10132 };
10133 for (const auto &grf_override : default_grf_overrides) {
10134 SetNewGRFOverride(grf_override.first, grf_override.second);
10135 }
10136 }
10137
10138 uint num_grfs = 0;
10139 uint num_non_static = 0;
10140
10141 _cur.stage = stage;
10142 for (const auto &c : _grfconfig) {
10143 if (c->status == GCS_DISABLED || c->status == GCS_NOT_FOUND) continue;
10144 if (stage > GLS_INIT && c->flags.Test(GRFConfigFlag::InitOnly)) continue;
10145
10146 Subdirectory subdir = num_grfs < num_baseset ? BASESET_DIR : NEWGRF_DIR;
10147 if (!FioCheckFileExists(c->filename, subdir)) {
10148 Debug(grf, 0, "NewGRF file is missing '{}'; disabling", c->filename);
10149 c->status = GCS_NOT_FOUND;
10150 continue;
10151 }
10152
10153 if (stage == GLS_LABELSCAN) InitNewGRFFile(*c);
10154
10156 if (num_non_static == NETWORK_MAX_GRF_COUNT) {
10157 Debug(grf, 0, "'{}' is not loaded as the maximum number of non-static GRFs has been reached", c->filename);
10158 c->status = GCS_DISABLED;
10159 c->error = {STR_NEWGRF_ERROR_MSG_FATAL, STR_NEWGRF_ERROR_TOO_MANY_NEWGRFS_LOADED};
10160 continue;
10161 }
10162 num_non_static++;
10163 }
10164
10165 num_grfs++;
10166
10167 LoadNewGRFFile(*c, stage, subdir, false);
10168 if (stage == GLS_RESERVE) {
10170 } else if (stage == GLS_ACTIVATION) {
10172 assert(GetFileByGRFID(c->ident.grfid) == _cur.grffile);
10175 Debug(sprite, 2, "LoadNewGRF: Currently {} sprites are loaded", _cur.spriteid);
10176 } else if (stage == GLS_INIT && c->flags.Test(GRFConfigFlag::InitOnly)) {
10177 /* We're not going to activate this, so free whatever data we allocated */
10179 }
10180 }
10181 }
10182
10183 /* Pseudo sprite processing is finished; free temporary stuff */
10184 _cur.ClearDataForNextFile();
10185
10186 /* Call any functions that should be run after GRFs have been loaded. */
10187 AfterLoadGRFs();
10188
10189 /* Now revert back to the original situation */
10192 TimerGameCalendar::date_fract = date_fract;
10193
10194 TimerGameEconomy::year = economy_year;
10195 TimerGameEconomy::date = economy_date;
10196 TimerGameEconomy::date_fract = economy_date_fract;
10197
10198 TimerGameTick::counter = tick_counter;
10199 _display_opt = display_opt;
10200}
static const uint INVALID_AIRPORTTILE
id for an invalid airport tile
Definition airport.h:25
static const uint NEW_AIRPORTTILE_OFFSET
offset of first newgrf airport tile
Definition airport.h:24
static const uint NUM_AIRPORTTILES_PER_GRF
Number of airport tiles per NewGRF; limited to 255 to allow extending Action3 with an extended byte l...
Definition airport.h:21
@ NEW_AIRPORT_OFFSET
Number of the first newgrf airport.
Definition airport.h:39
@ NUM_AIRPORTS_PER_GRF
Maximal number of airports per NewGRF.
Definition airport.h:40
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.
constexpr uint8_t FindFirstBit(T x)
Search the first set bit in a value.
constexpr enable_if_t< is_integral_v< T >, T > byteswap(T x) noexcept
Custom implementation of std::byteswap; remove once we build with C++23.
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 CargoType
Cargo slots to indicate a cargo type within a game.
Definition cargo_type.h:22
bool IsValidCargoType(CargoType t)
Test whether cargo type is not INVALID_CARGO.
Definition cargo_type.h:105
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 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
static const CargoType NUM_CARGO
Maximum number of cargo types in a game.
Definition cargo_type.h:74
std::span< const CargoLabel > GetClimateDependentCargoTranslationTable()
Get default climate-dependent cargo translation table for a NewGRF, used if the NewGRF does not provi...
bool IsDefaultCargo(CargoType cargo_type)
Test if a cargo is a default cargo type.
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 SetupCargoForClimate(LandscapeType l)
Set up the default cargo types for the given landscape type.
Definition cargotype.cpp:64
void InitializeSortedCargoSpecs()
Initialize the list of sorted cargo specifications.
CargoTypes _cargo_mask
Bitmask of cargo types available.
Definition cargotype.cpp:33
@ CC_MAIL
Mail.
Definition cargotype.h:52
@ CC_REFRIGERATED
Refrigerated cargo (Food, Fruit)
Definition cargotype.h:58
@ CC_ARMOURED
Armoured cargo (Valuables, Gold, Diamonds)
Definition cargotype.h:54
@ CC_BULK
Bulk cargo (Coal, Grain etc., Ores, Fruit)
Definition cargotype.h:55
@ CC_EXPRESS
Express cargo (Goods, Food, Candy, but also possible for passengers)
Definition cargotype.h:53
@ CC_LIQUID
Liquids (Oil, Water, Rubber)
Definition cargotype.h:57
@ CC_PIECE_GOODS
Piece goods (Livestock, Wood, Steel, Paper)
Definition cargotype.h:56
@ CC_PASSENGERS
Passengers.
Definition cargotype.h:51
@ INVALID_TPE
Invalid town production effect.
Definition cargotype.h:45
@ TPE_NONE
Town will not produce this cargo type.
Definition cargotype.h:36
@ TPE_PASSENGERS
Cargo behaves passenger-like for production.
Definition cargotype.h:37
@ TPE_MAIL
Cargo behaves mail-like for production.
Definition cargotype.h:38
uint16_t CargoClasses
Bitmask of cargo classes.
Definition cargotype.h:70
@ TAE_GOODS
Cargo behaves goods/candy-like.
Definition cargotype.h:27
@ TAE_NONE
Cargo has no effect.
Definition cargotype.h:24
@ TAE_PASSENGERS
Cargo behaves passenger-like.
Definition cargotype.h:25
@ TAE_MAIL
Cargo behaves mail-like.
Definition cargotype.h:26
@ TAE_FOOD
Cargo behaves food/fizzy-drinks-like.
Definition cargotype.h:29
@ TAE_WATER
Cargo behaves water-like.
Definition cargotype.h:28
Class to read from a NewGRF file.
Definition newgrf.cpp:216
constexpr Tstorage base() const noexcept
Retrieve the raw value behind this EnumBitSet.
constexpr EnumBitSet & Set(Tenum value)
Set the enum value.
constexpr bool Any(const EnumBitSet &other) const
Test if any of the enum values are set.
constexpr EnumBitSet & Reset(Tenum value)
Reset the enum value to not set.
constexpr bool Test(Tenum value) const
Test if the enum value is set.
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:117
uint16_t max_speed
Maximum speed for vehicles travelling on this rail type.
Definition rail.h:221
TimerGameCalendar::Date introduction_date
Introduction date.
Definition rail.h:245
RailTypes powered_railtypes
bitmask to the OTHER railtypes on which an engine of THIS railtype generates power
Definition rail.h:178
RailTypes introduces_railtypes
Bitmask of which other railtypes are introduced when this railtype is introduced.
Definition rail.h:256
RailTypes introduction_required_railtypes
Bitmask of railtypes that are required for this railtype to be introduced at a given introduction_dat...
Definition rail.h:251
uint8_t sorting_order
The sorting order of this railtype for the toolbar dropdown.
Definition rail.h:261
RailTypeLabel label
Unique 32 bit rail type identifier.
Definition rail.h:226
struct RailTypeInfo::@24 strings
Strings associated with the rail type.
uint16_t maintenance_multiplier
Cost multiplier for maintenance of this rail type.
Definition rail.h:211
const SpriteGroup * group[RTSG_END]
Sprite groups for resolving sprites.
Definition rail.h:271
uint8_t map_colour
Colour on mini-map.
Definition rail.h:236
StringID menu_text
Name of this rail type in the main toolbar dropdown.
Definition rail.h:168
StringID name
Name of this rail type.
Definition rail.h:166
RailTypes compatible_railtypes
bitmask to the OTHER railtypes on which an engine of THIS railtype can physically travel
Definition rail.h:181
uint8_t fallback_railtype
Original railtype number to use when drawing non-newgrf railtypes, or when drawing stations.
Definition rail.h:191
StringID toolbar_caption
Caption in the construction toolbar GUI for this rail type.
Definition rail.h:167
RailTypeFlags flags
Bit mask of rail type flags.
Definition rail.h:201
uint8_t curve_speed
Multiplier for curve maximum speed advantage.
Definition rail.h:196
uint16_t cost_multiplier
Cost multiplier for building this rail type.
Definition rail.h:206
StringID replace_text
Text used in the autoreplace GUI.
Definition rail.h:170
RailTypeLabelList alternate_labels
Rail type labels this type provides in addition to the main label.
Definition rail.h:231
StringID build_caption
Caption of the build vehicle GUI for this rail type.
Definition rail.h:169
StringID new_loco
Name of an engine for this type of rail in the engine preview GUI.
Definition rail.h:171
const GRFFile * grffile[RTSG_END]
NewGRF providing the Action3 for the railtype.
Definition rail.h:266
uint8_t acceleration_type
Acceleration type of this rail type.
Definition rail.h:216
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:95
StringID replace_text
Text used in the autoreplace GUI.
Definition road.h:97
RoadTypeLabelList alternate_labels
Road type labels this type provides in addition to the main label.
Definition road.h:142
RoadTypes powered_roadtypes
bitmask to the OTHER roadtypes on which a vehicle of THIS roadtype generates power
Definition road.h:112
RoadTypes introduces_roadtypes
Bitmask of which other roadtypes are introduced when this roadtype is introduced.
Definition road.h:167
TimerGameCalendar::Date introduction_date
Introduction date.
Definition road.h:156
const SpriteGroup * group[ROTSG_END]
Sprite groups for resolving sprites.
Definition road.h:182
uint8_t sorting_order
The sorting order of this roadtype for the toolbar dropdown.
Definition road.h:172
uint16_t maintenance_multiplier
Cost multiplier for maintenance of this road type.
Definition road.h:127
RoadTypeFlags flags
Bit mask of road type flags.
Definition road.h:117
uint8_t map_colour
Colour on mini-map.
Definition road.h:147
const GRFFile * grffile[ROTSG_END]
NewGRF providing the Action3 for the roadtype.
Definition road.h:177
uint16_t max_speed
Maximum speed for vehicles travelling on this road type.
Definition road.h:132
StringID name
Name of this rail type.
Definition road.h:93
StringID toolbar_caption
Caption in the construction toolbar GUI for this rail type.
Definition road.h:94
struct RoadTypeInfo::@27 strings
Strings associated with the rail type.
StringID new_engine
Name of an engine for this type of road in the engine preview GUI.
Definition road.h:98
RoadTypes introduction_required_roadtypes
Bitmask of roadtypes that are required for this roadtype to be introduced at a given introduction_dat...
Definition road.h:162
uint16_t cost_multiplier
Cost multiplier for building this road type.
Definition road.h:122
StringID build_caption
Caption of the build vehicle GUI for this rail type.
Definition road.h:96
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:161
uint8_t GetNewgrfCurrencyIdConverted(uint8_t grfcurr_id)
Will return the ottd's index correspondence to the ttdpatch's id.
Definition currency.cpp:117
std::array< CurrencySpec, CURRENCY_END > _currency_specs
Array of currencies used by the system.
Definition currency.cpp:78
Functions to handle different currencies.
@ CURRENCY_END
always the last item
Definition currency.h:72
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.
@ RoadIsTram
Road vehicle is a tram/light rail vehicle.
@ Uses2CC
Vehicle uses two company colours.
static const EngineID INVALID_ENGINE
Constant denoting an invalid engine.
uint16_t EngineID
Unique identification number of an engine.
Definition engine_type.h:23
EngineClass
Type of rail engine.
Definition engine_type.h:35
@ EC_DIESEL
Diesel rail engine.
Definition engine_type.h:37
@ EC_STEAM
Steam rail engine.
Definition engine_type.h:36
@ EC_MAGLEV
Maglev engine.
Definition engine_type.h:40
@ EC_ELECTRIC
Electric rail engine.
Definition engine_type.h:38
@ EC_MONORAIL
Mono rail engine.
Definition engine_type.h:39
@ RAILVEH_SINGLEHEAD
indicates a "standalone" locomotive
Definition engine_type.h:29
@ RAILVEH_WAGON
simple wagon, not motorized
Definition engine_type.h:31
@ RAILVEH_MULTIHEAD
indicates a combination of two locomotives
Definition engine_type.h:30
constexpr std::underlying_type_t< enum_type > to_underlying(enum_type e)
Implementation of std::to_underlying (from C++23)
Definition enum_type.hpp:15
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:122
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:69
Functions related to world/map generation.
uint32_t SpriteID
The number of a sprite, without mapping bits and colourtables.
Definition gfx_type.h:17
FontSize
Available font sizes.
Definition gfx_type.h:242
uint32_t PaletteID
The number of the palette.
Definition gfx_type.h:18
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.
void SetSnowLine(std::unique_ptr< SnowLine > &&snow_line)
Set a variable snow line, as loaded from a newgrf file.
static const HouseID NUM_HOUSES
Total number of houses.
Definition house.h:28
static const HouseID NEW_HOUSE_OFFSET
Offset for new houses.
Definition house.h:27
static const HouseID NUM_HOUSES_PER_GRF
Number of supported houses per NewGRF.
Definition house.h:31
static const uint HOUSE_ORIGINAL_NUM_ACCEPTS
Original number of accepted cargo types.
Definition house.h:34
HouseZones
Definition house.h:67
@ HZ_ZONALL
1F This is just to englobe all above types at once
Definition house.h:74
@ HZ_CLIMALL
Bitmask of all climate bits.
Definition house.h:80
@ HZ_ZON5
center of town
Definition house.h:73
@ HZ_SUBARTC_ABOVE
11 800 can appear in sub-arctic climate above the snow line
Definition house.h:75
@ 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:69
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.
IndustryTileSpecialFlags
Flags for miscellaneous industry tile specialities.
IndustryLifeType
Available types of industry lifetimes.
std::vector< IndustryTileLayoutTile > IndustryTileLayout
A complete tile layout for an industry is a list of tiles.
@ CHECK_NOTHING
Always succeeds.
IndustryBehaviour
Various industry behaviours mostly to represent original TTD 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
LandscapeType
Landscape types.
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:2066
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 bool IsInsideMM(const size_t x, const size_t min, const size_t max) noexcept
Checks if a value is in an interval.
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
void MemSetT(T *ptr, uint8_t value, size_t num=1)
Type-safe version of memset().
Definition mem_func.hpp:49
static constexpr CargoType SG_PURCHASE
Used in purchase lists before an item exists.
static constexpr CargoType SG_DEFAULT
Default type used when no more-specific cargo matches.
static constexpr CargoType SG_DEFAULT_NA
Used only by stations and roads when no more-specific cargo matches.
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:9530
static void FinalisePriceBaseMultipliers()
Decide whether price base multipliers of grfs shall apply globally or only to the grf specifying them...
Definition newgrf.cpp:9831
std::span< const Action5Type > GetAction5Types()
Get list of all action 5 types.
Definition newgrf.cpp:6501
static void ResetCustomStations()
Reset and clear all NewGRF stations.
Definition newgrf.cpp:8736
static void SkipAct12(ByteReader &buf)
Action 0x12 (SKIP)
Definition newgrf.cpp:8116
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:8994
bool GetGlobalVariable(uint8_t param, uint32_t *value, const GRFFile *grffile)
Reads a variable common to VarAction2 and Action7/9/D.
Definition newgrf.cpp:6618
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:8325
bool(* BranchHandler)(ByteReader &)
Type of callback function for branch nodes.
Definition newgrf.cpp:8399
static ChangeInfoResult RoadVehicleChangeInfo(uint first, uint last, int prop, ByteReader &buf)
Define properties for road vehicles.
Definition newgrf.cpp:1374
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:6445
static void FinaliseIndustriesArray()
Add all new industries to the industry array.
Definition newgrf.cpp:9482
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:8342
std::span< const CargoLabel > GetCargoTranslationTable(const GRFFile &grffile)
Get the cargo translation table to use for the given GRF file.
Definition newgrf.cpp:5625
static ChangeInfoResult LoadTranslationTable(uint first, uint last, ByteReader &buf, TGetTableFunc gettable, std::string_view name)
Load a cargo- or railtype-translation table.
Definition newgrf.cpp:2738
static bool ChangeGRFNumUsedParams(size_t len, ByteReader &buf)
Callback function for 'INFO'->'NPAR' to set the number of valid parameters.
Definition newgrf.cpp:8216
void ResetPersistentNewGRFData()
Reset NewGRF data which is stored persistently in savegames.
Definition newgrf.cpp:8905
static constexpr AllowedSubtags _tags_info[]
Action14 tags for the INFO node.
Definition newgrf.cpp:8495
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:8209
static ChangeInfoResult AirportChangeInfo(uint first, uint last, int prop, ByteReader &buf)
Define properties for airports.
Definition newgrf.cpp:3971
bool(* DataHandler)(size_t, ByteReader &)
Type of callback function for binary nodes.
Definition newgrf.cpp:8397
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:9548
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:8318
static ChangeInfoResult CanalChangeInfo(uint first, uint last, int prop, ByteReader &buf)
Define properties for water features.
Definition newgrf.cpp:2237
static ChangeInfoResult StationChangeInfo(uint first, uint last, int prop, ByteReader &buf)
Define properties for stations.
Definition newgrf.cpp:1957
static ChangeInfoResult SoundEffectChangeInfo(uint first, uint last, int prop, ByteReader &buf)
Define properties for sound effects.
Definition newgrf.cpp:3243
static bool ChangeGRFMinVersion(size_t len, ByteReader &buf)
Callback function for 'INFO'->'MINV' to the minimum compatible version of the NewGRF.
Definition newgrf.cpp:8289
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:9333
static bool ChangeGRFParamDefault(size_t len, ByteReader &buf)
Callback function for 'INFO'->'PARAM'->param_num->'DFLT' to set the default value.
Definition newgrf.cpp:8385
static void TranslateGRFStrings(ByteReader &buf)
Action 0x13.
Definition newgrf.cpp:8142
static void GRFUnsafe(ByteReader &)
Set the current NewGRF as unsafe for static use.
Definition newgrf.cpp:8637
static void DefineGotoLabel(ByteReader &buf)
Action 0x10 - Define goto label.
Definition newgrf.cpp:7915
static void ActivateOldShore()
Relocates the old shore sprites at new positions.
Definition newgrf.cpp:9779
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:9379
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:7487
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:8425
static GRFFile * GetCurrentGRFOverride()
Get overridden GRF for current GRF if present.
Definition newgrf.cpp:609
static void FinaliseEngineArray()
Check for invalid engines.
Definition newgrf.cpp:9236
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:5235
static bool HandleParameterInfo(ByteReader &buf)
Callback function for 'INFO'->'PARA' to set extra information about the parameters.
Definition newgrf.cpp:8468
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:8308
static bool HandleNodes(ByteReader &buf, std::span< const AllowedSubtags > tags)
Handle the contents of a 'C' choice of an Action14.
Definition newgrf.cpp:8612
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 void ResetNewGRFErrors()
Clear all NewGRF errors.
Definition newgrf.cpp:8796
uint8_t _misc_grf_features
Miscellaneous GRF features, set by Action 0x0D, parameter 0x9E.
Definition newgrf.cpp:78
static void LoadNewGRFFileFromFile(GRFConfig &config, GrfLoadingStage stage, SpriteFile &file)
Load a particular NewGRF from a SpriteFile.
Definition newgrf.cpp:9654
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:8195
static std::vector< StringIDMapping > _string_to_grf_mapping
Strings to be mapped during load.
Definition newgrf.cpp:466
StringID MapGRFStringID(uint32_t grfid, GRFStringID 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 ChangeInfoResult AircraftVehicleChangeInfo(uint first, uint last, int prop, ByteReader &buf)
Define properties for aircraft.
Definition newgrf.cpp:1782
static ChangeInfoResult GlobalVarChangeInfo(uint first, uint last, int prop, ByteReader &buf)
Define properties for global variables.
Definition newgrf.cpp:2784
static void LoadGRFSound(size_t offs, SoundEntry *sound)
Load a sound from a file.
Definition newgrf.cpp:7964
bool(* TextHandler)(uint8_t, std::string_view str)
Type of callback function for text nodes.
Definition newgrf.cpp:8398
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
static ChangeInfoResult ObjectChangeInfo(uint first, uint last, int prop, ByteReader &buf)
Define properties for objects.
Definition newgrf.cpp:4171
void LoadNewGRF(SpriteID load_index, uint num_baseset)
Load all the NewGRFs.
Definition newgrf.cpp:10070
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:6896
static void InitializeGRFSpecial()
Initialize the TTDPatch flags.
Definition newgrf.cpp:8647
static constexpr AllowedSubtags _tags_root[]
Action14 root tags.
Definition newgrf.cpp:8508
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:2769
static void ClearTemporaryNewGRFData(GRFFile *gf)
Reset all NewGRFData that was used only while processing data.
Definition newgrf.cpp:422
static ChangeInfoResult CargoChangeInfo(uint first, uint last, int prop, ByteReader &buf)
Define properties for cargoes.
Definition newgrf.cpp:3085
static StringID TTDPStringIDToOTTDStringIDMapping(GRFStringID 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
static void FinaliseCanals()
Set to use the correct action0 properties for each canal feature.
Definition newgrf.cpp:9225
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 IgnoreObjectProperty(uint prop, ByteReader &buf)
Ignore properties for objects.
Definition newgrf.cpp:4124
void ResetNewGRFData()
Reset all NewGRF loaded data.
Definition newgrf.cpp:8806
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:7149
static void CalculateRefitMasks()
Precalculate refit masks from cargo classes for all vehicles.
Definition newgrf.cpp:9029
void FinaliseCargoArray()
Check for invalid cargoes.
Definition newgrf.cpp:9303
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:8627
static ChangeInfoResult ShipVehicleChangeInfo(uint first, uint last, int prop, ByteReader &buf)
Define properties for ships.
Definition newgrf.cpp:1585
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:4826
static ChangeInfoResult IgnoreIndustryProperty(int prop, ByteReader &buf)
Ignore an industry property.
Definition newgrf.cpp:3473
static void BuildCargoTranslationMap()
Construct the Cargo Mapping.
Definition newgrf.cpp:8920
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:8364
static void ImportGRFSound(SoundEntry *sound)
Process a sound import from another GRF file.
Definition newgrf.cpp:7933
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:8519
static ChangeInfoResult RailVehicleChangeInfo(uint first, uint last, int prop, ByteReader &buf)
Define properties for rail vehicles.
Definition newgrf.cpp:1060
static ChangeInfoResult IgnoreTownHouseProperty(int prop, ByteReader &buf)
Ignore a house property.
Definition newgrf.cpp:2385
static ChangeInfoResult IndustriesChangeInfo(uint first, uint last, int prop, ByteReader &buf)
Define properties for industries.
Definition newgrf.cpp:3596
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:8744
EngineID GetNewEngineID(const GRFFile *file, VehicleType type, uint16_t internal_id)
Return the ID of a new engine.
Definition newgrf.cpp:711
static ChangeInfoResult RoadTypeChangeInfo(uint first, uint last, int prop, ByteReader &buf, RoadTramType rtt)
Define properties for roadtypes.
Definition newgrf.cpp:4519
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:8202
static ChangeInfoResult IndustrytilesChangeInfo(uint first, uint last, int prop, ByteReader &buf)
Define properties for industry tiles.
Definition newgrf.cpp:3338
static void LoadFontGlyph(ByteReader &buf)
Action 0x12.
Definition newgrf.cpp:8085
static void ResetCustomIndustries()
Reset and clear all NewGRF industries.
Definition newgrf.cpp:8761
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:8770
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:9404
static bool ChangeGRFPalette(size_t len, ByteReader &buf)
Callback function for 'INFO'->'PALS' to set the number of valid parameters.
Definition newgrf.cpp:8228
static constexpr auto _action5_types
The information about action 5 types.
Definition newgrf.cpp:6467
static void InitNewGRFFile(const GRFConfig &config)
Prepare loading a NewGRF file with its config.
Definition newgrf.cpp:8939
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 ChangeGRFVersion(size_t len, ByteReader &buf)
Callback function for 'INFO'->'VRSN' to the version of the NewGRF.
Definition newgrf.cpp:8276
static bool ValidateIndustryLayout(const IndustryTileLayout &layout)
Validate the industry layout; e.g.
Definition newgrf.cpp:3563
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 ActivateOldTramDepot()
Replocate the old tram depot sprites to the new position, if no new ones were loaded.
Definition newgrf.cpp:9816
static uint32_t _ttdpatch_flags[8]
32 * 8 = 256 flags.
Definition newgrf.cpp:81
static ChangeInfoResult RailTypeChangeInfo(uint first, uint last, int prop, ByteReader &buf)
Define properties for railtypes.
Definition newgrf.cpp:4301
void LoadNewGRFFile(GRFConfig &config, GrfLoadingStage stage, Subdirectory subdir, bool temporary)
Load a particular NewGRF.
Definition newgrf.cpp:9743
static void AddStringForMapping(GRFStringID source, std::function< void(StringID)> &&func)
Record a static StringID for getting translated later.
Definition newgrf.cpp:473
static ChangeInfoResult IgnoreIndustryTileProperty(int prop, ByteReader &buf)
Ignore an industry tile property.
Definition newgrf.cpp:3298
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:9947
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:8311
static bool HandleNode(uint8_t type, uint32_t id, ByteReader &buf, std::span< const AllowedSubtags > subtags)
Handle the nodes of an Action14.
Definition newgrf.cpp:8559
static void ResetNewGRF()
Reset and clear all NewGRFs.
Definition newgrf.cpp:8785
void InitGRFTownGeneratorNames()
Allocate memory for the NewGRF town names.
static bool ChangeGRFBlitter(size_t len, ByteReader &buf)
Callback function for 'INFO'->'BLTR' to set the blitter info.
Definition newgrf.cpp:8254
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:7837
static void ResetCustomAirports()
Reset and clear all NewGRF airports.
Definition newgrf.cpp:8752
static ChangeInfoResult BridgeChangeInfo(uint first, uint last, int prop, ByteReader &buf)
Define properties for bridges.
Definition newgrf.cpp:2275
static std::vector< CachedCallback > _cached_callback_groups
Sorted list of cached callback result spritegroups.
Definition newgrf.cpp:5190
static ChangeInfoResult TownHouseChangeInfo(uint first, uint last, int prop, ByteReader &buf)
Define properties for houses.
Definition newgrf.cpp:2452
static constexpr AllowedSubtags _tags_parameters[]
Action14 parameter tags.
Definition newgrf.cpp:8452
@ SHORE_REPLACE_ACTION_A
Shore sprites were replaced by ActionA (using grass tiles for the corner-shores).
Definition newgrf.h:166
@ SHORE_REPLACE_NONE
No shore sprites were replaced.
Definition newgrf.h:164
@ SHORE_REPLACE_ONLY_NEW
Only corner-shores were loaded by Action5 (openttd(w/d).grf only).
Definition newgrf.h:167
@ SHORE_REPLACE_ACTION_5
Shore sprites were replaced by Action5.
Definition newgrf.h:165
@ TRAMWAY_REPLACE_DEPOT_WITH_TRACK
Electrified depot graphics with tram track were loaded.
Definition newgrf.h:172
@ TRAMWAY_REPLACE_DEPOT_NO_TRACK
Electrified depot graphics without tram track were loaded.
Definition newgrf.h:173
@ TRAMWAY_REPLACE_DEPOT_NONE
No tram depot graphics were loaded.
Definition newgrf.h:171
@ 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:62
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.
@ CustomRefit
Custom refit mask.
@ CBID_VEHICLE_CUSTOM_REFIT
Called to get custom engine refit mask.
static const uint CALLBACK_FAILED
Different values for Callback result evaluations.
std::array< WaterFeature, CF_END > _water_feature
Table of canal 'feature' sprite groups.
Handling of NewGRF canals.
CargoType GetCargoTranslation(uint8_t cargo, const GRFFile *grffile, bool usebit)
Translate a GRF-local cargo slot/bitnum into a CargoType.
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.
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....
static const uint TLR_MAX_VAR10
Maximum value for var 10.
GRFConfigList _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.
@ 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.
@ InitOnly
GRF file is processed up to GLS_INIT.
@ Reserved
GRF file passed GLS_RESERVE stage.
@ System
GRF file is an openttd-internal system grf.
@ Static
GRF file is used statically (can be used in any MP game)
@ Unsafe
GRF file is unsafe for static usage.
@ Invalid
GRF is unusable with this version of OpenTTD.
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.
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.
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,...
@ Uses2CC
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 GetGRFStringID(uint32_t grfid, GRFStringID stringid)
Returns the index for this stringid associated with its grfID.
StringID AddGRFString(uint32_t grfid, GRFStringID 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.
Header of Action 04 "universal holder" structure and functions.
StrongType::Typedef< uint16_t, struct GRFStringIDTag, StrongType::Compare, StrongType::Integer > GRFStringID
Type for GRF-internal string IDs.
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:297
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
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:277
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:332
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:8408
uint32_t id
The identifier for this node.
Definition newgrf.cpp:8412
std::variant< DataHandler, TextHandler, BranchHandler, Span > handler
The handler for this node.
Definition newgrf.cpp:8413
std::pair< const AllowedSubtags *, const AllowedSubtags * > Span
Custom 'span' of subtags.
Definition newgrf.cpp:8410
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:41
CanalCallbackMasks callback_mask
Bitmask of canal callbacks that have to be called.
Definition newgrf.h:42
uint8_t flags
Flags controlling display.
Definition newgrf.h:43
Specification of a cargo type.
Definition cargotype.h:77
int32_t initial_payment
Initial payment rate before inflation is applied.
Definition cargotype.h:85
CargoClasses classes
Classes of this cargo type.
Definition cargotype.h:84
uint16_t multiplier
Capacity multiplier for vehicles. (8 fractional bits)
Definition cargotype.h:83
StringID units_volume
Name of a single unit of cargo of this type.
Definition cargotype.h:96
static CargoSpec * Get(size_t index)
Retrieve cargo details for the given cargo type.
Definition cargotype.h:140
StringID abbrev
Two letter abbreviation for this cargo type.
Definition cargotype.h:98
uint8_t bitnum
Cargo bit number, is INVALID_CARGO_BITNUM for a non-used spec.
Definition cargotype.h:79
StringID quantifier
Text for multiple units of cargo of this type.
Definition cargotype.h:97
SpriteID sprite
Icon to display this cargo type, may be 0xFFF (which means to resolve an action123 chain).
Definition cargotype.h:100
bool is_freight
Cargo type is considered to be freight (affects train freight multiplier).
Definition cargotype.h:88
uint8_t weight
Weight of a single unit of this cargo type in 1/16 ton (62.5 kg).
Definition cargotype.h:82
CargoLabel label
Unique label of the cargo type.
Definition cargotype.h:78
const struct GRFFile * grffile
NewGRF where group belongs to.
Definition cargotype.h:102
static IterateWrapper Iterate(size_t from=0)
Returns an iterable ensemble of all valid CargoSpec.
Definition cargotype.h:196
static CargoSpec array[NUM_CARGO]
Array holding all CargoSpecs.
Definition cargotype.h:202
StringID name
Name of this type of cargo.
Definition cargotype.h:94
TownProductionEffect town_production_effect
The effect on town cargo production.
Definition cargotype.h:90
TownAcceptanceEffect town_acceptance_effect
The effect that delivering this cargo type has on towns. Also affects destination of subsidies.
Definition cargotype.h:89
CargoCallbackMasks callback_mask
Bitmask of cargo callbacks that have to be called.
Definition cargotype.h:92
uint16_t town_production_multiplier
Town production multipler, if commanded by TownProductionEffect.
Definition cargotype.h:91
bool IsValid() const
Tests for validity of this cargospec.
Definition cargotype.h:121
StringID name_single
Name of a single entity of this type of cargo.
Definition cargotype.h:95
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.
LandscapeTypes climates
Climates supported by the engine.
EngineMiscFlags misc_flags
Miscellaneous flags.
EngineID variant_id
Engine variant ID. If set, will be treated specially in purchase lists.
StringID string_id
Default name of engine.
VehicleCallbackMasks callback_mask
Bitmask of vehicle callbacks that have to be called.
TimerGameCalendar::Date base_intro
Basic date of engine introduction (without random parts).
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:83
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:61
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.
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)
GRFStatus status
NOSAVE: GRFStatus, enum.
std::optional< GRFError > error
NOSAVE: Error/Warning during GRF loading (Action 0x0B)
GRFConfigFlags flags
NOSAVE: GCF_Flags, bitset.
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:109
std::array< uint8_t, NUM_CARGO > cargo_map
Inverse cargo translation table (CargoType -> local ID)
Definition newgrf.h:131
std::vector< RailTypeLabel > railtype_list
Railtype translation table.
Definition newgrf.h:133
uint32_t GetParam(uint number) const
Get GRF Parameter with range checking.
Definition newgrf.h:155
CanalProperties canal_local_properties[CF_END]
Canal properties as set by this NewGRF.
Definition newgrf.h:142
GRFFile(const struct GRFConfig &config)
Constructor for GRFFile.
Definition newgrf.cpp:8956
std::vector< RoadTypeLabel > roadtype_list
Roadtype translation table (road)
Definition newgrf.h:136
uint32_t grf_features
Bitset of GrfSpecFeature the grf uses.
Definition newgrf.h:149
std::vector< RoadTypeLabel > tramtype_list
Roadtype translation table (tram)
Definition newgrf.h:139
std::vector< CargoLabel > cargo_list
Cargo translation table (local ID -> label)
Definition newgrf.h:130
uint traininfo_vehicle_width
Width (in pixels) of a 8/8 train vehicle in depot GUI and vehicle details.
Definition newgrf.h:147
int traininfo_vehicle_pitch
Vertical offset for drawing train images in depot GUI and vehicle details.
Definition newgrf.h:146
std::unordered_map< uint8_t, LanguageMap > language_map
Mappings related to the languages.
Definition newgrf.h:144
std::vector< GRFLabel > labels
List of labels.
Definition newgrf.h:128
PriceMultipliers price_base_multipliers
Price base multipliers as set by the grf.
Definition newgrf.h:150
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:177
ShoreReplacement shore
In which way shore sprites were replaced.
Definition newgrf.h:179
uint64_t used_liveries
Bitmask of LiveryScheme used by the defined engines.
Definition newgrf.h:178
TramReplacement tram
In which way tram depots were replaced.
Definition newgrf.h:180
Information about one grf parameter.
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.
std::vector< ValueName > value_names
Names for each value.
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
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
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
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.
LandscapeType 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
CargoType accepts_cargo[HOUSE_NUM_ACCEPTS]
input cargo slots
Definition house.h:102
bool enabled
the house is available to build (true by default, but can be disabled by newgrf)
Definition house.h:105
CargoLabel accepts_cargo_label[HOUSE_ORIGINAL_NUM_ACCEPTS]
input landscape cargo slots
Definition house.h:119
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:103
uint8_t population
population (Zero on other tiles in multi tile house.)
Definition house.h:96
uint8_t cargo_acceptance[HOUSE_NUM_ACCEPTS]
acceptance level for the cargo slots
Definition house.h:101
TimerGameCalendar::Year min_year
introduction year of the house
Definition house.h:94
GRFFileProps grf_prop
Properties related the the grf file.
Definition house.h:108
HouseZones building_availability
where can it be built (climates, zones)
Definition house.h:104
static std::vector< HouseSpec > & Specs()
Get a reference to all HouseSpecs.
CargoType cargo_input[INDUSTRY_NUM_INPUTS]
Which input cargoes to take from (only cb version 2)
CargoType cargo_output[INDUSTRY_NUM_OUTPUTS]
Which output cargoes to add to (only cb version 2)
uint16_t add_output[INDUSTRY_NUM_OUTPUTS]
Add this much output cargo when successful (unsigned, is indirect in cb version 1+)
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.
Defines the data structure for constructing industry.
std::array< CargoType, INDUSTRY_NUM_INPUTS > accepts_cargo
16 accepted cargoes.
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
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.
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.
std::array< CargoType, INDUSTRY_NUM_INPUTS > accepts_cargo
Cargo accepted by this tile.
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:2716
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:22
SpriteID sprite
The 'real' sprite.
Definition gfx_type.h:23
PaletteID pal
The palette (use PAL_NONE) if not needed)
Definition gfx_type.h:24
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:44
uint16_t power
Power of engine (hp); For multiheaded engines the sum of both engine powers.
Definition engine_type.h:52
uint8_t user_def_data
Property 0x25: "User-defined bit mask" Used only for (very few) NewGRF vehicles.
Definition engine_type.h:64
uint8_t running_cost
Running cost of engine; For multiheaded engines the sum of both running costs.
Definition engine_type.h:54
uint8_t cost_factor
Purchase cost factor; For multiheaded engines the sum of both engine prices.
Definition engine_type.h:47
uint8_t shorten_factor
length on main map for this type is 8 - shorten_factor
Definition engine_type.h:61
RailType intended_railtype
Intended railtype, regardless of elrail being enabled or disabled.
Definition engine_type.h:49
uint16_t pow_wag_power
Extra power applied to consist if wagon should be powered.
Definition engine_type.h:58
uint16_t max_speed
Maximum speed (1 unit = 1/1.6 mph = 1 km-ish/h)
Definition engine_type.h:51
int16_t curve_speed_mod
Modifier to maximum speed in curves (fixed-point binary with 8 fractional bits)
Definition engine_type.h:65
uint16_t weight
Weight of vehicle (tons); For multiheaded engines the weight of each single engine.
Definition engine_type.h:53
uint8_t capacity
Cargo capacity of vehicle; For multiheaded engines the capacity of each single engine.
Definition engine_type.h:57
uint8_t visual_effect
Bitstuffed NewGRF visual effect data.
Definition engine_type.h:60
uint8_t air_drag
Coefficient of air drag.
Definition engine_type.h:63
EngineClass engclass
Class of engine for this vehicle.
Definition engine_type.h:56
uint8_t ai_passenger_only
Bit value to tell AI that this engine is for passenger use only.
Definition engine_type.h:50
RailType railtype
Railtype, mangled if elrail is disabled.
Definition engine_type.h:48
uint8_t tractive_effort
Tractive effort coefficient.
Definition engine_type.h:62
uint8_t pow_wag_weight
Extra weight applied to consist if wagon should be powered.
Definition engine_type.h:59
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:69
bool old_refittable
Is ship refittable; only used during initialisation. Later use EngineInfo::refit_mask.
Definition engine_type.h:77
uint8_t ocean_speed_frac
Fraction of maximum speed for ocean tiles.
Definition engine_type.h:79
uint8_t visual_effect
Bitstuffed NewGRF visual effect data.
Definition engine_type.h:78
uint16_t max_speed
Maximum speed (1 unit = 1/3.2 mph = 0.5 km-ish/h)
Definition engine_type.h:74
uint8_t acceleration
Acceleration (1 unit = 1/3.2 mph per tick = 0.5 km-ish/h per tick)
Definition engine_type.h:73
uint8_t canal_speed_frac
Fraction of maximum speed for canal/river tiles.
Definition engine_type.h:80
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.
GRFFilePropsBase< NUM_CARGO+3 > grf_prop
Properties related the the grf file.
std::vector< NewGRFSpriteLayout > renderdata
Number of tile layouts.
@ NoWires
Tile should NOT contain catenary wires.
@ Pylons
Tile should contain catenary pylons.
@ Blocked
Tile is blocked to vehicles.
Information for mapping static StringIDs.
Definition newgrf.cpp:457
uint32_t grfid
Source NewGRF.
Definition newgrf.cpp:458
std::function< void(StringID)> func
Function for mapping result.
Definition newgrf.cpp:460
GRFStringID source
Source grf-local GRFStringID.
Definition newgrf.cpp:459
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
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.