- exported all texts from Strife's dialogues to the string table.

Now all this content can be localized. However, since this is actual game content it was placed in a secondary file in zd_extra.pk3, so that it won't affect the GPL-compatible status of the main one.
This commit is contained in:
Christoph Oelckers 2019-02-05 13:39:38 +01:00
parent c0e4ef159b
commit 0936a2fa19
3 changed files with 1209 additions and 148 deletions

View file

@ -103,10 +103,10 @@ static int ConversationMenuY;
static FStrifeDialogueNode *PrevNode;
static int StaticLastReply;
static bool LoadScriptFile(FLevelLocals *Level, int lumpnum, FileReader &lump, int numnodes, bool include, int type);
static FStrifeDialogueNode *ReadRetailNode (FLevelLocals *Level, FileReader &lump, uint32_t &prevSpeakerType);
static FStrifeDialogueNode *ReadTeaserNode (FLevelLocals *Level, FileReader &lump, uint32_t &prevSpeakerType);
static void ParseReplies (FStrifeDialogueReply **replyptr, Response *responses);
static bool LoadScriptFile(FLevelLocals *Level, const char *name, int lumpnum, FileReader &lump, int numnodes, bool include, int type);
static FStrifeDialogueNode *ReadRetailNode (FLevelLocals *Level, const char *name, FileReader &lump, uint32_t &prevSpeakerType);
static FStrifeDialogueNode *ReadTeaserNode (FLevelLocals *Level, const char *name, FileReader &lump, uint32_t &prevSpeakerType);
static void ParseReplies (const char *name, int pos, FStrifeDialogueReply **replyptr, Response *responses);
static bool DrawConversationMenu ();
static void PickConversationReply (int replyindex);
static void TerminalResponse (const char *str);
@ -165,7 +165,7 @@ void P_LoadStrifeConversations (FLevelLocals *Level, MapData *map, const char *m
{
if (map->Size(ML_CONVERSATION) > 0)
{
LoadScriptFile (Level, map->lumpnum, map->Reader(ML_CONVERSATION), map->Size(ML_CONVERSATION), false, 0);
LoadScriptFile (Level, nullptr, map->lumpnum, map->Reader(ML_CONVERSATION), map->Size(ML_CONVERSATION), false, 0);
}
else
{
@ -218,11 +218,16 @@ bool LoadScriptFile (FLevelLocals *Level, const char *name, bool include, int ty
}
FileReader lump = Wads.ReopenLumpReader (lumpnum);
bool res = LoadScriptFile(Level, lumpnum, lump, Wads.LumpLength(lumpnum), include, type);
auto fn = Wads.GetLumpFile(lumpnum);
auto wadname = Wads.GetWadName(fn);
if (stricmp(wadname, "STRIFE0.WAD") && stricmp(wadname, "STRIFE1.WAD") && stricmp(wadname, "SVE.WAD")) name = nullptr; // Only localize IWAD content.
if (name && !stricmp(name, "SCRIPT00")) name = nullptr; // This only contains random string references which already use the string table.
bool res = LoadScriptFile(Level, name, lumpnum, lump, Wads.LumpLength(lumpnum), include, type);
return res;
}
static bool LoadScriptFile(FLevelLocals *Level, int lumpnum, FileReader &lump, int numnodes, bool include, int type)
static bool LoadScriptFile(FLevelLocals *Level, const char *name, int lumpnum, FileReader &lump, int numnodes, bool include, int type)
{
int i;
uint32_t prevSpeakerType;
@ -279,11 +284,11 @@ static bool LoadScriptFile(FLevelLocals *Level, int lumpnum, FileReader &lump, i
{
if (!(gameinfo.flags & GI_SHAREWARE))
{
node = ReadRetailNode (Level, lump, prevSpeakerType);
node = ReadRetailNode (Level, name, lump, prevSpeakerType);
}
else
{
node = ReadTeaserNode (Level, lump, prevSpeakerType);
node = ReadTeaserNode (Level, name, lump, prevSpeakerType);
}
node->ThisNodeNum = Level->StrifeDialogues.Push(node);
}
@ -299,7 +304,17 @@ static bool LoadScriptFile(FLevelLocals *Level, int lumpnum, FileReader &lump, i
//
//============================================================================
static FStrifeDialogueNode *ReadRetailNode (FLevelLocals *Level, FileReader &lump, uint32_t &prevSpeakerType)
static FString TokenFromString(const char *speech)
{
FString token = speech;
token.ToUpper();
token.ReplaceChars(".,-+!?'", ' ');
token.Substitute(" ", "");
token.Truncate(5);
return token;
}
static FStrifeDialogueNode *ReadRetailNode (FLevelLocals *Level, const char *name, FileReader &lump, uint32_t &prevSpeakerType)
{
FStrifeDialogueNode *node;
Speech speech;
@ -309,6 +324,7 @@ static FStrifeDialogueNode *ReadRetailNode (FLevelLocals *Level, FileReader &lum
node = new FStrifeDialogueNode;
auto pos = lump.Tell();
lump.Read (&speech, sizeof(speech));
// Byte swap all the ints in the original data
@ -332,7 +348,16 @@ static FStrifeDialogueNode *ReadRetailNode (FLevelLocals *Level, FileReader &lum
}
// Convert the rest of the data to our own internal format.
if (name)
{
FStringf label("$TXT_DLG_%s_d%d_%s", name, int(pos), TokenFromString(speech.Dialogue));
node->Dialogue = label;
}
else
{
node->Dialogue = speech.Dialogue;
}
// The speaker's portrait, if any.
speech.Dialogue[0] = 0; //speech.Backdrop[8] = 0;
@ -362,7 +387,7 @@ static FStrifeDialogueNode *ReadRetailNode (FLevelLocals *Level, FileReader &lum
node->ItemCheckNode = speech.Link;
node->Children = NULL;
ParseReplies (&node->Children, &speech.Responses[0]);
ParseReplies (name, int(pos), &node->Children, &speech.Responses[0]);
return node;
}
@ -375,7 +400,7 @@ static FStrifeDialogueNode *ReadRetailNode (FLevelLocals *Level, FileReader &lum
//
//============================================================================
static FStrifeDialogueNode *ReadTeaserNode (FLevelLocals *Level, FileReader &lump, uint32_t &prevSpeakerType)
static FStrifeDialogueNode *ReadTeaserNode (FLevelLocals *Level, const char *name, FileReader &lump, uint32_t &prevSpeakerType)
{
FStrifeDialogueNode *node;
TeaserSpeech speech;
@ -385,6 +410,7 @@ static FStrifeDialogueNode *ReadTeaserNode (FLevelLocals *Level, FileReader &lum
node = new FStrifeDialogueNode;
auto pos = lump.Tell() * 1516 / 1488;
lump.Read (&speech, sizeof(speech));
// Byte swap all the ints in the original data
@ -407,7 +433,15 @@ static FStrifeDialogueNode *ReadTeaserNode (FLevelLocals *Level, FileReader &lum
}
// Convert the rest of the data to our own internal format.
if (name)
{
FStringf label("$TXT_DLG_%s_d%d_%s", name, pos, TokenFromString(speech.Dialogue));
node->Dialogue = label;
}
else
{
node->Dialogue = speech.Dialogue;
}
// The Teaser version doesn't have portraits.
node->Backdrop = "";
@ -440,7 +474,7 @@ static FStrifeDialogueNode *ReadTeaserNode (FLevelLocals *Level, FileReader &lum
node->ItemCheckNode = 0;
node->Children = NULL;
ParseReplies (&node->Children, &speech.Responses[0]);
ParseReplies (name, int(pos), &node->Children, &speech.Responses[0]);
return node;
}
@ -455,7 +489,7 @@ static FStrifeDialogueNode *ReadTeaserNode (FLevelLocals *Level, FileReader &lum
//
//============================================================================
static void ParseReplies (FStrifeDialogueReply **replyptr, Response *responses)
static void ParseReplies (const char *name, int pos, FStrifeDialogueReply **replyptr, Response *responses)
{
FStrifeDialogueReply *reply;
int j, k;
@ -509,25 +543,53 @@ static void ParseReplies (FStrifeDialogueReply **replyptr, Response *responses)
reply->ItemCheckRequire.Clear();
reply->ItemCheckExclude.Clear();
if (name)
{
FStringf label("$TXT_RPLY%d_%s_d%d_%s", j, name, pos, TokenFromString(rsp->Reply));
reply->Reply = label;
}
else
{
reply->Reply = rsp->Reply;
}
// If the first item check has a positive amount required, then
// add that to the reply string. Otherwise, use the reply as-is.
reply->Reply = rsp->Reply;
reply->NeedsGold = (rsp->Count[0] > 0);
// QuickYes messages are shown when you meet the item checks.
// QuickNo messages are shown when you don't.
if (rsp->Yes[0] == '_' && rsp->Yes[1] == 0)
// Note that empty nodes contain a '_' in retail Strife, a '.' in the teasers and an empty string in SVE.
if (((rsp->Yes[0] == '_' || rsp->Yes[0] == '.') && rsp->Yes[1] == 0) || rsp->Yes[0] == 0)
{
reply->QuickYes = "";
}
else
{
if (name)
{
FStringf label("$TXT_RYES%d_%s_d%d_%s", j, name, pos, TokenFromString(rsp->Yes));
reply->QuickYes = label;
}
else
{
reply->QuickYes = rsp->Yes;
}
}
if (reply->ItemCheck[0].Item != 0)
{
if (name && strncmp(rsp->No, "NO. ", 4)) // All 'no' nodes starting with 'NO.' won't ever be shown and they all contain broken text.
{
FStringf label("$TXT_RNO%d_%s_d%d_%s", j, name, pos, TokenFromString(rsp->No));
reply->QuickNo = label;
}
else
{
reply->QuickNo = rsp->No;
}
}
else
{
reply->QuickNo = "";

View file

@ -2943,131 +2943,3 @@ MSG_TALISMANRED = "You have a feeling that it wasn't to be touched...";
MSG_TALISMANGREEN = "Whatever it is, it doesn't belong in this world...";
MSG_TALISMANBLUE = "It must do something...";
MSG_TALISMANPOWER = "You have super strength!";
// Strings from Hexen's IWAD scripts. Technically they are not needed here for English, they are mainly meant to be documentation for translating.
TXT_ACS_map01_5_THEDO = "THE DOOR IS LOCKED";
TXT_ACS_map02_9_GREET = "GREETINGS, MORTAL";
TXT_ACS_map02_11_AREYO = "ARE YOU READY TO DIE?";
TXT_ACS_map02_20_ADOOR = "A DOOR OPENED ON THE GUARDIAN OF ICE";
TXT_ACS_map03_12_THISP = "THIS PATH IS BARRED";
TXT_ACS_map04_9_ONEHA = "ONE HALF OF THE PUZZLE HAS BEEN SOLVED";
TXT_ACS_map04_10_ONTHE = "ON THE SEVEN PORTALS";
TXT_ACS_map04_11_ONETH = "ONE THIRD OF THE PUZZLE HAS BEEN SOLVED";
TXT_ACS_map04_12_STAIR = "STAIRS HAVE RISEN ON THE SEVEN PORTALS";
TXT_ACS_map05_6_ONETH = "ONE THIRD OF THE PUZZLE HAS BEEN SOLVED";
TXT_ACS_map05_7_ONTHE = "ON THE SEVEN PORTALS";
TXT_ACS_map05_8_STAIR = "STAIRS HAVE RISEN ON THE SEVEN PORTALS";
TXT_ACS_map05_9_YOUHA = "YOU HAVE TO FIND ANOTHER SWITCH...";
TXT_ACS_map05_10_STONE = "STONES GRIND ON THE SEVEN PORTALS";
TXT_ACS_map08_6_ONESI = "ONE SIXTH OF THE PUZZLE HAS BEEN SOLVED";
TXT_ACS_map08_7_ONTHE = "ON THE SHADOW WOOD";
TXT_ACS_map08_10_THEDO = "THE DOOR IS BARRED FROM THE INSIDE";
TXT_ACS_map08_11_YOUHE = "YOU HEAR A DOOR OPEN IN THE DISTANCE";
TXT_ACS_map09_6_ONESI = "ONE SIXTH OF THE PUZZLE HAS BEEN SOLVED";
TXT_ACS_map09_7_ONTHE = "ON THE SHADOW WOOD";
TXT_ACS_map10_6_ONESI = "ONE SIXTH OF THE PUZZLE HAS BEEN SOLVED";
TXT_ACS_map10_7_ONTHE = "ON THE SHADOW WOOD";
TXT_ACS_map11_0_ETTIN = " ETTINS LEFT";
TXT_ACS_map11_1_YOUWA = "YOU WAITED TOO LONG, NOW YOU DIE!";
TXT_ACS_map11_7_ADOOR = "A DOOR OPENED ON THE FORSAKEN OUTPOST";
TXT_ACS_map12_9_THISD = "THIS DOOR WON'T OPEN YET";
TXT_ACS_map13_11_MYSER = "MY SERVANTS CAN SMELL YOUR BLOOD, HUMAN";
TXT_ACS_map21_0_ADOOR = "A DOOR OPENED IN THE GIBBET";
TXT_ACS_map21_2_THEDO = "THE DOOR IS BARRED FROM THE INSIDE";
TXT_ACS_map22_3_APLAT = "A PLATFORM HAS LOWERED IN THE TOWER";
TXT_ACS_map22_27_YOUHA = "YOU HAVE PLAYED THIS GAME TOO LONG, MORTAL...";
TXT_ACS_map22_29_ITHIN = "I THINK I SHALL REMOVE YOU FROM THE BOARD";
TXT_ACS_map23_10_YOUHE = "YOU HEAR A DOOR OPEN UPSTAIRS";
TXT_ACS_map27_8_WORSH = "WORSHIP ME, AND I MAY YET BE MERCIFUL";
TXT_ACS_map27_10_THENA = "THEN AGAIN, MAYBE NOT";
TXT_ACS_map28_6_ONENI = "ONE NINTH OF THE PUZZLE HAS BEEN SOLVED";
TXT_ACS_map28_7_ONTHE = "ON THE MONASTERY";
TXT_ACS_map30_6_ONENI = "ONE NINTH OF THE PUZZLE HAS BEEN SOLVED";
TXT_ACS_map30_7_ONTHE = "ON THE MONASTERY";
TXT_ACS_map34_1_ONENI = "ONE NINTH OF THE PUZZLE HAS BEEN SOLVED";
TXT_ACS_map34_2_ONTHE = "ON THE MONASTERY";
TXT_ACS_map35_0_THEPO = "THE PORTAL HAS BEEN SEALED";
TXT_ACS_map35_1_CHOOS = "CHOOSE YOUR FATE";
TXT_ACS_map35_3_THEDO = "THE DOOR IS BARRED FROM THE INSIDE";
TXT_ACS_map35_12_AREYO = "ARE YOU STRONG ENOUGH";
TXT_ACS_map35_14_TOFAC = "TO FACE YOUR OWN MASTERS?";
// Deathkings texts
TXT_ACS_map33_6_YOUDA = "YOU DARE BATTLE IN THE READY ROOM?";
TXT_ACS_map33_7_FORTH = "FOR THAT, YOU SHALL DIE!";
TXT_ACS_map41_6_THEWA = "THE WATERFALL IS OPEN";
TXT_ACS_map41_7_THEWA = "THE WATERFALL IS BLOCKED";
TXT_ACS_map41_8_ADOOR = "A DOOR HAS OPENED IN THE CHAPEL";
TXT_ACS_map42_4_NOWTH = "NOW THAT'S ODD...";
TXT_ACS_map44_1_THREE = "THREE MORE PARTS OF THE PUZZLE REMAIN";
TXT_ACS_map44_2_TWOMO = "TWO MORE PARTS OF THE PUZZLE REMAIN";
TXT_ACS_map44_3_ONEMO = "ONE MORE PART OF THE PUZZLE REMAINS";
TXT_ACS_map44_4_THEPU = "THE PUZZLE IS COMPLETE";
TXT_ACS_map44_6_YOUHA = "YOU HAVE NOT COMPLETED THE PUZZLE";
TXT_ACS_map44_8_THEFL = "THE FLOOR IS NOT SAFE!";
TXT_ACS_map44_10_ONETH = "ONE THIRD OF THE PUZZLE IS SOLVED";
TXT_ACS_map44_11_TWOTH = "TWO THIRDS OF THE PUZZLE IS SOLVED";
TXT_ACS_map45_1_YOUHE = "YOU HEAR A PLATFORM MOVING IN THE DISTANCE";
TXT_ACS_map46_0_ITISD = "IT IS DONE...";
TXT_ACS_map46_1_YOUHA = "YOU HAVE NOT COMPLETED THE PUZZLE";
TXT_ACS_map46_2_I'MWA = "I'M WARNING YOU...";
TXT_ACS_map46_3_STUBB = "STUBBORN, AREN'T YOU?";
TXT_ACS_map46_4_ANDST = "AND STUPID, TOO";
TXT_ACS_map46_8_ONEFO = "ONE FOURTH OF THIS PUZZLE IS COMPLETE";
TXT_ACS_map46_9_BADCH = "BAD CHOICE...";
TXT_ACS_map47_2_THESY = "THE SYMBOLS ARE NOT ALIGNED";
TXT_ACS_map48_2_THEDO = "THE DOOR WON'T OPEN FROM THIS SIDE";
TXT_ACS_map50_1_THEDO = "THE DOOR IS BARRED FROM THE OUTSIDE";
TXT_ACS_map51_5_SACRI = "SACRILEGE !";
TXT_ACS_map51_6_YOUHA = "YOU HAVE DEFILED ERIC'S TOMB !!";
TXT_ACS_map51_7_ANDNO = "AND NOW YOU DIE !!!";
TXT_ACS_map51_8_ONETH = "ONE THIRD OF THE PUZZLE IS SOLVED";
TXT_ACS_map51_9_TWOTH = "TWO THIRDS OF THE PUZZLE IS SOLVED";
TXT_ACS_map51_10_THECR = "THE CRYPT IS OPEN";
TXT_ACS_map51_11_BEWAR = "BEWARE THE SPIDER'S TOMB";
TXT_ACS_map51_13_YOUHE = "YOU HEAR A PLATFORM RISE OUTSIDE";
TXT_ACS_map51_14_DOYOU = "DO YOU FEEL LUCKY?";
TXT_ACS_map51_15_YOUGU = "YOU GUESSED WRONG!";
TXT_ACS_map51_16_GOODG = "GOOD GUESS";
TXT_ACS_map51_17_CANYO = "CAN YOU DO ALL THE SCRIPTING FOR MY LEVEL?";
TXT_ACS_map51_18_DON'T = "DON'T TOUCH MY GLOPPY";
TXT_ACS_map51_19_VORPA = "VORPAL ?!?!?!";
TXT_ACS_map51_20_GIMME = "GIMME SOME SUGAR, BABY";
TXT_ACS_map51_21_DUHUH = "DUH-UHHH...";
TXT_ACS_map51_22_FILMI = "FILM IN AN HOUR?";
TXT_ACS_map51_23_IDON' = "I DON'T EVEN GET MY OWN TOMBSTONE - CF";
TXT_ACS_map51_24_LETNO = "LET NO BLOOD BE SPILT";
TXT_ACS_map51_25_LETNO = "LET NO HAND BE RAISED IN ANGER";
TXT_ACS_map52_9_WHODA = "WHO DARES DISTURB OUR SLUMBER?";
TXT_ACS_map52_10_THEWA = "THE WAY IS OPEN";
TXT_ACS_map53_2_YOUHA = "YOU HAVE ";
TXT_ACS_map53_3_SWITC = " SWITCHES LEFT";
TXT_ACS_map53_4_YOUHA = "YOU HAVE ONLY ";
TXT_ACS_map53_5_SWITC = " SWITCH LEFT";
TXT_ACS_map53_6_THEEX = "THE EXIT IS OPEN";
TXT_ACS_map54_1_THEDO = "THE DOORS WON'T OPEN FROM THIS SIDE";
TXT_ACS_map54_4_THEDO = "THE DOORS ARE OPEN...";
TXT_ACS_map54_5_IFYOU = "...IF YOU ARE READY";
TXT_ACS_map54_9_ADOOR = "A DOOR HAS OPENED";
TXT_ACS_map54_10_ONTHE = "ON THE CHANTRY";
TXT_ACS_map54_11_ABRID = "A BRIDGE HAS BEEN BUILT";
TXT_ACS_map54_12_ONTHE = "ON THE ABATTOIR";
TXT_ACS_map54_13_ASTAI = "A STAIR HAS BEEN BUILT";
TXT_ACS_map54_14_ONTHE = "ON THE DARK WATCH";
TXT_ACS_map54_15_ONEGE = "ONE GEAR HAS BEEN PLACED";
TXT_ACS_map54_16_GEARS = " GEARS HAVE BEEN PLACED";
TXT_ACS_map54_17_ABARR = "A BARRICADE HAS OPENED";
TXT_ACS_map54_18_ONTHE = "ON THE CLOACA";
TXT_ACS_map54_20_THEWA = "THE WAY BACK IS OPEN";
TXT_ACS_map55_9_THEDO = "THE DOOR IS BARRED FROM THE INSIDE";
TXT_ACS_map56_0_YOUDA = "YOU DARE PLUNDER THE TOMB";
TXT_ACS_map56_1_OFTHE = "OF THE EXECUTIONER?";
TXT_ACS_map56_2_PREPA = "PREPARE TO DIE";
TXT_ACS_map59_1_YOUHA = "YOU HAVE ";
TXT_ACS_map59_2_MORES = " MORE SWITCHES TO FIND";
TXT_ACS_map59_3_YOUHA = "YOU HAVE ONLY ";
TXT_ACS_map59_4_SWITC = " SWITCH LEFT";
TXT_ACS_map59_5_THEWA = "THE WAY TO THE TOWER IS OPEN";
TXT_ACS_map60_3_THEWA = "THE WAY IS OPEN";

File diff suppressed because it is too large Load diff