# HG changeset patch # User glx # Date 2007-06-18 23:00:55 # Node ID 6398843f1341883f34c9769789a657d72858f4e4 # Parent 42f59093f6f9a31a146325632b58764f1bc3391e (svn r10211) -Feature: [NewGRF] Add support for action 0F diff --git a/projects/openttd.vcproj b/projects/openttd.vcproj --- a/projects/openttd.vcproj +++ b/projects/openttd.vcproj @@ -564,6 +564,9 @@ RelativePath=".\..\src\newgrf_town.h"> + + + + + + @@ -1659,6 +1663,10 @@ RelativePath=".\..\src\newgrf_town.cpp" > + + townnameparts); - GetString(chat_tab_temp_buffer, t->townnametype, lastof(chat_tab_temp_buffer)); + SetDParam(0, t->index); + GetString(chat_tab_temp_buffer, STR_TOWN, lastof(chat_tab_temp_buffer)); return &chat_tab_temp_buffer[0]; } } diff --git a/src/newgrf.cpp b/src/newgrf.cpp --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -42,6 +42,7 @@ #include "industry.h" #include "newgrf_canal.h" #include "newgrf_commons.h" +#include "newgrf_townname.h" /* TTDPatch extended GRF format codec * (c) Petr Baudis 2004 (GPL'd) @@ -3898,6 +3899,106 @@ static void GRFInhibit(byte *buf, int le } } +/* Action 0x0F */ +static void FeatureTownName(byte *buf, int len) +{ + /* <0F> + * + * B id ID of this definition in bottom 7 bits (final definition if bit 7 set) + * V style-name Name of the style (only for final definition) + * B num-parts Number of parts in this definition + * V parts The parts */ + + if (!check_length(len, 1, "FeatureTownName: definition ID")) return; + buf++; len--; + + uint32 grfid = _cur_grffile->grfid; + + GRFTownName *townname = AddGRFTownName(grfid); + + byte id = grf_load_byte(&buf); + len--; + grfmsg(6, "FeatureTownName: definition 0x%02X", id & 0x7F); + + if (HASBIT(id, 7)) { + /* Final definition */ + CLRBIT(id, 7); + bool new_scheme = _cur_grffile->grf_version >= 7; + + if (!check_length(len, 1, "FeatureTownName: lang_id")) return; + byte lang = grf_load_byte(&buf); + len--; + + byte nb_gen = townname->nb_gen; + do { + CLRBIT(lang, 7); + + if (!check_length(len, 1, "FeatureTownName: style name")) return; + const char *name = grf_load_string(&buf, len); + len -= strlen(name) + 1; + grfmsg(6, "FeatureTownName: lang 0x%X -> '%s'", lang, TranslateTTDPatchCodes(name)); + + townname->name[nb_gen] = AddGRFString(grfid, id, lang, new_scheme, name, STR_UNDEFINED); + + if (!check_length(len, 1, "FeatureTownName: lang_id")) return; + lang = grf_load_byte(&buf); + len--; + } while (lang != 0); + townname->id[nb_gen] = id; + townname->nb_gen++; + } + + if (!check_length(len, 1, "FeatureTownName: number of parts")) return; + byte nb = grf_load_byte(&buf); + len--; + grfmsg(6, "FeatureTownName: %d parts", nb, nb); + + townname->nbparts[id] = nb; + townname->partlist[id] = CallocT(nb); + + for (int i = 0; i < nb; i++) { + if (!check_length(len, 3, "FeatureTownName: parts header")) return; + byte nbtext = grf_load_byte(&buf); + townname->partlist[id][i].bitstart = grf_load_byte(&buf); + townname->partlist[id][i].bitcount = grf_load_byte(&buf); + townname->partlist[id][i].maxprob = 0; + townname->partlist[id][i].partcount = nbtext; + townname->partlist[id][i].parts = CallocT(nbtext); + len -= 3; + grfmsg(6, "FeatureTownName: part %d contains %d texts and will use GB(seed, %d, %d)", i, nbtext, townname->partlist[id][i].bitstart, townname->partlist[id][i].bitcount); + + for (int j = 0; j < nbtext; j++) { + if (!check_length(len, 2, "FeatureTownName: part")) return; + byte prob = grf_load_byte(&buf); + len--; + + if (HASBIT(prob, 7)) { + byte ref_id = grf_load_byte(&buf); + len--; + + if (townname->nbparts[ref_id] == 0) { + grfmsg(0, "FeatureTownName: definition 0x%02X doesn't exist, deactivating", ref_id); + DelGRFTownName(grfid); + _cur_grfconfig->status = GCS_DISABLED; + _skip_sprites = -1; + return; + } + + grfmsg(6, "FeatureTownName: part %d, text %d, uses intermediate definition 0x%02X (with probability %d)", i, j, ref_id, prob & 0x7F); + townname->partlist[id][i].parts[j].data.id = ref_id; + } else { + const char *text = grf_load_string(&buf, len); + len -= strlen(text) + 1; + townname->partlist[id][i].parts[j].data.text = TranslateTTDPatchCodes(text); + grfmsg(6, "FeatureTownName: part %d, text %d, '%s' (with probability %d)", i, j, townname->partlist[id][i].parts[j].data.text, prob); + } + townname->partlist[id][i].parts[j].prob = prob; + townname->partlist[id][i].maxprob += GB(prob, 0, 7); + } + grfmsg(6, "FeatureTownName: part %d, total probability %d", i, townname->partlist[id][i].maxprob); + } +} + /* Action 0x10 */ static void DefineGotoLabel(byte *buf, int len) { @@ -4241,7 +4342,7 @@ static void InitializeGRFSpecial() | ((_patches.freight_trains > 1 ? 1 : 0) << 0x18) // freighttrains | (1 << 0x19) // newhouses | (1 << 0x1A) // newbridges - | (0 << 0x1B) // newtownnames + | (1 << 0x1B) // newtownnames | (0 << 0x1C) // moreanimations | ((_patches.wagon_speed_limits ? 1 : 0) << 0x1D) // wagonspeedlimits | (1 << 0x1E) // newshistory @@ -4418,6 +4519,7 @@ static void ResetNewGRFErrors() static void ResetNewGRFData() { CleanUpStrings(); + CleanUpGRFTownNames(); /* Copy/reset original engine info data */ memcpy(&_engine_info, &orig_engine_info, sizeof(orig_engine_info)); @@ -4787,7 +4889,7 @@ static void DecodeSpecialSprite(uint num /* 0x0C */ { NULL, NULL, NULL, GRFComment, NULL, GRFComment, }, /* 0x0D */ { NULL, SafeParamSet, NULL, ParamSet, ParamSet, ParamSet, }, /* 0x0E */ { NULL, SafeGRFInhibit, NULL, GRFInhibit, GRFInhibit, GRFInhibit, }, - /* 0x0F */ { NULL, NULL, NULL, NULL, NULL, NULL, }, + /* 0x0F */ { NULL, GRFUnsafe, NULL, FeatureTownName, NULL, NULL, }, /* 0x10 */ { NULL, NULL, DefineGotoLabel, NULL, NULL, NULL, }, /* 0x11 */ { NULL, GRFUnsafe, NULL, NULL, NULL, GRFSound, }, /* 0x12 */ { NULL, NULL, NULL, NULL, NULL, LoadFontGlyph, }, @@ -4917,6 +5019,8 @@ void LoadNewGRFFile(GRFConfig *config, u void InitDepotWindowBlockSizes(); +extern void SortTownGeneratorNames(); + static void AfterLoadGRFs() { /* Update the bitmasks for the vehicle lists */ @@ -4941,6 +5045,9 @@ static void AfterLoadGRFs() /* Map cargo strings. This is a separate step because cargos are * loaded before strings... */ MapNewCargoStrings(); + + /* Update the townname generators list */ + SortTownGeneratorNames(); } void LoadNewGRF(uint load_index, uint file_index) @@ -4959,6 +5066,7 @@ void LoadNewGRF(uint load_index, uint fi _cur_spriteid = load_index; for (GRFConfig *c = _grfconfig; c != NULL; c = c->next) { if (c->status == GCS_DISABLED || c->status == GCS_NOT_FOUND) continue; + if (stage > GLS_INIT && HASBIT(c->flags, GCF_INIT_ONLY)) continue; /* @todo usererror() */ if (!FioCheckFileExists(c->full_path)) error("NewGRF file is missing '%s'", c->filename); diff --git a/src/newgrf_config.cpp b/src/newgrf_config.cpp --- a/src/newgrf_config.cpp +++ b/src/newgrf_config.cpp @@ -124,8 +124,9 @@ void ClearGRFConfigList(GRFConfig **conf /** Copy a GRF Config list * @param dst pointer to destination list * @param src pointer to source list values + * @param init_only the copied GRF will be processed up to GLS_INIT * @return pointer to the last value added to the destination list */ -GRFConfig **CopyGRFConfigList(GRFConfig **dst, const GRFConfig *src) +GRFConfig **CopyGRFConfigList(GRFConfig **dst, const GRFConfig *src, bool init_only) { /* Clear destination as it will be overwritten */ ClearGRFConfigList(dst); @@ -143,6 +144,8 @@ GRFConfig **CopyGRFConfigList(GRFConfig if (src->error->custom_message != NULL) c->error->custom_message = strdup(src->error->custom_message); } + if (init_only) SETBIT(c->flags, GCF_INIT_ONLY); + *dst = c; dst = &c->next; } @@ -190,7 +193,7 @@ void AppendStaticGRFConfigs(GRFConfig ** GRFConfig **tail = dst; while (*tail != NULL) tail = &(*tail)->next; - CopyGRFConfigList(tail, _grfconfig_static); + CopyGRFConfigList(tail, _grfconfig_static, false); RemoveDuplicatesFromGRFConfigList(*dst); } @@ -210,14 +213,7 @@ void AppendToGRFConfigList(GRFConfig **d /* Reset the current GRF Config to either blank or newgame settings */ void ResetGRFConfig(bool defaults) { - GRFConfig **c = &_grfconfig; - - if (defaults) { - c = CopyGRFConfigList(c, _grfconfig_newgame); - } else { - ClearGRFConfigList(c); - } - + CopyGRFConfigList(&_grfconfig, _grfconfig_newgame, !defaults); AppendStaticGRFConfigs(&_grfconfig); } diff --git a/src/newgrf_config.h b/src/newgrf_config.h --- a/src/newgrf_config.h +++ b/src/newgrf_config.h @@ -14,6 +14,7 @@ enum GCF_Flags { GCF_STATIC, ///< GRF file is used statically (can be used in any MP game) GCF_COMPATIBLE,///< GRF file does not exactly match the requested GRF (different MD5SUM), but grfid matches) GCF_COPY, ///< The data is copied from a grf in _all_grfs + GCF_INIT_ONLY, ///< GRF file is processed up to GLS_INIT }; enum GRFStatus { @@ -74,7 +75,7 @@ extern GRFConfig *_grfconfig_static; void ScanNewGRFFiles(); const GRFConfig *FindGRFConfig(uint32 grfid, const uint8 *md5sum = NULL); GRFConfig *GetGRFConfig(uint32 grfid); -GRFConfig **CopyGRFConfigList(GRFConfig **dst, const GRFConfig *src); +GRFConfig **CopyGRFConfigList(GRFConfig **dst, const GRFConfig *src, bool init_only); void AppendStaticGRFConfigs(GRFConfig **dst); void AppendToGRFConfigList(GRFConfig **dst, GRFConfig *el); void ClearGRFConfig(GRFConfig **config); diff --git a/src/newgrf_gui.cpp b/src/newgrf_gui.cpp --- a/src/newgrf_gui.cpp +++ b/src/newgrf_gui.cpp @@ -307,12 +307,12 @@ static void NewGRFConfirmationCallback(W GRFConfig *c; int i = 0; - CopyGRFConfigList(nd->orig_list, *nd->list); + CopyGRFConfigList(nd->orig_list, *nd->list, false); ReloadNewGRFData(); /* Show new, updated list */ for (c = *nd->list; c != NULL && c != nd->sel; c = c->next, i++); - CopyGRFConfigList(nd->list, *nd->orig_list); + CopyGRFConfigList(nd->list, *nd->orig_list, false); for (c = *nd->list; c != NULL && i > 0; c = c->next, i--); nd->sel = c; @@ -469,7 +469,9 @@ static void NewGRFWndProc(Window *w, Win NewGRFConfirmationCallback ); } else { - CopyGRFConfigList(WP(w, newgrf_d).orig_list, *WP(w, newgrf_d).list); + CopyGRFConfigList(WP(w, newgrf_d).orig_list, *WP(w, newgrf_d).list, true); + ResetGRFConfig(false); + ReloadNewGRFData(); } break; @@ -498,7 +500,9 @@ static void NewGRFWndProc(Window *w, Win case WE_DESTROY: if (!WP(w, newgrf_d).execute) { - CopyGRFConfigList(WP(w, newgrf_d).orig_list, *WP(w, newgrf_d).list); + CopyGRFConfigList(WP(w, newgrf_d).orig_list, *WP(w, newgrf_d).list, true); + ResetGRFConfig(false); + ReloadNewGRFData(); } /* Remove the temporary copy of grf-list used in window */ ClearGRFConfigList(WP(w, newgrf_d).list); @@ -565,7 +569,7 @@ void ShowNewGRFSettings(bool editable, b if (w == NULL) return; w->resize.step_height = 14; - CopyGRFConfigList(&local, *config); + CopyGRFConfigList(&local, *config, false); /* Clear selections */ WP(w, newgrf_d).sel = NULL; diff --git a/src/newgrf_townname.cpp b/src/newgrf_townname.cpp new file mode 100644 --- /dev/null +++ b/src/newgrf_townname.cpp @@ -0,0 +1,132 @@ +/* $Id$ */ + +/** @file newgrf_townname.cpp + * Implementation of Action 0F "universal holder" structure and functions. + * This file implements a linked-lists of townname generators, + * holding everything that the newgrf action 0F will send over to OpenTTD. + */ + +#include "stdafx.h" +#include "openttd.h" +#include "table/strings.h" +#include "newgrf_townname.h" +#include "string.h" + +static GRFTownName *_grf_townnames = NULL; + +GRFTownName *GetGRFTownName(uint32 grfid) +{ + GRFTownName *t = _grf_townnames; + for (; t != NULL; t = t->next) { + if (t->grfid == grfid) return t; + } + return NULL; +} + +GRFTownName *AddGRFTownName(uint32 grfid) +{ + GRFTownName *t = GetGRFTownName(grfid); + if (t == NULL) { + t = CallocT(1); + t->grfid = grfid; + t->next = _grf_townnames; + _grf_townnames = t; + } + return t; +} + +void DelGRFTownName(uint32 grfid) +{ + GRFTownName *t = _grf_townnames; + GRFTownName *p = NULL; + for (;t != NULL; p = t, t = t->next) if (t->grfid == grfid) break; + if (t != NULL) { + for (int i = 0; i < 128; i++) { + for (int j = 0; j < t->nbparts[i]; j++) { + for (int k = 0; k < t->partlist[i][j].partcount; k++) { + if (!HASBIT(t->partlist[i][j].parts[k].prob, 7)) free(t->partlist[i][j].parts[k].data.text); + } + free(t->partlist[i][j].parts); + } + free(t->partlist[i]); + } + if (p != NULL) { + p->next = t->next; + } else { + _grf_townnames = t->next; + } + free(t); + } +} + +static char *RandomPart(char *buf, GRFTownName *t, uint32 seed, byte id, const char *last) +{ + assert(t != NULL); + for (int i = 0; i < t->nbparts[id]; i++) { + byte count = t->partlist[id][i].bitcount; + uint16 maxprob = t->partlist[id][i].maxprob; + uint32 r = (GB(seed, t->partlist[id][i].bitstart, count) * maxprob) >> count; + for (int j = 0; j < t->partlist[id][i].partcount; j++) { + byte prob = t->partlist[id][i].parts[j].prob; + maxprob -= GB(prob, 0, 7); + if (maxprob > r) continue; + if (HASBIT(prob, 7)) { + buf = RandomPart(buf, t, seed, t->partlist[id][i].parts[j].data.id, last); + } else { + buf = strecat(buf, t->partlist[id][i].parts[j].data.text, last); + } + break; + } + } + return buf; +} + +char *GRFTownNameGenerate(char *buf, uint32 grfid, uint16 gen, uint32 seed, const char *last) +{ + strecpy(buf, "", last); + for (GRFTownName *t = _grf_townnames; t != NULL; t = t->next) { + if (t->grfid == grfid) { + assert(gen < t->nb_gen); + buf = RandomPart(buf, t, seed, t->id[gen], last); + break; + } + } + return buf; +} + +StringID *GetGRFTownNameList() +{ + int nb_names = 0, n = 0; + for (GRFTownName *t = _grf_townnames; t != NULL; t = t->next) nb_names += t->nb_gen; + StringID *list = MallocT(nb_names + 1); + for (GRFTownName *t = _grf_townnames; t != NULL; t = t->next) { + for (int j = 0; j < t->nb_gen; j++) list[n++] = t->name[j]; + } + list[n] = INVALID_STRING_ID; + return list; +} + +void CleanUpGRFTownNames() +{ + while (_grf_townnames != NULL) DelGRFTownName(_grf_townnames->grfid); +} + +uint32 GetGRFTownNameId(int gen) +{ + for (GRFTownName *t = _grf_townnames; t != NULL; t = t->next) { + if (gen < t->nb_gen) return t->grfid; + gen -= t->nb_gen; + } + /* Fallback to no NewGRF */ + return 0; +} + +uint16 GetGRFTownNameType(int gen) +{ + for (GRFTownName *t = _grf_townnames; t != NULL; t = t->next) { + if (gen < t->nb_gen) return gen; + gen -= t->nb_gen; + } + /* Fallback to english original */ + return SPECSTR_TOWNNAME_ENGLISH; +} diff --git a/src/newgrf_townname.h b/src/newgrf_townname.h new file mode 100644 --- /dev/null +++ b/src/newgrf_townname.h @@ -0,0 +1,44 @@ +/* $Id$ */ +#ifndef NEWGRF_TOWNNAME_H +#define NEWGRF_TOWNNAME_H + +/** @file newgrf_townname.h + * Header of Action 0F "universal holder" structure and functions + */ + +struct NamePart { + byte prob; ///< The relative probablity of the following name to appear in the bottom 7 bits. + union { + char *text; ///< If probability bit 7 is clear + byte id; ///< If probability bit 7 is set + } data; +}; + +struct NamePartList { + byte partcount; + byte bitstart; + byte bitcount; + uint16 maxprob; + NamePart *parts; +}; + +struct GRFTownName { + uint32 grfid; + byte nb_gen; + byte id[128]; + StringID name[128]; + byte nbparts[128]; + NamePartList *partlist[128]; + GRFTownName *next; +}; + +GRFTownName *AddGRFTownName(uint32 grfid); +GRFTownName *GetGRFTownName(uint32 grfid); +void DelGRFTownName(uint32 grfid); +void CleanUpGRFTownNames(); +StringID *GetGRFTownNameList(); +char *GRFTownNameGenerate(char *buf, uint32 grfid, uint16 gen, uint32 seed, const char *last); +uint32 GetGRFTownNameId(int gen); +uint16 GetGRFTownNameType(int gen); + +#endif /* NEWGRF_TOWNNAME_H */ diff --git a/src/saveload.cpp b/src/saveload.cpp --- a/src/saveload.cpp +++ b/src/saveload.cpp @@ -29,7 +29,7 @@ #include #include -extern const uint16 SAVEGAME_VERSION = 65; +extern const uint16 SAVEGAME_VERSION = 66; uint16 _sl_version; ///< the major savegame version identifier byte _sl_minor_version; ///< the minor savegame version, DO NOT USE! diff --git a/src/settings.cpp b/src/settings.cpp --- a/src/settings.cpp +++ b/src/settings.cpp @@ -1306,7 +1306,8 @@ static const SettingDesc _gameopt_settin SDT_VAR(GameOptions, diff_level, SLE_UINT8, 0, 0, 0, 0, 3, 0, STR_NULL, NULL), SDT_OMANY(GameOptions, currency, SLE_UINT8, N, 0, 0, CUSTOM_CURRENCY_ID, "GBP|USD|EUR|YEN|ATS|BEF|CHF|CZK|DEM|DKK|ESP|FIM|FRF|GRD|HUF|ISK|ITL|NLG|NOK|PLN|ROL|RUR|SIT|SEK|YTL|SKK|BRR|custom", STR_NULL, NULL, NULL), SDT_OMANY(GameOptions, units, SLE_UINT8, N, 0, 1, 2, "imperial|metric|si", STR_NULL, NULL, NULL), - SDT_OMANY(GameOptions, town_name, SLE_UINT8, 0, 0, 0, 20, "english|french|german|american|latin|silly|swedish|dutch|finnish|polish|slovakish|norwegian|hungarian|austrian|romanian|czech|swiss|danish|turkish|italian|catalan", STR_NULL, NULL, NULL), + /* There are only 21 predefined town_name values (0-20), but you can have more with newgrf action F so allow these bigger values (21-255). Invalid values will fallback to english on use and (undefined string) in GUI. */ + SDT_OMANY(GameOptions, town_name, SLE_UINT8, 0, 0, 0, 255, "english|french|german|american|latin|silly|swedish|dutch|finnish|polish|slovakish|norwegian|hungarian|austrian|romanian|czech|swiss|danish|turkish|italian|catalan", STR_NULL, NULL, NULL), SDT_OMANY(GameOptions, landscape, SLE_UINT8, 0, 0, 0, 3, "temperate|arctic|tropic|toyland", STR_NULL, NULL, ConvertLandscape), SDT_VAR(GameOptions, snow_line, SLE_UINT8, 0, 0, 7 * TILE_HEIGHT, 2 * TILE_HEIGHT, 13 * TILE_HEIGHT, 0, STR_NULL, NULL), SDT_CONDOMANY(GameOptions,autosave, SLE_UINT8, 0, 22, N, 0, 0, 0, "", STR_NULL, NULL, NULL), diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -24,6 +24,7 @@ #include "vehicle.h" #include "date.h" #include "helpers.hpp" +#include "newgrf_townname.h" static uint32 _difficulty_click_a; static uint32 _difficulty_click_b; @@ -66,19 +67,44 @@ static StringID *BuildDynamicDropdown(St return buf; } -static StringID _town_names[SPECSTR_TOWNNAME_LAST - SPECSTR_TOWNNAME_START + 2] = {STR_NULL}; +int _nb_orig_names = SPECSTR_TOWNNAME_LAST - SPECSTR_TOWNNAME_START + 1; +static StringID *_town_names = NULL; +static StringID *_grf_names = NULL; +static int _nb_grf_names = 0; void SortTownGeneratorNames() { - int nb_town_names = SPECSTR_TOWNNAME_LAST - SPECSTR_TOWNNAME_START + 1; - /* Init the strings */ - if (_town_names[0] == STR_NULL) { - for (int i = 0; i < nb_town_names; i++) _town_names[i] = STR_TOWNNAME_ORIGINAL_ENGLISH + i; - _town_names[nb_town_names] = INVALID_STRING_ID; - } + int n = 0; + + /* Get Newgrf generators' names */ + free(_grf_names); + _grf_names = GetGRFTownNameList(); + _nb_grf_names = 0; + for (StringID *s = _grf_names; *s != INVALID_STRING_ID; s++) _nb_grf_names++; + + /* Prepare the list */ + free(_town_names); + _town_names = MallocT(_nb_orig_names + _nb_grf_names + 1); + + /* Put the original strings */ + for (int i = 0; i < _nb_orig_names; i++) _town_names[n++] = STR_TOWNNAME_ORIGINAL_ENGLISH + i; + + /* Put the grf strings */ + for (int i = 0; i < _nb_grf_names; i++) _town_names[n++] = _grf_names[i]; + + /* Put the terminator */ + _town_names[n] = INVALID_STRING_ID; /* Sort the strings */ - qsort(&_town_names[0], nb_town_names, sizeof(StringID), &StringIDSorter); + qsort(&_town_names[0], _nb_orig_names + _nb_grf_names, sizeof(StringID), &StringIDSorter); +} + +static inline StringID TownName(int town_name) +{ + if (town_name < _nb_orig_names) return STR_TOWNNAME_ORIGINAL_ENGLISH + town_name; + town_name -= _nb_orig_names; + if (town_name < _nb_grf_names) return _grf_names[town_name]; + return STR_UNDEFINED; } static int GetCurRes() @@ -120,7 +146,7 @@ static void GameOptionsWndProc(Window *w SetDParam(1, _currency_specs[_opt_ptr->currency].name); SetDParam(2, STR_UNITS_IMPERIAL + _opt_ptr->units); SetDParam(3, STR_02E9_DRIVE_ON_LEFT + _opt_ptr->road_side); - SetDParam(4, STR_TOWNNAME_ORIGINAL_ENGLISH + _opt_ptr->town_name); + SetDParam(4, TownName(_opt_ptr->town_name)); SetDParam(5, _autosave_dropdown[_opt_ptr->autosave]); SetDParam(6, SPECSTR_LANGUAGE_START + _dynlang.curr); i = GetCurRes(); @@ -152,8 +178,8 @@ static void GameOptionsWndProc(Window *w } return; case 13: case 14: { /* Setup townname dropdown */ uint sel = 0; - for (uint i = 0; i < lengthof(_town_names) - 1; i++) { - if (_town_names[i] == STR_TOWNNAME_ORIGINAL_ENGLISH + _opt_ptr->town_name) { + for (uint i = 0; _town_names[i] != INVALID_STRING_ID; i++) { + if (_town_names[i] == TownName(_opt_ptr->town_name)) { sel = i; break; } @@ -214,7 +240,12 @@ static void GameOptionsWndProc(Window *w break; case 14: /* Town names */ if (_game_mode == GM_MENU) { - _opt_ptr->town_name = _town_names[e->we.dropdown.index] - STR_TOWNNAME_ORIGINAL_ENGLISH; + for (uint i = 0; _town_names[i] != INVALID_STRING_ID; i++) { + if (_town_names[e->we.dropdown.index] == TownName(i)) { + _opt_ptr->town_name = i; + break; + } + } InvalidateWindow(WC_GAME_OPTIONS, 0); } break; diff --git a/src/strings.cpp b/src/strings.cpp --- a/src/strings.cpp +++ b/src/strings.cpp @@ -28,6 +28,7 @@ #include "cargotype.h" #include "group.h" #include "debug.h" +#include "newgrf_townname.h" /* for opendir/readdir/closedir */ # include "fios.h" @@ -825,8 +826,8 @@ static char* FormatString(char* buff, co buff = GetStringWithArgs(buff, STR_UNKNOWN_DESTINATION, NULL, last); } else { int32 temp[2]; - temp[0] = st->town->townnametype; - temp[1] = st->town->townnameparts; + temp[0] = STR_TOWN; + temp[1] = st->town->index; buff = GetStringWithArgs(buff, st->string_id, temp, last); } break; @@ -839,7 +840,21 @@ static char* FormatString(char* buff, co assert(IsValidTown(t)); temp[0] = t->townnameparts; - buff = GetStringWithArgs(buff, t->townnametype, temp, last); + uint32 grfid = t->townnamegrfid; + + if (grfid == 0) { + /* Original town name */ + buff = GetStringWithArgs(buff, t->townnametype, temp, last); + } else { + /* Newgrf town name */ + if (GetGRFTownName(grfid) != NULL) { + /* The grf is loaded */ + buff = GRFTownNameGenerate(buff, t->townnamegrfid, t->townnametype, t->townnameparts, last); + } else { + /* Fallback to english original */ + buff = GetStringWithArgs(buff, SPECSTR_TOWNNAME_ENGLISH, temp, last); + } + } break; } diff --git a/src/town.h b/src/town.h --- a/src/town.h +++ b/src/town.h @@ -83,6 +83,7 @@ struct Town { uint32 population; /* Town name */ + uint32 townnamegrfid; uint16 townnametype; uint32 townnameparts; diff --git a/src/town_cmd.cpp b/src/town_cmd.cpp --- a/src/town_cmd.cpp +++ b/src/town_cmd.cpp @@ -39,6 +39,7 @@ #include "newgrf_callbacks.h" #include "newgrf_house.h" #include "newgrf_commons.h" +#include "newgrf_townname.h" /** * Called if a new block is added to the town-pool @@ -1295,6 +1296,7 @@ static void UpdateTownRadius(Town *t) static bool CreateTownName(uint32 *townnameparts) { + extern int _nb_orig_names; Town *t2; char buf1[64]; char buf2[64]; @@ -1305,7 +1307,9 @@ static bool CreateTownName(uint32 *townn * the other towns may take considerable amount of time (10000 is * too much). */ int tries = 1000; - uint16 townnametype = SPECSTR_TOWNNAME_START + _opt.town_name; + bool grf = (_opt.town_name >= _nb_orig_names); + uint32 grfid = grf ? GetGRFTownNameId(_opt.town_name - _nb_orig_names) : 0; + uint16 townnametype = grf ? GetGRFTownNameType(_opt.town_name - _nb_orig_names) : SPECSTR_TOWNNAME_START + _opt.town_name; assert(townnameparts); @@ -1314,7 +1318,11 @@ restart: r = Random(); SetDParam(0, r); - GetString(buf1, townnametype, lastof(buf1)); + if (grf && grfid != 0) { + GRFTownNameGenerate(buf1, grfid, townnametype, r, lastof(buf1)); + } else { + GetString(buf1, townnametype, lastof(buf1)); + } /* Check size and width */ if (strlen(buf1) >= 31 || GetStringBoundingBox(buf1).width > 130) continue; @@ -1351,6 +1359,7 @@ void UpdateTownMaxPass(Town *t) */ static void DoCreateTown(Town *t, TileIndex tile, uint32 townnameparts, TownSizeMode size_mode, uint size) { + extern int _nb_orig_names; int x, i; /* clear the town struct */ @@ -1392,7 +1401,15 @@ static void DoCreateTown(Town *t, TileIn t->exclusive_counter = 0; t->statues = 0; - t->townnametype = SPECSTR_TOWNNAME_START + _opt.town_name; + if (_opt.town_name < _nb_orig_names) { + /* Original town name */ + t->townnamegrfid = 0; + t->townnametype = SPECSTR_TOWNNAME_START + _opt.town_name; + } else { + /* Newgrf town name */ + t->townnamegrfid = GetGRFTownNameId(_opt.town_name - _nb_orig_names); + t->townnametype = GetGRFTownNameType(_opt.town_name - _nb_orig_names); + } t->townnameparts = townnameparts; UpdateTownVirtCoord(t); @@ -2338,6 +2355,7 @@ static const SaveLoad _town_desc[] = { SLE_VAR(Town, num_houses, SLE_UINT16), + SLE_CONDVAR(Town, townnamegrfid, SLE_UINT32, 66, SL_MAX_VERSION), SLE_VAR(Town, townnametype, SLE_UINT16), SLE_VAR(Town, townnameparts, SLE_UINT32),