From b3c7b81893ace04a5d419a98a75739a651ffc753 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 11 Apr 2020 18:12:28 +0200 Subject: [PATCH] - decoupled the string table from game implementation details. Using callbacks now to query needed game state. --- src/d_main.cpp | 21 ++++++++++-- src/doomstat.cpp | 1 - src/g_cvars.cpp | 2 +- src/gamedata/d_dehacked.cpp | 2 +- src/gamedata/stringtable.cpp | 62 ++++++++++++++++++++---------------- src/gamedata/stringtable.h | 46 +++++++++++++++++++++----- 6 files changed, 94 insertions(+), 40 deletions(-) diff --git a/src/d_main.cpp b/src/d_main.cpp index e28bd3f38..088b17c2f 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -2539,6 +2539,7 @@ static const char *DoomButtons[] = "moveup" }; CVAR(Bool, lookspring, true, CVAR_ARCHIVE); // Generate centerview when -mlook encountered? +EXTERN_CVAR(String, language) void Mlook_ReleaseHandler() { @@ -2548,6 +2549,17 @@ void Mlook_ReleaseHandler() } } +int StrTable_GetGender() +{ + return players[consoleplayer].userinfo.GetGender(); +} + +bool StrTable_ValidFilter(const char* str) +{ + if (gameinfo.gametype == GAME_Strife && (gameinfo.flags & GI_SHAREWARE) && !stricmp(str, "strifeteaser")) return true; + return stricmp(str, GameNames[gameinfo.gametype]) == 0; +} + //========================================================================== // // D_DoomMain @@ -2570,7 +2582,12 @@ static int D_DoomMain_Internal (void) buttonMap.GetButton(Button_Mlook)->bReleaseLock = true; buttonMap.GetButton(Button_Klook)->bReleaseLock = true; - // button != &Button_Mlook && button != &Button_Klook) + static StringtableCallbacks stblcb = + { + StrTable_ValidFilter, + StrTable_GetGender + }; + GStrings.SetCallbacks(&stblcb); std::set_new_handler(NewFailure); const char *batchout = Args->CheckValue("-errorlog"); @@ -2778,7 +2795,7 @@ static int D_DoomMain_Internal (void) } // [RH] Initialize localizable strings. - GStrings.LoadStrings (); + GStrings.LoadStrings (language); V_InitFontColors (); diff --git a/src/doomstat.cpp b/src/doomstat.cpp index 851948906..a2e4a38ce 100644 --- a/src/doomstat.cpp +++ b/src/doomstat.cpp @@ -35,7 +35,6 @@ int SaveVersion; // Localizable strings -FStringTable GStrings; // Game speed EGameSpeed GameSpeed = SPEED_Normal; diff --git a/src/g_cvars.cpp b/src/g_cvars.cpp index 47b7e1d81..7c5e6a0e5 100644 --- a/src/g_cvars.cpp +++ b/src/g_cvars.cpp @@ -201,7 +201,7 @@ CUSTOM_CVAR(Bool, ui_generic, false, CVAR_NOINITCALL) // This is for allowing to CUSTOM_CVAR(String, language, "auto", CVAR_ARCHIVE | CVAR_NOINITCALL | CVAR_GLOBALCONFIG) { - GStrings.UpdateLanguage(); + GStrings.UpdateLanguage(self); for (auto Level : AllLevels()) { // does this even make sense on secondary levels...? diff --git a/src/gamedata/d_dehacked.cpp b/src/gamedata/d_dehacked.cpp index b4d076b15..e8b5fa1ed 100644 --- a/src/gamedata/d_dehacked.cpp +++ b/src/gamedata/d_dehacked.cpp @@ -3079,7 +3079,7 @@ void FinishDehPatch () StateMap.Reset(); TouchedActors.Reset(); EnglishStrings.Clear(); - GStrings.SetDehackedStrings(std::move(DehStrings)); + GStrings.SetOverrideStrings(std::move(DehStrings)); // Now it gets nasty: We have to fiddle around with the weapons' ammo use info to make Doom's original // ammo consumption work as intended. diff --git a/src/gamedata/stringtable.cpp b/src/gamedata/stringtable.cpp index 3c0a256ca..bf685c92e 100644 --- a/src/gamedata/stringtable.cpp +++ b/src/gamedata/stringtable.cpp @@ -37,14 +37,11 @@ #include "stringtable.h" #include "cmdlib.h" #include "filesystem.h" -#include "i_system.h" #include "sc_man.h" #include "c_dispatch.h" #include "v_text.h" -#include "gi.h" -#include "d_player.h" - -EXTERN_CVAR(String, language) +#include "c_cvars.h" +#include "printf.h" //========================================================================== // @@ -52,7 +49,7 @@ EXTERN_CVAR(String, language) // //========================================================================== -void FStringTable::LoadStrings () +void FStringTable::LoadStrings (const char *language) { int lastlump, lump; @@ -70,7 +67,7 @@ void FStringTable::LoadStrings () if (!ParseLanguageCSV(lump, lumpdata)) LoadLanguage (lump, lumpdata); } - UpdateLanguage(); + UpdateLanguage(language); allMacros.Clear(); } @@ -172,7 +169,7 @@ bool FStringTable::readMacros(int lumpnum) auto language = data[i][1]; if (macroname.IsEmpty() || language.IsEmpty()) continue; FStringf combined_name("%s/%s", language.GetChars(), macroname.GetChars()); - FName name = combined_name; + FName name = combined_name.GetChars(); StringMacro macro; @@ -240,12 +237,26 @@ bool FStringTable::ParseLanguageCSV(int lumpnum, const TArray &buffer) if (filtercol > -1) { auto filterstr = row[filtercol]; - auto filter = filterstr.Split(" ", FString::TOK_SKIPEMPTY); - if (filter.Size() > 0 && filter.FindEx([](const auto &str) { return str.CompareNoCase(GameNames[gameinfo.gametype]) == 0; }) == filter.Size()) - continue; + if (filterstr.IsNotEmpty()) + { + bool ok = false; + if (callbacks && callbacks->ValidFilter) + { + auto filter = filterstr.Split(" ", FString::TOK_SKIPEMPTY); + for (auto& entry : filter) + { + if (callbacks->ValidFilter(entry)) + { + ok = true; + break; + } + } + } + if (!ok) continue; + } } - FName strName = row[labelcol]; + FName strName = row[labelcol].GetChars(); if (hasDefaultEntry) { DeleteForLabel(lumpnum, strName); @@ -348,14 +359,7 @@ void FStringTable::LoadLanguage (int lumpnum, const TArray &buffer) sc.MustGetStringName("ifgame"); sc.MustGetStringName("("); sc.MustGetString(); - if (sc.Compare("strifeteaser")) - { - skip |= (gameinfo.gametype != GAME_Strife) || !(gameinfo.flags & GI_SHAREWARE); - } - else - { - skip |= !sc.Compare(GameTypeName()); - } + skip |= (!callbacks || !callbacks->ValidFilter || !callbacks->ValidFilter(sc.String)); sc.MustGetStringName(")"); sc.MustGetString(); @@ -445,11 +449,11 @@ void FStringTable::InsertString(int lumpnum, int langid, FName label, const FStr FString macroname(te.strings[0].GetChars() + index + 2, endindex - index - 2); FStringf lookupstr("%s/%s", strlangid, macroname.GetChars()); FStringf replacee("@[%s]", macroname.GetChars()); - FName lookupname(lookupstr, true); + FName lookupname(lookupstr.GetChars(), true); auto replace = allMacros.CheckKey(lookupname); for (int i = 0; i < 4; i++) { - const char *replacement = replace && replace->Replacements[i] ? replace->Replacements[i] : ""; + const char *replacement = replace && replace->Replacements[i] ? replace->Replacements[i].GetChars() : ""; te.strings[i].Substitute(replacee, replacement); } } @@ -462,8 +466,10 @@ void FStringTable::InsertString(int lumpnum, int langid, FName label, const FStr // //========================================================================== -void FStringTable::UpdateLanguage() +void FStringTable::UpdateLanguage(const char *language) { + if (language) activeLanguage = language; + else language = activeLanguage.GetChars(); size_t langlen = strlen(language); int LanguageID = (langlen < 2 || langlen > 3) ? @@ -479,7 +485,7 @@ void FStringTable::UpdateLanguage() currentLanguageSet.Push(std::make_pair(lang_id, list)); }; - checkone(dehacked_table); + checkone(override_table); checkone(global_table); checkone(LanguageID); checkone(LanguageID & MAKE_ID(0xff, 0xff, 0, 0)); @@ -534,7 +540,7 @@ bool FStringTable::exists(const char *name) FName nm(name, true); if (nm != NAME_None) { - uint32_t defaultStrings[] = { default_table, global_table, dehacked_table }; + uint32_t defaultStrings[] = { default_table, global_table, override_table }; for (auto mapid : defaultStrings) { @@ -561,7 +567,7 @@ const char *FStringTable::GetString(const char *name, uint32_t *langtable, int g { return nullptr; } - if (gender == -1) gender = players[consoleplayer].userinfo.GetGender(); + if (gender == -1 && callbacks && callbacks->GetPlayerGender) gender = callbacks->GetPlayerGender(); if (gender < 0 || gender > 3) gender = 0; FName nm(name, true); if (nm != NAME_None) @@ -591,7 +597,7 @@ const char *FStringTable::GetLanguageString(const char *name, uint32_t langtable { return nullptr; } - if (gender == -1) gender = players[consoleplayer].userinfo.GetGender(); + if (gender == -1 && callbacks && callbacks->GetPlayerGender) gender = callbacks->GetPlayerGender(); if (gender < 0 || gender > 3) gender = 0; FName nm(name, true); if (nm != NAME_None) @@ -657,3 +663,5 @@ const char *StringMap::MatchString (const char *string) const } return nullptr; } + +FStringTable GStrings; diff --git a/src/gamedata/stringtable.h b/src/gamedata/stringtable.h index 37dac5553..f9f714f3e 100644 --- a/src/gamedata/stringtable.h +++ b/src/gamedata/stringtable.h @@ -44,8 +44,18 @@ #include -#include "doomdef.h" -#include "doomtype.h" +#include "basics.h" +#include "zstring.h" +#include "tarray.h" +#include "name.h" + + +struct StringtableCallbacks +{ + // These two functions would create a dependency on the game code so they are installed as callbacks. + bool (*ValidFilter)(const char* str); + int (*GetPlayerGender)(); +}; struct TableElement { @@ -74,19 +84,19 @@ public: { default_table = MAKE_ID('*', '*', 0, 0), global_table = MAKE_ID('*', 0, 0, 0), - dehacked_table = MAKE_ID('*', '*', '*', 0) + override_table = MAKE_ID('*', '*', '*', 0) }; using LangMap = TMap; using StringMacroMap = TMap; - void LoadStrings (); - void UpdateLanguage(); + void LoadStrings(const char *language); + void UpdateLanguage(const char* language); StringMap GetDefaultStrings() { return allStrings[default_table]; } // Dehacked needs these for comparison - void SetDehackedStrings(StringMap && map) + void SetOverrideStrings(StringMap && map) { - allStrings.Insert(dehacked_table, map); - UpdateLanguage(); + allStrings.Insert(override_table, map); + UpdateLanguage(nullptr); } const char *GetLanguageString(const char *name, uint32_t langtable, int gender = -1) const; @@ -98,12 +108,15 @@ public: return GetString(name, nullptr); } bool exists(const char *name); + void SetCallbacks(StringtableCallbacks* cb) { callbacks = cb; } private: + FString activeLanguage; StringMacroMap allMacros; LangMap allStrings; TArray> currentLanguageSet; + StringtableCallbacks* callbacks = nullptr; void LoadLanguage (int lumpnum, const TArray &buffer); TArray> parseCSV(const TArray &buffer); @@ -116,6 +129,23 @@ private: void DeleteForLabel(int lumpnum, FName label); static size_t ProcessEscapes (char *str); +public: + static FString MakeMacro(const char *str) + { + if (*str == '$') return str; + return FString("$") + str; + } + + static FString MakeMacro(const char *str, size_t len) + { + if (*str == '$') return FString(str, len); + return "$" + FString(str, len); + } + + const char* localize(const char* str) + { + return *str == '$' ? operator()(str + 1) : str; + } }; #endif //__STRINGTABLE_H__