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