diff --git a/newgrf.c b/newgrf.c index ed757edf52..eb942a913f 100644 --- a/newgrf.c +++ b/newgrf.c @@ -2471,8 +2471,8 @@ static void SkipIf(byte *buf, int len) } -/* Action 0x08 (GLS_FILESCAN) */ -static void ScanInfo(byte *buf, int len) +/* Action 0x08 (GLS_SAFETYSCAN) */ +static void SafeInfo(byte *buf, int len) { uint8 version; uint32 grfid; @@ -2487,6 +2487,9 @@ static void ScanInfo(byte *buf, int len) _cur_grfconfig->grfid = grfid; + /* GRF IDs starting with 0xFF are reserved for internal TTDPatch use */ + if (GB(grfid, 24, 8) == 0xFF) SETBIT(_cur_grfconfig->flags, GCF_SYSTEM); + len -= 6; name = (const char*)buf; name_len = ttd_strnlen(name, len); @@ -2502,7 +2505,14 @@ static void ScanInfo(byte *buf, int len) _cur_grfconfig->info = TranslateTTDPatchCodes(info); } } +} +/* Action 0x08 (GLS_INFOSCAN) */ +static void ScanInfo(byte *buf, int len) +{ + SafeInfo(buf, len); + + /* GLS_INFOSCAN only looks for the action 8, so we can skip the rest of the file */ _skip_sprites = -1; } @@ -3177,6 +3187,17 @@ static void GRFDataBlock(byte *buf, int len) } } + +/* Used during safety scan on unsafe actions */ +static void GRFUnsafe(byte *buf, int len) +{ + SETBIT(_cur_grfconfig->flags, GCF_UNSAFE); + + /* Skip remainder of GRF if GRF ID is set */ + if (_cur_grfconfig->grfid != 0) _skip_sprites = -1; +} + + static void InitializeGRFSpecial(void) { _ttdpatch_flags[0] = ((_patches.always_small_airport ? 1 : 0) << 0x0C) // keepsmallairport @@ -3517,25 +3538,25 @@ static void DecodeSpecialSprite(uint num, GrfLoadingStage stage) * is not in memory and scanning the file every time would be too expensive. * In other stages we skip action 0x10 since it's already dealt with. */ static const SpecialSpriteHandler handlers[][GLS_END] = { - /* 0x00 */ { NULL, NULL, NULL, FeatureChangeInfo, }, - /* 0x01 */ { NULL, NULL, NULL, NewSpriteSet, }, - /* 0x02 */ { NULL, NULL, NULL, NewSpriteGroup, }, - /* 0x03 */ { NULL, NULL, NULL, FeatureMapSpriteGroup, }, - /* 0x04 */ { NULL, NULL, NULL, FeatureNewName, }, - /* 0x05 */ { NULL, NULL, NULL, GraphicsNew, }, - /* 0x06 */ { NULL, NULL, CfgApply, CfgApply, }, - /* 0x07 */ { NULL, NULL, NULL, SkipIf, }, - /* 0x08 */ { ScanInfo, NULL, GRFInfo, GRFInfo, }, - /* 0x09 */ { NULL, NULL, SkipIf, SkipIf, }, - /* 0x0A */ { NULL, NULL, NULL, SpriteReplace, }, - /* 0x0B */ { NULL, NULL, GRFError, GRFError, }, - /* 0x0C */ { NULL, NULL, GRFComment, GRFComment, }, - /* 0x0D */ { NULL, NULL, ParamSet, ParamSet, }, - /* 0x0E */ { NULL, NULL, GRFInhibit, GRFInhibit, }, - /* 0x0F */ { NULL, NULL, NULL, NULL, }, - /* 0x10 */ { NULL, DefineGotoLabel, NULL, NULL, }, - /* 0x11 */ { NULL, NULL, NULL, GRFSound, }, - /* 0x12 */ { NULL, NULL, NULL, LoadFontGlyph, }, + /* 0x00 */ { NULL, GRFUnsafe, NULL, NULL, FeatureChangeInfo, }, + /* 0x01 */ { NULL, GRFUnsafe, NULL, NULL, NewSpriteSet, }, + /* 0x02 */ { NULL, GRFUnsafe, NULL, NULL, NewSpriteGroup, }, + /* 0x03 */ { NULL, GRFUnsafe, NULL, NULL, FeatureMapSpriteGroup, }, + /* 0x04 */ { NULL, NULL, NULL, NULL, FeatureNewName, }, + /* 0x05 */ { NULL, NULL, NULL, NULL, GraphicsNew, }, + /* 0x06 */ { NULL, NULL, NULL, CfgApply, CfgApply, }, + /* 0x07 */ { NULL, NULL, NULL, NULL, SkipIf, }, + /* 0x08 */ { ScanInfo, SafeInfo, NULL, GRFInfo, GRFInfo, }, + /* 0x09 */ { NULL, NULL, NULL, SkipIf, SkipIf, }, + /* 0x0A */ { NULL, NULL, NULL, NULL, SpriteReplace, }, + /* 0x0B */ { NULL, NULL, NULL, GRFError, GRFError, }, + /* 0x0C */ { NULL, NULL, NULL, GRFComment, GRFComment, }, + /* 0x0D */ { NULL, GRFUnsafe, NULL, ParamSet, ParamSet, }, + /* 0x0E */ { NULL, GRFUnsafe, NULL, GRFInhibit, GRFInhibit, }, + /* 0x0F */ { NULL, NULL, NULL, NULL, NULL, }, + /* 0x10 */ { NULL, NULL, DefineGotoLabel, NULL, NULL, }, + /* 0x11 */ { NULL, GRFUnsafe, NULL, NULL, GRFSound, }, + /* 0x12 */ { NULL, NULL, NULL, NULL, LoadFontGlyph, }, }; byte* buf; @@ -3591,7 +3612,7 @@ void LoadNewGRFFile(GRFConfig *config, uint file_index, GrfLoadingStage stage) * 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_LABELSCAN) { + if (stage != GLS_FILESCAN && stage != GLS_SAFETYSCAN && stage != GLS_LABELSCAN) { _cur_grffile = GetFileByFilename(filename); if (_cur_grffile == NULL) error("File ``%s'' lost in cache.\n", filename); if (stage == GLS_ACTIVATION && !HASBIT(config->flags, GCF_ACTIVATED)) return; diff --git a/newgrf.h b/newgrf.h index 77ed2f5bf9..4d57ff4c9f 100644 --- a/newgrf.h +++ b/newgrf.h @@ -8,6 +8,7 @@ typedef enum GrfLoadingStage { GLS_FILESCAN, + GLS_SAFETYSCAN, GLS_LABELSCAN, GLS_INIT, GLS_ACTIVATION, diff --git a/newgrf_config.c b/newgrf_config.c index ac7b60fd5b..ef607c2b87 100644 --- a/newgrf_config.c +++ b/newgrf_config.c @@ -28,6 +28,7 @@ GRFConfig *_all_grfs; GRFConfig *_grfconfig; GRFConfig *_grfconfig_newgame; +GRFConfig *_grfconfig_static; /* Calculate the MD5 Sum for a GRF */ @@ -58,7 +59,7 @@ static bool CalcGRFMD5Sum(GRFConfig *config) /* Find the GRFID and calculate the md5sum */ -bool FillGRFDetails(GRFConfig *config) +bool FillGRFDetails(GRFConfig *config, bool is_static) { if (!FioCheckFileExists(config->filename)) { SETBIT(config->flags, GCF_NOT_FOUND); @@ -68,7 +69,10 @@ bool FillGRFDetails(GRFConfig *config) /* Find and load the Action 8 information */ /* 62 is the last file slot before sample.cat. * Should perhaps be some "don't care" value */ - LoadNewGRFFile(config, 62, GLS_FILESCAN); + LoadNewGRFFile(config, 62, is_static ? GLS_SAFETYSCAN : GLS_FILESCAN); + + /* GCF_UNSAFE is set if GLS_SAFETYSCAN finds unsafe actions */ + if (HASBIT(config->flags, GCF_UNSAFE)) return false; /* Skip if the grfid is 0 (not read) or 0xFFFFFFFF (ttdp system grf) */ if (config->grfid == 0 || config->grfid == 0xFFFFFFFF) return false; @@ -77,22 +81,28 @@ bool FillGRFDetails(GRFConfig *config) } +void ClearGRFConfig(GRFConfig *config) +{ + free(config->filename); + free(config->name); + free(config->info); + free(config); +} + + /* Clear a GRF Config list */ void ClearGRFConfigList(GRFConfig *config) { GRFConfig *c, *next; for (c = config; c != NULL; c = next) { next = c->next; - free(c->filename); - free(c->name); - free(c->info); - free(c); + ClearGRFConfig(c); } } /* Copy a GRF Config list */ -static void CopyGRFConfigList(GRFConfig **dst, GRFConfig *src) +static GRFConfig **CopyGRFConfigList(GRFConfig **dst, GRFConfig *src) { GRFConfig *c; @@ -106,15 +116,21 @@ static void CopyGRFConfigList(GRFConfig **dst, GRFConfig *src) *dst = c; dst = &c->next; } + + return dst; } /* Reset the current GRF Config to either blank or newgame settings */ void ResetGRFConfig(bool defaults) { + GRFConfig **c = &_grfconfig; + ClearGRFConfigList(_grfconfig); _grfconfig = NULL; - if (defaults) CopyGRFConfigList(&_grfconfig, _grfconfig_newgame); + + if (defaults) c = CopyGRFConfigList(c, _grfconfig_newgame); + CopyGRFConfigList(c, _grfconfig_static); } @@ -138,7 +154,7 @@ bool IsGoodGRFConfigList(void) res = false; } else { - DEBUG(grf, 1) ("[GRF] Loading GRF %X from %s", BSWAP32(c->grfid), f->filename); + DEBUG(grf, 1) ("[GRF] Loading GRF %08X from %s", BSWAP32(c->grfid), f->filename); c->filename = strdup(f->filename); c->name = strdup(f->name); c->info = strdup(f->info); @@ -186,7 +202,7 @@ static uint ScanPath(const char *path) c = calloc(1, sizeof(*c)); c->filename = strdup(file); - if (FillGRFDetails(c)) { + if (FillGRFDetails(c, false)) { if (_all_grfs == NULL) { _all_grfs = c; } else { @@ -294,6 +310,7 @@ static void Save_NGRF(void) int index = 0; for (c = _grfconfig; c != NULL; c = c->next) { + if (HASBIT(c->flags, GCF_STATIC)) continue; SlSetArrayIndex(index++); SlObject(c, _grfconfig_desc); } @@ -314,6 +331,9 @@ static void Load_NGRF(void) last = &c->next; } + /* Append static NewGRF configuration */ + CopyGRFConfigList(last, _grfconfig_static); + ClearGRFConfigList(_grfconfig); _grfconfig = first; } diff --git a/newgrf_config.h b/newgrf_config.h index 45d0e270da..cb490ebad8 100644 --- a/newgrf_config.h +++ b/newgrf_config.h @@ -8,6 +8,9 @@ enum { GCF_DISABLED, GCF_NOT_FOUND, GCF_ACTIVATED, + GCF_SYSTEM, + GCF_UNSAFE, + GCF_STATIC, }; typedef struct GRFConfig { @@ -33,13 +36,17 @@ extern GRFConfig *_grfconfig; /* First item in list of default GRF set up */ extern GRFConfig *_grfconfig_newgame; +/* First item in list of static GRF set up */ +extern GRFConfig *_grfconfig_static; + void ScanNewGRFFiles(void); const GRFConfig *FindGRFConfig(uint32 grfid, uint8 *md5sum); const GRFConfig *GetGRFConfig(uint32 grfid); +void ClearGRFConfig(GRFConfig *config); void ClearGRFConfigList(GRFConfig *config); void ResetGRFConfig(bool defaults); bool IsGoodGRFConfigList(void); -bool FillGRFDetails(GRFConfig *config); +bool FillGRFDetails(GRFConfig *config, bool is_static); char *GRFBuildParamList(char *dst, const GRFConfig *c, const char *last); /* In newgrf_gui.c */ diff --git a/newgrf_gui.c b/newgrf_gui.c index c2e76a0212..b31c0b177b 100644 --- a/newgrf_gui.c +++ b/newgrf_gui.c @@ -274,6 +274,8 @@ static void NewGRFWndProc(Window *w, WindowEvent *e) /* Pick a colour */ if (HASBIT(c->flags, GCF_NOT_FOUND) || HASBIT(c->flags, GCF_DISABLED)) { pal = PALETTE_TO_RED; + } else if (HASBIT(c->flags, GCF_STATIC)) { + pal = PALETTE_TO_YELLOW; } else if (HASBIT(c->flags, GCF_ACTIVATED)) { pal = PALETTE_TO_GREEN; } else { diff --git a/settings.c b/settings.c index ee1f8e6756..498f5d2f10 100644 --- a/settings.c +++ b/settings.c @@ -1495,41 +1495,62 @@ static const SettingDesc _currency_settings[] = { #undef NO #undef CR -static const char *GRFProcessParams(const IniItem *item, uint index) + +/* Load a GRF configuration from the given group name */ +static GRFConfig *GRFLoadConfig(IniFile *ini, const char *grpname, bool is_static) { - GRFConfig *c; + IniGroup *group = ini_getgroup(ini, grpname, -1); + IniItem *item; + GRFConfig *first = NULL; + GRFConfig **curr = &first; - /* Saving newgrf stuff to configuration, not done since it is kept the same */ - if (item == NULL) return NULL; + if (group == NULL) return NULL; - /* Loading newgrf stuff from configuration file */ - c = calloc(1, sizeof(*c)); - c->filename = strdup(item->name); - if (!FillGRFDetails(c)) { - ShowInfoF("ini: ignoring invalid NewGRF '%s'", c->filename); - return NULL; - } + for (item = group->item; item != NULL; item = item->next) { + GRFConfig *c = calloc(1, sizeof(*c)); + c->filename = strdup(item->name); - if (*item->value != '\0') { - c->num_params = parse_intlist(item->value, (int*)c->param, lengthof(c->param)); - if (c->num_params == (byte)-1) { - ShowInfoF("ini: error in array '%s'", item->name); - c->num_params = 0; + /* Parse parameters */ + if (*item->value != '\0') { + c->num_params = parse_intlist(item->value, (int*)c->param, lengthof(c->param)); + if (c->num_params == (byte)-1) { + ShowInfoF("ini: error in array '%s'", item->name); + c->num_params = 0; + } } + + /* Check if item is valid */ + if (!FillGRFDetails(c, is_static)) { + const char *msg; + + if (HASBIT(c->flags, GCF_NOT_FOUND)) { + msg = "not found"; + } else if (HASBIT(c->flags, GCF_UNSAFE)) { + msg = "unsafe for static use"; + } else if (HASBIT(c->flags, GCF_SYSTEM)) { + msg = "system NewGRF"; + } else { + msg = "unknown"; + } + + ShowInfoF("ini: ignoring invalid NewGRF '%s': %s", item->name, msg); + ClearGRFConfig(c); + continue; + } + + /* Mark file as static to avoid saving in savegame. */ + if (is_static) SETBIT(c->flags, GCF_STATIC); + + /* Add item to list */ + *curr = c; + curr = &c->next; } - if (_grfconfig_newgame == NULL) { - _grfconfig_newgame = c; - } else { - GRFConfig *c2; - /* Attach the label to the end of the list */ - for (c2 = _grfconfig_newgame; c2->next != NULL; c2 = c2->next); - c2->next = c; - } - - return c->filename; + return first; } + +/* Save a GRF configuration to the given group name */ static void GRFSaveConfig(IniFile *ini, const char *grpname, const GRFConfig *list) { IniGroup *group = ini_getgroup(ini, grpname, -1); @@ -1575,7 +1596,8 @@ void LoadFromConfig(void) { IniFile *ini = ini_load(_config_file); HandleSettingDescs(ini, ini_load_settings, ini_load_setting_list); - ini_load_setting_list(ini, "newgrf", NULL, 0, GRFProcessParams); + _grfconfig_newgame = GRFLoadConfig(ini, "newgrf", false); + _grfconfig_static = GRFLoadConfig(ini, "newgrf-static", true); ini_free(ini); } @@ -1585,6 +1607,7 @@ void SaveToConfig(void) IniFile *ini = ini_load(_config_file); HandleSettingDescs(ini, ini_save_settings, ini_save_setting_list); GRFSaveConfig(ini, "newgrf", _grfconfig_newgame); + GRFSaveConfig(ini, "newgrf-static", _grfconfig_static); ini_save(_config_file, ini); ini_free(ini); }