From 2da34ec3d621ce77d12127fd269e7ac8cc7a8af2 Mon Sep 17 00:00:00 2001 From: rubidium Date: Mon, 9 Aug 2010 21:48:19 +0000 Subject: [PATCH] (svn r20430) [1.0] -Backport from trunk: - Fix: Initialize fund-industry buttons when opening window (r20386) - Fix: Update cursor dimensions when reloading grfs resp. changing base graphics, so the cursor does not glitch if it becomes bigger (r20384) - Fix: Stop vehicle following after zooming out [FS#3989] (r20361) - Fix: [NoAI] Ship depots were constructed along the wrong axis [FS#4004] (r20348) - Fix: When it is known the loading an old savegame is going to fail, bail out immediately (using an exception) instead of going on until e.g. the expected number of byte is read (r20247) --- src/ai/api/ai_marine.cpp | 2 +- src/ai/api/ai_marine.hpp | 1 + src/fontcache.h | 1 + src/gfx.cpp | 40 ++++++++-- src/gfx_func.h | 1 + src/gfxinit.cpp | 2 + src/industry_gui.cpp | 1 + src/saveload/oldloader.cpp | 18 +++-- src/saveload/oldloader.h | 1 - src/saveload/oldloader_sl.cpp | 18 +++-- src/strings.cpp | 137 +++++++++++++++++----------------- 11 files changed, 134 insertions(+), 88 deletions(-) diff --git a/src/ai/api/ai_marine.cpp b/src/ai/api/ai_marine.cpp index 07de889da1..532d04d4df 100644 --- a/src/ai/api/ai_marine.cpp +++ b/src/ai/api/ai_marine.cpp @@ -77,7 +77,7 @@ EnforcePrecondition(false, ::IsValidTile(front)); EnforcePrecondition(false, (::TileX(front) == ::TileX(tile)) != (::TileY(front) == ::TileY(tile))); - return AIObject::DoCommand(tile, ::TileY(front) == ::TileY(tile), 0, CMD_BUILD_SHIP_DEPOT); + return AIObject::DoCommand(tile, ::TileX(front) == ::TileX(tile), 0, CMD_BUILD_SHIP_DEPOT); } /* static */ bool AIMarine::BuildDock(TileIndex tile, StationID station_id) diff --git a/src/ai/api/ai_marine.hpp b/src/ai/api/ai_marine.hpp index 19bc4b1d98..c97961d563 100644 --- a/src/ai/api/ai_marine.hpp +++ b/src/ai/api/ai_marine.hpp @@ -106,6 +106,7 @@ public: * @exception AIMarine::ERR_MARINE_MUST_BE_BUILT_ON_WATER * @return Whether the water depot has been/can be build or not. * @note A WaterDepot is 1 tile in width, and 2 tiles in length. + * @note The depot will be built towards the south from 'tile', not necessarily towards 'front'. */ static bool BuildWaterDepot(TileIndex tile, TileIndex front); diff --git a/src/fontcache.h b/src/fontcache.h index affc2606c4..b4bdc7a993 100644 --- a/src/fontcache.h +++ b/src/fontcache.h @@ -53,6 +53,7 @@ uint GetGlyphWidth(FontSize size, uint32 key); * @param settings the settings to overwrite the fontname of. * @param language_isocode the language, e.g. en_GB. * @param winlangid the language ID windows style. + * @param str Sample string. * @return true if a font has been set, false otherwise. */ bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, int winlangid, const char *str); diff --git a/src/gfx.cpp b/src/gfx.cpp index c8e9229f20..d84ab8b3c5 100644 --- a/src/gfx.cpp +++ b/src/gfx.cpp @@ -1645,22 +1645,37 @@ bool FillDrawPixelInfo(DrawPixelInfo *n, int left, int top, int width, int heigh return true; } -static void SetCursorSprite(CursorID cursor, PaletteID pal) +/** + * Update cursor dimension. + * Called when changing cursor sprite resp. reloading grfs. + */ +void UpdateCursorSize() { CursorVars *cv = &_cursor; - const Sprite *p; + const Sprite *p = GetSprite(GB(cv->sprite, 0, SPRITE_WIDTH), ST_NORMAL); - if (cv->sprite == cursor) return; - - p = GetSprite(GB(cursor, 0, SPRITE_WIDTH), ST_NORMAL); - cv->sprite = cursor; - cv->pal = pal; cv->size.y = p->height; cv->size.x = p->width; cv->offs.x = p->x_offs; cv->offs.y = p->y_offs; cv->dirty = true; +} + +/** + * Switch cursor to different sprite. + * @param cursor Sprite to draw for the cursor. + * @param pal Palette to use for recolouring. + */ +static void SetCursorSprite(CursorID cursor, PaletteID pal) +{ + CursorVars *cv = &_cursor; + if (cv->sprite == cursor) return; + + cv->sprite = cursor; + cv->pal = pal; + UpdateCursorSize(); + cv->short_vehicle_offset = 0; } @@ -1682,6 +1697,12 @@ void CursorTick() SwitchAnimatedCursor(); } +/** + * Assign a single non-animated sprite to the cursor. + * @param sprite Sprite to draw for the cursor. + * @param pal Palette to use for recolouring. + * @see SetAnimatedMouseCursor + */ void SetMouseCursor(CursorID sprite, PaletteID pal) { /* Turn off animation */ @@ -1690,6 +1711,11 @@ void SetMouseCursor(CursorID sprite, PaletteID pal) SetCursorSprite(sprite, pal); } +/** + * Assign an animation to the cursor. + * @param table Array of animation states. + * @see SetMouseCursor + */ void SetAnimatedMouseCursor(const AnimCursor *table) { _cursor.animate_list = table; diff --git a/src/gfx_func.h b/src/gfx_func.h index 5f7bee2fae..5bcdd48302 100644 --- a/src/gfx_func.h +++ b/src/gfx_func.h @@ -152,6 +152,7 @@ void DrawOverlappedWindowForAll(int left, int top, int right, int bottom); void SetMouseCursor(CursorID cursor, PaletteID pal); void SetAnimatedMouseCursor(const AnimCursor *table); void CursorTick(); +void UpdateCursorSize(); bool ChangeResInGame(int w, int h); void SortResolutions(int count); bool ToggleFullScreen(bool fs); diff --git a/src/gfxinit.cpp b/src/gfxinit.cpp index 998ba3128a..5cda582b4b 100644 --- a/src/gfxinit.cpp +++ b/src/gfxinit.cpp @@ -201,6 +201,8 @@ void GfxLoadSprites() GfxInitSpriteMem(); LoadSpriteTables(); GfxInitPalettes(); + + UpdateCursorSize(); } bool GraphicsSet::FillSetDetails(IniFile *ini, const char *path, const char *full_filename) diff --git a/src/industry_gui.cpp b/src/industry_gui.cpp index c165ae5387..6de0309f68 100644 --- a/src/industry_gui.cpp +++ b/src/industry_gui.cpp @@ -206,6 +206,7 @@ public: this->callback_timer = DAY_TICKS; this->InitNested(&_build_industry_desc, 0); + this->SetWidgetDisabledState(DPIW_FUND_WIDGET, !this->enabled[this->selected_index]); } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) diff --git a/src/saveload/oldloader.cpp b/src/saveload/oldloader.cpp index c7cff72798..f921945279 100644 --- a/src/saveload/oldloader.cpp +++ b/src/saveload/oldloader.cpp @@ -21,6 +21,7 @@ #include "saveload_internal.h" #include "oldloader.h" +#include enum { TTO_HEADER_SIZE = 41, @@ -51,13 +52,14 @@ static byte ReadByteFromFile(LoadgameState *ls) /* To avoid slow reads, we read BUFFER_SIZE of bytes per time and just return a byte per time */ if (ls->buffer_cur >= ls->buffer_count) { + /* Read some new bytes from the file */ int count = (int)fread(ls->buffer, 1, BUFFER_SIZE, ls->file); /* We tried to read, but there is nothing in the file anymore.. */ if (count == 0) { DEBUG(oldloader, 0, "Read past end of file, loading failed"); - ls->failed = true; + throw std::exception(); } ls->buffer_count = count; @@ -121,8 +123,6 @@ bool LoadChunk(LoadgameState *ls, void *base, const OldChunks *chunks) if (chunk->type & OC_DEREFERENCE_POINTER) ptr = *(byte**)ptr; for (uint i = 0; i < chunk->amount; i++) { - if (ls->failed) return false; - /* Handle simple types */ if (GetOldChunkType(chunk->type) != 0) { switch (GetOldChunkType(chunk->type)) { @@ -137,7 +137,7 @@ bool LoadChunk(LoadgameState *ls, void *base, const OldChunks *chunks) case OC_ASSERT: DEBUG(oldloader, 4, "Assert point: 0x%X / 0x%X", ls->total_read, chunk->offset + _bump_assert_value); - if (ls->total_read != chunk->offset + _bump_assert_value) ls->failed = true; + if (ls->total_read != chunk->offset + _bump_assert_value) throw std::exception(); default: break; } } else { @@ -191,7 +191,6 @@ static void InitLoading(LoadgameState *ls) { ls->chunk_size = 0; ls->total_read = 0; - ls->failed = false; ls->decoding = false; ls->decode_char = 0; @@ -303,7 +302,14 @@ bool LoadOldSaveGame(const char *file) _savegame_type = type; - if (proc == NULL || !proc(&ls)) { + bool game_loaded; + try { + game_loaded = proc != NULL && proc(&ls); + } catch (...) { + game_loaded = false; + } + + if (!game_loaded) { SetSaveLoadError(STR_GAME_SAVELOAD_ERROR_DATA_INTEGRITY_CHECK_FAILED); fclose(ls.file); return false; diff --git a/src/saveload/oldloader.h b/src/saveload/oldloader.h index d1908e1364..8bddcad17f 100644 --- a/src/saveload/oldloader.h +++ b/src/saveload/oldloader.h @@ -33,7 +33,6 @@ struct LoadgameState { byte buffer[BUFFER_SIZE]; uint total_read; - bool failed; }; /* OldChunk-Type */ diff --git a/src/saveload/oldloader_sl.cpp b/src/saveload/oldloader_sl.cpp index e45a7876a4..777fa25899 100644 --- a/src/saveload/oldloader_sl.cpp +++ b/src/saveload/oldloader_sl.cpp @@ -1479,7 +1479,7 @@ static bool LoadOldMapPart1(LoadgameState *ls, int num) } } - return !ls->failed; + return true; } static bool LoadOldMapPart2(LoadgameState *ls, int num) @@ -1493,7 +1493,7 @@ static bool LoadOldMapPart2(LoadgameState *ls, int num) _m[i].m5 = ReadByte(ls); } - return !ls->failed; + return true; } static bool LoadTTDPatchExtraChunks(LoadgameState *ls, int num) @@ -1549,7 +1549,7 @@ static bool LoadTTDPatchExtraChunks(LoadgameState *ls, int num) } } - return !ls->failed; + return true; } extern TileIndex _cur_tileloop_tile; @@ -1733,11 +1733,17 @@ bool LoadTTDMain(LoadgameState *ls) SmallStackSafeStackAlloc map3; _old_map3 = map3.data; _old_vehicle_names = NULL; - if (!LoadChunk(ls, NULL, main_chunk)) { - DEBUG(oldloader, 0, "Loading failed"); + try { + if (!LoadChunk(ls, NULL, main_chunk)) { + DEBUG(oldloader, 0, "Loading failed"); + free(_old_vehicle_names); + return false; + } + } catch (...) { free(_old_vehicle_names); - return false; + throw; } + DEBUG(oldloader, 3, "Done, converting game data..."); FixTTDMapArray(); diff --git a/src/strings.cpp b/src/strings.cpp index 834bb52719..8a8c167cc8 100644 --- a/src/strings.cpp +++ b/src/strings.cpp @@ -1527,6 +1527,38 @@ const char *GetCurrentLanguageIsoCode() return _langpack->isocode; } +/** + * Check whether there are glyphs missing in the current language. + * @param Pointer to an address for storing the text pointer. + * @return If glyphs are missing, return \c true, else return \false. + * @pre *str must not be \c NULL. + * @post If \c true is returned, *str points to a string that is found to contain at least one missing glyph. + */ +static bool FindMissingGlyphs(const char **str) +{ + const Sprite *question_mark = GetGlyph(FS_NORMAL, '?'); + for (uint i = 0; i != 32; i++) { + for (uint j = 0; j < _langtab_num[i]; j++) { + const char *text = _langpack_offs[_langtab_start[i] + j]; + *str = text; + for (WChar c = Utf8Consume(&text); c != '\0'; c = Utf8Consume(&text)) { + if (c == SCC_SETX) { + /* SetX is, together with SetXY as special character that + * uses the next (two) characters as data points. We have + * to skip those, otherwise the UTF8 reading will go haywire. */ + text++; + } else if (c == SCC_SETXY) { + text += 2; + } else if (IsPrintable(c) && c != '?' && GetGlyph(FS_NORMAL, c) == question_mark) { + /* The character is printable, but not in the normal font. This is the case we were testing for. */ + return true; + } + } + } + } + return false; +} + /** * Check whether the currently loaded language pack * uses characters that the currently loaded font @@ -1544,81 +1576,52 @@ void CheckForMissingGlyphsInLoadedLanguagePack() * automatically choose another font. This resets that choice. */ UninitFreeType(); InitFreeType(); - bool retry = false; #endif - for (;;) { - const Sprite *question_mark = GetGlyph(FS_NORMAL, '?'); - - for (uint i = 0; i != 32; i++) { - for (uint j = 0; j < _langtab_num[i]; j++) { - const char *string = _langpack_offs[_langtab_start[i] + j]; - WChar c; - while ((c = Utf8Consume(&string)) != '\0') { - if (c == SCC_SETX) { - /* - * SetX is, together with SetXY as special character that - * uses the next (two) characters as data points. We have - * to skip those, otherwise the UTF8 reading will go - * haywire. - */ - string++; - } else if (c == SCC_SETXY) { - string += 2; - } else if (IsPrintable(c) && c != '?' && GetGlyph(FS_NORMAL, c) == question_mark) { + const char *str; + bool bad_font = FindMissingGlyphs(&str); #ifdef WITH_FREETYPE - if (!retry) { - /* We found an unprintable character... lets try whether we can - * find a fallback font that can print the characters in the - * current language. */ - retry = true; + if (bad_font) { + /* We found an unprintable character... lets try whether we can find + * a fallback font that can print the characters in the current language. */ + FreeTypeSettings backup; + memcpy(&backup, &_freetype, sizeof(backup)); - FreeTypeSettings backup; - memcpy(&backup, &_freetype, sizeof(backup)); + bool success = SetFallbackFont(&_freetype, _langpack->isocode, _langpack->winlangid, str); + if (success) { + UninitFreeType(); + InitFreeType(); + } - bool success = SetFallbackFont(&_freetype, _langpack->isocode, _langpack->winlangid, string); - if (success) { - UninitFreeType(); - InitFreeType(); - } + memcpy(&_freetype, &backup, sizeof(backup)); - memcpy(&_freetype, &backup, sizeof(backup)); - - if (success) continue; - } else { - /* Our fallback font does miss characters too, so keep the - * user chosen font as that is more likely to be any good than - * the wild guess we made */ - UninitFreeType(); - InitFreeType(); - } -#endif - /* - * The character is printable, but not in the normal font. - * This is the case we were testing for. In this case we - * have to show the error. As we do not want the string to - * be translated by the translators, we 'force' it into the - * binary and 'load' it via a BindCString. To do this - * properly we have to set the colour of the string, - * otherwise we end up with a lot of artefacts. The colour - * 'character' might change in the future, so for safety - * we just Utf8 Encode it into the string, which takes - * exactly three characters, so it replaces the "XXX" with - * the colour marker. - */ - static char *err_str = strdup("XXXThe current font is missing some of the characters used in the texts for this language. Read the readme to see how to solve this."); - Utf8Encode(err_str, SCC_YELLOW); - SetDParamStr(0, err_str); - ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, 0, 0); - - /* Reset the font width */ - LoadStringWidthTable(); - return; - } - } + if (success) { + bad_font = FindMissingGlyphs(&str); + if (bad_font) { + /* Our fallback font does miss characters too, so keep the + * user chosen font as that is more likely to be any good than + * the wild guess we made */ + UninitFreeType(); + InitFreeType(); } } - break; + } +#endif + + if (bad_font) { + /* All attempts have failed. Display an error. As we do not want the string to be translated by + * the translators, we 'force' it into the binary and 'load' it via a BindCString. To do this + * properly we have to set the colour of the string, otherwise we end up with a lot of artefacts. + * The colour 'character' might change in the future, so for safety we just Utf8 Encode it into + * the string, which takes exactly three characters, so it replaces the "XXX" with the colour marker. */ + static char *err_str = strdup("XXXThe current font is missing some of the characters used in the texts for this language. Read the readme to see how to solve this."); + Utf8Encode(err_str, SCC_YELLOW); + SetDParamStr(0, err_str); + ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, 0, 0); + + /* Reset the font width */ + LoadStringWidthTable(); + return; } /* Update the font with cache */