mirror of
https://github.com/ZDoom/qzdoom.git
synced 2025-01-18 23:21:41 +00:00
- implemented string table macros.
This commit is contained in:
parent
fa123f37c7
commit
ce1ecd0d4b
6 changed files with 228 additions and 67 deletions
|
@ -2581,7 +2581,8 @@ void D_DoomMain (void)
|
|||
};
|
||||
for (p = 0; p < 5; ++p)
|
||||
{
|
||||
const char *str = GStrings[startupString[p]];
|
||||
// At this point we cannot use the player's gender info yet so force 'male' here.
|
||||
const char *str = GStrings.GetString(startupString[p], nullptr, 0);
|
||||
if (str != NULL && str[0] != '\0')
|
||||
{
|
||||
Printf("%s\n", str);
|
||||
|
|
|
@ -2164,13 +2164,14 @@ static int PatchMusic (int dummy)
|
|||
|
||||
while ((result = GetLine()) == 1)
|
||||
{
|
||||
const char *newname = skipwhite (Line2);
|
||||
FString newname = skipwhite (Line2);
|
||||
FString keystring;
|
||||
|
||||
keystring << "MUSIC_" << Line1;
|
||||
|
||||
DehStrings.Insert(keystring, newname);
|
||||
DPrintf (DMSG_SPAMMY, "Music %s set to:\n%s\n", keystring.GetChars(), newname);
|
||||
TableElement te = { newname, newname, newname, newname };
|
||||
DehStrings.Insert(keystring, te);
|
||||
DPrintf (DMSG_SPAMMY, "Music %s set to:\n%s\n", keystring.GetChars(), newname.GetChars());
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -2283,7 +2284,9 @@ static int PatchText (int oldSize)
|
|||
str = EnglishStrings.MatchString(oldStr);
|
||||
if (str != NULL)
|
||||
{
|
||||
DehStrings.Insert(str, newStr);
|
||||
FString newname = newStr;
|
||||
TableElement te = { newname, newname, newname, newname };
|
||||
DehStrings.Insert(str, te);
|
||||
EnglishStrings.Remove(str); // remove entry so that it won't get found again by the next iteration or by another replacement later
|
||||
good = true;
|
||||
}
|
||||
|
@ -2337,7 +2340,8 @@ static int PatchStrings (int dummy)
|
|||
// Account for a discrepancy between Boom's and ZDoom's name for the red skull key pickup message
|
||||
const char *ll = Line1;
|
||||
if (!stricmp(ll, "GOTREDSKULL")) ll = "GOTREDSKUL";
|
||||
DehStrings.Insert(ll, holdstring);
|
||||
TableElement te = { holdstring, holdstring, holdstring, holdstring };
|
||||
DehStrings.Insert(ll, te);
|
||||
DPrintf (DMSG_SPAMMY, "%s set to:\n%s\n", Line1, holdstring.GetChars());
|
||||
}
|
||||
|
||||
|
|
|
@ -42,9 +42,16 @@
|
|||
#include "c_dispatch.h"
|
||||
#include "v_text.h"
|
||||
#include "gi.h"
|
||||
#include "d_player.h"
|
||||
#include "xlsxread/xlsxio_read.h"
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FStringTable::LoadStrings ()
|
||||
{
|
||||
int lastlump, lump;
|
||||
|
@ -58,8 +65,14 @@ void FStringTable::LoadStrings ()
|
|||
}
|
||||
SetLanguageIDs();
|
||||
UpdateLanguage();
|
||||
allMacros.Clear();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool FStringTable::LoadLanguageFromSpreadsheet(int lumpnum)
|
||||
{
|
||||
|
@ -69,14 +82,60 @@ bool FStringTable::LoadLanguageFromSpreadsheet(int lumpnum)
|
|||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!readSheetIntoTable(xlsxio, "strings")) return false;
|
||||
// readMacros(xlsxio, "macros");
|
||||
readMacros(xlsxio, "macros");
|
||||
readSheetIntoTable(xlsxio, "strings");
|
||||
|
||||
xlsxioread_close(xlsxio);
|
||||
return true;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool FStringTable::readMacros(xlsxioreader reader, const char *sheetname)
|
||||
{
|
||||
xlsxioreadersheet sheet = xlsxioread_sheet_open(reader, sheetname, XLSXIOREAD_SKIP_NONE);
|
||||
if (sheet == nullptr) return false;
|
||||
|
||||
while (xlsxioread_sheet_next_row(sheet))
|
||||
{
|
||||
auto macroname = xlsxioread_sheet_next_cell(sheet);
|
||||
auto language = xlsxioread_sheet_next_cell(sheet);
|
||||
if (!macroname || !language) continue;
|
||||
FStringf combined_name("%s/%s", language, macroname);
|
||||
free(language);
|
||||
free(macroname);
|
||||
FName name = combined_name;
|
||||
|
||||
StringMacro macro;
|
||||
|
||||
char *value;
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
value = xlsxioread_sheet_next_cell(sheet);
|
||||
macro.Replacements[i] = value;
|
||||
free(value);
|
||||
}
|
||||
// This is needed because the reader code would choke on incompletely read rows.
|
||||
while ((value = xlsxioread_sheet_next_cell(sheet)) != nullptr)
|
||||
{
|
||||
free(value);
|
||||
}
|
||||
allMacros.Insert(name, macro);
|
||||
}
|
||||
xlsxioread_sheet_close(sheet);
|
||||
return true;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool FStringTable::readSheetIntoTable(xlsxioreader reader, const char *sheetname)
|
||||
{
|
||||
|
||||
|
@ -94,7 +153,7 @@ bool FStringTable::readSheetIntoTable(xlsxioreader reader, const char *sheetname
|
|||
while ((value = xlsxioread_sheet_next_cell(sheet)) != nullptr)
|
||||
{
|
||||
auto vcopy = value;
|
||||
if (table.Size() <= row) table.Reserve(1);
|
||||
if (table.Size() <= (unsigned)row) table.Reserve(1);
|
||||
while (*vcopy && iswspace((unsigned char)*vcopy)) vcopy++; // skip over leaading whitespace;
|
||||
auto vend = vcopy + strlen(vcopy);
|
||||
while (vend > vcopy && iswspace((unsigned char)vend[-1])) *--vend = 0; // skip over trailing whitespace
|
||||
|
@ -105,12 +164,13 @@ bool FStringTable::readSheetIntoTable(xlsxioreader reader, const char *sheetname
|
|||
}
|
||||
row++;
|
||||
}
|
||||
xlsxioread_sheet_close(sheet);
|
||||
|
||||
int labelcol = -1;
|
||||
int filtercol = -1;
|
||||
TArray<std::pair<int, unsigned>> langrows;
|
||||
|
||||
if (table.Size() > 0)
|
||||
{
|
||||
for (unsigned column = 0; column < table[0].Size(); column++)
|
||||
{
|
||||
auto &entry = table[0][column];
|
||||
|
@ -157,15 +217,21 @@ bool FStringTable::readSheetIntoTable(xlsxioreader reader, const char *sheetname
|
|||
auto str = row[langentry.first];
|
||||
if (str.Len() > 0)
|
||||
{
|
||||
allStrings[langentry.second].Insert(strName, str);
|
||||
str.Substitute("\n", "|");
|
||||
Printf(PRINT_LOG, "Setting %s for %s to %.40s\n\n", strName.GetChars(), &langentry.second, str.GetChars());
|
||||
InsertString(langentry.second, strName, str);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
xlsxioread_sheet_close(sheet);
|
||||
return true;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FStringTable::LoadLanguage (int lumpnum)
|
||||
{
|
||||
bool errordone = false;
|
||||
|
@ -262,13 +328,52 @@ void FStringTable::LoadLanguage (int lumpnum)
|
|||
// Insert the string into all relevant tables.
|
||||
for (auto map : activeMaps)
|
||||
{
|
||||
allStrings[map].Insert(strName, strText);
|
||||
InsertString(map, strName, strText);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FStringTable::InsertString(int langid, FName label, const FString &string)
|
||||
{
|
||||
const char *strlangid = (const char *)&langid;
|
||||
TableElement te = { string, string, string, string };
|
||||
long index;
|
||||
while ((index = te.strings[0].IndexOf("@[")) >= 0)
|
||||
{
|
||||
auto endindex = te.strings[0].IndexOf(']', index);
|
||||
if (endindex == -1)
|
||||
{
|
||||
Printf("Bad macro in %s : %s\n", strlangid, label.GetChars());
|
||||
break;
|
||||
}
|
||||
FString macroname(string.GetChars() + index + 2, endindex - index - 2);
|
||||
FStringf lookupstr("%s/%s", strlangid, macroname.GetChars());
|
||||
FStringf replacee("@[%s]", macroname.GetChars());
|
||||
FName lookupname(lookupstr, true);
|
||||
auto replace = allMacros.CheckKey(lookupname);
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
const char *replacement = replace && replace->Replacements[i] ? replace->Replacements[i] : "";
|
||||
te.strings[i].Substitute(replacee, replacement);
|
||||
}
|
||||
}
|
||||
allStrings[langid].Insert(label, te);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FStringTable::UpdateLanguage()
|
||||
{
|
||||
currentLanguageSet.Clear();
|
||||
|
@ -290,7 +395,12 @@ void FStringTable::UpdateLanguage()
|
|||
checkone(default_table);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Replace \ escape sequences in a string with the escaped characters.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
size_t FStringTable::ProcessEscapes (char *iptr)
|
||||
{
|
||||
char *sptr = iptr, *optr = iptr, c;
|
||||
|
@ -317,10 +427,15 @@ size_t FStringTable::ProcessEscapes (char *iptr)
|
|||
return optr - sptr;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Checks if the given key exists in any one of the default string tables that are valid for all languages.
|
||||
// To replace IWAD content this condition must be true.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool FStringTable::exists(const char *name)
|
||||
{
|
||||
// Checks if the given key exists in any one of the default string tables that are valid for all languages.
|
||||
// To replace IWAD content this condition must be true.
|
||||
if (name == nullptr || *name == 0)
|
||||
{
|
||||
return false;
|
||||
|
@ -343,13 +458,20 @@ bool FStringTable::exists(const char *name)
|
|||
return false;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Finds a string by name and returns its value
|
||||
const char *FStringTable::GetString(const char *name, uint32_t *langtable) const
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
const char *FStringTable::GetString(const char *name, uint32_t *langtable, int gender) const
|
||||
{
|
||||
if (name == nullptr || *name == 0)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
if (gender == -1) gender = players[consoleplayer].userinfo.GetGender();
|
||||
if (gender < 0 || gender > 3) gender = 0;
|
||||
FName nm(name, true);
|
||||
if (nm != NAME_None)
|
||||
{
|
||||
|
@ -359,20 +481,27 @@ const char *FStringTable::GetString(const char *name, uint32_t *langtable) const
|
|||
if (item)
|
||||
{
|
||||
if (langtable) *langtable = map.first;
|
||||
return item->GetChars();
|
||||
return item->strings[gender].GetChars();
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Finds a string by name in a given language
|
||||
const char *FStringTable::GetLanguageString(const char *name, uint32_t langtable) const
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
const char *FStringTable::GetLanguageString(const char *name, uint32_t langtable, int gender) const
|
||||
{
|
||||
if (name == nullptr || *name == 0)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
if (gender == -1) gender = players[consoleplayer].userinfo.GetGender();
|
||||
if (gender < 0 || gender > 3) gender = 0;
|
||||
FName nm(name, true);
|
||||
if (nm != NAME_None)
|
||||
{
|
||||
|
@ -381,14 +510,19 @@ const char *FStringTable::GetLanguageString(const char *name, uint32_t langtable
|
|||
auto item = map->CheckKey(nm);
|
||||
if (item)
|
||||
{
|
||||
return item->GetChars();
|
||||
return item->strings[gender].GetChars();
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Finds a string by name and returns its value. If the string does
|
||||
// not exist, returns the passed name instead.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
const char *FStringTable::operator() (const char *name) const
|
||||
{
|
||||
const char *str = operator[] (name);
|
||||
|
@ -396,7 +530,14 @@ const char *FStringTable::operator() (const char *name) const
|
|||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Find a string with the same exact text. Returns its name.
|
||||
// This does not need to check genders, it is only used by
|
||||
// Dehacked on the English table for finding stock strings.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
const char *StringMap::MatchString (const char *string) const
|
||||
{
|
||||
StringMap::ConstIterator it(*this);
|
||||
|
@ -404,7 +545,7 @@ const char *StringMap::MatchString (const char *string) const
|
|||
|
||||
while (it.NextPair(pair))
|
||||
{
|
||||
if (pair->Value.CompareNoCase(string) == 0)
|
||||
if (pair->Value.strings[0].CompareNoCase(string) == 0)
|
||||
{
|
||||
return pair->Key.GetChars();
|
||||
}
|
||||
|
|
|
@ -47,14 +47,25 @@
|
|||
#include "doomdef.h"
|
||||
#include "doomtype.h"
|
||||
|
||||
struct TableElement
|
||||
{
|
||||
FString strings[4];
|
||||
};
|
||||
|
||||
// This public interface is for Dehacked
|
||||
class StringMap : public TMap<FName, FString>
|
||||
class StringMap : public TMap<FName, TableElement>
|
||||
{
|
||||
public:
|
||||
const char *MatchString(const char *string) const;
|
||||
};
|
||||
|
||||
|
||||
struct StringMacro
|
||||
{
|
||||
FString Replacements[4];
|
||||
};
|
||||
|
||||
|
||||
class FStringTable
|
||||
{
|
||||
public:
|
||||
|
@ -66,6 +77,7 @@ public:
|
|||
};
|
||||
|
||||
using LangMap = TMap<uint32_t, StringMap>;
|
||||
using StringMacroMap = TMap<FName, StringMacro>;
|
||||
|
||||
void LoadStrings ();
|
||||
void UpdateLanguage();
|
||||
|
@ -76,8 +88,8 @@ public:
|
|||
UpdateLanguage();
|
||||
}
|
||||
|
||||
const char *GetLanguageString(const char *name, uint32_t langtable) const;
|
||||
const char *GetString(const char *name, uint32_t *langtable) const;
|
||||
const char *GetLanguageString(const char *name, uint32_t langtable, int gender = -1) const;
|
||||
const char *GetString(const char *name, uint32_t *langtable, int gender = -1) const;
|
||||
const char *operator() (const char *name) const; // Never returns NULL
|
||||
const char *operator[] (const char *name) const
|
||||
{
|
||||
|
@ -87,12 +99,15 @@ public:
|
|||
|
||||
private:
|
||||
|
||||
StringMacroMap allMacros;
|
||||
LangMap allStrings;
|
||||
TArray<std::pair<uint32_t, StringMap*>> currentLanguageSet;
|
||||
|
||||
void LoadLanguage (int lumpnum);
|
||||
bool LoadLanguageFromSpreadsheet(int lumpnum);
|
||||
bool readMacros(struct xlsxio_read_struct *reader, const char *sheet);
|
||||
bool readSheetIntoTable(struct xlsxio_read_struct *reader, const char *sheet);
|
||||
void InsertString(int langid, FName label, const FString &string);
|
||||
|
||||
static size_t ProcessEscapes (char *str);
|
||||
};
|
||||
|
|
|
@ -261,12 +261,12 @@ void ClientObituary (AActor *self, AActor *inflictor, AActor *attacker, int dmgf
|
|||
|
||||
if (message != NULL && message[0] == '$')
|
||||
{
|
||||
message = GStrings[message+1];
|
||||
message = GStrings.GetString(message+1, nullptr, self->player->userinfo.GetGender());
|
||||
}
|
||||
|
||||
if (message == NULL)
|
||||
{
|
||||
message = GStrings("OB_DEFAULT");
|
||||
message = GStrings.GetString("OB_DEFAULT", nullptr, self->player->userinfo.GetGender());
|
||||
}
|
||||
|
||||
// [CK] Don't display empty strings
|
||||
|
|
|
@ -63,7 +63,7 @@ void zip_close(zip_t *zipfile)
|
|||
|
||||
zip_file_t *zip_fopen(zip_t *zipfile, const char *filename)
|
||||
{
|
||||
if (!zipfile) return NULL;
|
||||
if (!zipfile || !filename) return NULL;
|
||||
auto lump = zipfile->FindLump(filename);
|
||||
if (!lump) return NULL;
|
||||
return new FileReader(std::move(lump->NewReader()));
|
||||
|
|
Loading…
Reference in a new issue