mirror of
https://github.com/ZDoom/qzdoom-gpl.git
synced 2024-11-25 21:31:10 +00:00
- scriptified the remaining parts of the conversationmenu.
- do not resolve the backdrop texture to a texture ID at load time. This will allow custom menu classes to use this info differently. - added a new ZSDF userstring property to dialog pages to give mods more means for customization. - allow overriding the conversation menu class both globally through MAPINFO and per conversation in ZSDF.
This commit is contained in:
parent
d85b9cdd71
commit
e05242e44d
10 changed files with 197 additions and 191 deletions
|
@ -38,6 +38,7 @@ conversation
|
|||
page
|
||||
{
|
||||
drop = <string>;
|
||||
userstring = <string>; New field which can be used to pass data to custom conversation menu classes.
|
||||
ifitem
|
||||
{
|
||||
item = <string>;
|
||||
|
@ -63,10 +64,6 @@ either refuse loading dialogues with the 'ZDoom' namespace or if it does not
|
|||
outright abort on incompatible namespaces fail with a type mismatch error on
|
||||
one of the specified propeties.
|
||||
|
||||
In addition ZDoom defines one new field in the top level of a conversation block:
|
||||
|
||||
id = <integer>; Assigns a conversation ID for use in Thing_SetConversation or in UDMF's 'conversation' actor property.
|
||||
|
||||
ZDoom-format dialogues need to start with the line:
|
||||
|
||||
namespace = "ZDoom";
|
||||
|
@ -86,6 +83,7 @@ conversation // Starts a dialog.
|
|||
// the standard conversation ID ('actor' property) is used instead
|
||||
// for this purpose but since 'ZDoom' namespace requires the actor
|
||||
// to be a class name it needs a separate field for this.
|
||||
class = <string>; //Override the default conversation menu class for this conversation.
|
||||
|
||||
page
|
||||
{
|
||||
|
|
|
@ -362,6 +362,7 @@ void FMapInfoParser::ParseGameInfo()
|
|||
GAMEINFOKEY_INT(TextScreenX, "textscreenx")
|
||||
GAMEINFOKEY_INT(TextScreenY, "textscreeny")
|
||||
GAMEINFOKEY_STRING(DefaultEndSequence, "defaultendsequence")
|
||||
GAMEINFOKEY_STRING(DefaultConversationMenuClass, "defaultconversationmenuclass")
|
||||
GAMEINFOKEY_FONT(mStatscreenMapNameFont, "statscreen_mapnamefont")
|
||||
GAMEINFOKEY_FONT(mStatscreenFinishedFont, "statscreen_finishedfont")
|
||||
GAMEINFOKEY_FONT(mStatscreenEnteringFont, "statscreen_enteringfont")
|
||||
|
|
1
src/gi.h
1
src/gi.h
|
@ -172,6 +172,7 @@ struct gameinfo_t
|
|||
double gibfactor;
|
||||
int TextScreenX;
|
||||
int TextScreenY;
|
||||
FName DefaultConversationMenuClass;
|
||||
FName DefaultEndSequence;
|
||||
FString mMapArrow, mCheatMapArrow;
|
||||
FString mEasyKey, mCheatKey;
|
||||
|
|
|
@ -653,6 +653,7 @@ xx(Link)
|
|||
xx(Goodbye)
|
||||
xx(Require)
|
||||
xx(Exclude)
|
||||
xx(Userstring)
|
||||
|
||||
// Special menus
|
||||
xx(Mainmenu)
|
||||
|
|
|
@ -61,6 +61,7 @@
|
|||
#include "p_local.h"
|
||||
#include "menu/menu.h"
|
||||
#include "g_levellocals.h"
|
||||
#include "virtual.h"
|
||||
|
||||
// The conversations as they exist inside a SCRIPTxx lump.
|
||||
struct Response
|
||||
|
@ -124,9 +125,6 @@ static void TerminalResponse (const char *str);
|
|||
|
||||
static FStrifeDialogueNode *PrevNode;
|
||||
|
||||
#define NUM_RANDOM_LINES 10
|
||||
#define NUM_RANDOM_GOODBYES 3
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// GetStrifeType
|
||||
|
@ -351,7 +349,7 @@ static FStrifeDialogueNode *ReadRetailNode (FileReader *lump, DWORD &prevSpeaker
|
|||
|
||||
// The speaker's portrait, if any.
|
||||
speech.Dialogue[0] = 0; //speech.Backdrop[8] = 0;
|
||||
node->Backdrop = TexMan.CheckForTexture (speech.Backdrop, FTexture::TEX_MiscPatch);
|
||||
node->Backdrop = speech.Backdrop;
|
||||
|
||||
// The speaker's voice for this node, if any.
|
||||
speech.Backdrop[0] = 0; //speech.Sound[8] = 0;
|
||||
|
@ -425,7 +423,7 @@ static FStrifeDialogueNode *ReadTeaserNode (FileReader *lump, DWORD &prevSpeaker
|
|||
node->Dialogue = speech.Dialogue;
|
||||
|
||||
// The Teaser version doesn't have portraits.
|
||||
node->Backdrop.SetInvalid();
|
||||
node->Backdrop = "";
|
||||
|
||||
// The speaker's voice for this node, if any.
|
||||
if (speech.VoiceNumber != 0)
|
||||
|
@ -743,153 +741,6 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// The conversation menu
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
class DConversationMenu : public DMenu
|
||||
{
|
||||
DECLARE_CLASS(DConversationMenu, DMenu)
|
||||
|
||||
public:
|
||||
FString mSpeaker;
|
||||
DBrokenLines *mDialogueLines;
|
||||
TArray<FString> mResponseLines;
|
||||
TArray<unsigned int> mResponses;
|
||||
bool mShowGold;
|
||||
FStrifeDialogueNode *mCurNode;
|
||||
int mYpos;
|
||||
player_t *mPlayer;
|
||||
int mSelection;
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
DConversationMenu(FStrifeDialogueNode *CurNode, player_t *player, int activereply)
|
||||
{
|
||||
mCurNode = CurNode;
|
||||
mPlayer = player;
|
||||
mDialogueLines = NULL;
|
||||
mShowGold = false;
|
||||
|
||||
// Format the speaker's message.
|
||||
const char * toSay = CurNode->Dialogue;
|
||||
if (strncmp (toSay, "RANDOM_", 7) == 0)
|
||||
{
|
||||
FString dlgtext;
|
||||
|
||||
dlgtext.Format("TXT_%s_%02d", toSay, 1+(pr_randomspeech() % NUM_RANDOM_LINES));
|
||||
toSay = GStrings[dlgtext];
|
||||
if (toSay == NULL)
|
||||
{
|
||||
toSay = GStrings["TXT_GOAWAY"]; // Ok, it's lame - but it doesn't look like an error to the player. ;)
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// handle string table replacement
|
||||
if (toSay[0] == '$')
|
||||
{
|
||||
toSay = GStrings(toSay + 1);
|
||||
}
|
||||
}
|
||||
if (toSay == NULL)
|
||||
{
|
||||
toSay = ".";
|
||||
}
|
||||
unsigned int count;
|
||||
auto bl = V_BreakLines (SmallFont, screen->GetWidth()/CleanXfac - 24*2, toSay, true, &count);
|
||||
mDialogueLines = new DBrokenLines(bl, count);
|
||||
|
||||
mSelection = -1;
|
||||
|
||||
FStrifeDialogueReply *reply;
|
||||
int r = -1;
|
||||
int i,j;
|
||||
for (reply = CurNode->Children, i = 1; reply != NULL; reply = reply->Next)
|
||||
{
|
||||
r++;
|
||||
if (ShouldSkipReply(reply, mPlayer))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (activereply == r) mSelection = i - 1;
|
||||
|
||||
mShowGold |= reply->NeedsGold;
|
||||
|
||||
const char *ReplyText = reply->Reply;
|
||||
if (ReplyText[0] == '$')
|
||||
{
|
||||
ReplyText = GStrings(ReplyText + 1);
|
||||
}
|
||||
FString ReplyString = ReplyText;
|
||||
if (reply->NeedsGold) ReplyString.AppendFormat(" for %u", reply->PrintAmount);
|
||||
|
||||
FBrokenLines *ReplyLines = V_BreakLines (SmallFont, 320-50-10, ReplyString);
|
||||
|
||||
mResponses.Push(mResponseLines.Size());
|
||||
for (j = 0; ReplyLines[j].Width >= 0; ++j)
|
||||
{
|
||||
mResponseLines.Push(ReplyLines[j].Text);
|
||||
}
|
||||
|
||||
++i;
|
||||
V_FreeBrokenLines (ReplyLines);
|
||||
}
|
||||
if (mSelection == -1)
|
||||
{
|
||||
mSelection = r < activereply ? r + 1 : 0;
|
||||
}
|
||||
const char *goodbyestr = CurNode->Goodbye;
|
||||
if (*goodbyestr == 0)
|
||||
{
|
||||
char goodbye[25];
|
||||
mysnprintf(goodbye, countof(goodbye), "TXT_RANDOMGOODBYE_%d", 1 + (pr_randomspeech() % NUM_RANDOM_GOODBYES));
|
||||
goodbyestr = GStrings[goodbye];
|
||||
}
|
||||
else if (strncmp(goodbyestr, "RANDOM_", 7) == 0)
|
||||
{
|
||||
FString byetext;
|
||||
|
||||
byetext.Format("TXT_%s_%02d", goodbyestr, 1 + (pr_randomspeech() % NUM_RANDOM_LINES));
|
||||
goodbyestr = GStrings[byetext];
|
||||
}
|
||||
else if (goodbyestr[0] == '$')
|
||||
{
|
||||
goodbyestr = GStrings(goodbyestr + 1);
|
||||
}
|
||||
if (goodbyestr == nullptr) goodbyestr = "Bye.";
|
||||
mResponses.Push(mResponseLines.Size());
|
||||
mResponseLines.Push(FString(goodbyestr));
|
||||
|
||||
// Determine where the top of the reply list should be positioned.
|
||||
mYpos = MIN<int> (140, 192 - mResponseLines.Size() * OptionSettings.mLinespacing);
|
||||
i = 44 + count * (OptionSettings.mLinespacing + 2);
|
||||
if (mYpos - 100 < i - screen->GetHeight() / CleanYfac / 2)
|
||||
{
|
||||
mYpos = i - screen->GetHeight() / CleanYfac / 2 + 100;
|
||||
}
|
||||
ConversationMenuY = mYpos;
|
||||
//ConversationMenu.indent = 50;
|
||||
|
||||
// Because replies can be selectively hidden mResponses.Size() won't be consistent.
|
||||
// So make sure mSelection doesn't exceed mResponses.Size(). [FishyClockwork]
|
||||
if (mSelection >= (int)mResponses.Size())
|
||||
{
|
||||
mSelection = mResponses.Size() - 1;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
IMPLEMENT_CLASS(DConversationMenu, true, false)
|
||||
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// P_FreeStrifeConversations
|
||||
|
@ -909,7 +760,7 @@ void P_FreeStrifeConversations ()
|
|||
ClassRoots.Clear();
|
||||
|
||||
PrevNode = NULL;
|
||||
if (CurrentMenu != NULL && CurrentMenu->IsKindOf(RUNTIME_CLASS(DConversationMenu)))
|
||||
if (CurrentMenu != NULL && CurrentMenu->IsKindOf("ConversationMenu"))
|
||||
{
|
||||
CurrentMenu->Close();
|
||||
}
|
||||
|
@ -1007,8 +858,21 @@ void P_StartConversation (AActor *npc, AActor *pc, bool facetalker, bool saveang
|
|||
S_Sound (npc, CHAN_VOICE|CHAN_NOPAUSE, CurNode->SpeakerVoice, 1, ATTN_NORM);
|
||||
}
|
||||
|
||||
DConversationMenu *cmenu = new DConversationMenu(CurNode, pc->player, StaticLastReply);
|
||||
// Create the menu. This may be a user-defined class so check if it is good to use.
|
||||
FName cls = CurNode->MenuClassName;
|
||||
if (cls == NAME_None) cls = gameinfo.DefaultConversationMenuClass;
|
||||
if (cls == NAME_None) cls = "ConversationMenu";
|
||||
auto mcls = PClass::FindClass(cls);
|
||||
if (mcls == nullptr || !mcls->IsDescendantOf("ConversationMenu")) mcls = PClass::FindClass("ConversationMenu");
|
||||
assert(mcls);
|
||||
|
||||
auto cmenu = mcls->CreateNew();
|
||||
IFVIRTUALPTRNAME(cmenu, "ConversationMenu", Init)
|
||||
{
|
||||
VMValue params[] = { cmenu, CurNode, pc->player, StaticLastReply };
|
||||
VMReturn ret(&ConversationMenuY);
|
||||
GlobalVMStack.Call(func, params, countof(params), &ret, 1);
|
||||
}
|
||||
|
||||
if (CurNode != PrevNode)
|
||||
{ // Only reset the selection if showing a different menu.
|
||||
|
@ -1018,7 +882,7 @@ void P_StartConversation (AActor *npc, AActor *pc, bool facetalker, bool saveang
|
|||
|
||||
// And open the menu
|
||||
M_StartControlPanel (false);
|
||||
M_ActivateMenu(cmenu);
|
||||
M_ActivateMenu((DMenu*)cmenu);
|
||||
menuactive = MENU_OnNoPause;
|
||||
}
|
||||
}
|
||||
|
@ -1255,8 +1119,7 @@ void P_ConversationCommand (int netcode, int pnum, BYTE **stream)
|
|||
|
||||
// The conversation menus are normally closed by the menu code, but that
|
||||
// doesn't happen during demo playback, so we need to do it here.
|
||||
if (demoplayback && CurrentMenu != NULL &&
|
||||
CurrentMenu->IsKindOf(RUNTIME_CLASS(DConversationMenu)))
|
||||
if (demoplayback && CurrentMenu != NULL && CurrentMenu->IsKindOf("ConversationMenu"))
|
||||
{
|
||||
CurrentMenu->Close();
|
||||
}
|
||||
|
@ -1332,6 +1195,8 @@ DEFINE_FIELD(FStrifeDialogueNode, Backdrop);
|
|||
DEFINE_FIELD(FStrifeDialogueNode, Dialogue);
|
||||
DEFINE_FIELD(FStrifeDialogueNode, Goodbye);
|
||||
DEFINE_FIELD(FStrifeDialogueNode, Children);
|
||||
DEFINE_FIELD(FStrifeDialogueNode, MenuClassName);
|
||||
DEFINE_FIELD(FStrifeDialogueNode, UserData);
|
||||
|
||||
DEFINE_FIELD(FStrifeDialogueReply, Next);
|
||||
DEFINE_FIELD(FStrifeDialogueReply, GiveType);
|
||||
|
@ -1345,14 +1210,3 @@ DEFINE_FIELD(FStrifeDialogueReply, LogString);
|
|||
DEFINE_FIELD(FStrifeDialogueReply, NextNode);
|
||||
DEFINE_FIELD(FStrifeDialogueReply, LogNumber);
|
||||
DEFINE_FIELD(FStrifeDialogueReply, NeedsGold);
|
||||
|
||||
|
||||
DEFINE_FIELD(DConversationMenu, mSpeaker);
|
||||
DEFINE_FIELD(DConversationMenu, mDialogueLines);
|
||||
DEFINE_FIELD(DConversationMenu, mResponseLines);
|
||||
DEFINE_FIELD(DConversationMenu, mResponses);
|
||||
DEFINE_FIELD(DConversationMenu, mShowGold);
|
||||
DEFINE_FIELD(DConversationMenu, mCurNode);
|
||||
DEFINE_FIELD(DConversationMenu, mYpos);
|
||||
DEFINE_FIELD(DConversationMenu, mPlayer);
|
||||
DEFINE_FIELD(DConversationMenu, mSelection);
|
||||
|
|
|
@ -28,11 +28,13 @@ struct FStrifeDialogueNode
|
|||
PClassActor *SpeakerType;
|
||||
FString SpeakerName;
|
||||
FSoundID SpeakerVoice;
|
||||
FTextureID Backdrop;
|
||||
FString Backdrop;
|
||||
FString Dialogue;
|
||||
FString Goodbye; // must init to null for binary scripts to work as intended
|
||||
|
||||
FStrifeDialogueReply *Children;
|
||||
FName MenuClassName;
|
||||
FString UserData;
|
||||
};
|
||||
|
||||
// FStrifeDialogueReply holds responses the player can give to the NPC
|
||||
|
|
|
@ -316,7 +316,14 @@ class USDFParser : public UDMFParserBase
|
|||
break;
|
||||
|
||||
case NAME_Panel:
|
||||
node->Backdrop = TexMan.CheckForTexture (CheckString(key), FTexture::TEX_MiscPatch);
|
||||
node->Backdrop = CheckString(key);
|
||||
break;
|
||||
|
||||
case NAME_Userstring:
|
||||
if (namespace_bits == Zd)
|
||||
{
|
||||
node->UserData = CheckString(key);
|
||||
}
|
||||
break;
|
||||
|
||||
case NAME_Voice:
|
||||
|
@ -391,6 +398,7 @@ class USDFParser : public UDMFParserBase
|
|||
{
|
||||
PClassActor *type = NULL;
|
||||
int dlgid = -1;
|
||||
FName clsid;
|
||||
unsigned int startpos = StrifeDialogues.Size();
|
||||
|
||||
while (!sc.CheckToken('}'))
|
||||
|
@ -415,6 +423,13 @@ class USDFParser : public UDMFParserBase
|
|||
dlgid = CheckInt(key);
|
||||
}
|
||||
break;
|
||||
|
||||
case NAME_Class:
|
||||
if (namespace_bits == Zd)
|
||||
{
|
||||
clsid = CheckString(key);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -440,6 +455,7 @@ class USDFParser : public UDMFParserBase
|
|||
for(;startpos < StrifeDialogues.Size(); startpos++)
|
||||
{
|
||||
StrifeDialogues[startpos]->SpeakerType = type;
|
||||
StrifeDialogues[startpos]->MenuClassName = clsid;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -1219,6 +1219,14 @@ DEFINE_ACTION_FUNCTION(FStringStruct, Mid)
|
|||
ACTION_RETURN_STRING(s);
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(FStringStruct, Left)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(FString);
|
||||
PARAM_UINT(len);
|
||||
FString s = self->Left(len);
|
||||
ACTION_RETURN_STRING(s);
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(FStringStruct, Truncate)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(FString);
|
||||
|
|
|
@ -580,6 +580,7 @@ struct StringStruct native
|
|||
native vararg void AppendFormat(String fmt, ...);
|
||||
|
||||
native void Replace(String pattern, String replacement);
|
||||
native String Left(int len);
|
||||
native String Mid(int pos = 0, int len = 2147483647);
|
||||
native void Truncate(int newlen);
|
||||
native String CharAt(int pos);
|
||||
|
|
|
@ -41,7 +41,7 @@ struct StrifeDialogueNode native
|
|||
native Class<Actor> SpeakerType;
|
||||
native String SpeakerName;
|
||||
native Sound SpeakerVoice;
|
||||
native TextureID Backdrop;
|
||||
native String Backdrop;
|
||||
native String Dialogue;
|
||||
native String Goodbye;
|
||||
|
||||
|
@ -68,23 +68,147 @@ struct StrifeDialogueReply native
|
|||
}
|
||||
|
||||
|
||||
class ConversationMenu : Menu native
|
||||
class ConversationMenu : Menu
|
||||
{
|
||||
native String mSpeaker;
|
||||
native BrokenLines mDialogueLines;
|
||||
native Array<String> mResponseLines;
|
||||
native Array<uint> mResponses;
|
||||
native bool mShowGold;
|
||||
native StrifeDialogueNode mCurNode;
|
||||
native int mYpos;
|
||||
native PlayerInfo mPlayer;
|
||||
native int mSelection;
|
||||
String mSpeaker;
|
||||
BrokenLines mDialogueLines;
|
||||
Array<String> mResponseLines;
|
||||
Array<uint> mResponses;
|
||||
bool mShowGold;
|
||||
StrifeDialogueNode mCurNode;
|
||||
int mYpos;
|
||||
PlayerInfo mPlayer;
|
||||
int mSelection;
|
||||
int ConversationPauseTic;
|
||||
|
||||
int SpeechWidth;
|
||||
int ReplyWidth;
|
||||
|
||||
native static void SendConversationReply(int node, int reply);
|
||||
|
||||
//ConversationPauseTic = gametic + 20;
|
||||
// DontDim = true;
|
||||
const NUM_RANDOM_LINES = 10;
|
||||
const NUM_RANDOM_GOODBYES = 3;
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// returns the y position of the replies boy for positioning the terminal response.
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
virtual int Init(StrifeDialogueNode CurNode, PlayerInfo player, int activereply)
|
||||
{
|
||||
mCurNode = CurNode;
|
||||
mPlayer = player;
|
||||
mShowGold = false;
|
||||
ConversationPauseTic = gametic + 20;
|
||||
DontDim = true;
|
||||
|
||||
ReplyWidth = 320-50-10;
|
||||
SpeechWidth = screen.GetWidth()/CleanXfac - 24*2;
|
||||
|
||||
FormatSpeakerMessage();
|
||||
return FormatReplies(activereply);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
virtual int FormatReplies(int activereply)
|
||||
{
|
||||
mSelection = -1;
|
||||
|
||||
StrifeDialogueReply reply;
|
||||
int r = -1;
|
||||
int i = 1,j;
|
||||
for (reply = mCurNode.Children; reply != NULL; reply = reply.Next)
|
||||
{
|
||||
r++;
|
||||
if (reply.ShouldSkipReply(mPlayer))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (activereply == r) mSelection = i - 1;
|
||||
|
||||
mShowGold |= reply.NeedsGold;
|
||||
|
||||
let ReplyText = Stringtable.Localize(reply.Reply);
|
||||
if (reply.NeedsGold) ReplyText.AppendFormat(" for %u", reply.PrintAmount);
|
||||
|
||||
let ReplyLines = SmallFont.BreakLines (ReplyText, ReplyWidth);
|
||||
|
||||
mResponses.Push(mResponseLines.Size());
|
||||
for (j = 0; j < ReplyLines.Count(); ++j)
|
||||
{
|
||||
mResponseLines.Push(ReplyLines.StringAt(j));
|
||||
}
|
||||
|
||||
++i;
|
||||
ReplyLines.Destroy();
|
||||
}
|
||||
if (mSelection == -1)
|
||||
{
|
||||
mSelection = r < activereply ? r + 1 : 0;
|
||||
}
|
||||
let goodbyestr = mCurNode.Goodbye;
|
||||
if (goodbyestr.Length() == 0)
|
||||
{
|
||||
goodbyestr = String.Format("$TXT_RANDOMGOODBYE_%d", Random[RandomSpeech](1, NUM_RANDOM_GOODBYES));
|
||||
}
|
||||
else if (goodbyestr.Left(7) == "RANDOM_")
|
||||
{
|
||||
goodbyestr = String.Format("$TXT_%s_%02d", goodbyestr, Random[RandomSpeech](1, NUM_RANDOM_LINES));
|
||||
}
|
||||
goodbyestr = Stringtable.Localize(goodbyestr);
|
||||
if (goodbyestr.Length() == 0 || goodbyestr.CharAt(0) == "$") goodbyestr = "Bye.";
|
||||
mResponses.Push(mResponseLines.Size());
|
||||
mResponseLines.Push(goodbyestr);
|
||||
|
||||
// Determine where the top of the reply list should be positioned.
|
||||
mYpos = MIN (140, 192 - mResponseLines.Size() * OptionMenuSettings.mLinespacing);
|
||||
i = 44 + mResponseLines.Size() * OptionMenuSettings.mLinespacing;
|
||||
if (mYpos - 100 < i - screen.GetHeight() / CleanYfac / 2)
|
||||
{
|
||||
mYpos = i - screen.GetHeight() / CleanYfac / 2 + 100;
|
||||
}
|
||||
|
||||
if (mSelection >= mResponses.Size())
|
||||
{
|
||||
mSelection = mResponses.Size() - 1;
|
||||
}
|
||||
return mYpos;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
virtual void FormatSpeakerMessage()
|
||||
{
|
||||
// Format the speaker's message.
|
||||
String toSay = mCurNode.Dialogue;
|
||||
if (toSay.Left(7) == "RANDOM_")
|
||||
{
|
||||
let dlgtext = String.Format("$TXT_%s_%02d", toSay, random[RandomSpeech](1, NUM_RANDOM_LINES));
|
||||
toSay = Stringtable.Localize(dlgtext);
|
||||
if (toSay.CharAt(0) == "$") toSay = Stringtable.Localize("$TXT_GOAWAY");
|
||||
}
|
||||
else
|
||||
{
|
||||
// handle string table replacement
|
||||
toSay = Stringtable.Localize(toSay);
|
||||
}
|
||||
if (toSay.Length() == 0)
|
||||
{
|
||||
toSay = ".";
|
||||
}
|
||||
mDialogueLines = SmallFont.BreakLines(toSay, SpeechWidth);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
|
@ -233,9 +357,10 @@ class ConversationMenu : Menu native
|
|||
|
||||
virtual bool DrawBackdrop()
|
||||
{
|
||||
if (mCurNode.Backdrop.isValid())
|
||||
let tex = TexMan.CheckForTexture (mCurNode.Backdrop, TexMan.Type_MiscPatch);
|
||||
if (tex.isValid())
|
||||
{
|
||||
screen.DrawTexture(mCurNode.Backdrop, false, 0, 0, DTA_320x200, true);
|
||||
screen.DrawTexture(tex, false, 0, 0, DTA_320x200, true);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -381,9 +506,8 @@ class ConversationMenu : Menu native
|
|||
|
||||
override void Ticker()
|
||||
{
|
||||
// will be reactivated later.
|
||||
// [CW] Freeze the game depending on MAPINFO options.
|
||||
//if (ConversationPauseTic < gametic && !multiplayer && !level.no_dlg_freeze)
|
||||
if (ConversationPauseTic < gametic && !multiplayer && !level.no_dlg_freeze)
|
||||
{
|
||||
menuactive = Menu.On;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue