Codechange: let NewGRF make use of SpriteFile instead of most of the FIO slot functions

(cherry picked from commit 10e35ca8e4)
pull/266/head
Rubidium 3 years ago committed by Jonathan G Rennison
parent 6bd12e24d7
commit eecf7c8525

@ -51,16 +51,15 @@ int _progsig_grf_file_index;
* Load an old fashioned GRF file.
* @param filename The name of the file to open.
* @param load_index The offset of the first sprite.
* @param file_index The Fio offset to load the file in.
* @param needs_palette_remap Whether the colours in the GRF file need a palette remap.
* @return The number of loaded sprites.
*/
static uint LoadGrfFile(const char *filename, uint load_index, int file_index, bool needs_palette_remap)
static uint LoadGrfFile(const char *filename, uint load_index, bool needs_palette_remap)
{
uint load_index_org = load_index;
uint sprite_id = 0;
SpriteFile &file = FioOpenFile(file_index, filename, BASESET_DIR, needs_palette_remap);
SpriteFile &file = OpenCachedSpriteFile(filename, BASESET_DIR, needs_palette_remap);
DEBUG(sprite, 2, "Reading grf-file '%s'", filename);
@ -89,16 +88,15 @@ static uint LoadGrfFile(const char *filename, uint load_index, int file_index, b
* Load an old fashioned GRF file to replace already loaded sprites.
* @param filename The name of the file to open.
* @param index_tbl The offsets of each of the sprites.
* @param file_index The Fio offset to load the file in.
* @param needs_palette_remap Whether the colours in the GRF file need a palette remap.
* @return The number of loaded sprites.
*/
static void LoadGrfFileIndexed(const char *filename, const SpriteID *index_tbl, int file_index, bool needs_palette_remap)
static void LoadGrfFileIndexed(const char *filename, const SpriteID *index_tbl, bool needs_palette_remap)
{
uint start;
uint sprite_id = 0;
SpriteFile &file = FioOpenFile(file_index, filename, BASESET_DIR, needs_palette_remap);
SpriteFile &file = OpenCachedSpriteFile(filename, BASESET_DIR, needs_palette_remap);
DEBUG(sprite, 2, "Reading indexed grf-file '%s'", filename);
@ -173,14 +171,13 @@ void CheckExternalFiles()
/** Actually load the sprite tables. */
static void LoadSpriteTables()
{
uint i = FIRST_GRF_SLOT;
const GraphicsSet *used_set = BaseGraphics::GetUsedSet();
LoadGrfFile(used_set->files[GFT_BASE].filename, 0, i++, (PAL_DOS != used_set->palette));
LoadGrfFile(used_set->files[GFT_BASE].filename, 0, PAL_DOS != used_set->palette);
/* Progsignal sprites. */
_progsig_grf_file_index = i;
LoadGrfFile("progsignals.grf", SPR_PROGSIGNAL_BASE, i++, false);
//_progsig_grf_file_index = i;
LoadGrfFile("progsignals.grf", SPR_PROGSIGNAL_BASE, false);
/* Fill duplicate programmable pre-signal graphics sprite block */
for (uint i = 0; i < PROGSIGNAL_SPRITE_COUNT; i++) {
@ -188,7 +185,7 @@ static void LoadSpriteTables()
}
/* Tracerestrict sprites. */
LoadGrfFile("tracerestrict.grf", SPR_TRACERESTRICT_BASE, i++, false);
LoadGrfFile("tracerestrict.grf", SPR_TRACERESTRICT_BASE, false);
/* Fill duplicate original signal graphics sprite block */
for (uint i = 0; i < DUP_ORIGINAL_SIGNALS_SPRITE_COUNT; i++) {
@ -201,7 +198,7 @@ static void LoadSpriteTables()
* has a few sprites less. However, we do not care about those missing
* sprites as they are not shown anyway (logos in intro game).
*/
LoadGrfFile(used_set->files[GFT_LOGOS].filename, 4793, i++, (PAL_DOS != used_set->palette));
LoadGrfFile(used_set->files[GFT_LOGOS].filename, 4793, PAL_DOS != used_set->palette);
/*
* Load additional sprites for climates other than temperate.
@ -212,15 +209,14 @@ static void LoadSpriteTables()
LoadGrfFileIndexed(
used_set->files[GFT_ARCTIC + _settings_game.game_creation.landscape - 1].filename,
_landscape_spriteindexes[_settings_game.game_creation.landscape - 1],
i++,
(PAL_DOS != used_set->palette)
PAL_DOS != used_set->palette
);
}
LoadGrfFile("innerhighlight.grf", SPR_ZONING_INNER_HIGHLIGHT_BASE, i++, false);
LoadGrfFile("innerhighlight.grf", SPR_ZONING_INNER_HIGHLIGHT_BASE, false);
/* Load route step graphics */
LoadGrfFile("route_step.grf", SPR_ROUTE_STEP_BASE, i++, false);
LoadGrfFile("route_step.grf", SPR_ROUTE_STEP_BASE, false);
/* Initialize the unicode to sprite mapping table */
InitializeUnicodeGlyphMap();
@ -257,7 +253,7 @@ static void LoadSpriteTables()
master->next = extra;
_grfconfig = master;
LoadNewGRF(SPR_NEWGRFS_BASE, i, 2);
LoadNewGRF(SPR_NEWGRFS_BASE, 2);
uint total_extra_graphics = SPR_NEWGRFS_BASE - SPR_OPENTTD_BASE;
_missing_extra_graphics = GetSpriteCountForFile(used_set->files[GFT_EXTRA].filename, SPR_OPENTTD_BASE, SPR_NEWGRFS_BASE);
@ -267,14 +263,13 @@ static void LoadSpriteTables()
* Let's say everything which provides less than 500 sprites misses the rest intentionally. */
if (500 + _missing_extra_graphics > total_extra_graphics) _missing_extra_graphics = 0;
_first_user_grf_file_index = i + 1;
_opengfx_grf_file_index = -1;
uint index = i;
for (GRFConfig *c = master; c != nullptr; c = c->next, index++) {
//_first_user_grf_file_index = i + 1;
//_opengfx_grf_file_index = -1;
for (GRFConfig *c = master; c != nullptr; c = c->next) {
if (c->status == GCS_DISABLED || c->status == GCS_NOT_FOUND || HasBit(c->flags, GCF_INIT_ONLY)) continue;
if (c->ident.grfid == BSWAP32(0xFF4F4701)) {
/* Detect OpenGFX GRF ID */
_opengfx_grf_file_index = index;
//_opengfx_grf_file_index = index;
break;
}
}

@ -81,6 +81,7 @@ static uint32 _ttdpatch_flags[8];
GRFLoadedFeatures _loaded_newgrf_features;
static const uint MAX_SPRITEGROUP = UINT8_MAX; ///< Maximum GRF-local ID for a spritegroup.
static const uint MAX_GRF_COUNT = 256; ///< Maximum number of NewGRF files that could be loaded.
/** Base GRF ID for OpenTTD's base graphics GRFs. */
static const uint32 OPENTTD_GRAPHICS_BASE_GRF_ID = BSWAP32(0xFF4F5400);
@ -6565,19 +6566,20 @@ static void CfgApply(ByteReader *buf)
* to place where parameter is to be stored. */
/* Preload the next sprite */
size_t pos = FioGetPos();
uint32 num = _cur.file->GetContainerVersion() >= 2 ? FioReadDword() : FioReadWord();
uint8 type = FioReadByte();
SpriteFile &file = *_cur.file;
size_t pos = file.GetPos();
uint32 num = file.GetContainerVersion() >= 2 ? file.ReadDword() : file.ReadWord();
uint8 type = file.ReadByte();
byte *preload_sprite = nullptr;
/* Check if the sprite is a pseudo sprite. We can't operate on real sprites. */
if (type == 0xFF) {
preload_sprite = MallocT<byte>(num);
FioReadBlock(preload_sprite, num);
file.ReadBlock(preload_sprite, num);
}
/* Reset the file position to the start of the next sprite */
FioSeekTo(pos, SEEK_SET);
file.SeekTo(pos, SEEK_SET);
if (type != 0xFF) {
grfmsg(2, "CfgApply: Ignoring (next sprite is real, unsupported)");
@ -6823,7 +6825,7 @@ static void SkipIf(ByteReader *buf)
if (choice != nullptr) {
grfmsg(2, "SkipIf: Jumping to label 0x%0X at line %d, test was true", choice->label, choice->nfo_line);
FioSeekTo(choice->pos, SEEK_SET);
_cur.file->SeekTo(choice->pos, SEEK_SET);
_cur.nfo_line = choice->nfo_line;
return;
}
@ -7663,7 +7665,7 @@ static void DefineGotoLabel(ByteReader *buf)
GRFLabel *label = MallocT<GRFLabel>(1);
label->label = nfo_label;
label->nfo_line = _cur.nfo_line;
label->pos = FioGetPos();
label->pos = _cur.file->GetPos();
label->next = nullptr;
/* Set up a linked list of goto targets which we will search in an Action 0x7/0x9 */
@ -7686,8 +7688,8 @@ static void DefineGotoLabel(ByteReader *buf)
static void ImportGRFSound(SoundEntry *sound)
{
const GRFFile *file;
uint32 grfid = FioReadDword();
SoundID sound_id = FioReadWord();
uint32 grfid = _cur.file->ReadDword();
SoundID sound_id = _cur.file->ReadWord();
file = GetFileByGRFID(grfid);
if (file == nullptr || file->sound_offset == 0) {
@ -7747,6 +7749,8 @@ static void GRFSound(ByteReader *buf)
sound = GetSound(_cur.grffile->sound_offset);
}
SpriteFile &file = *_cur.file;
byte grf_container_version = file.GetContainerVersion();
for (int i = 0; i < num; i++) {
_cur.nfo_line++;
@ -7754,22 +7758,21 @@ static void GRFSound(ByteReader *buf)
* While this is invalid, we do not check for this. But we should prevent it from causing bigger trouble */
bool invalid = i >= _cur.grffile->num_sounds;
size_t offs = FioGetPos();
size_t offs = file.GetPos();
byte grf_container_version = _cur.file->GetContainerVersion();
uint32 len = grf_container_version >= 2 ? FioReadDword() : FioReadWord();
byte type = FioReadByte();
uint32 len = grf_container_version >= 2 ? file.ReadDword() : file.ReadWord();
byte type = file.ReadByte();
if (grf_container_version >= 2 && type == 0xFD) {
/* Reference to sprite section. */
if (invalid) {
grfmsg(1, "GRFSound: Sound index out of range (multiple Action 11?)");
FioSkipBytes(len);
file.SkipBytes(len);
} else if (len != 4) {
grfmsg(1, "GRFSound: Invalid sprite section import");
FioSkipBytes(len);
file.SkipBytes(len);
} else {
uint32 id = FioReadDword();
uint32 id = file.ReadDword();
if (_cur.stage == GLS_INIT) LoadGRFSound(GetGRFSpriteOffset(id), sound + i);
}
continue;
@ -7777,17 +7780,17 @@ static void GRFSound(ByteReader *buf)
if (type != 0xFF) {
grfmsg(1, "GRFSound: Unexpected RealSprite found, skipping");
FioSkipBytes(7);
file.SkipBytes(7);
SkipSpriteData(*_cur.file, type, len - 8);
continue;
}
if (invalid) {
grfmsg(1, "GRFSound: Sound index out of range (multiple Action 11?)");
FioSkipBytes(len);
file.SkipBytes(len);
}
byte action = FioReadByte();
byte action = file.ReadByte();
switch (action) {
case 0xFF:
/* Allocate sound only in init stage. */
@ -7798,23 +7801,23 @@ static void GRFSound(ByteReader *buf)
LoadGRFSound(offs, sound + i);
}
}
FioSkipBytes(len - 1); // already read <action>
file.SkipBytes(len - 1); // already read <action>
break;
case 0xFE:
if (_cur.stage == GLS_ACTIVATION) {
/* XXX 'Action 0xFE' isn't really specified. It is only mentioned for
* importing sounds, so this is probably all wrong... */
if (FioReadByte() != 0) grfmsg(1, "GRFSound: Import type mismatch");
if (file.ReadByte() != 0) grfmsg(1, "GRFSound: Import type mismatch");
ImportGRFSound(sound + i);
} else {
FioSkipBytes(len - 1); // already read <action>
file.SkipBytes(len - 1); // already read <action>
}
break;
default:
grfmsg(1, "GRFSound: Unexpected Action %x found, skipping", action);
FioSkipBytes(len - 1); // already read <action>
file.SkipBytes(len - 1); // already read <action>
break;
}
}
@ -9857,14 +9860,14 @@ static void DecodeSpecialSprite(byte *buf, uint num, GrfLoadingStage stage)
if (it == _grf_line_to_action6_sprite_override.end()) {
/* No preloaded sprite to work with; read the
* pseudo sprite content. */
FioReadBlock(buf, num);
_cur.file->ReadBlock(buf, num);
} else {
/* Use the preloaded sprite data. */
buf = it->second;
grfmsg(7, "DecodeSpecialSprite: Using preloaded pseudo sprite data");
/* Skip the real (original) content of this action. */
FioSeekTo(num, SEEK_CUR);
_cur.file->SeekTo(num, SEEK_CUR);
}
ByteReader br(buf, buf + num);
@ -9891,48 +9894,20 @@ static void DecodeSpecialSprite(byte *buf, uint num, GrfLoadingStage stage)
}
}
/**
* Load a particular NewGRF.
* @param config The configuration of the to be loaded NewGRF.
* @param file_index The Fio index of the first NewGRF to load.
* @param stage The loading stage of the NewGRF.
* @param subdir The sub directory to find the NewGRF in.
* Load a particular NewGRF from a SpriteFile.
* @param config The configuration of the to be loaded NewGRF.
* @param stage The loading stage of the NewGRF.
* @param file The file to load the GRF data from.
*/
void LoadNewGRFFile(GRFConfig *config, uint file_index, GrfLoadingStage stage, Subdirectory subdir)
static void LoadNewGRFFileFromFile(GRFConfig *config, GrfLoadingStage stage, SpriteFile &file)
{
const char *filename = config->filename;
/* A .grf file is activated only if it was active when the game was
* started. If a game is loaded, only its active .grfs will be
* reactivated, unless "loadallgraphics on" is used. A .grf file is
* considered active if its action 8 has been processed, i.e. its
* action 8 hasn't been skipped using an action 7.
*
* During activation, only actions 0, 1, 2, 3, 4, 5, 7, 8, 9, 0A and 0B are
* carried out. All others are ignored, because they only need to be
* processed once at initialization. */
if (stage != GLS_FILESCAN && stage != GLS_SAFETYSCAN && stage != GLS_LABELSCAN) {
_cur.grffile = GetFileByFilename(filename);
if (_cur.grffile == nullptr) usererror("File '%s' lost in cache.\n", filename);
if (stage == GLS_RESERVE && config->status != GCS_INITIALISED) return;
if (stage == GLS_ACTIVATION && !HasBit(config->flags, GCF_RESERVED)) return;
}
if (file_index >= MAX_FILE_SLOTS) {
DEBUG(grf, 0, "'%s' is not loaded as the maximum number of file slots has been reached", filename);
config->status = GCS_DISABLED;
config->error = new GRFError(STR_NEWGRF_ERROR_MSG_FATAL, STR_NEWGRF_ERROR_TOO_MANY_NEWGRFS_LOADED);
return;
}
_cur.file = &FioOpenFile(file_index, filename, subdir, config->palette & GRFP_USE_MASK);
config->full_filename = _cur.file->GetFilename();
_cur.file = &file;
_cur.grfconfig = config;
DEBUG(grf, 2, "LoadNewGRFFile: Reading NewGRF-file '%s'", config->GetDisplayPath());
byte grf_container_version = _cur.file->GetContainerVersion();
byte grf_container_version = file.GetContainerVersion();
if (grf_container_version == 0) {
DEBUG(grf, 7, "LoadNewGRFFile: Custom .grf has invalid format");
return;
@ -9941,15 +9916,15 @@ void LoadNewGRFFile(GRFConfig *config, uint file_index, GrfLoadingStage stage, S
if (stage == GLS_INIT || stage == GLS_ACTIVATION) {
/* We need the sprite offsets in the init stage for NewGRF sounds
* and in the activation stage for real sprites. */
ReadGRFSpriteOffsets(*_cur.file);
ReadGRFSpriteOffsets(file);
} else {
/* Skip sprite section offset if present. */
if (grf_container_version >= 2) FioReadDword();
if (grf_container_version >= 2) file.ReadDword();
}
if (grf_container_version >= 2) {
/* Read compression value. */
byte compression = FioReadByte();
byte compression = file.ReadByte();
if (compression != 0) {
DEBUG(grf, 7, "LoadNewGRFFile: Unsupported compression format");
return;
@ -9959,9 +9934,9 @@ void LoadNewGRFFile(GRFConfig *config, uint file_index, GrfLoadingStage stage, S
/* Skip the first sprite; we don't care about how many sprites this
* does contain; newest TTDPatches and George's longvehicles don't
* neither, apparently. */
uint32 num = grf_container_version >= 2 ? FioReadDword() : FioReadWord();
if (num == 4 && FioReadByte() == 0xFF) {
FioReadDword();
uint32 num = grf_container_version >= 2 ? file.ReadDword() : file.ReadWord();
if (num == 4 && file.ReadByte() == 0xFF) {
file.ReadDword();
} else {
DEBUG(grf, 7, "LoadNewGRFFile: Custom .grf has invalid format");
return;
@ -9971,8 +9946,8 @@ void LoadNewGRFFile(GRFConfig *config, uint file_index, GrfLoadingStage stage, S
ReusableBuffer<byte> buf;
while ((num = (grf_container_version >= 2 ? FioReadDword() : FioReadWord())) != 0) {
byte type = FioReadByte();
while ((num = (grf_container_version >= 2 ? file.ReadDword() : file.ReadWord())) != 0) {
byte type = file.ReadByte();
_cur.nfo_line++;
if (type == 0xFF) {
@ -9984,7 +9959,7 @@ void LoadNewGRFFile(GRFConfig *config, uint file_index, GrfLoadingStage stage, S
continue;
} else {
FioSkipBytes(num);
file.SkipBytes(num);
}
} else {
if (_cur.skip_sprites == 0) {
@ -9995,10 +9970,10 @@ void LoadNewGRFFile(GRFConfig *config, uint file_index, GrfLoadingStage stage, S
if (grf_container_version >= 2 && type == 0xFD) {
/* Reference to data section. Container version >= 2 only. */
FioSkipBytes(num);
file.SkipBytes(num);
} else {
FioSkipBytes(7);
SkipSpriteData(*_cur.file, type, num - 8);
file.SkipBytes(7);
SkipSpriteData(file, type, num - 8);
}
}
@ -10006,6 +9981,43 @@ void LoadNewGRFFile(GRFConfig *config, uint file_index, GrfLoadingStage stage, S
}
}
/**
* Load a particular NewGRF.
* @param config The configuration of the to be loaded NewGRF.
* @param stage The loading stage of the NewGRF.
* @param subdir The sub directory to find the NewGRF in.
* @param temporary The NewGRF/sprite file is to be loaded temporarily and should be closed immediately,
* contrary to loading the SpriteFile and having it cached by the SpriteCache.
*/
void LoadNewGRFFile(GRFConfig *config, GrfLoadingStage stage, Subdirectory subdir, bool temporary)
{
const char *filename = config->filename;
/* A .grf file is activated only if it was active when the game was
* started. If a game is loaded, only its active .grfs will be
* reactivated, unless "loadallgraphics on" is used. A .grf file is
* considered active if its action 8 has been processed, i.e. its
* action 8 hasn't been skipped using an action 7.
*
* During activation, only actions 0, 1, 2, 3, 4, 5, 7, 8, 9, 0A and 0B are
* carried out. All others are ignored, because they only need to be
* processed once at initialization. */
if (stage != GLS_FILESCAN && stage != GLS_SAFETYSCAN && stage != GLS_LABELSCAN) {
_cur.grffile = GetFileByFilename(filename);
if (_cur.grffile == nullptr) usererror("File '%s' lost in cache.\n", filename);
if (stage == GLS_RESERVE && config->status != GCS_INITIALISED) return;
if (stage == GLS_ACTIVATION && !HasBit(config->flags, GCF_RESERVED)) return;
}
bool needs_palette_remap = config->palette & GRFP_USE_MASK;
if (temporary) {
SpriteFile temporarySpriteFile(filename, subdir, needs_palette_remap);
LoadNewGRFFileFromFile(config, stage, temporarySpriteFile);
} else {
LoadNewGRFFileFromFile(config, stage, OpenCachedSpriteFile(filename, subdir, needs_palette_remap));
}
}
/**
* Relocates the old shore sprites at new positions.
*
@ -10301,10 +10313,9 @@ static void AfterLoadGRFs()
/**
* Load all the NewGRFs.
* @param load_index The offset for the first sprite to add.
* @param file_index The Fio index of the first NewGRF to load.
* @param num_baseset Number of NewGRFs at the front of the list to look up in the baseset dir instead of the newgrf dir.
*/
void LoadNewGRF(uint load_index, uint file_index, uint num_baseset)
void LoadNewGRF(uint load_index, uint num_baseset)
{
/* In case of networking we need to "sync" the start values
* so all NewGRFs are loaded equally. For this we use the
@ -10366,15 +10377,14 @@ void LoadNewGRF(uint load_index, uint file_index, uint num_baseset)
}
}
uint slot = file_index;
uint num_non_static = 0;
uint num_grfs = 0;
_cur.stage = stage;
for (GRFConfig *c = _grfconfig; c != nullptr; c = c->next) {
if (c->status == GCS_DISABLED || c->status == GCS_NOT_FOUND) continue;
if (stage > GLS_INIT && HasBit(c->flags, GCF_INIT_ONLY)) continue;
Subdirectory subdir = slot < file_index + num_baseset ? BASESET_DIR : NEWGRF_DIR;
Subdirectory subdir = num_grfs < num_baseset ? BASESET_DIR : NEWGRF_DIR;
if (!FioCheckFileExists(c->filename, subdir)) {
DEBUG(grf, 0, "NewGRF file is missing '%s'; disabling", c->filename);
c->status = GCS_NOT_FOUND;
@ -10383,16 +10393,15 @@ void LoadNewGRF(uint load_index, uint file_index, uint num_baseset)
if (stage == GLS_LABELSCAN) InitNewGRFFile(c);
if (!HasBit(c->flags, GCF_STATIC) && !HasBit(c->flags, GCF_SYSTEM)) {
if (slot == MAX_FILE_SLOTS) {
DEBUG(grf, 0, "'%s' is not loaded as the maximum number of non-static GRFs has been reached", c->filename);
c->status = GCS_DISABLED;
c->error = new GRFError(STR_NEWGRF_ERROR_MSG_FATAL, STR_NEWGRF_ERROR_TOO_MANY_NEWGRFS_LOADED);
continue;
}
num_non_static++;
if (num_grfs >= MAX_GRF_COUNT) {
DEBUG(grf, 0, "'%s' is not loaded as the maximum number of file slots has been reached", c->filename);
c->status = GCS_DISABLED;
c->error = new GRFError(STR_NEWGRF_ERROR_MSG_FATAL, STR_NEWGRF_ERROR_TOO_MANY_NEWGRFS_LOADED);
continue;
}
LoadNewGRFFile(c, slot++, stage, subdir);
num_grfs++;
LoadNewGRFFile(c, stage, subdir, false);
if (stage == GLS_RESERVE) {
SetBit(c->flags, GCF_RESERVED);
} else if (stage == GLS_ACTIVATION) {

@ -312,8 +312,8 @@ static inline bool HasGrfMiscBit(GrfMiscBit bit)
/* Indicates which are the newgrf features currently loaded ingame */
extern GRFLoadedFeatures _loaded_newgrf_features;
void LoadNewGRFFile(struct GRFConfig *config, uint file_index, GrfLoadingStage stage, Subdirectory subdir);
void LoadNewGRF(uint load_index, uint file_index, uint num_baseset);
void LoadNewGRFFile(struct GRFConfig *config, GrfLoadingStage stage, Subdirectory subdir, bool temporary);
void LoadNewGRF(uint load_index, uint num_baseset);
void ReloadNewGRFData(); // in saveload/afterload.cpp
void ResetNewGRFData();
void ResetPersistentNewGRFData();

@ -465,7 +465,7 @@ bool FillGRFDetails(GRFConfig *config, bool is_static, Subdirectory subdir)
}
/* Find and load the Action 8 information */
LoadNewGRFFile(config, CONFIG_SLOT, GLS_FILESCAN, subdir);
LoadNewGRFFile(config, GLS_FILESCAN, subdir, true);
config->SetSuitablePalette();
config->FinalizeParameterInfo();
@ -474,7 +474,7 @@ bool FillGRFDetails(GRFConfig *config, bool is_static, Subdirectory subdir)
if (is_static) {
/* Perform a 'safety scan' for static GRFs */
LoadNewGRFFile(config, CONFIG_SLOT, GLS_SAFETYSCAN, subdir);
LoadNewGRFFile(config, GLS_SAFETYSCAN, subdir, true);
/* GCF_UNSAFE is set if GLS_SAFETYSCAN finds unsafe actions */
if (HasBit(config->flags, GCF_UNSAFE)) return false;

Loading…
Cancel
Save