diff --git a/src/functions.h b/src/functions.h --- a/src/functions.h +++ b/src/functions.h @@ -33,10 +33,6 @@ void PlaceTreesRandomly(); void InitializeLandscapeVariables(bool only_constants); -/* misc.cpp */ -bool IsCustomName(StringID id); -char *CopyFromOldName(StringID id); - /* misc functions */ /** * Mark a tile given by its coordinate dirty for repaint. @@ -68,11 +64,8 @@ void AskExitToGameMenu(); void RedrawAutosave(); -StringID RemapOldStringID(StringID s); - void UpdateViewportSignPos(ViewportSign *sign, int left, int top, StringID str); - /* callback from drivers that is called if the game size changes dynamically */ void GameSizeChanged(); const char *GetCurrentLocale(const char *param); diff --git a/src/misc.cpp b/src/misc.cpp --- a/src/misc.cpp +++ b/src/misc.cpp @@ -23,14 +23,12 @@ #include "date_func.h" #include "vehicle_func.h" #include "texteff.hpp" -#include "string_func.h" #include "gfx_func.h" #include "core/alloc_type.hpp" #include "table/strings.h" #include "table/sprites.h" -char _name_array[512][32]; extern TileIndex _cur_tileloop_tile; void InitializeVehicles(); @@ -49,10 +47,10 @@ void InitializeTrees(); void InitializeSigns(); void InitializeStations(); void InitializeCargoPackets(); -static void InitializeNameMgr(); void InitializePlayers(); void InitializeCheats(); void InitializeNPF(); +void InitializeOldNames(); void InitializeGame(int mode, uint size_x, uint size_y) { @@ -93,7 +91,7 @@ void InitializeGame(int mode, uint size_ InitializeIndustries(); InitializeBuildingCounts(); - InitializeNameMgr(); + InitializeOldNames(); InitializeVehiclesGuiList(); InitializeTrains(); InitializeNPF(); @@ -111,60 +109,6 @@ void InitializeGame(int mode, uint size_ ResetObjectToPlace(); } -bool IsCustomName(StringID id) -{ - return GB(id, 11, 5) == 15; -} - - -static void InitializeNameMgr() -{ - memset(_name_array, 0, sizeof(_name_array)); -} - -/* Copy and convert old custom names to UTF-8 */ -char *CopyFromOldName(StringID id) -{ - if (!IsCustomName(id)) return NULL; - - if (CheckSavegameVersion(37)) { - /* Old names were 32 characters long, so 128 characters should be - * plenty to allow for expansion when converted to UTF-8. */ - char tmp[128]; - const char *strfrom = _name_array[GB(id, 0, 9)]; - char *strto = tmp; - - for (; *strfrom != '\0'; strfrom++) { - WChar c = (byte)*strfrom; - - /* Map from non-ISO8859-15 characters to UTF-8. */ - switch (c) { - case 0xA4: c = 0x20AC; break; // Euro - case 0xA6: c = 0x0160; break; // S with caron - case 0xA8: c = 0x0161; break; // s with caron - case 0xB4: c = 0x017D; break; // Z with caron - case 0xB8: c = 0x017E; break; // z with caron - case 0xBC: c = 0x0152; break; // OE ligature - case 0xBD: c = 0x0153; break; // oe ligature - case 0xBE: c = 0x0178; break; // Y with diaresis - default: break; - } - - /* Check character will fit into our buffer. */ - if (strto + Utf8CharLen(c) > lastof(tmp)) break; - - strto += Utf8Encode(strto, c); - } - - /* Terminate the new string and copy it back to the name array */ - *strto = '\0'; - - return strdup(tmp); - } else { - /* Name will already be in UTF-8. */ - return strdup(_name_array[GB(id, 0, 9)]); - } -} /* Calculate constants that depend on the landscape type. */ void InitializeLandscapeVariables(bool only_constants) @@ -177,15 +121,6 @@ void InitializeLandscapeVariables(bool o } } -static void Load_NAME() -{ - int index; - - while ((index = SlIterateArray()) != -1) { - SlArray(_name_array[index], SlGetFieldLength(), SLE_UINT8); - } -} - static const SaveLoadGlobVarList _date_desc[] = { SLEG_CONDVAR(_date, SLE_FILE_U16 | SLE_VAR_I32, 0, 30), SLEG_CONDVAR(_date, SLE_INT32, 31, SL_MAX_VERSION), @@ -469,7 +404,6 @@ extern const ChunkHandler _misc_chunk_ha { 'MAPE', Save_MAP6, Load_MAP6, CH_RIFF }, { 'MAP7', Save_MAP7, Load_MAP7, CH_RIFF }, - { 'NAME', NULL, Load_NAME, CH_ARRAY}, { 'DATE', SaveLoad_DATE, SaveLoad_DATE, CH_RIFF}, { 'VIEW', SaveLoad_VIEW, SaveLoad_VIEW, CH_RIFF | CH_LAST}, }; diff --git a/src/oldloader.cpp b/src/oldloader.cpp --- a/src/oldloader.cpp +++ b/src/oldloader.cpp @@ -24,6 +24,7 @@ #include "date_func.h" #include "vehicle_func.h" #include "variables.h" +#include "strings_func.h" #include "table/strings.h" @@ -84,6 +85,12 @@ enum OldChunkType { OC_TILE = OC_VAR_U32 | OC_FILE_U16, + /** + * Dereference the pointer once before writing to it, + * so we do not have to use big static arrays. + */ + OC_DEREFERENCE_POINTER = 1 << 31, + OC_END = 0 ///< End of the whole chunk, all 32bits set to zero }; @@ -201,10 +208,10 @@ static bool LoadChunk(LoadgameState *ls, byte *base_ptr = (byte*)base; while (chunk->type != OC_END) { - byte* ptr = (byte*)chunk->ptr; - uint i; + byte *ptr = (byte*)chunk->ptr; + if ((chunk->type & OC_DEREFERENCE_POINTER) != 0) ptr = *(byte**)ptr; - for (i = 0; i < chunk->amount; i++) { + for (uint i = 0; i < chunk->amount; i++) { if (ls->failed) return false; /* Handle simple types */ @@ -391,7 +398,7 @@ static void FixOldVehicles() extern TileIndex *_animated_tile_list; extern uint _animated_tile_count; -extern char _name_array[512][32]; +extern char *_old_name_array; static byte _old_vehicle_multiplier; static uint8 _old_map3[OLD_MAP_SIZE * 2]; @@ -1521,7 +1528,7 @@ static const OldChunks main_chunk[] = { OCL_ASSERT( 0x6F0F2 ), - OCL_VAR ( OC_UINT8, 32 * 500, &_name_array[0] ), + OCL_VAR ( OC_UINT8 | OC_DEREFERENCE_POINTER, 32 * 500, &_old_name_array ), OCL_NULL( 0x2000 ), ///< Old hash-table, no longer in use diff --git a/src/openttd.cpp b/src/openttd.cpp --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -91,6 +91,7 @@ void IncreaseDate(); void DoPaletteAnimations(); void MusicLoop(); void ResetMusic(); +void ResetOldNames(); extern void SetDifficultyLevel(int mode, GameOptions *gm_opt); extern Player* DoStartupNewPlayer(bool is_ai); @@ -1390,6 +1391,9 @@ bool AfterLoadGame() } } + /* From this point the old names array is cleared. */ + ResetOldNames(); + /* convert road side to my format. */ if (_opt.road_side) _opt.road_side = 1; diff --git a/src/saveload.cpp b/src/saveload.cpp --- a/src/saveload.cpp +++ b/src/saveload.cpp @@ -1248,6 +1248,7 @@ static void UninitWriteZlib() /* these define the chunks */ extern const ChunkHandler _misc_chunk_handlers[]; +extern const ChunkHandler _name_chunk_handlers[]; extern const ChunkHandler _cheat_chunk_handlers[] ; extern const ChunkHandler _setting_chunk_handlers[]; extern const ChunkHandler _player_chunk_handlers[]; @@ -1268,6 +1269,7 @@ extern const ChunkHandler _cargopacket_c static const ChunkHandler * const _chunk_handlers[] = { _misc_chunk_handlers, + _name_chunk_handlers, _cheat_chunk_handlers, _setting_chunk_handlers, _veh_chunk_handlers, diff --git a/src/strings.cpp b/src/strings.cpp --- a/src/strings.cpp +++ b/src/strings.cpp @@ -37,6 +37,7 @@ #include "settings_type.h" #include "video/video_driver.hpp" #include "engine_func.h" +#include "saveload.h" #include "table/strings.h" #include "table/control_codes.h" @@ -1226,31 +1227,6 @@ static char *GetSpecialPlayerNameString( return NULL; } -/** - * remap a string ID from the old format to the new format - * @param s StringID that requires remapping - * @return translated ID*/ -StringID RemapOldStringID(StringID s) -{ - switch (s) { - case 0x0006: return STR_SV_EMPTY; - case 0x7000: return STR_SV_UNNAMED; - case 0x70E4: return SPECSTR_PLAYERNAME_ENGLISH; - case 0x70E9: return SPECSTR_PLAYERNAME_ENGLISH; - case 0x8864: return STR_SV_TRAIN_NAME; - case 0x902B: return STR_SV_ROADVEH_NAME; - case 0x9830: return STR_SV_SHIP_NAME; - case 0xA02F: return STR_SV_AIRCRAFT_NAME; - - default: - if (IsInsideMM(s, 0x300F, 0x3030)) { - return s - 0x300F + STR_SV_STNAME; - } else { - return s; - } - } -} - #ifdef ENABLE_NETWORK extern void SortNetworkLanguages(); #else /* ENABLE_NETWORK */ @@ -1548,3 +1524,118 @@ void CheckForMissingGlyphsInLoadedLangua } } } + + +/* --- Handling of saving/loading string IDs from old savegames --- */ + +/** + * Remap a string ID from the old format to the new format + * @param s StringID that requires remapping + * @return translated ID + */ +StringID RemapOldStringID(StringID s) +{ + switch (s) { + case 0x0006: return STR_SV_EMPTY; + case 0x7000: return STR_SV_UNNAMED; + case 0x70E4: return SPECSTR_PLAYERNAME_ENGLISH; + case 0x70E9: return SPECSTR_PLAYERNAME_ENGLISH; + case 0x8864: return STR_SV_TRAIN_NAME; + case 0x902B: return STR_SV_ROADVEH_NAME; + case 0x9830: return STR_SV_SHIP_NAME; + case 0xA02F: return STR_SV_AIRCRAFT_NAME; + + default: + if (IsInsideMM(s, 0x300F, 0x3030)) { + return s - 0x300F + STR_SV_STNAME; + } else { + return s; + } + } +} + +/** Location to load the old names to. */ +char *_old_name_array = NULL; + +/** + * Copy and convert old custom names to UTF-8. + * They were all stored in a 512 by 32 long string array and are + * now stored with stations, waypoints and other places with names. + * @param id the StringID of the custom name to clone. + * @return the clones custom name. + */ +char *CopyFromOldName(StringID id) +{ + /* Is this name an (old) custom name? */ + if (GB(id, 11, 5) != 15) return NULL; + + if (CheckSavegameVersion(37)) { + /* Old names were 32 characters long, so 128 characters should be + * plenty to allow for expansion when converted to UTF-8. */ + char tmp[128]; + const char *strfrom = &_old_name_array[32 * GB(id, 0, 9)]; + char *strto = tmp; + + for (; *strfrom != '\0'; strfrom++) { + WChar c = (byte)*strfrom; + + /* Map from non-ISO8859-15 characters to UTF-8. */ + switch (c) { + case 0xA4: c = 0x20AC; break; // Euro + case 0xA6: c = 0x0160; break; // S with caron + case 0xA8: c = 0x0161; break; // s with caron + case 0xB4: c = 0x017D; break; // Z with caron + case 0xB8: c = 0x017E; break; // z with caron + case 0xBC: c = 0x0152; break; // OE ligature + case 0xBD: c = 0x0153; break; // oe ligature + case 0xBE: c = 0x0178; break; // Y with diaresis + default: break; + } + + /* Check character will fit into our buffer. */ + if (strto + Utf8CharLen(c) > lastof(tmp)) break; + + strto += Utf8Encode(strto, c); + } + + /* Terminate the new string and copy it back to the name array */ + *strto = '\0'; + + return strdup(tmp); + } else { + /* Name will already be in UTF-8. */ + return strdup(&_old_name_array[32 * GB(id, 0, 9)]); + } +} + +/** + * Free the memory of the old names array. + * Should be called once the old names have all been converted. + */ +void ResetOldNames() +{ + free(_old_name_array); + _old_name_array = NULL; +} + +/** + * Initialize the old names table memory. + */ +void InitializeOldNames() +{ + free(_old_name_array); + _old_name_array = CallocT(512 * 32); +} + +static void Load_NAME() +{ + int index; + + while ((index = SlIterateArray()) != -1) { + SlArray(&_old_name_array[32 * index], SlGetFieldLength(), SLE_UINT8); + } +} + +extern const ChunkHandler _name_chunk_handlers[] = { + { 'NAME', NULL, Load_NAME, CH_ARRAY | CH_LAST}, +}; diff --git a/src/strings_func.h b/src/strings_func.h --- a/src/strings_func.h +++ b/src/strings_func.h @@ -78,4 +78,7 @@ struct StringIDCompare void CheckForMissingGlyphsInLoadedLanguagePack(); +StringID RemapOldStringID(StringID s); +char *CopyFromOldName(StringID id); + #endif /* STRINGS_TYPE_H */