From aab91d287ae5830bd89c92df102692de5af8e821 Mon Sep 17 00:00:00 2001 From: belugas Date: Fri, 21 Apr 2006 03:00:20 +0000 Subject: (svn r4493) Newgrf : Action 04. Beginning of implementation. Some TODOs left, but the core is there. Thanks to Peter1138 for code, advice and patience And to Patchman for letting us define a lot of langids :) --- Makefile | 1 + lang/english.txt | 1 + newgrf.c | 90 +++++++++++++++----- newgrf_text.c | 250 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ newgrf_text.h | 41 +++++++++ openttd.dsp | 8 ++ openttd.vcproj | 6 ++ strings.c | 11 +++ 8 files changed, 386 insertions(+), 22 deletions(-) create mode 100644 newgrf_text.c create mode 100644 newgrf_text.h diff --git a/Makefile b/Makefile index 682bb3312..414421822 100644 --- a/Makefile +++ b/Makefile @@ -638,6 +638,7 @@ SRCS += newgrf.c SRCS += newgrf_engine.c SRCS += newgrf_spritegroup.c SRCS += newgrf_station.c +SRCS += newgrf_text.c SRCS += news_gui.c SRCS += npf.c SRCS += oldloader.c diff --git a/lang/english.txt b/lang/english.txt index 84e91ef63..ecd765e64 100644 --- a/lang/english.txt +++ b/lang/english.txt @@ -1711,6 +1711,7 @@ STR_306B_HELIPORT :{BLACK}Heliport STR_306C_STATION_TOO_SPREAD_OUT :{WHITE}...station too spread out STR_306D_NONUNIFORM_STATIONS_DISALLOWED :{WHITE}...nonuniform stations disabled +STR_UNDEFINED :(undefined string) STR_STAT_CLASS_DFLT :Default station STR_STAT_CLASS_WAYP :Waypoints diff --git a/newgrf.c b/newgrf.c index 9e67f193d..f276c12d8 100644 --- a/newgrf.c +++ b/newgrf.c @@ -20,6 +20,7 @@ #include "economy.h" #include "newgrf_engine.h" #include "vehicle.h" +#include "newgrf_text.h" #include "newgrf_spritegroup.h" @@ -57,6 +58,7 @@ typedef enum grfspec_feature { GSF_CANAL, GSF_BRIDGE, GSF_TOWNHOUSE, + GSF_INDUSTRIES, GSF_GLOBALVAR, } grfspec_feature; @@ -1704,18 +1706,26 @@ static void VehicleNewName(byte *buf, int len) { /* <04> * - * B veh-type see action 0 - * B language-id language ID with bit 7 cleared (see below) + * B veh-type see action 0 (as 00..07, + 0A + * But IF veh-type = 48, then generic text + * B language-id If bit 6 is set, This is the extended language scheme, + with up to 64 language. + Otherwise, it is a mapping where set bits have meaning + 0 = american, 1 = english, 2 = german, 3 = french, 4 = spanish + Bit 7 set means this is a generic text, not a vehicle one (or else) * B num-veh number of vehicles which are getting a new name * B/W offset number of the first vehicle that gets a new name + * Byte : ID of vehicle to change + * Word : ID of string to change/add * S data new texts, each of them zero-terminated, after * which the next name begins. */ /* TODO: No support for changing non-vehicle text. Perhaps we shouldn't * implement it at all, but it could be useful for some "modpacks" * (completely new scenarios changing all graphics and logically also * factory names etc). We should then also support all languages (by - * name), not only the original four ones. --pasky */ - /* TODO: Support for custom station class/type names. */ + * name), not only the original four ones. --pasky + * TODO: Support for custom station class/type names. + * All of the above are coming. In Time. Some sooner than others :)*/ uint8 feature; uint8 lang; @@ -1731,36 +1741,70 @@ static void VehicleNewName(byte *buf, int len) num = grf_load_byte(&buf); id = (lang & 0x80) ? grf_load_word(&buf) : grf_load_byte(&buf); - if (feature > 3) { - DEBUG(grf, 7) ("VehicleNewName: Unsupported feature %d, skipping", feature); - return; + if (feature < GSF_AIRCRAFT+1) { + id += _vehshifts[feature]; } - - id += _vehshifts[feature]; endid = id + num; DEBUG(grf, 6) ("VehicleNewName: About to rename engines %d..%d (feature %d) in language 0x%x.", id, endid, feature, lang); - if (lang & 0x80) { - grfmsg(GMS_WARN, "VehicleNewName: No support for changing in-game texts. Skipping."); - return; - } - - if (!(lang & 3)) { - /* XXX: If non-English name, silently skip it. */ - DEBUG(grf, 7) ("VehicleNewName: Skipping non-English name."); - return; - } - - name = (const char*)buf; + name = (const char*)buf; /*transfer read value*/ len -= (lang & 0x80) ? 6 : 5; for (; id < endid && len > 0; id++) { size_t ofs = strlen(name) + 1; if (ofs < 128) { DEBUG(grf, 8) ("VehicleNewName: %d <- %s", id, name); - SetCustomEngineName(id, name); + + switch (feature) { + case GSF_TRAIN: + case GSF_ROAD: + case GSF_SHIP: + case GSF_AIRCRAFT: + SetCustomEngineName(id, name); + /*SetCustomEngineName(id, AddGRFString(_cur_grffile->grfid, id, lang, name));*/ + break; + +#if 0 + case GSF_STATION: + switch (GB(id, 8, 8)) { + case 0xC4: { /* Station class name */ + StationClassID sclass = _cur_grffile->stations[GB(id, 0, 8)].sclass; + SetStationClassName(sclass, AddGRFString(_cur_grffile->grfid, id, lang, name)); + break; + } + + case 0xC5: /* Station name */ + _cur_grffile->stations[GB(id, 0, 8)].name = AddGRFString(_cur_grffile->grfid, id, lang, name); + break; + + default: + DEBUG(grf, 7) ("VehicleNewName: Unsupported ID (%x)", id); + break; + } + break; + + case GSF_CANAL : + case GSF_BRIDGE : + case GSF_TOWNHOUSE : + AddGRFString(_cur_spriteid, id, lang, name); + switch (GB(id, 8,8)) { + case 0xC9: /* House name */ + default: + DEBUG(grf, 7) ("VehicleNewName: Unsupported ID (%x)", id); + } + break; + + case GSF_INDUSTRIES : + case 0x48 : /* for generic strings */ + AddGRFString(_cur_spriteid, id, lang, name); + break; + default : + DEBUG(grf,7) ("VehicleNewName: Unsupported feature (%x)", feature); + break; +#endif + } } else { DEBUG(grf, 7) ("VehicleNewName: Too long a name (%d)", ofs); } @@ -2382,6 +2426,8 @@ static void ResetNewGRFData(void) { uint i; + CleanUpStrings(); + // Copy/reset original engine info data memcpy(&_engine_info, &orig_engine_info, sizeof(orig_engine_info)); memcpy(&_rail_vehicle_info, &orig_rail_vehicle_info, sizeof(orig_rail_vehicle_info)); diff --git a/newgrf_text.c b/newgrf_text.c new file mode 100644 index 000000000..7a6121a3b --- /dev/null +++ b/newgrf_text.c @@ -0,0 +1,250 @@ +/* $Id$ */ + +/** @file + * Implementation of Action 04 "universal holder" structure and functions. + * This file implements a linked-lists of strings, + * holding everything that the newgrf action 04 will send over to OpenTTD. + * One of the biggest problems is that Dynamic lang Array uses ISO codes + * as way to identifying current user lang, while newgrf uses bit shift codes + * not related to ISO. So equivalence functionnality had to be set. + */ + +#include "stdafx.h" +#include "debug.h" +#include "openttd.h" +#include "string.h" +#include "variables.h" +#include "macros.h" +#include "table/strings.h" +#include "newgrf_text.h" + +#define GRFTAB 28 +#define TABSIZE 11 + +/** + * Explains the newgrf shift bit positionning. + * the grf base will not be used in order to find the string, but rather for + * jumping from standard langID scheme to the new one. + */ +typedef enum grf_base_languages { + GRFLB_AMERICAN = 0x01, + GRFLB_ENGLISH = 0x02, + GRFLB_GERMAN = 0x04, + GRFLB_FRENCH = 0x08, + GRFLB_SPANISH = 0x10, + GRFLB_GENERIC = 0x80, +} grf_base_language; + +typedef enum grf_extended_languages { + GRFLX_AMERICAN = 0x00, + GRFLX_ENGLISH = 0x01, + GRFLX_GERMAN = 0x02, + GRFLX_FRENCH = 0x03, + GRFLX_SPANISH = 0x04, + GRFLX_RUSSIAN = 0x07, + GRFLX_CZECH = 0x15, + GRFLX_SLOVAK = 0x16, + GRFLX_DEUTCH = 0x1F, + GRFLX_CATALAN = 0x22, + GRFLX_HUNGARIAN = 0x24, + GRFLX_ITALIAN = 0x27, + GRFLX_ROMANIAN = 0x28, + GRFLX_ICELANDIC = 0x29, + GRFLX_LATVIAN = 0x2A, + GRFLX_LITHUANIAN = 0x2B, + GRFLX_SLOVENIAN = 0x2C, + GRFLX_DANISH = 0x2D, + GRFLX_SEWDISH = 0x2E, + GRFLX_NORWEGIAN = 0x2F, + GRFLX_POLISH = 0x30, + GRFLX_GALICIAN = 0x31, + GRFLX_FRISIAN = 0x32, + GRFLX_ESTONIAN = 0x34, + GRFLX_FINNISH = 0x35, + GRFLX_PORTUGUESE = 0x36, + GRFLX_BRAZIZILAN = 0x37, + GRFLX_TURKISH = 0x3E, +} grf_language; + + +typedef struct iso_grf{ + char code[6]; + byte grfLangID; +}iso_grf; + +/** + * ISO code VS NewGrf langID conversion array. + * This array is used in two ways: + * 1-its ISO part is matching OpenTTD dynamic language id + * with newgrf bit positionning language id + * 2-its shift part is used to know what is the shift to + * watch for when inserting new strings, hence analysing newgrf langid + */ +const iso_grf iso_codes[MAX_LANG] = { + {"en_US", GRFLX_AMERICAN}, + {"en_GB", GRFLX_ENGLISH}, + {"de", GRFLX_GERMAN}, + {"fr", GRFLX_FRENCH}, + {"es", GRFLX_SPANISH}, + {"cs", GRFLX_CZECH}, + {"ca", GRFLX_CATALAN}, + {"da", GRFLX_DANISH}, + {"nl", GRFLX_DEUTCH}, + {"et", GRFLX_ESTONIAN}, + {"fi", GRFLX_FINNISH}, + {"fy", GRFLX_FRISIAN}, + {"gl", GRFLX_GALICIAN}, + {"hu", GRFLX_HUNGARIAN}, + {"is", GRFLX_ICELANDIC}, + {"it", GRFLX_ITALIAN}, + {"lv", GRFLX_LATVIAN}, + {"lt", GRFLX_LITHUANIAN}, + {"nb", GRFLX_NORWEGIAN}, + {"pl", GRFLX_POLISH}, + {"pt", GRFLX_PORTUGUESE}, + {"ro", GRFLX_ROMANIAN}, + {"ru", GRFLX_RUSSIAN}, + {"sk", GRFLX_SLOVAK}, + {"sl", GRFLX_SLOVENIAN}, + {"sv", GRFLX_SEWDISH}, + {"tr", GRFLX_TURKISH}, + {"gen", GRFLB_GENERIC} //this is not iso code, but there has to be something... +}; + + +static uint _num_grf_texts = 0; +static GRFTextEntry _grf_text[(1 << TABSIZE) * 3]; +static byte _currentLangID = GRFLX_ENGLISH; //by default, english is used. + + +/** + * Add the new read stirng into our structure. + * TODO : ajust the old scheme to the new one for german,french and spanish + */ +StringID AddGRFString(uint32 grfid, uint16 stringid, byte langid_to_add, const char *text_to_add) +{ + uint id; + + GRFText *newtext = calloc(1, sizeof(*newtext)); + + newtext->langid = langid_to_add; + newtext->text = strdup(text_to_add); + newtext->next = NULL; + + str_validate(newtext->text); + + for (id = 0; id < _num_grf_texts; id++) { + if (_grf_text[id].grfid == grfid && _grf_text[id].stringid == stringid) { + break; + } + } + + /* Too many strings allocated, return empty */ + if (id == lengthof(_grf_text)) return STR_EMPTY; + + /* Raise the number of strings added*/ + if (id == _num_grf_texts) _num_grf_texts++; + + /* When working with old scheme (BIT 6 of langid is clear) and + * English or american is among the set bits, simply add it as + * english on new scheme, as langid = 1. + * If there are more langid, we simply don't need them + */ + if (!HASBIT(6,langid_to_add)) { + if (HASBITS( GRFLB_AMERICAN | GRFLB_ENGLISH, langid_to_add)) { + newtext->langid = langid_to_add = GRFLX_ENGLISH; + } else { + /* If old scheme and not english nor american, scanning will + * have to be done. At this stage, only 3 are remaining: + * german,french and spanish : 0x04=2,0x08=3,0x10=4 + */ + } + } + + if (_grf_text[id].textholder == NULL) { + _grf_text[id].grfid = grfid; + _grf_text[id].stringid = stringid; + _grf_text[id].textholder = newtext; + } else { + GRFText *textptr = _grf_text[id].textholder; + while (textptr->next != NULL) textptr = textptr->next; + textptr->next = newtext; + } + + debug("Added %x: grfid %x string %x lang %x string %s", id, grfid, stringid, langid_to_add, newtext->text); + + return (GRFTAB << TABSIZE) + id; +} + + +/** + * Returns the index for this stringid associated with its grfID + */ +StringID GetGRFStringID(uint32 grfid, uint16 stringid) +{ + uint id; + for (id = 0; id < _num_grf_texts; id++) { + if (_grf_text[id].grfid == grfid && _grf_text[id].stringid == stringid) { + return (GRFTAB << TABSIZE) + id; + } + } + + return STR_UNDEFINED; +} + + +char *GetGRFString(char *buff, uint16 stringid) +{ + GRFText *search_text; + + assert(_grf_text[stringid].grfid != 0); + /*Search the list of lang-strings of this stringid for current lang */ + for (search_text = _grf_text[stringid].textholder; search_text != NULL; search_text = search_text->next) { + if (search_text->langid == _currentLangID){ + return strecpy(buff, search_text->text, NULL); + } + } + + /* Use the first text if the specific language isn't available */ + return strecpy(buff, _grf_text[stringid].textholder->text, NULL); +} + +/** + * Equivalence Setter function between game and newgrf langID. + * This function will adjust _currentLangID as to what is the LangID + * of the current language set by the user. + * The array iso_codes will be used to find that match. + * If not found, it will have to be standard english + * This function is called after the user changed language, + * from strings.c:ReadLanguagePack + * @param iso code of current selection + */ +void SetCurrentGrfLangID( const char *iso_name ) +{ + byte ret,i; + + ret = GRFLX_ENGLISH; //by default, english (not american) will be used + + for (i=0; i < MAX_LANG+1; i++) { + if (strcmp(iso_codes[i].code, iso_name)==0){ //we have a match? + ret = i; //we'll use this one then. + break; + } + } + _currentLangID = ret; +} + +/** + * House cleaning. + * TODO : Have to be written. + */ +void CleanUpStrings(void) +{ + uint id; + + GRFText *text_to_clear; + + for (id = 0; id < _num_grf_texts; id++) { + text_to_clear = _grf_text[id].textholder; + } +} diff --git a/newgrf_text.h b/newgrf_text.h new file mode 100644 index 000000000..2eed88ccb --- /dev/null +++ b/newgrf_text.h @@ -0,0 +1,41 @@ +/* $Id$ */ +#ifndef NEWGRF_TEXT_H +#define NEWGRF_TEXT_H + +/** @file + * Header of Action 04 "universal holder" structure and functions + */ + +#define MAX_LANG 28 + +/** + * Element of the linked list. + * Each of those elements represent the string, + * but according to a different lang. + */ +typedef struct GRFText { + byte langid; + char *text; + struct GRFText *next; +} GRFText; + + +/** + * Holder of the above structure. + * Putting both grfid and stringid togueter allow us to avoid duplicates, + * since it is NOT SUPPOSED to happen. + */ +typedef struct GRFTextEntry { + uint32 grfid; + uint16 stringid; + GRFText *textholder; +} GRFTextEntry; + + +StringID AddGRFString(uint32 grfid, uint16 stringid, byte langid, const char *text_to_add); +StringID GetGRFStringID(uint32 grfid, uint16 stringid); +char *GetGRFString(char *buff, uint16 stringid); +void CleanUpStrings(void); +void SetCurrentGrfLangID(const char *iso_name); + +#endif /* NEWGRF_TEXT_H */ diff --git a/openttd.dsp b/openttd.dsp index 83045befb..e63e3e221 100644 --- a/openttd.dsp +++ b/openttd.dsp @@ -292,6 +292,10 @@ SOURCE=.\newgrf_station.c # End Source File # Begin Source File +SOURCE=.\newgrf_text.c +# End Source File +# Begin Source File + SOURCE=.\npf.c # End Source File # Begin Source File @@ -658,6 +662,10 @@ SOURCE=.\newgrf_station.h # End Source File # Begin Source File +SOURCE=.\newgrf_text.h +# End Source File +# Begin Source File + SOURCE=.\news.h # End Source File # Begin Source File diff --git a/openttd.vcproj b/openttd.vcproj index 9cb54d103..f1e00ee4d 100644 --- a/openttd.vcproj +++ b/openttd.vcproj @@ -283,6 +283,9 @@ + + @@ -509,6 +512,9 @@ + + diff --git a/strings.c b/strings.c index 5a16e2a8c..022a4180a 100644 --- a/strings.c +++ b/strings.c @@ -16,6 +16,7 @@ #include "waypoint.h" #include "industry.h" #include "variables.h" +#include "newgrf_text.h" char _userstring[128]; @@ -178,6 +179,15 @@ char *GetStringWithArgs(char *buffr, uint string, const int32 *argv) case 15: return GetName(index, buffr); + case 28: + return GetGRFString(buffr, index); + + case 29: + return GetGRFString(buffr, index + 0x800); + + case 30: + return GetGRFString(buffr, index + 0x1000); + case 31: // dynamic strings. These are NOT to be passed through the formatter, // but passed through verbatim. @@ -1153,6 +1163,7 @@ bool ReadLanguagePack(int lang_index) ttd_strlcpy(_dynlang.curr_file, _dynlang.ent[lang_index].file, sizeof(_dynlang.curr_file)); _dynlang.curr = lang_index; + SetCurrentGrfLangID(_langpack->isocode); return true; } -- cgit v1.2.3-70-g09d2