From aa550310f6300c0f640d705f22f0ba4f5395cce8 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 15 Feb 2019 00:29:24 +0100 Subject: [PATCH] - allow the language table to supersede the title patches, if appropriate For the Doom IWADs the provided font looks almost identical to the characters used on the title patches. So, for any level name that got replaced in some language, it will now check if the retrieved name comes from the default table, and if not, ignore the title patch and print the name with the specified font. This also required removing the 'en' label from the default table, because with this present, the text would always be picked from 'en' instead of 'default'. Since 'en' and 'default' had the same contents, in any English locale the 'default' table was never hit, so this won't make any difference for the texts being chosen. Last but not least, wminfo has been made a local variable in G_DoCompleted. There were two places where this was accessed from outside the summary screen or its setup code, and both were incorrect. --- src/d_iwad.cpp | 7 ++++ src/d_main.h | 2 +- src/g_game.cpp | 4 +-- src/g_hub.cpp | 5 +-- src/g_level.cpp | 35 +++++++++++++++++-- src/gamedata/g_mapinfo.cpp | 8 ++--- src/gamedata/g_mapinfo.h | 2 +- src/gamedata/gi.h | 22 +++++++----- src/gamedata/stringtable.cpp | 26 ++++++++------ src/gamedata/stringtable.h | 21 ++++++++--- src/p_setup.cpp | 4 +-- src/scripting/backend/codegen.cpp | 2 +- src/utility/zstring.cpp | 2 +- src/wi_stuff.cpp | 9 ++--- src/wi_stuff.h | 4 +-- wadsrc/static/iwadinfo.txt | 11 +++++- wadsrc/static/language.enu | 2 +- .../static/zscript/statscreen/statscreen.txt | 3 +- wadsrc/static/zscript/statscreen/types.txt | 1 + wadsrc_extra/static/language.enu | 2 +- 20 files changed, 114 insertions(+), 58 deletions(-) diff --git a/src/d_iwad.cpp b/src/d_iwad.cpp index 2716d1eb14..6f33c718e3 100644 --- a/src/d_iwad.cpp +++ b/src/d_iwad.cpp @@ -163,6 +163,13 @@ void FIWadManager::ParseIWadInfo(const char *fn, const char *data, int datasize, sc.MustGetString(); iwad->BkColor = V_GetColor(NULL, sc); } + else if (sc.Compare("IgnoreTitlePatches")) + { + sc.MustGetStringName("="); + sc.MustGetNumber(); + if (sc.Number) iwad->flags |= GI_IGNORETITLEPATCHES; + else iwad->flags &= ~GI_IGNORETITLEPATCHES; + } else if (sc.Compare("Load")) { sc.MustGetStringName("="); diff --git a/src/d_main.h b/src/d_main.h index 05d818f145..bc8f54adab 100644 --- a/src/d_main.h +++ b/src/d_main.h @@ -160,7 +160,7 @@ public: int GetIWadFlags(unsigned int num) const { if (num < mIWadInfos.Size()) return mIWadInfos[num].flags; - else return false; + else return 0; } }; diff --git a/src/g_game.cpp b/src/g_game.cpp index d389dc5300..861b506a85 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -174,9 +174,7 @@ uint8_t* zdembodyend; // end of ZDEM BODY chunk bool singledemo; // quit after playing a demo from cmdline bool precache = true; // if true, load all graphics at start - -wbstartstruct_t wminfo; // parms for world map / intermission - + short consistancy[MAXPLAYERS][BACKUPTICS]; diff --git a/src/g_hub.cpp b/src/g_hub.cpp index 677b991609..0e70deb1ab 100644 --- a/src/g_hub.cpp +++ b/src/g_hub.cpp @@ -129,12 +129,13 @@ void G_LeavingHub(FLevelLocals *Level, int mode, cluster_info_t * cluster, wbsta { if (cluster->flags & CLUSTER_LOOKUPNAME) { - Level->LevelName = GStrings(cluster->ClusterName); + wbs->thisname = GStrings(cluster->ClusterName); } else { - Level->LevelName = cluster->ClusterName; + wbs->thisname = cluster->ClusterName; } + wbs->LName0.SetInvalid(); // The level's own name was just invalidated, and so was its name patch. } } } diff --git a/src/g_level.cpp b/src/g_level.cpp index 66b4b84f17..d86618ebeb 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -81,6 +81,7 @@ #include "a_dynlight.h" #include "p_conversation.h" #include "p_effect.h" +#include "stringtable.h" #include "gi.h" @@ -779,6 +780,8 @@ void G_DoCompleted (void) // Close the conversation menu if open. P_FreeStrifeConversations (); + wbstartstruct_t wminfo; // parms for world map / intermission + if (primaryLevel->DoCompleted(nextlevel, wminfo)) { gamestate = GS_INTERMISSION; @@ -802,12 +805,14 @@ bool FLevelLocals::DoCompleted (FString nextlevel, wbstartstruct_t &wminfo) if (!(flags & LEVEL_CHANGEMAPCHEAT)) FindLevelInfo (MapName)->flags |= LEVEL_VISITED; + uint32_t langtable[2] = {}; wminfo.finished_ep = cluster - 1; wminfo.LName0 = TexMan.CheckForTexture(info->PName, ETextureType::MiscPatch); + wminfo.thisname = info->LookupLevelName(&langtable[0]); // re-get the name so we have more info about its origin. wminfo.current = MapName; if (deathmatch && - (dmflags & DF_SAME_LEVEL) && + (*dmflags & DF_SAME_LEVEL) && !(flags & LEVEL_CHANGEMAPCHEAT)) { wminfo.next = MapName; @@ -818,13 +823,37 @@ bool FLevelLocals::DoCompleted (FString nextlevel, wbstartstruct_t &wminfo) level_info_t *nextinfo = FindLevelInfo (nextlevel, false); if (nextinfo == NULL || strncmp (nextlevel, "enDSeQ", 6) == 0) { - wminfo.next = nextlevel; + wminfo.next = ""; wminfo.LName1.SetInvalid(); + wminfo.nextname = ""; } else { wminfo.next = nextinfo->MapName; wminfo.LName1 = TexMan.CheckForTexture(nextinfo->PName, ETextureType::MiscPatch); + wminfo.nextname = info->LookupLevelName(&langtable[1]); + } + } + + // Ignore the (C)WILVxx lumps from the original Doom IWADs so that the name can be localized properly, if the retrieved text does not come from the default table. + // This is only active for those IWADS where the style of these graphics matches the provided BIGFONT for the respective game. + if (gameinfo.flags & GI_IGNORETITLEPATCHES) + { + FTextureID *texids[] = { &wminfo.LName0, &wminfo.LName1 }; + for (int i = 0; i < 2; i++) + { + if (texids[i]->isValid() && langtable[i] != FStringTable::default_table) + { + FTexture *tex = TexMan.GetTexture(*texids[i]); + if (tex != nullptr) + { + int filenum = Wads.GetLumpFile(tex->GetSourceLump()); + if (filenum >= 0 && filenum <= Wads.GetIwadNum()) + { + texids[i]->SetInvalid(); + } + } + } } } @@ -1296,7 +1325,7 @@ DEFINE_ACTION_FUNCTION(FLevelLocals, WorldDone) void G_DoWorldDone (void) { gamestate = GS_LEVEL; - if (wminfo.next[0] == 0) + if (nextlevel.IsEmpty()) { // Don't crash if no next map is given. Just repeat the current one. Printf ("No next map specified.\n"); diff --git a/src/gamedata/g_mapinfo.cpp b/src/gamedata/g_mapinfo.cpp index 826f44181d..97645273da 100644 --- a/src/gamedata/g_mapinfo.cpp +++ b/src/gamedata/g_mapinfo.cpp @@ -299,14 +299,14 @@ void level_info_t::Reset() // //========================================================================== -FString level_info_t::LookupLevelName() +FString level_info_t::LookupLevelName(uint32_t *langtable) { + // All IWAD names that may be substituted by a graphics patch are declared as language strings. + if (langtable) *langtable = 0; if (flags & LEVEL_LOOKUPLEVELNAME) { const char *thename; - const char *lookedup; - - lookedup = GStrings[LevelName]; + const char *lookedup = GStrings.GetString(LevelName, langtable); if (lookedup == NULL) { thename = LevelName; diff --git a/src/gamedata/g_mapinfo.h b/src/gamedata/g_mapinfo.h index bb6ae9886d..f9cd2f6f4a 100644 --- a/src/gamedata/g_mapinfo.h +++ b/src/gamedata/g_mapinfo.h @@ -400,7 +400,7 @@ struct level_info_t } void Reset(); bool isValid(); - FString LookupLevelName (); + FString LookupLevelName (uint32_t *langtable = nullptr); void ClearDefered() { deferred.Clear(); diff --git a/src/gamedata/gi.h b/src/gamedata/gi.h index 769076d4d2..4f27a6969b 100644 --- a/src/gamedata/gi.h +++ b/src/gamedata/gi.h @@ -38,15 +38,19 @@ #include "zstring.h" // Flags are not user configurable and only depend on the standard IWADs -#define GI_MAPxx 0x00000001 -#define GI_SHAREWARE 0x00000002 -#define GI_MENUHACK_EXTENDED 0x00000004 // (Heretic) -#define GI_TEASER2 0x00000008 // Alternate version of the Strife Teaser -#define GI_COMPATSHORTTEX 0x00000010 // always force COMPAT_SHORTTEX for IWAD maps. -#define GI_COMPATSTAIRS 0x00000020 // same for stairbuilding -#define GI_COMPATPOLY1 0x00000040 // Hexen's MAP36 needs old polyobject drawing -#define GI_COMPATPOLY2 0x00000080 // so does HEXDD's MAP47 -#define GI_NOTEXTCOLOR 0x00000100 // Chex Quest 3 would have everything green +enum +{ + GI_MAPxx = 0x00000001, + GI_SHAREWARE = 0x00000002, + GI_MENUHACK_EXTENDED = 0x00000004, // (Heretic) + GI_TEASER2 = 0x00000008, // Alternate version of the Strife Teaser + GI_COMPATSHORTTEX = 0x00000010, // always force COMPAT_SHORTTEX for IWAD maps. + GI_COMPATSTAIRS = 0x00000020, // same for stairbuilding + GI_COMPATPOLY1 = 0x00000040, // Hexen's MAP36 needs old polyobject drawing + GI_COMPATPOLY2 = 0x00000080, // so does HEXDD's MAP47 + GI_NOTEXTCOLOR = 0x00000100, // Chex Quest 3 would have everything green + GI_IGNORETITLEPATCHES = 0x00000200, // Ignore the map name graphics when not runnning in English language +}; #include "gametype.h" diff --git a/src/gamedata/stringtable.cpp b/src/gamedata/stringtable.cpp index 1afc68e439..679735c121 100644 --- a/src/gamedata/stringtable.cpp +++ b/src/gamedata/stringtable.cpp @@ -83,11 +83,11 @@ void FStringTable::LoadLanguage (int lumpnum) } if (len == 1 && sc.String[0] == '*') { - activeMaps.Push(MAKE_ID('*', 0, 0, 0)); + activeMaps.Push(global_table); } else if (len == 7 && stricmp (sc.String, "default") == 0) { - activeMaps.Push(MAKE_ID('*', '*', 0, 0)); + activeMaps.Push(default_table); } else { @@ -167,18 +167,18 @@ void FStringTable::UpdateLanguage() auto checkone = [&](uint32_t lang_id) { auto list = allStrings.CheckKey(lang_id); - if (list && currentLanguageSet.Find(list) == currentLanguageSet.Size()) - currentLanguageSet.Push(list); + if (list && currentLanguageSet.FindEx([&](const auto &element) { return element.first == lang_id; }) == currentLanguageSet.Size()) + currentLanguageSet.Push(std::make_pair(lang_id, list)); }; - checkone(MAKE_ID('*', '*', '*', 0)); - checkone(MAKE_ID('*', 0, 0, 0)); + checkone(dehacked_table); + checkone(global_table); for (int i = 0; i < 4; ++i) { checkone(LanguageIDs[i]); checkone(LanguageIDs[i] & MAKE_ID(0xff, 0xff, 0, 0)); } - checkone(MAKE_ID('*', '*', 0, 0)); + checkone(default_table); } // Replace \ escape sequences in a string with the escaped characters. @@ -219,7 +219,7 @@ bool FStringTable::exists(const char *name) FName nm(name, true); if (nm != NAME_None) { - uint32_t defaultStrings[] = { MAKE_ID('*', '*', '*', 0), MAKE_ID('*', 0, 0, 0), MAKE_ID('*', '*', 0, 0) }; + uint32_t defaultStrings[] = { default_table, global_table, dehacked_table }; for (auto mapid : defaultStrings) { @@ -235,7 +235,7 @@ bool FStringTable::exists(const char *name) } // Finds a string by name and returns its value -const char *FStringTable::operator[] (const char *name) const +const char *FStringTable::GetString(const char *name, uint32_t *langtable) const { if (name == nullptr || *name == 0) { @@ -246,8 +246,12 @@ const char *FStringTable::operator[] (const char *name) const { for (auto map : currentLanguageSet) { - auto item = map->CheckKey(nm); - if (item) return item->GetChars(); + auto item = map.second->CheckKey(nm); + if (item) + { + if (langtable) *langtable = map.first; + return item->GetChars(); + } } } return nullptr; diff --git a/src/gamedata/stringtable.h b/src/gamedata/stringtable.h index 11416367c1..97201a582d 100644 --- a/src/gamedata/stringtable.h +++ b/src/gamedata/stringtable.h @@ -58,25 +58,36 @@ public: class FStringTable { public: + enum : uint32_t + { + default_table = MAKE_ID('*', '*', 0, 0), + global_table = MAKE_ID('*', 0, 0, 0), + dehacked_table = MAKE_ID('*', '*', '*', 0) + }; + using LangMap = TMap; void LoadStrings (); void UpdateLanguage(); - StringMap GetDefaultStrings() { return allStrings[MAKE_ID('*', '*', 0, 0)]; } // Dehacked needs these for comparison + StringMap GetDefaultStrings() { return allStrings[default_table]; } // Dehacked needs these for comparison void SetDehackedStrings(StringMap && map) { - allStrings.Insert(MAKE_ID('*', '*', '*', 0), map); + allStrings.Insert(dehacked_table, map); UpdateLanguage(); } - + + const char *GetString(const char *name, uint32_t *langtable) const; const char *operator() (const char *name) const; // Never returns NULL - const char *operator[] (const char *name) const; // Can return NULL + const char *operator[] (const char *name) const + { + return GetString(name, nullptr); + } bool exists(const char *name); private: LangMap allStrings; - TArray currentLanguageSet; + TArray> currentLanguageSet; void LoadLanguage (int lumpnum); static size_t ProcessEscapes (char *str); diff --git a/src/p_setup.cpp b/src/p_setup.cpp index dddfe2d46c..2842587b40 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -260,8 +260,7 @@ void FLevelLocals::ClearLevelData() ClearAllSubsectorLinks(); // can't be done as part of the polyobj deletion process. total_monsters = total_items = total_secrets = - killed_monsters = found_items = found_secrets = - wminfo.maxfrags = 0; + killed_monsters = found_items = found_secrets = 0; for (int i = 0; i < 4; i++) { @@ -375,7 +374,6 @@ void P_SetupLevel(FLevelLocals *Level, int position, bool newGame) // This is motivated as follows: Level->maptype = MAPTYPE_UNKNOWN; - wminfo.partime = 180; if (!savegamerestore) { diff --git a/src/scripting/backend/codegen.cpp b/src/scripting/backend/codegen.cpp index 7c8f207d6c..98ff002033 100644 --- a/src/scripting/backend/codegen.cpp +++ b/src/scripting/backend/codegen.cpp @@ -322,7 +322,7 @@ static FxExpression *StringConstToChar(FxExpression *basex) int chr = str.GetNextCharacter(position); // Only succeed if the full string is consumed, i.e. it contains only one code point. - if (position == str.Len()) + if (position == (int)str.Len()) { return new FxConstant(chr, basex->ScriptPosition); } diff --git a/src/utility/zstring.cpp b/src/utility/zstring.cpp index 5845d47c32..fa56229ad3 100644 --- a/src/utility/zstring.cpp +++ b/src/utility/zstring.cpp @@ -485,7 +485,7 @@ void FString::DeleteLastCharacter() { if (Len() == 0) return; auto pos = Len() - 1; - while (pos > 0 && Chars[pos] >= 0x80 && Chars[pos] < 0xc0) pos--; + while (pos > 0 && uint8_t(Chars[pos]) >= 0x80 && uint8_t(Chars[pos]) < 0xc0) pos--; if (pos <= 0) { Data()->Release(); diff --git a/src/wi_stuff.cpp b/src/wi_stuff.cpp index c752be66d1..1849d471cf 100644 --- a/src/wi_stuff.cpp +++ b/src/wi_stuff.cpp @@ -760,13 +760,7 @@ void WI_Start(wbstartstruct_t *wbstartstruct) I_FatalError("Cannot create status screen"); } } - // Set up some global stuff that is always needed. - auto info = FindLevelInfo(wbstartstruct->next, false); - if (info == nullptr) - { - wbstartstruct->next = ""; - } - else wbstartstruct->nextname = info->LookupLevelName(); + V_SetBlend(0, 0, 0, 0); S_StopAllChannels(); for (auto Level : AllLevels()) @@ -863,6 +857,7 @@ DEFINE_FIELD_X(WBStartStruct, wbstartstruct_t, next_ep); DEFINE_FIELD_X(WBStartStruct, wbstartstruct_t, current); DEFINE_FIELD_X(WBStartStruct, wbstartstruct_t, next); DEFINE_FIELD_X(WBStartStruct, wbstartstruct_t, nextname); +DEFINE_FIELD_X(WBStartStruct, wbstartstruct_t, thisname); DEFINE_FIELD_X(WBStartStruct, wbstartstruct_t, LName0); DEFINE_FIELD_X(WBStartStruct, wbstartstruct_t, LName1); DEFINE_FIELD_X(WBStartStruct, wbstartstruct_t, maxkills); diff --git a/src/wi_stuff.h b/src/wi_stuff.h index 4b12820f00..6f06037811 100644 --- a/src/wi_stuff.h +++ b/src/wi_stuff.h @@ -30,6 +30,7 @@ #include "doomdef.h" class FTexture; +struct FLevelLocals; // // INTERMISSION @@ -54,6 +55,7 @@ struct wbstartstruct_t FString current; // [RH] Name of map just finished FString next; // next level, [RH] actual map name FString nextname; // printable name for next level. + FString thisname; // printable name for next level. FTextureID LName0; FTextureID LName1; @@ -78,8 +80,6 @@ struct wbstartstruct_t // Intermission stats. // Parameters for world map / intermission. -extern wbstartstruct_t wminfo; - // Called by main loop, animate the intermission. void WI_Ticker (); diff --git a/wadsrc/static/iwadinfo.txt b/wadsrc/static/iwadinfo.txt index 12d5db1b56..c75fc166d1 100644 --- a/wadsrc/static/iwadinfo.txt +++ b/wadsrc/static/iwadinfo.txt @@ -318,6 +318,7 @@ IWad "DPHOOF","BFGGA0","HEADA1","CYBRA1","SPIDA1D1", "E4M2", "DMENUPIC", "M_ACPT", "M_CAN", "M_EXITO", "M_CHG" BannerColors = "54 54 54", "a8 a8 a8" + IgnoreTitlePatches = 1 } IWad @@ -330,6 +331,7 @@ IWad Compatibility = "Shorttex" MustContain = "SMOOSHED", "ANIMDEFS", "LANGUAGE", "MAPINFO", "ENDOOM", "M_DOOM", "TITLEPIC", "TEXTURES" BannerColors = "a8 00 00", "a8 a8 a8" + IgnoreTitlePatches = 1 } IWad @@ -345,6 +347,7 @@ IWad "E3M1","E3M2","E3M3","E3M4","E3M5","E3M6","E3M7","E3M8","E3M9", "DPHOOF","BFGGA0","HEADA1","CYBRA1","SPIDA1D1", "E4M2" BannerColors = "54 54 54", "a8 a8 a8" + IgnoreTitlePatches = 1 } IWad @@ -360,6 +363,7 @@ IWad "E3M1","E3M2","E3M3","E3M4","E3M5","E3M6","E3M7","E3M8","E3M9", "DPHOOF","BFGGA0","HEADA1","CYBRA1","SPIDA1D1" BannerColors = "54 54 54", "a8 a8 a8" + IgnoreTitlePatches = 1 } IWad @@ -371,6 +375,7 @@ IWad Compatibility = "Shareware", "Shorttex" MustContain = "E1M1" BannerColors = "54 54 54", "a8 a8 a8" + IgnoreTitlePatches = 1 } IWad @@ -384,6 +389,7 @@ IWad Compatibility = "Shorttex", "Stairs" MustContain = "MAP01", "REDTNT2" BannerColors = "a8 00 00", "a8 a8 a8" + IgnoreTitlePatches = 1 } IWad @@ -397,6 +403,7 @@ IWad Compatibility = "Shorttex" MustContain = "MAP01", "CAMO1" BannerColors = "a8 00 00", "a8 a8 a8" + IgnoreTitlePatches = 1 } IWad @@ -411,9 +418,10 @@ IWad MustContain = "MAP01", "DMENUPIC", "M_ACPT", "M_CAN", "M_EXITO", "M_CHG" BannerColors = "a8 00 00", "a8 a8 a8" Load = "nerve.wad" + IgnoreTitlePatches = 1 } -// Doom 2 must be last to be checked becaude MAP01 is its only requirement +// Doom 2 must be last to be checked because MAP01 is its only requirement IWad { Name = "DOOM 2: Hell on Earth" @@ -426,6 +434,7 @@ IWad MustContain = "MAP01" BannerColors = "a8 00 00", "a8 a8 a8" Load = "nerve.wad" + IgnoreTitlePatches = 1 } diff --git a/wadsrc/static/language.enu b/wadsrc/static/language.enu index fbbd2e1665..cf4fa12702 100644 --- a/wadsrc/static/language.enu +++ b/wadsrc/static/language.enu @@ -1,6 +1,6 @@ /* U.S. English. (Sorry, it's not English English.) */ -[en default] +[default] SECRETMESSAGE = "A secret is revealed!"; diff --git a/wadsrc/static/zscript/statscreen/statscreen.txt b/wadsrc/static/zscript/statscreen/statscreen.txt index 7edde60c42..0903299abb 100644 --- a/wadsrc/static/zscript/statscreen/statscreen.txt +++ b/wadsrc/static/zscript/statscreen/statscreen.txt @@ -705,8 +705,7 @@ class StatusScreen abstract play version("2.5") Sucks = TexMan.CheckForTexture("WISUCKS", TexMan.Type_MiscPatch); // "sucks" Par = TexMan.CheckForTexture("WIPAR", TexMan.Type_MiscPatch); // "par" - // Use the local level structure which can be overridden by hubs - lnametexts[0] = Level.LevelName; + lnametexts[0] = wbstartstruct.thisname; lnametexts[1] = wbstartstruct.nextname; bg = InterBackground.Create(wbs); diff --git a/wadsrc/static/zscript/statscreen/types.txt b/wadsrc/static/zscript/statscreen/types.txt index c3dad0c765..972a47b0c5 100644 --- a/wadsrc/static/zscript/statscreen/types.txt +++ b/wadsrc/static/zscript/statscreen/types.txt @@ -23,6 +23,7 @@ struct WBStartStruct native version("2.4") native String current; // [RH] Name of map just finished native String next; // next level, [RH] actual map name native String nextname; // next level, printable name + native String thisname; // this level, printable name native TextureID LName0; native TextureID LName1; diff --git a/wadsrc_extra/static/language.enu b/wadsrc_extra/static/language.enu index 36290df475..ce0a737250 100644 --- a/wadsrc_extra/static/language.enu +++ b/wadsrc_extra/static/language.enu @@ -1,4 +1,4 @@ -[en default] +[default] // Strings from Hexen's IWAD scripts. Technically they are not needed here for English, they are mainly meant to be documentation for translating.