mirror of https://github.com/OpenTTD/OpenTTD
(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)release/1.0
parent
cc9c1ff2b0
commit
2da34ec3d6
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
40
src/gfx.cpp
40
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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -201,6 +201,8 @@ void GfxLoadSprites()
|
|||
GfxInitSpriteMem();
|
||||
LoadSpriteTables();
|
||||
GfxInitPalettes();
|
||||
|
||||
UpdateCursorSize();
|
||||
}
|
||||
|
||||
bool GraphicsSet::FillSetDetails(IniFile *ini, const char *path, const char *full_filename)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
#include "saveload_internal.h"
|
||||
#include "oldloader.h"
|
||||
#include <exception>
|
||||
|
||||
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;
|
||||
|
|
|
@ -33,7 +33,6 @@ struct LoadgameState {
|
|||
byte buffer[BUFFER_SIZE];
|
||||
|
||||
uint total_read;
|
||||
bool failed;
|
||||
};
|
||||
|
||||
/* OldChunk-Type */
|
||||
|
|
|
@ -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<byte, OLD_MAP_SIZE * 2> 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();
|
||||
|
|
137
src/strings.cpp
137
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 */
|
||||
|
|
Loading…
Reference in New Issue