- decoupled the string table from game implementation details.

Using callbacks now to query needed game state.
This commit is contained in:
Christoph Oelckers 2020-04-11 18:12:28 +02:00
parent c3a381ed92
commit b3c7b81893
6 changed files with 94 additions and 40 deletions

View File

@ -2539,6 +2539,7 @@ static const char *DoomButtons[] =
"moveup" }; "moveup" };
CVAR(Bool, lookspring, true, CVAR_ARCHIVE); // Generate centerview when -mlook encountered? CVAR(Bool, lookspring, true, CVAR_ARCHIVE); // Generate centerview when -mlook encountered?
EXTERN_CVAR(String, language)
void Mlook_ReleaseHandler() 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 // D_DoomMain
@ -2570,7 +2582,12 @@ static int D_DoomMain_Internal (void)
buttonMap.GetButton(Button_Mlook)->bReleaseLock = true; buttonMap.GetButton(Button_Mlook)->bReleaseLock = true;
buttonMap.GetButton(Button_Klook)->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); std::set_new_handler(NewFailure);
const char *batchout = Args->CheckValue("-errorlog"); const char *batchout = Args->CheckValue("-errorlog");
@ -2778,7 +2795,7 @@ static int D_DoomMain_Internal (void)
} }
// [RH] Initialize localizable strings. // [RH] Initialize localizable strings.
GStrings.LoadStrings (); GStrings.LoadStrings (language);
V_InitFontColors (); V_InitFontColors ();

View File

@ -35,7 +35,6 @@
int SaveVersion; int SaveVersion;
// Localizable strings // Localizable strings
FStringTable GStrings;
// Game speed // Game speed
EGameSpeed GameSpeed = SPEED_Normal; EGameSpeed GameSpeed = SPEED_Normal;

View File

@ -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) CUSTOM_CVAR(String, language, "auto", CVAR_ARCHIVE | CVAR_NOINITCALL | CVAR_GLOBALCONFIG)
{ {
GStrings.UpdateLanguage(); GStrings.UpdateLanguage(self);
for (auto Level : AllLevels()) for (auto Level : AllLevels())
{ {
// does this even make sense on secondary levels...? // does this even make sense on secondary levels...?

View File

@ -3079,7 +3079,7 @@ void FinishDehPatch ()
StateMap.Reset(); StateMap.Reset();
TouchedActors.Reset(); TouchedActors.Reset();
EnglishStrings.Clear(); 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 // 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. // ammo consumption work as intended.

View File

@ -37,14 +37,11 @@
#include "stringtable.h" #include "stringtable.h"
#include "cmdlib.h" #include "cmdlib.h"
#include "filesystem.h" #include "filesystem.h"
#include "i_system.h"
#include "sc_man.h" #include "sc_man.h"
#include "c_dispatch.h" #include "c_dispatch.h"
#include "v_text.h" #include "v_text.h"
#include "gi.h" #include "c_cvars.h"
#include "d_player.h" #include "printf.h"
EXTERN_CVAR(String, language)
//========================================================================== //==========================================================================
// //
@ -52,7 +49,7 @@ EXTERN_CVAR(String, language)
// //
//========================================================================== //==========================================================================
void FStringTable::LoadStrings () void FStringTable::LoadStrings (const char *language)
{ {
int lastlump, lump; int lastlump, lump;
@ -70,7 +67,7 @@ void FStringTable::LoadStrings ()
if (!ParseLanguageCSV(lump, lumpdata)) if (!ParseLanguageCSV(lump, lumpdata))
LoadLanguage (lump, lumpdata); LoadLanguage (lump, lumpdata);
} }
UpdateLanguage(); UpdateLanguage(language);
allMacros.Clear(); allMacros.Clear();
} }
@ -172,7 +169,7 @@ bool FStringTable::readMacros(int lumpnum)
auto language = data[i][1]; auto language = data[i][1];
if (macroname.IsEmpty() || language.IsEmpty()) continue; if (macroname.IsEmpty() || language.IsEmpty()) continue;
FStringf combined_name("%s/%s", language.GetChars(), macroname.GetChars()); FStringf combined_name("%s/%s", language.GetChars(), macroname.GetChars());
FName name = combined_name; FName name = combined_name.GetChars();
StringMacro macro; StringMacro macro;
@ -240,12 +237,26 @@ bool FStringTable::ParseLanguageCSV(int lumpnum, const TArray<uint8_t> &buffer)
if (filtercol > -1) if (filtercol > -1)
{ {
auto filterstr = row[filtercol]; auto filterstr = row[filtercol];
auto filter = filterstr.Split(" ", FString::TOK_SKIPEMPTY); if (filterstr.IsNotEmpty())
if (filter.Size() > 0 && filter.FindEx([](const auto &str) { return str.CompareNoCase(GameNames[gameinfo.gametype]) == 0; }) == filter.Size()) {
continue; 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) if (hasDefaultEntry)
{ {
DeleteForLabel(lumpnum, strName); DeleteForLabel(lumpnum, strName);
@ -348,14 +359,7 @@ void FStringTable::LoadLanguage (int lumpnum, const TArray<uint8_t> &buffer)
sc.MustGetStringName("ifgame"); sc.MustGetStringName("ifgame");
sc.MustGetStringName("("); sc.MustGetStringName("(");
sc.MustGetString(); sc.MustGetString();
if (sc.Compare("strifeteaser")) skip |= (!callbacks || !callbacks->ValidFilter || !callbacks->ValidFilter(sc.String));
{
skip |= (gameinfo.gametype != GAME_Strife) || !(gameinfo.flags & GI_SHAREWARE);
}
else
{
skip |= !sc.Compare(GameTypeName());
}
sc.MustGetStringName(")"); sc.MustGetStringName(")");
sc.MustGetString(); 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); FString macroname(te.strings[0].GetChars() + index + 2, endindex - index - 2);
FStringf lookupstr("%s/%s", strlangid, macroname.GetChars()); FStringf lookupstr("%s/%s", strlangid, macroname.GetChars());
FStringf replacee("@[%s]", macroname.GetChars()); FStringf replacee("@[%s]", macroname.GetChars());
FName lookupname(lookupstr, true); FName lookupname(lookupstr.GetChars(), true);
auto replace = allMacros.CheckKey(lookupname); auto replace = allMacros.CheckKey(lookupname);
for (int i = 0; i < 4; i++) 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); 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); size_t langlen = strlen(language);
int LanguageID = (langlen < 2 || langlen > 3) ? int LanguageID = (langlen < 2 || langlen > 3) ?
@ -479,7 +485,7 @@ void FStringTable::UpdateLanguage()
currentLanguageSet.Push(std::make_pair(lang_id, list)); currentLanguageSet.Push(std::make_pair(lang_id, list));
}; };
checkone(dehacked_table); checkone(override_table);
checkone(global_table); checkone(global_table);
checkone(LanguageID); checkone(LanguageID);
checkone(LanguageID & MAKE_ID(0xff, 0xff, 0, 0)); checkone(LanguageID & MAKE_ID(0xff, 0xff, 0, 0));
@ -534,7 +540,7 @@ bool FStringTable::exists(const char *name)
FName nm(name, true); FName nm(name, true);
if (nm != NAME_None) 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) for (auto mapid : defaultStrings)
{ {
@ -561,7 +567,7 @@ const char *FStringTable::GetString(const char *name, uint32_t *langtable, int g
{ {
return nullptr; 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; if (gender < 0 || gender > 3) gender = 0;
FName nm(name, true); FName nm(name, true);
if (nm != NAME_None) if (nm != NAME_None)
@ -591,7 +597,7 @@ const char *FStringTable::GetLanguageString(const char *name, uint32_t langtable
{ {
return nullptr; 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; if (gender < 0 || gender > 3) gender = 0;
FName nm(name, true); FName nm(name, true);
if (nm != NAME_None) if (nm != NAME_None)
@ -657,3 +663,5 @@ const char *StringMap::MatchString (const char *string) const
} }
return nullptr; return nullptr;
} }
FStringTable GStrings;

View File

@ -44,8 +44,18 @@
#include <stdlib.h> #include <stdlib.h>
#include "doomdef.h" #include "basics.h"
#include "doomtype.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 struct TableElement
{ {
@ -74,19 +84,19 @@ public:
{ {
default_table = MAKE_ID('*', '*', 0, 0), default_table = MAKE_ID('*', '*', 0, 0),
global_table = MAKE_ID('*', 0, 0, 0), global_table = MAKE_ID('*', 0, 0, 0),
dehacked_table = MAKE_ID('*', '*', '*', 0) override_table = MAKE_ID('*', '*', '*', 0)
}; };
using LangMap = TMap<uint32_t, StringMap>; using LangMap = TMap<uint32_t, StringMap>;
using StringMacroMap = TMap<FName, StringMacro>; using StringMacroMap = TMap<FName, StringMacro>;
void LoadStrings (); void LoadStrings(const char *language);
void UpdateLanguage(); void UpdateLanguage(const char* language);
StringMap GetDefaultStrings() { return allStrings[default_table]; } // Dehacked needs these for comparison StringMap GetDefaultStrings() { return allStrings[default_table]; } // Dehacked needs these for comparison
void SetDehackedStrings(StringMap && map) void SetOverrideStrings(StringMap && map)
{ {
allStrings.Insert(dehacked_table, map); allStrings.Insert(override_table, map);
UpdateLanguage(); UpdateLanguage(nullptr);
} }
const char *GetLanguageString(const char *name, uint32_t langtable, int gender = -1) const; const char *GetLanguageString(const char *name, uint32_t langtable, int gender = -1) const;
@ -98,12 +108,15 @@ public:
return GetString(name, nullptr); return GetString(name, nullptr);
} }
bool exists(const char *name); bool exists(const char *name);
void SetCallbacks(StringtableCallbacks* cb) { callbacks = cb; }
private: private:
FString activeLanguage;
StringMacroMap allMacros; StringMacroMap allMacros;
LangMap allStrings; LangMap allStrings;
TArray<std::pair<uint32_t, StringMap*>> currentLanguageSet; TArray<std::pair<uint32_t, StringMap*>> currentLanguageSet;
StringtableCallbacks* callbacks = nullptr;
void LoadLanguage (int lumpnum, const TArray<uint8_t> &buffer); void LoadLanguage (int lumpnum, const TArray<uint8_t> &buffer);
TArray<TArray<FString>> parseCSV(const TArray<uint8_t> &buffer); TArray<TArray<FString>> parseCSV(const TArray<uint8_t> &buffer);
@ -116,6 +129,23 @@ private:
void DeleteForLabel(int lumpnum, FName label); void DeleteForLabel(int lumpnum, FName label);
static size_t ProcessEscapes (char *str); 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__ #endif //__STRINGTABLE_H__