Index: src/gfxinit.cpp =================================================================== --- src/gfxinit.cpp (revision 27730) +++ src/gfxinit.cpp (working copy) @@ -230,6 +230,14 @@ LoadNewGRF(SPR_NEWGRFS_BASE, i, 2); + uint total_extra_graphics = SPR_NEWGRFS_BASE - SPR_OPENTTD_BASE; + _missing_extra_graphics = GetSpriteCountForSlot(i, SPR_OPENTTD_BASE, SPR_NEWGRFS_BASE); + DEBUG(sprite, 1, "%u extra sprites, %u from baseset, %u from fallback", total_extra_graphics, total_extra_graphics - _missing_extra_graphics, _missing_extra_graphics); + + /* The original baseset extra graphics intentionally make use of the fallback graphics. + * 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; + /* Free and remove the top element. */ delete extra; delete master; Index: src/intro_gui.cpp =================================================================== --- src/intro_gui.cpp (revision 27730) +++ src/intro_gui.cpp (working copy) @@ -60,13 +60,21 @@ virtual void OnInit() { - bool missing = _current_language->missing >= _settings_client.gui.missing_strings_threshold && !IsReleasedVersion(); - this->GetWidget(WID_SGI_TRANSLATION_SELECTION)->SetDisplayedPlane(missing ? 0 : SZSP_NONE); + bool missing_sprites = _missing_extra_graphics > 0 && !IsReleasedVersion(); + this->GetWidget(WID_SGI_BASESET_SELECTION)->SetDisplayedPlane(missing_sprites ? 0 : SZSP_NONE); + + bool missing_lang = _current_language->missing >= _settings_client.gui.missing_strings_threshold && !IsReleasedVersion(); + this->GetWidget(WID_SGI_TRANSLATION_SELECTION)->SetDisplayedPlane(missing_lang ? 0 : SZSP_NONE); } virtual void DrawWidget(const Rect &r, int widget) const { switch (widget) { + case WID_SGI_BASESET: + SetDParam(0, _missing_extra_graphics); + DrawStringMultiLine(r.left, r.right, r.top, r.bottom, STR_INTRO_BASESET, TC_FROMSTRING, SA_CENTER); + break; + case WID_SGI_TRANSLATION: SetDParam(0, _current_language->missing); DrawStringMultiLine(r.left, r.right, r.top, r.bottom, STR_INTRO_TRANSLATION, TC_FROMSTRING, SA_CENTER); @@ -76,20 +84,29 @@ virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { + StringID str = 0; switch (widget) { - case WID_SGI_TRANSLATION: { + case WID_SGI_BASESET: + SetDParam(0, _missing_extra_graphics); + str = STR_INTRO_BASESET; + break; + + case WID_SGI_TRANSLATION: SetDParam(0, _current_language->missing); - int height = GetStringHeight(STR_INTRO_TRANSLATION, size->width); - if (height > 3 * FONT_HEIGHT_NORMAL) { - /* Don't let the window become too high. */ - Dimension textdim = GetStringBoundingBox(STR_INTRO_TRANSLATION); - textdim.height *= 3; - textdim.width -= textdim.width / 2; - *size = maxdim(*size, textdim); - } else { - size->height = height + padding.height; - } + str = STR_INTRO_TRANSLATION; break; + } + + if (str != 0) { + int height = GetStringHeight(str, size->width); + if (height > 3 * FONT_HEIGHT_NORMAL) { + /* Don't let the window become too high. */ + Dimension textdim = GetStringBoundingBox(str); + textdim.height *= 3; + textdim.width -= textdim.width / 2; + *size = maxdim(*size, textdim); + } else { + size->height = height + padding.height; } } } @@ -199,6 +216,11 @@ EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 7), + NWidget(NWID_SELECTION, INVALID_COLOUR, WID_SGI_BASESET_SELECTION), + NWidget(NWID_VERTICAL), + NWidget(WWT_EMPTY, COLOUR_ORANGE, WID_SGI_BASESET), SetMinimalSize(316, 12), SetFill(1, 0), SetPadding(0, 10, 7, 10), + EndContainer(), + EndContainer(), NWidget(NWID_SELECTION, INVALID_COLOUR, WID_SGI_TRANSLATION_SELECTION), NWidget(NWID_VERTICAL), NWidget(WWT_EMPTY, COLOUR_ORANGE, WID_SGI_TRANSLATION), SetMinimalSize(316, 12), SetFill(1, 0), SetPadding(0, 10, 7, 10), Index: src/lang/english.txt =================================================================== --- src/lang/english.txt (revision 27730) +++ src/lang/english.txt (working copy) @@ -1761,6 +1761,7 @@ STR_INTRO_TOOLTIP_SCRIPT_SETTINGS :{BLACK}Display AI/Game script settings STR_INTRO_TOOLTIP_QUIT :{BLACK}Exit 'OpenTTD' +STR_INTRO_BASESET :{BLACK}The currently selected base graphics set is missing {NUM} sprite{P "" s}. Please check for updates for the baseset. STR_INTRO_TRANSLATION :{BLACK}This translation misses {NUM} string{P "" s}. Please help make OpenTTD better by signing up as translator. See readme.txt for details. # Quit window @@ -2907,8 +2908,6 @@ STR_NEWGRF_ERROR_CORRUPT_SPRITE :{YELLOW}{RAW_STRING} contains a corrupt sprite. All corrupt sprites will be shown as a red question mark (?) STR_NEWGRF_ERROR_MULTIPLE_ACTION_8 :Contains multiple Action 8 entries (sprite {3:NUM}) STR_NEWGRF_ERROR_READ_BOUNDS :Read past end of pseudo-sprite (sprite {3:NUM}) -STR_NEWGRF_ERROR_MISSING_SPRITES :{WHITE}The currently used base graphics set is missing a number of sprites.{}Please update the base graphics set -STR_NEWGRF_ERROR_MISSING_SPRITES_UNSTABLE :{WHITE}The currently used base graphics set is missing a number of sprites.{}Please update the base graphics set.{}Since you are playing a {YELLOW}development snapshot of OpenTTD{WHITE}, you might also need a {YELLOW}development snapshot of the base graphics{WHITE} STR_NEWGRF_ERROR_GRM_FAILED :Requested GRF resources not available (sprite {3:NUM}) STR_NEWGRF_ERROR_FORCEFULLY_DISABLED :{1:RAW_STRING} was disabled by {2:RAW_STRING} STR_NEWGRF_ERROR_INVALID_SPRITE_LAYOUT :Invalid/unknown sprite layout format (sprite {3:NUM}) Index: src/newgrf.cpp =================================================================== --- src/newgrf.cpp (revision 27730) +++ src/newgrf.cpp (working copy) @@ -5694,35 +5694,6 @@ } /** - * Check whether we are (obviously) missing some of the extra - * (Action 0x05) sprites that we like to use. - * When missing sprites are found a warning will be shown. - */ -void CheckForMissingSprites() -{ - /* Don't break out quickly, but allow to check the other - * sprites as well, so we can give the best information. */ - bool missing = false; - for (uint8 i = 0; i < lengthof(_action5_types); i++) { - const Action5Type *type = &_action5_types[i]; - if (type->block_type == A5BLOCK_INVALID) continue; - - for (uint j = 0; j < type->max_sprites; j++) { - if (!SpriteExists(type->sprite_base + j)) { - DEBUG(grf, 0, "%s sprites are missing", type->name); - missing = true; - /* No need to log more of the same. */ - break; - } - } - } - - if (missing) { - ShowErrorMessage(IsReleasedVersion() ? STR_NEWGRF_ERROR_MISSING_SPRITES : STR_NEWGRF_ERROR_MISSING_SPRITES_UNSTABLE, INVALID_STRING_ID, WL_CRITICAL); - } -} - -/** * Reads a variable common to VarAction2 and Action7/9/D. * * Returns VarAction2 variable 'param' resp. Action7/9/D variable '0x80 + param'. Index: src/newgrf_config.cpp =================================================================== --- src/newgrf_config.cpp (revision 27730) +++ src/newgrf_config.cpp (working copy) @@ -192,6 +192,7 @@ GRFConfig *_grfconfig; GRFConfig *_grfconfig_newgame; GRFConfig *_grfconfig_static; +uint _missing_extra_graphics = 0; /** * Construct a new GRFError. Index: src/newgrf_config.h =================================================================== --- src/newgrf_config.h (revision 27730) +++ src/newgrf_config.h (working copy) @@ -202,6 +202,7 @@ extern GRFConfig *_grfconfig; ///< First item in list of current GRF set up extern GRFConfig *_grfconfig_newgame; ///< First item in list of default GRF set up extern GRFConfig *_grfconfig_static; ///< First item in list of static GRF set up +extern uint _missing_extra_graphics; ///< Number of sprites provided by the fallback extra GRF, i.e. missing in the baseset. /** Callback for NewGRF scanning. */ struct NewGRFScanCallback { @@ -214,7 +215,6 @@ size_t GRFGetSizeOfDataSection(FILE *f); void ScanNewGRFFiles(NewGRFScanCallback *callback); -void CheckForMissingSprites(); const GRFConfig *FindGRFConfig(uint32 grfid, FindGRFConfigMode mode, const uint8 *md5sum = NULL, uint32 desired_version = 0); GRFConfig *GetGRFConfig(uint32 grfid, uint32 mask = 0xFFFFFFFF); GRFConfig **CopyGRFConfigList(GRFConfig **dst, const GRFConfig *src, bool init_only); Index: src/openttd.cpp =================================================================== --- src/openttd.cpp (revision 27730) +++ src/openttd.cpp (working copy) @@ -339,7 +339,6 @@ _pause_mode = PM_UNPAUSED; _cursor.fix_at = false; - if (load_newgrfs) CheckForMissingSprites(); CheckForMissingGlyphs(); /* Play main theme */ Index: src/script/api/game/game_window.hpp.sq =================================================================== --- src/script/api/game/game_window.hpp.sq (revision 27730) +++ src/script/api/game/game_window.hpp.sq (working copy) @@ -582,6 +582,8 @@ SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_ARCTIC_LANDSCAPE, "WID_SGI_ARCTIC_LANDSCAPE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_TROPIC_LANDSCAPE, "WID_SGI_TROPIC_LANDSCAPE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_TOYLAND_LANDSCAPE, "WID_SGI_TOYLAND_LANDSCAPE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_BASESET_SELECTION, "WID_SGI_BASESET_SELECTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_BASESET, "WID_SGI_BASESET"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_TRANSLATION_SELECTION, "WID_SGI_TRANSLATION_SELECTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_TRANSLATION, "WID_SGI_TRANSLATION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_OPTIONS, "WID_SGI_OPTIONS"); Index: src/script/api/script_window.hpp =================================================================== --- src/script/api/script_window.hpp (revision 27730) +++ src/script/api/script_window.hpp (working copy) @@ -1497,8 +1497,10 @@ WID_SGI_ARCTIC_LANDSCAPE = ::WID_SGI_ARCTIC_LANDSCAPE, ///< Select arctic landscape button. WID_SGI_TROPIC_LANDSCAPE = ::WID_SGI_TROPIC_LANDSCAPE, ///< Select tropic landscape button. WID_SGI_TOYLAND_LANDSCAPE = ::WID_SGI_TOYLAND_LANDSCAPE, ///< Select toyland landscape button. + WID_SGI_BASESET_SELECTION = ::WID_SGI_BASESET_SELECTION, ///< Baseset selection. + WID_SGI_BASESET = ::WID_SGI_BASESET, ///< Baseset errors. WID_SGI_TRANSLATION_SELECTION = ::WID_SGI_TRANSLATION_SELECTION, ///< Translation selection. - WID_SGI_TRANSLATION = ::WID_SGI_TRANSLATION, ///< Translation. + WID_SGI_TRANSLATION = ::WID_SGI_TRANSLATION, ///< Translation errors. WID_SGI_OPTIONS = ::WID_SGI_OPTIONS, ///< Options button. WID_SGI_HIGHSCORE = ::WID_SGI_HIGHSCORE, ///< Highscore button. WID_SGI_SETTINGS_OPTIONS = ::WID_SGI_SETTINGS_OPTIONS, ///< Settings button. Index: src/spritecache.cpp =================================================================== --- src/spritecache.cpp (revision 27730) +++ src/spritecache.cpp (working copy) @@ -150,6 +150,25 @@ } /** + * Count the sprites which originate from a specific file slot in a range of SpriteIDs. + * @param file_slot FIOS file slot. + * @param begin First sprite in range. + * @param end First sprite not in range. + * @return Number of sprites. + */ +uint GetSpriteCountForSlot(uint file_slot, SpriteID begin, SpriteID end) +{ + uint count = 0; + for (SpriteID i = begin; i != end; i++) { + if (SpriteExists(i)) { + SpriteCache *sc = GetSpriteCache(i); + if (sc->file_slot == file_slot) count++; + } + } + return count; +} + +/** * Get a reasonable (upper bound) estimate of the maximum * SpriteID used in OpenTTD; there will be no sprites with * a higher SpriteID, although there might be up to roughly Index: src/spritecache.h =================================================================== --- src/spritecache.h (revision 27730) +++ src/spritecache.h (working copy) @@ -32,6 +32,7 @@ SpriteType GetSpriteType(SpriteID sprite); uint GetOriginFileSlot(SpriteID sprite); +uint GetSpriteCountForSlot(uint file_slot, SpriteID begin, SpriteID end); uint GetMaxSpriteID(); Index: src/widgets/intro_widget.h =================================================================== --- src/widgets/intro_widget.h (revision 27730) +++ src/widgets/intro_widget.h (working copy) @@ -24,8 +24,10 @@ WID_SGI_ARCTIC_LANDSCAPE, ///< Select arctic landscape button. WID_SGI_TROPIC_LANDSCAPE, ///< Select tropic landscape button. WID_SGI_TOYLAND_LANDSCAPE, ///< Select toyland landscape button. + WID_SGI_BASESET_SELECTION, ///< Baseset selection. + WID_SGI_BASESET, ///< Baseset errors. WID_SGI_TRANSLATION_SELECTION, ///< Translation selection. - WID_SGI_TRANSLATION, ///< Translation. + WID_SGI_TRANSLATION, ///< Translation errors. WID_SGI_OPTIONS, ///< Options button. WID_SGI_HIGHSCORE, ///< Highscore button. WID_SGI_SETTINGS_OPTIONS, ///< Settings button.