From c4a90f39afb4af38f7586b1841f77bf7947334fd Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 19 Feb 2017 11:49:59 +0100 Subject: [PATCH 01/12] - split up DConversationMenu::Drawer for future flexibility. - fixed: The in-conversation gold display did not work because it relied on an unused global variable. --- src/p_conversation.cpp | 216 ++++++++++++++++++++++++++--------------- 1 file changed, 136 insertions(+), 80 deletions(-) diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index 9dc0d4ae6..3250651d1 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -112,7 +112,6 @@ static FDialogueMap ClassRoots; static int ConversationMenuY; static int ConversationPauseTic; -static bool ShowGold; static int StaticLastReply; static bool LoadScriptFile(int lumpnum, FileReader *lump, int numnodes, bool include, int type); @@ -1026,91 +1025,121 @@ public: //============================================================================ // - // DrawConversationMenu + // Draw the backdrop, returns true if the text background should be dimmed // //============================================================================ - void Drawer() + virtual bool DrawBackdrop() { - const char *speakerName; - int x, y, linesize; - int width, fontheight; - - player_t *cp = &players[consoleplayer]; - - assert (mDialogueLines != NULL); - assert (mCurNode != NULL); - - FStrifeDialogueNode *CurNode = mCurNode; - - if (CurNode == NULL) + if (mCurNode->Backdrop.isValid()) { - Close (); - return; + screen->DrawTexture(TexMan(mCurNode->Backdrop), 0, 0, DTA_320x200, true, TAG_DONE); + return false; } + return true; + } - // [CW] Freeze the game depending on MAPINFO options. - if (ConversationPauseTic < gametic && !multiplayer && !(level.flags2 & LEVEL2_CONV_SINGLE_UNFREEZE)) - { - menuactive = MENU_On; - } + //============================================================================ + // + // Draw the speaker text + // + //============================================================================ - if (CurNode->Backdrop.isValid()) - { - screen->DrawTexture (TexMan(CurNode->Backdrop), 0, 0, DTA_320x200, true, TAG_DONE); - } - x = 16 * screen->GetWidth() / 320; - y = 16 * screen->GetHeight() / 200; - linesize = 10 * CleanYfac; + virtual void DrawSpeakerText(bool dimbg) + { + FString speakerName; + int x = 16 * screen->GetWidth() / 320; + int y = 16 * screen->GetHeight() / 200; + int linesize = (OptionSettings.mLinespacing+2) * CleanYfac; // Who is talking to you? - if (CurNode->SpeakerName.IsNotEmpty()) + if (mCurNode->SpeakerName.IsNotEmpty()) { - speakerName = CurNode->SpeakerName; - if (speakerName[0] == '$') speakerName = GStrings(speakerName+1); + speakerName = mCurNode->SpeakerName; + if (speakerName[0] == '$') speakerName = GStrings(speakerName + 1); } else { - speakerName = cp->ConversationNPC->GetTag("Person"); + speakerName = players[consoleplayer].ConversationNPC->GetTag("Person"); } // Dim the screen behind the dialogue (but only if there is no backdrop). - if (!CurNode->Backdrop.isValid()) + if (dimbg) { int i = mDialogueLines->mCount; - screen->Dim (0, 0.45f, 14 * screen->GetWidth() / 320, 13 * screen->GetHeight() / 200, - 308 * screen->GetWidth() / 320 - 14 * screen->GetWidth () / 320, - speakerName == NULL ? linesize * i + 6 * CleanYfac - : linesize * i + 6 * CleanYfac + linesize * 3/2); + screen->Dim(0, 0.45f, 14 * screen->GetWidth() / 320, 13 * screen->GetHeight() / 200, + 308 * screen->GetWidth() / 320 - 14 * screen->GetWidth() / 320, + speakerName.IsEmpty() ? linesize * i + 6 * CleanYfac + : linesize * i + 6 * CleanYfac + linesize * 3 / 2); } - // Dim the screen behind the PC's choices. - - screen->Dim (0, 0.45f, (24-160) * CleanXfac + screen->GetWidth()/2, - (mYpos - 2 - 100) * CleanYfac + screen->GetHeight()/2, - 272 * CleanXfac, - MIN(mResponseLines.Size() * OptionSettings.mLinespacing + 4, 200 - mYpos) * CleanYfac); - - if (speakerName != NULL) + if (speakerName.IsNotEmpty()) { - screen->DrawText (SmallFont, CR_WHITE, x, y, speakerName, + screen->DrawText(SmallFont, CR_WHITE, x, y, speakerName, DTA_CleanNoMove, true, TAG_DONE); y += linesize * 3 / 2; } x = 24 * screen->GetWidth() / 320; for (int i = 0; i < mDialogueLines->mCount; ++i) { - screen->DrawText (SmallFont, CR_UNTRANSLATED, x, y, mDialogueLines->mBroken[i].Text, + screen->DrawText(SmallFont, CR_UNTRANSLATED, x, y, mDialogueLines->mBroken[i].Text, DTA_CleanNoMove, true, TAG_DONE); y += linesize; } + } - if (ShowGold) + + virtual void DrawReplies() + { + // Dim the screen behind the PC's choices. + screen->Dim(0, 0.45f, (24 - 160) * CleanXfac + screen->GetWidth() / 2, + (mYpos - 2 - 100) * CleanYfac + screen->GetHeight() / 2, + 272 * CleanXfac, + MIN(mResponseLines.Size() * OptionSettings.mLinespacing + 4, 200 - mYpos) * CleanYfac); + + int y = mYpos; + int fontheight = OptionSettings.mLinespacing; + + int response = 0; + for (unsigned i = 0; i < mResponseLines.Size(); i++, y += fontheight) + { + int width = SmallFont->StringWidth(mResponseLines[i]); + int x = 64; + + screen->DrawText(SmallFont, CR_GREEN, x, y, mResponseLines[i], DTA_Clean, true, TAG_DONE); + + if (i == mResponses[response]) + { + char tbuf[16]; + + response++; + mysnprintf(tbuf, countof(tbuf), "%d.", response); + x = 50 - SmallFont->StringWidth(tbuf); + screen->DrawText(SmallFont, CR_GREY, x, y, tbuf, DTA_Clean, true, TAG_DONE); + + if (response == mSelection + 1) + { + int color = ((MenuTime % 8) < 4) || CurrentMenu != this ? CR_RED : CR_GREY; + + x = (50 + 3 - 160) * CleanXfac + screen->GetWidth() / 2; + int yy = (y + fontheight / 2 - 5 - 100) * CleanYfac + screen->GetHeight() / 2; + screen->DrawText(ConFont, color, x, yy, "\xd", + DTA_CellX, 8 * CleanXfac, + DTA_CellY, 8 * CleanYfac, + TAG_DONE); + } + } + } + } + + virtual void DrawGold() + { + if (mShowGold) { auto cointype = PClass::FindActor("Coin"); if (cointype) { - AInventory *coin = cp->ConversationPC->FindInventory(cointype); + AInventory *coin = players[consoleplayer].ConversationPC->FindInventory(cointype); char goldstr[32]; mysnprintf(goldstr, countof(goldstr), "%d", coin != NULL ? coin->Amount : 0); @@ -1125,39 +1154,32 @@ public: } } - y = mYpos; - fontheight = OptionSettings.mLinespacing; + } - int response = 0; - for (unsigned i = 0; i < mResponseLines.Size(); i++, y += fontheight) + //============================================================================ + // + // DrawConversationMenu + // + //============================================================================ + + void Drawer() + { + if (mCurNode == NULL) { - width = SmallFont->StringWidth(mResponseLines[i]); - x = 64; - - screen->DrawText (SmallFont, CR_GREEN, x, y, mResponseLines[i], DTA_Clean, true, TAG_DONE); - - if (i == mResponses[response]) - { - char tbuf[16]; - - response++; - mysnprintf (tbuf, countof(tbuf), "%d.", response); - x = 50 - SmallFont->StringWidth (tbuf); - screen->DrawText (SmallFont, CR_GREY, x, y, tbuf, DTA_Clean, true, TAG_DONE); - - if (response == mSelection+1) - { - int color = ((MenuTime%8) < 4) || CurrentMenu != this ? CR_RED:CR_GREY; - - x = (50 + 3 - 160) * CleanXfac + screen->GetWidth() / 2; - int yy = (y + fontheight/2 - 5 - 100) * CleanYfac + screen->GetHeight() / 2; - screen->DrawText (ConFont, color, x, yy, "\xd", - DTA_CellX, 8 * CleanXfac, - DTA_CellY, 8 * CleanYfac, - TAG_DONE); - } - } + Close (); + return; } + + // [CW] Freeze the game depending on MAPINFO options. + if (ConversationPauseTic < gametic && !multiplayer && !(level.flags2 & LEVEL2_CONV_SINGLE_UNFREEZE)) + { + menuactive = MENU_On; + } + + bool dimbg = DrawBackdrop(); + DrawSpeakerText(dimbg); + DrawReplies(); + DrawGold(); } }; @@ -1598,3 +1620,37 @@ static void TerminalResponse (const char *str) } } +DEFINE_FIELD(FStrifeDialogueNode, DropType); +DEFINE_FIELD(FStrifeDialogueNode, ThisNodeNum); +DEFINE_FIELD(FStrifeDialogueNode, ItemCheckNode); +DEFINE_FIELD(FStrifeDialogueNode, SpeakerType); +DEFINE_FIELD(FStrifeDialogueNode, SpeakerName); +DEFINE_FIELD(FStrifeDialogueNode, SpeakerVoice); +DEFINE_FIELD(FStrifeDialogueNode, Backdrop); +DEFINE_FIELD(FStrifeDialogueNode, Dialogue); +DEFINE_FIELD(FStrifeDialogueNode, Goodbye); +DEFINE_FIELD(FStrifeDialogueNode, Children); + +DEFINE_FIELD(FStrifeDialogueReply, Next); +DEFINE_FIELD(FStrifeDialogueReply, GiveType); +DEFINE_FIELD(FStrifeDialogueReply, ActionSpecial); +DEFINE_FIELD(FStrifeDialogueReply, Args); +DEFINE_FIELD(FStrifeDialogueReply, PrintAmount); +DEFINE_FIELD(FStrifeDialogueReply, Reply); +DEFINE_FIELD(FStrifeDialogueReply, QuickYes); +DEFINE_FIELD(FStrifeDialogueReply, QuickNo); +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); From 3c8a5fdbe77b4c877bbd20f36154fba064921f07 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 19 Feb 2017 12:28:05 +0100 Subject: [PATCH 02/12] - scriptified the drawer functions of the conversation menu. --- src/p_conversation.cpp | 161 ------------ wadsrc/static/zscript.txt | 1 + .../static/zscript/menu/conversationmenu.txt | 247 ++++++++++++++++++ 3 files changed, 248 insertions(+), 161 deletions(-) create mode 100644 wadsrc/static/zscript/menu/conversationmenu.txt diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index 3250651d1..dbee57a4e 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -1022,166 +1022,6 @@ public: } return Super::Responder(ev); } - - //============================================================================ - // - // Draw the backdrop, returns true if the text background should be dimmed - // - //============================================================================ - - virtual bool DrawBackdrop() - { - if (mCurNode->Backdrop.isValid()) - { - screen->DrawTexture(TexMan(mCurNode->Backdrop), 0, 0, DTA_320x200, true, TAG_DONE); - return false; - } - return true; - } - - //============================================================================ - // - // Draw the speaker text - // - //============================================================================ - - virtual void DrawSpeakerText(bool dimbg) - { - FString speakerName; - int x = 16 * screen->GetWidth() / 320; - int y = 16 * screen->GetHeight() / 200; - int linesize = (OptionSettings.mLinespacing+2) * CleanYfac; - - // Who is talking to you? - if (mCurNode->SpeakerName.IsNotEmpty()) - { - speakerName = mCurNode->SpeakerName; - if (speakerName[0] == '$') speakerName = GStrings(speakerName + 1); - } - else - { - speakerName = players[consoleplayer].ConversationNPC->GetTag("Person"); - } - - // Dim the screen behind the dialogue (but only if there is no backdrop). - if (dimbg) - { - int i = mDialogueLines->mCount; - screen->Dim(0, 0.45f, 14 * screen->GetWidth() / 320, 13 * screen->GetHeight() / 200, - 308 * screen->GetWidth() / 320 - 14 * screen->GetWidth() / 320, - speakerName.IsEmpty() ? linesize * i + 6 * CleanYfac - : linesize * i + 6 * CleanYfac + linesize * 3 / 2); - } - - if (speakerName.IsNotEmpty()) - { - screen->DrawText(SmallFont, CR_WHITE, x, y, speakerName, - DTA_CleanNoMove, true, TAG_DONE); - y += linesize * 3 / 2; - } - x = 24 * screen->GetWidth() / 320; - for (int i = 0; i < mDialogueLines->mCount; ++i) - { - screen->DrawText(SmallFont, CR_UNTRANSLATED, x, y, mDialogueLines->mBroken[i].Text, - DTA_CleanNoMove, true, TAG_DONE); - y += linesize; - } - } - - - virtual void DrawReplies() - { - // Dim the screen behind the PC's choices. - screen->Dim(0, 0.45f, (24 - 160) * CleanXfac + screen->GetWidth() / 2, - (mYpos - 2 - 100) * CleanYfac + screen->GetHeight() / 2, - 272 * CleanXfac, - MIN(mResponseLines.Size() * OptionSettings.mLinespacing + 4, 200 - mYpos) * CleanYfac); - - int y = mYpos; - int fontheight = OptionSettings.mLinespacing; - - int response = 0; - for (unsigned i = 0; i < mResponseLines.Size(); i++, y += fontheight) - { - int width = SmallFont->StringWidth(mResponseLines[i]); - int x = 64; - - screen->DrawText(SmallFont, CR_GREEN, x, y, mResponseLines[i], DTA_Clean, true, TAG_DONE); - - if (i == mResponses[response]) - { - char tbuf[16]; - - response++; - mysnprintf(tbuf, countof(tbuf), "%d.", response); - x = 50 - SmallFont->StringWidth(tbuf); - screen->DrawText(SmallFont, CR_GREY, x, y, tbuf, DTA_Clean, true, TAG_DONE); - - if (response == mSelection + 1) - { - int color = ((MenuTime % 8) < 4) || CurrentMenu != this ? CR_RED : CR_GREY; - - x = (50 + 3 - 160) * CleanXfac + screen->GetWidth() / 2; - int yy = (y + fontheight / 2 - 5 - 100) * CleanYfac + screen->GetHeight() / 2; - screen->DrawText(ConFont, color, x, yy, "\xd", - DTA_CellX, 8 * CleanXfac, - DTA_CellY, 8 * CleanYfac, - TAG_DONE); - } - } - } - } - - virtual void DrawGold() - { - if (mShowGold) - { - auto cointype = PClass::FindActor("Coin"); - if (cointype) - { - AInventory *coin = players[consoleplayer].ConversationPC->FindInventory(cointype); - char goldstr[32]; - - mysnprintf(goldstr, countof(goldstr), "%d", coin != NULL ? coin->Amount : 0); - screen->DrawText(SmallFont, CR_GRAY, 21, 191, goldstr, DTA_320x200, true, - DTA_FillColor, 0, DTA_Alpha, HR_SHADOW, TAG_DONE); - screen->DrawTexture(TexMan(((AInventory *)GetDefaultByType(cointype))->Icon), - 3, 190, DTA_320x200, true, - DTA_FillColor, 0, DTA_Alpha, HR_SHADOW, TAG_DONE); - screen->DrawText(SmallFont, CR_GRAY, 20, 190, goldstr, DTA_320x200, true, TAG_DONE); - screen->DrawTexture(TexMan(((AInventory *)GetDefaultByType(cointype))->Icon), - 2, 189, DTA_320x200, true, TAG_DONE); - } - } - - } - - //============================================================================ - // - // DrawConversationMenu - // - //============================================================================ - - void Drawer() - { - if (mCurNode == NULL) - { - Close (); - return; - } - - // [CW] Freeze the game depending on MAPINFO options. - if (ConversationPauseTic < gametic && !multiplayer && !(level.flags2 & LEVEL2_CONV_SINGLE_UNFREEZE)) - { - menuactive = MENU_On; - } - - bool dimbg = DrawBackdrop(); - DrawSpeakerText(dimbg); - DrawReplies(); - DrawGold(); - } - }; IMPLEMENT_CLASS(DConversationMenu, true, false) @@ -1316,7 +1156,6 @@ void P_StartConversation (AActor *npc, AActor *pc, bool facetalker, bool saveang // And open the menu M_StartControlPanel (false); M_ActivateMenu(cmenu); - ConversationPauseTic = gametic + 20; menuactive = MENU_OnNoPause; } } diff --git a/wadsrc/static/zscript.txt b/wadsrc/static/zscript.txt index cbe913fa3..528431575 100644 --- a/wadsrc/static/zscript.txt +++ b/wadsrc/static/zscript.txt @@ -23,6 +23,7 @@ #include "zscript/menu/textentermenu.txt" #include "zscript/menu/videomenu.txt" #include "zscript/menu/readthis.txt" +#include "zscript/menu/conversationmenu.txt" #include "zscript/inventory/inventory.txt" #include "zscript/inventory/inv_misc.txt" diff --git a/wadsrc/static/zscript/menu/conversationmenu.txt b/wadsrc/static/zscript/menu/conversationmenu.txt new file mode 100644 index 000000000..474fd50f2 --- /dev/null +++ b/wadsrc/static/zscript/menu/conversationmenu.txt @@ -0,0 +1,247 @@ +/* +** conversationmenu.txt +** The Strife dialogue display +** +**--------------------------------------------------------------------------- +** Copyright 2010-2017 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +struct StrifeDialogueNode native +{ + native Class DropType; + native int ThisNodeNum; + native int ItemCheckNode; + + native Class SpeakerType; + native String SpeakerName; + native Sound SpeakerVoice; + native TextureID Backdrop; + native String Dialogue; + native String Goodbye; + + native StrifeDialogueReply Children; +} + +// FStrifeDialogueReply holds responses the player can give to the NPC +struct StrifeDialogueReply native +{ + native StrifeDialogueReply Next; + native Class GiveType; + native int ActionSpecial; + native int Args[5]; + native int PrintAmount; + native String Reply; + native String QuickYes; + native String QuickNo; + native String LogString; + native int NextNode; // index into StrifeDialogues + native int LogNumber; + native bool NeedsGold; +} + + +class ConversationMenu : Menu native +{ + native String mSpeaker; + native BrokenLines mDialogueLines; + native Array mResponseLines; + native Array mResponses; + native bool mShowGold; + native StrifeDialogueNode mCurNode; + native int mYpos; + native PlayerInfo mPlayer; + native int mSelection; + + //ConversationPauseTic = gametic + 20; + + //============================================================================ + // + // Draw the backdrop, returns true if the text background should be dimmed + // + //============================================================================ + + virtual bool DrawBackdrop() + { + if (mCurNode.Backdrop.isValid()) + { + screen.DrawTexture(mCurNode.Backdrop, false, 0, 0, DTA_320x200, true); + return false; + } + return true; + } + + //============================================================================ + // + // Draw the speaker text + // + //============================================================================ + + virtual void DrawSpeakerText(bool dimbg) + { + String speakerName; + int linesize = OptionMenuSettings.mLinespacing * CleanYfac; + int cnt = mDialogueLines.Count(); + + // Who is talking to you? + if (mCurNode.SpeakerName.Length() > 0) + { + speakerName = Stringtable.Localize(mCurNode.SpeakerName); + } + else + { + speakerName = players[consoleplayer].ConversationNPC.GetTag("Person"); + } + + + // Dim the screen behind the dialogue (but only if there is no backdrop). + if (dimbg) + { + int x = 14 * screen.GetWidth() / 320; + int y = 13 * screen.GetHeight() / 200; + int w = 294 * screen.GetWidth() / 320; + int h = linesize * cnt + 6 * CleanYfac; + if (speakerName.Length() > 0) h += linesize * 3 / 2; + screen.Dim(0, 0.45f, x, y, w, h); + } + + int x = 16 * screen.GetWidth() / 320; + int y = 16 * screen.GetHeight() / 200; + + if (speakerName.Length() > 0) + { + screen.DrawText(SmallFont, Font.CR_WHITE, x, y, speakerName, DTA_CleanNoMove, true); + y += linesize * 3 / 2; + } + x = 24 * screen.GetWidth() / 320; + for (int i = 0; i < cnt; ++i) + { + screen.DrawText(SmallFont, Font.CR_UNTRANSLATED, x, y, mDialogueLines.StringAt(i), DTA_CleanNoMove, true); + y += linesize; + } + } + + + //============================================================================ + // + // Draw the replies + // + //============================================================================ + + virtual void DrawReplies() + { + // Dim the screen behind the PC's choices. + screen.Dim(0, 0.45, (24 - 160) * CleanXfac + screen.GetWidth() / 2, (mYpos - 2 - 100) * CleanYfac + screen.GetHeight() / 2, + 272 * CleanXfac, MIN(mResponseLines.Size() * OptionMenuSettings.mLinespacing + 4, 200 - mYpos) * CleanYfac); + + int y = mYpos; + int fontheight = OptionMenuSettings.mLinespacing; + + int response = 0; + for (int i = 0; i < mResponseLines.Size(); i++) + { + int width = SmallFont.StringWidth(mResponseLines[i]); + int x = 64; + + screen.DrawText(SmallFont, Font.CR_GREEN, x, y, mResponseLines[i], DTA_Clean, true); + + if (i == mResponses[response]) + { + String tbuf; + + response++; + tbuf = String.Format("%d.", response); + x = 50 - SmallFont.StringWidth(tbuf); + screen.DrawText(SmallFont, Font.CR_GREY, x, y, tbuf, DTA_Clean, true); + + if (response == mSelection + 1) + { + int colr = ((MenuTime() % 8) < 4) || GetCurrentMenu() != self ? Font.CR_RED : Font.CR_GREY; + + x = (50 + 3 - 160) * CleanXfac + screen.GetWidth() / 2; + int yy = (y + fontheight / 2 - 5 - 100) * CleanYfac + screen.GetHeight() / 2; + screen.DrawText(ConFont, colr, x, yy, "\xd", DTA_CellX, 8 * CleanXfac, DTA_CellY, 8 * CleanYfac); + } + } + y += fontheight; + } + } + + virtual void DrawGold() + { + if (mShowGold) + { + let coin = players[consoleplayer].ConversationPC.FindInventory("Coin"); + let icon = GetDefaultByType("Coin").Icon; + let goldstr = String.Format("%d", coin != NULL ? coin.Amount : 0); + screen.DrawText(SmallFont, Font.CR_GRAY, 21, 191, goldstr, DTA_320x200, true, DTA_FillColor, 0, DTA_Alpha, HR_SHADOW); + screen.DrawTexture(icon, false, 3, 190, DTA_320x200, true, DTA_FillColor, 0, DTA_Alpha, HR_SHADOW); + screen.DrawText(SmallFont, Font.CR_GRAY, 20, 190, goldstr, DTA_320x200, true); + screen.DrawTexture(icon, false, 2, 189, DTA_320x200, true); + } + + } + + //============================================================================ + // + // DrawConversationMenu + // + //============================================================================ + + override void Drawer() + { + if (mCurNode == NULL) + { + Close (); + return; + } + + bool dimbg = DrawBackdrop(); + DrawSpeakerText(dimbg); + DrawReplies(); + DrawGold(); + } + + + //============================================================================ + // + // + // + //============================================================================ + + override void Ticker() + { + // will be reactivated later. + // [CW] Freeze the game depending on MAPINFO options. + //if (ConversationPauseTic < gametic && !multiplayer && !level.no_dlg_freeze) + { + menuactive = Menu.On; + } + } + +} From d85b9cdd71bf8debe549fef5fbd17e3f506eb726 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 19 Feb 2017 13:07:49 +0100 Subject: [PATCH 03/12] - scriptified the input methods of DConversationMenu. - fixed handling of DimAllowed. --- src/g_level.cpp | 1 + src/menu/menu.cpp | 9 +- src/menu/menu.h | 2 +- src/p_conversation.cpp | 161 ++---------------- src/scripting/thingdef_data.cpp | 3 + wadsrc/static/zscript/base.txt | 1 + .../static/zscript/menu/conversationmenu.txt | 145 ++++++++++++++++ wadsrc/static/zscript/menu/listmenu.txt | 2 +- wadsrc/static/zscript/menu/menu.txt | 1 + wadsrc/static/zscript/menu/optionmenu.txt | 1 + 10 files changed, 169 insertions(+), 157 deletions(-) diff --git a/src/g_level.cpp b/src/g_level.cpp index eafdd7209..5bc7d44e0 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -1936,6 +1936,7 @@ DEFINE_FIELD_BIT(FLevelLocals, flags2, polygrind, LEVEL2_POLYGRIND) DEFINE_FIELD_BIT(FLevelLocals, flags2, nomonsters, LEVEL2_NOMONSTERS) DEFINE_FIELD_BIT(FLevelLocals, flags2, frozen, LEVEL2_FROZEN) DEFINE_FIELD_BIT(FLevelLocals, flags2, infinite_flight, LEVEL2_INFINITE_FLIGHT) +DEFINE_FIELD_BIT(FLevelLocals, flags2, no_dlg_freeze, LEVEL2_CONV_SINGLE_UNFREEZE) //========================================================================== // diff --git a/src/menu/menu.cpp b/src/menu/menu.cpp index 6569c00c7..b0bf096f8 100644 --- a/src/menu/menu.cpp +++ b/src/menu/menu.cpp @@ -160,6 +160,7 @@ DMenu::DMenu(DMenu *parent) mParentMenu = parent; mMouseCapture = false; mBackbuttonSelected = false; + DontDim = false; GC::WriteBarrier(this, parent); } @@ -445,11 +446,6 @@ DEFINE_ACTION_FUNCTION(DMenu, Close) return 0; } -bool DMenu::DimAllowed() -{ - return true; -} - bool DMenu::TranslateKeyboardEvents() { IFVIRTUAL(DMenu, TranslateKeyboardEvents) @@ -928,7 +924,7 @@ void M_Drawer (void) if (CurrentMenu != nullptr && menuactive != MENU_Off) { - if (CurrentMenu->DimAllowed()) + if (!CurrentMenu->DontDim) { screen->Dim(fade); V_SetBorderNeedRefresh(); @@ -1203,6 +1199,7 @@ CCMD(undocolorpic) DEFINE_FIELD(DMenu, mParentMenu) DEFINE_FIELD(DMenu, mMouseCapture); DEFINE_FIELD(DMenu, mBackbuttonSelected); +DEFINE_FIELD(DMenu, DontDim); DEFINE_FIELD(DMenuDescriptor, mMenuName) DEFINE_FIELD(DMenuDescriptor, mNetgameMessage) diff --git a/src/menu/menu.h b/src/menu/menu.h index 415e3dff6..7d1236ccf 100644 --- a/src/menu/menu.h +++ b/src/menu/menu.h @@ -271,13 +271,13 @@ public: TObjPtr mParentMenu; bool mMouseCapture; bool mBackbuttonSelected; + bool DontDim; DMenu(DMenu *parent = NULL); virtual bool Responder (event_t *ev); virtual bool MenuEvent (int mkey, bool fromcontroller); virtual void Ticker (); virtual void Drawer (); - virtual bool DimAllowed (); bool TranslateKeyboardEvents(); virtual void Close(); virtual bool MouseEvent(int type, int x, int y); diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index dbee57a4e..10562428b 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -689,8 +689,18 @@ static bool ShouldSkipReply(FStrifeDialogueReply *reply, player_t *player) return false; } -static void SendConversationReply(int node, int reply) +DEFINE_ACTION_FUNCTION(FStrifeDialogueReply, ShouldSkipReply) { + PARAM_SELF_STRUCT_PROLOGUE(FStrifeDialogueReply); + PARAM_POINTER(player, player_t); + ACTION_RETURN_BOOL(ShouldSkipReply(self, player)); +} + +DEFINE_ACTION_FUNCTION(DConversationMenu, SendConversationReply) +{ + PARAM_PROLOGUE; + PARAM_INT(node); + PARAM_INT(reply); switch (node) { case -1: @@ -708,6 +718,7 @@ static void SendConversationReply(int node, int reply) break; } StaticLastReply = reply; + return 0; } @@ -874,154 +885,6 @@ public: } } - //============================================================================= - // - // - // - //============================================================================= - - void OnDestroy() override - { - mDialogueLines->Destroy(); - mDialogueLines = NULL; - I_SetMusicVolume (1.f); - Super::OnDestroy(); - } - - bool DimAllowed() - { - return false; - } - - int GetReplyNum() - { - assert((unsigned)mCurNode->ThisNodeNum < StrifeDialogues.Size()); - assert(StrifeDialogues[mCurNode->ThisNodeNum] == mCurNode); - - // This is needed because mSelection represents the replies currently being displayed which will - // not match up with what's supposed to be selected if there are any hidden/skipped replies. [FishyClockwork] - FStrifeDialogueReply *reply = mCurNode->Children; - int replynum = mSelection; - for (int i = 0; i <= mSelection && reply != nullptr; reply = reply->Next) - { - if (ShouldSkipReply(reply, mPlayer)) - replynum++; - else - i++; - } - return replynum; - } - - //============================================================================= - // - // - // - //============================================================================= - - bool MenuEvent(int mkey, bool fromcontroller) - { - if (demoplayback) - { // During demo playback, don't let the user do anything besides close this menu. - if (mkey == MKEY_Back) - { - Close(); - return true; - } - return false; - } - if (mkey == MKEY_Up) - { - if (--mSelection < 0) mSelection = mResponses.Size() - 1; - return true; - } - else if (mkey == MKEY_Down) - { - if (++mSelection >= (int)mResponses.Size()) mSelection = 0; - return true; - } - else if (mkey == MKEY_Back) - { - SendConversationReply(-1, GetReplyNum()); - Close(); - return true; - } - else if (mkey == MKEY_Enter) - { - int replynum = GetReplyNum(); - if ((unsigned)mSelection >= mResponses.Size()) - { - SendConversationReply(-1, replynum); - } - else - { - // Send dialogue and reply numbers across the wire. - SendConversationReply(mCurNode->ThisNodeNum, replynum); - } - Close(); - return true; - } - return false; - } - - //============================================================================= - // - // - // - //============================================================================= - - bool MouseEvent(int type, int x, int y) - { - int sel = -1; - int fh = OptionSettings.mLinespacing; - - // convert x/y from screen to virtual coordinates, according to CleanX/Yfac use in DrawTexture - x = ((x - (screen->GetWidth() / 2)) / CleanXfac) + 160; - y = ((y - (screen->GetHeight() / 2)) / CleanYfac) + 100; - - if (x >= 24 && x <= 320-24 && y >= mYpos && y < mYpos + fh * (int)mResponseLines.Size()) - { - sel = (y - mYpos) / fh; - for(unsigned i=0;i sel) - { - sel = i-1; - break; - } - } - } - if (sel != -1 && sel != mSelection) - { - //S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE); - } - mSelection = sel; - if (type == MOUSE_Release) - { - return MenuEvent(MKEY_Enter, true); - } - return true; - } - - - //============================================================================= - // - // - // - //============================================================================= - - bool Responder(event_t *ev) - { - if (demoplayback) - { // No interaction during demo playback - return false; - } - if (ev->type == EV_GUI_Event && ev->subtype == EV_GUI_Char && ev->data1 >= '0' && ev->data1 <= '9') - { // Activate an item of type numberedmore (dialogue only) - mSelection = ev->data1 == '0' ? 9 : ev->data1 - '1'; - return MenuEvent(MKEY_Enter, false); - } - return Super::Responder(ev); - } }; IMPLEMENT_CLASS(DConversationMenu, true, false) diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 3808194e1..b527832fd 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -909,6 +909,9 @@ void InitThingdef() fieldptr = new PField("gametic", TypeSInt32, VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&gametic); Namespaces.GlobalNamespace->Symbols.AddSymbol(fieldptr); + fieldptr = new PField("demoplayback", TypeSInt32, VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&demoplayback); + Namespaces.GlobalNamespace->Symbols.AddSymbol(fieldptr); + // Argh. It sucks when bad hacks need to be supported. WP_NOCHANGE is just a bogus pointer but it used everywhere as a special flag. // It cannot be defined as constant because constants can either be numbers or strings but nothing else, so the only 'solution' diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index fcad86814..b2eff2601 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -463,6 +463,7 @@ struct LevelLocals native native bool nomonsters; native bool frozen; native bool infinite_flight; + native bool no_dlg_freeze; // level_info_t *info cannot be done yet. native String GetUDMFString(int type, int index, Name key); diff --git a/wadsrc/static/zscript/menu/conversationmenu.txt b/wadsrc/static/zscript/menu/conversationmenu.txt index 474fd50f2..efe843c51 100644 --- a/wadsrc/static/zscript/menu/conversationmenu.txt +++ b/wadsrc/static/zscript/menu/conversationmenu.txt @@ -63,6 +63,8 @@ struct StrifeDialogueReply native native int NextNode; // index into StrifeDialogues native int LogNumber; native bool NeedsGold; + + native bool ShouldSkipReply(PlayerInfo player); } @@ -78,8 +80,151 @@ class ConversationMenu : Menu native native PlayerInfo mPlayer; native int mSelection; + native static void SendConversationReply(int node, int reply); + //ConversationPauseTic = gametic + 20; + // DontDim = true; + //============================================================================= + // + // + // + //============================================================================= + + override void OnDestroy() + { + mDialogueLines.Destroy(); + SetMusicVolume (1); + Super.OnDestroy(); + } + + protected int GetReplyNum() + { + // This is needed because mSelection represents the replies currently being displayed which will + // not match up with what's supposed to be selected if there are any hidden/skipped replies. [FishyClockwork] + let reply = mCurNode.Children; + int replynum = mSelection; + for (int i = 0; i <= mSelection && reply != null; reply = reply.Next) + { + if (reply.ShouldSkipReply(mPlayer)) + replynum++; + else + i++; + } + return replynum; + } + + //============================================================================= + // + // + // + //============================================================================= + + override bool MenuEvent(int mkey, bool fromcontroller) + { + if (demoplayback) + { // During demo playback, don't let the user do anything besides close this menu. + if (mkey == MKEY_Back) + { + Close(); + return true; + } + return false; + } + if (mkey == MKEY_Up) + { + if (--mSelection < 0) mSelection = mResponses.Size() - 1; + return true; + } + else if (mkey == MKEY_Down) + { + if (++mSelection >= mResponses.Size()) mSelection = 0; + return true; + } + else if (mkey == MKEY_Back) + { + SendConversationReply(-1, GetReplyNum()); + Close(); + return true; + } + else if (mkey == MKEY_Enter) + { + int replynum = GetReplyNum(); + if (mSelection >= mResponses.Size()) + { + SendConversationReply(-2, replynum); + } + else + { + // Send dialogue and reply numbers across the wire. + SendConversationReply(mCurNode.ThisNodeNum, replynum); + } + Close(); + return true; + } + return false; + } + + //============================================================================= + // + // + // + //============================================================================= + + override bool MouseEvent(int type, int x, int y) + { + int sel = -1; + int fh = OptionMenuSettings.mLinespacing; + + // convert x/y from screen to virtual coordinates, according to CleanX/Yfac use in DrawTexture + x = ((x - (screen.GetWidth() / 2)) / CleanXfac) + 160; + y = ((y - (screen.GetHeight() / 2)) / CleanYfac) + 100; + + if (x >= 24 && x <= 320-24 && y >= mYpos && y < mYpos + fh * mResponseLines.Size()) + { + sel = (y - mYpos) / fh; + for(int i = 0; i < mResponses.Size(); i++) + { + if (mResponses[i] > sel) + { + sel = i-1; + break; + } + } + } + if (sel != -1 && sel != mSelection) + { + //S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE); + } + mSelection = sel; + if (type == MOUSE_Release) + { + return MenuEvent(MKEY_Enter, true); + } + return true; + } + + + //============================================================================= + // + // + // + //============================================================================= + + override bool Responder(InputEventData ev) + { + if (demoplayback) + { // No interaction during demo playback + return false; + } + if (ev.type == InputEventData.GUI_Event && ev.subtype == InputEventData.GUI_Char && ev.data1 >= 48 && ev.data1 <= 57) + { // Activate an item of type numberedmore (dialogue only) + mSelection = ev.data1 == 48 ? 9 : ev.data1 - 49; + return MenuEvent(MKEY_Enter, false); + } + return Super.Responder(ev); + } + //============================================================================ // // Draw the backdrop, returns true if the text background should be dimmed diff --git a/wadsrc/static/zscript/menu/listmenu.txt b/wadsrc/static/zscript/menu/listmenu.txt index db1a4a19c..5821d0323 100644 --- a/wadsrc/static/zscript/menu/listmenu.txt +++ b/wadsrc/static/zscript/menu/listmenu.txt @@ -47,7 +47,7 @@ class ListMenu : Menu virtual void Init(Menu parent = NULL, ListMenuDescriptor desc = NULL) { - mParentMenu = parent; + Super.Init(parent); mDesc = desc; if (desc.mCenter) { diff --git a/wadsrc/static/zscript/menu/menu.txt b/wadsrc/static/zscript/menu/menu.txt index 2f5d9454a..7d0c030df 100644 --- a/wadsrc/static/zscript/menu/menu.txt +++ b/wadsrc/static/zscript/menu/menu.txt @@ -89,6 +89,7 @@ class Menu : Object native native Menu mParentMenu; native bool mMouseCapture; native bool mBackbuttonSelected; + native bool DontDim; void Init(Menu parent) { diff --git a/wadsrc/static/zscript/menu/optionmenu.txt b/wadsrc/static/zscript/menu/optionmenu.txt index c6f0247a7..ed6189335 100644 --- a/wadsrc/static/zscript/menu/optionmenu.txt +++ b/wadsrc/static/zscript/menu/optionmenu.txt @@ -104,6 +104,7 @@ class OptionMenu : Menu { mParentMenu = parent; mDesc = desc; + DontDim = desc.mDontDim; if (mDesc != NULL && mDesc.mSelectedItem == -1) mDesc.mSelectedItem = FirstSelectable(); mDesc.CalcIndent(); } From e05242e44dc8119dbb839b0688edd324c4f95c78 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 19 Feb 2017 14:21:49 +0100 Subject: [PATCH 04/12] - 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. --- specs/usdf_zdoom.txt | 6 +- src/gi.cpp | 1 + src/gi.h | 1 + src/namedef.h | 1 + src/p_conversation.cpp | 190 ++---------------- src/p_conversation.h | 4 +- src/p_usdf.cpp | 18 +- src/scripting/thingdef_data.cpp | 8 + wadsrc/static/zscript/base.txt | 1 + .../static/zscript/menu/conversationmenu.txt | 158 +++++++++++++-- 10 files changed, 197 insertions(+), 191 deletions(-) diff --git a/specs/usdf_zdoom.txt b/specs/usdf_zdoom.txt index f800b5ae7..cd4393351 100644 --- a/specs/usdf_zdoom.txt +++ b/specs/usdf_zdoom.txt @@ -38,6 +38,7 @@ conversation page { drop = ; + userstring = ; New field which can be used to pass data to custom conversation menu classes. ifitem { item = ; @@ -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 = ; 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 = ; //Override the default conversation menu class for this conversation. page { diff --git a/src/gi.cpp b/src/gi.cpp index 247036ea7..c497bf176 100644 --- a/src/gi.cpp +++ b/src/gi.cpp @@ -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") diff --git a/src/gi.h b/src/gi.h index 1bab4e9a7..24053b002 100644 --- a/src/gi.h +++ b/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; diff --git a/src/namedef.h b/src/namedef.h index ebd9f3e8e..efc70273f 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -653,6 +653,7 @@ xx(Link) xx(Goodbye) xx(Require) xx(Exclude) +xx(Userstring) // Special menus xx(Mainmenu) diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index 10562428b..449f9e286 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -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 mResponseLines; - TArray 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 (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); diff --git a/src/p_conversation.h b/src/p_conversation.h index c10c4c697..302203bd2 100644 --- a/src/p_conversation.h +++ b/src/p_conversation.h @@ -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 diff --git a/src/p_usdf.cpp b/src/p_usdf.cpp index b8e290deb..d2a1bb25e 100644 --- a/src/p_usdf.cpp +++ b/src/p_usdf.cpp @@ -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; } diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index b527832fd..1abd0bc4c 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -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); diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index b2eff2601..500fe3abc 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -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); diff --git a/wadsrc/static/zscript/menu/conversationmenu.txt b/wadsrc/static/zscript/menu/conversationmenu.txt index efe843c51..dba162ad7 100644 --- a/wadsrc/static/zscript/menu/conversationmenu.txt +++ b/wadsrc/static/zscript/menu/conversationmenu.txt @@ -41,7 +41,7 @@ struct StrifeDialogueNode native native Class 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 mResponseLines; - native Array mResponses; - native bool mShowGold; - native StrifeDialogueNode mCurNode; - native int mYpos; - native PlayerInfo mPlayer; - native int mSelection; + String mSpeaker; + BrokenLines mDialogueLines; + Array mResponseLines; + Array 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; } From 9089beb110fd834e5b8d216d5ec93a3c84cc9631 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 19 Feb 2017 15:23:33 +0100 Subject: [PATCH 05/12] - scriptified most of the remaining parts of DMenu. Only the engine interface remains native now. --- src/gi.cpp | 1 + src/menu/menu.cpp | 236 ++++------------------------ src/menu/menu.h | 23 --- src/scripting/thingdef_data.cpp | 8 + wadsrc/static/zscript/base.txt | 1 + wadsrc/static/zscript/menu/menu.txt | 185 ++++++++++++++++++++-- 6 files changed, 211 insertions(+), 243 deletions(-) diff --git a/src/gi.cpp b/src/gi.cpp index c497bf176..18fd39f69 100644 --- a/src/gi.cpp +++ b/src/gi.cpp @@ -52,6 +52,7 @@ DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, ArmorIcon2) DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, gametype) DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, norandomplayerclass) DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, infoPages) +DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, mBackButton) const char *GameNames[17] = diff --git a/src/menu/menu.cpp b/src/menu/menu.cpp index b0bf096f8..c64b05711 100644 --- a/src/menu/menu.cpp +++ b/src/menu/menu.cpp @@ -164,53 +164,11 @@ DMenu::DMenu(DMenu *parent) GC::WriteBarrier(this, parent); } -bool DMenu::Responder (event_t *ev) -{ - bool res = false; - if (ev->type == EV_GUI_Event) - { - if (ev->subtype == EV_GUI_LButtonDown) - { - res = MouseEventBack(MOUSE_Click, ev->data1, ev->data2); - // make the menu's mouse handler believe that the current coordinate is outside the valid range - if (res) ev->data2 = -1; - res |= CallMouseEvent(MOUSE_Click, ev->data1, ev->data2); - if (res) - { - SetCapture(); - } - - } - else if (ev->subtype == EV_GUI_MouseMove) - { - BackbuttonTime = BACKBUTTON_TIME; - if (mMouseCapture || m_use_mouse == 1) - { - res = MouseEventBack(MOUSE_Move, ev->data1, ev->data2); - if (res) ev->data2 = -1; - res |= CallMouseEvent(MOUSE_Move, ev->data1, ev->data2); - } - } - else if (ev->subtype == EV_GUI_LButtonUp) - { - if (mMouseCapture) - { - ReleaseCapture(); - res = MouseEventBack(MOUSE_Release, ev->data1, ev->data2); - if (res) ev->data2 = -1; - res |= CallMouseEvent(MOUSE_Release, ev->data1, ev->data2); - } - } - } - return false; -} - -DEFINE_ACTION_FUNCTION(DMenu, Responder) -{ - PARAM_SELF_PROLOGUE(DMenu); - PARAM_POINTER(ev, event_t); - ACTION_RETURN_BOOL(self->Responder(ev)); -} +//============================================================================= +// +// +// +//============================================================================= bool DMenu::CallResponder(event_t *ev) { @@ -222,7 +180,7 @@ bool DMenu::CallResponder(event_t *ev) GlobalVMStack.Call(func, params, 2, &ret, 1, nullptr); return !!retval; } - else return Responder(ev); + else return false; } //============================================================================= @@ -231,29 +189,6 @@ bool DMenu::CallResponder(event_t *ev) // //============================================================================= -bool DMenu::MenuEvent (int mkey, bool fromcontroller) -{ - switch (mkey) - { - case MKEY_Back: - { - Close(); - S_Sound (CHAN_VOICE | CHAN_UI, - CurrentMenu != nullptr? "menu/backup" : "menu/clear", snd_menuvolume, ATTN_NONE); - return true; - } - } - return false; -} - -DEFINE_ACTION_FUNCTION(DMenu, MenuEvent) -{ - PARAM_SELF_PROLOGUE(DMenu); - PARAM_INT(key); - PARAM_BOOL(fromcontroller); - ACTION_RETURN_BOOL(self->MenuEvent(key, fromcontroller)); -} - bool DMenu::CallMenuEvent(int mkey, bool fromcontroller) { IFVIRTUAL(DMenu, MenuEvent) @@ -264,7 +199,7 @@ bool DMenu::CallMenuEvent(int mkey, bool fromcontroller) GlobalVMStack.Call(func, params, 3, &ret, 1, nullptr); return !!retval; } - else return MenuEvent(mkey, fromcontroller); + else return false; } //============================================================================= // @@ -272,6 +207,15 @@ bool DMenu::CallMenuEvent(int mkey, bool fromcontroller) // //============================================================================= +DEFINE_ACTION_FUNCTION(DMenu, SetMouseCapture) +{ + PARAM_PROLOGUE; + PARAM_BOOL(on); + if (on) I_SetMouseCapture(); + else I_ReleaseMouseCapture(); + return 0; +} + void DMenu::Close () { if (CurrentMenu == nullptr) return; // double closing can happen in the save menu. @@ -288,108 +232,19 @@ void DMenu::Close () } } -//============================================================================= -// -// -// -//============================================================================= - -bool DMenu::MouseEvent(int type, int x, int y) -{ - return true; -} - -DEFINE_ACTION_FUNCTION(DMenu, MouseEvent) +DEFINE_ACTION_FUNCTION(DMenu, Close) { PARAM_SELF_PROLOGUE(DMenu); - PARAM_INT(type); - PARAM_INT(x); - PARAM_INT(y); - ACTION_RETURN_BOOL(self->MouseEvent(type, x, y)); -} - -bool DMenu::CallMouseEvent(int type, int x, int y) -{ - IFVIRTUAL(DMenu, MouseEvent) - { - VMValue params[] = { (DObject*)this, type, x, y }; - int retval; - VMReturn ret(&retval); - GlobalVMStack.Call(func, params, 4, &ret, 1, nullptr); - return !!retval; - } - else return MouseEvent (type, x, y); -} - -//============================================================================= -// -// -// -//============================================================================= - -bool DMenu::MouseEventBack(int type, int x, int y) -{ - if (m_show_backbutton >= 0) - { - FTexture *tex = TexMan(gameinfo.mBackButton); - if (tex != nullptr) - { - if (m_show_backbutton&1) x -= screen->GetWidth() - tex->GetScaledWidth() * CleanXfac; - if (m_show_backbutton&2) y -= screen->GetHeight() - tex->GetScaledHeight() * CleanYfac; - mBackbuttonSelected = ( x >= 0 && x < tex->GetScaledWidth() * CleanXfac && - y >= 0 && y < tex->GetScaledHeight() * CleanYfac); - if (mBackbuttonSelected && type == MOUSE_Release) - { - if (m_use_mouse == 2) mBackbuttonSelected = false; - CallMenuEvent(MKEY_Back, true); - } - return mBackbuttonSelected; - } - } - return false; -} - -//============================================================================= -// -// -// -//============================================================================= - -void DMenu::SetCapture() -{ - if (!mMouseCapture) - { - mMouseCapture = true; - I_SetMouseCapture(); - } -} - -void DMenu::ReleaseCapture() -{ - if (mMouseCapture) - { - mMouseCapture = false; - I_ReleaseMouseCapture(); - } -} - -//============================================================================= -// -// -// -//============================================================================= - -void DMenu::Ticker () -{ -} - -DEFINE_ACTION_FUNCTION(DMenu, Ticker) -{ - PARAM_SELF_PROLOGUE(DMenu); - self->Ticker(); + self->Close(); return 0; } +//============================================================================= +// +// +// +//============================================================================= + void DMenu::CallTicker() { IFVIRTUAL(DMenu, Ticker) @@ -397,38 +252,9 @@ void DMenu::CallTicker() VMValue params[] = { (DObject*)this }; GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); } - else Ticker(); } -void DMenu::Drawer () -{ - if (this == CurrentMenu && BackbuttonAlpha > 0 && m_show_backbutton >= 0 && m_use_mouse) - { - FTexture *tex = TexMan(gameinfo.mBackButton); - int w = tex->GetScaledWidth() * CleanXfac; - int h = tex->GetScaledHeight() * CleanYfac; - int x = (!(m_show_backbutton&1))? 0:screen->GetWidth() - w; - int y = (!(m_show_backbutton&2))? 0:screen->GetHeight() - h; - if (mBackbuttonSelected && (mMouseCapture || m_use_mouse == 1)) - { - screen->DrawTexture(tex, x, y, DTA_CleanNoMove, true, DTA_ColorOverlay, MAKEARGB(40, 255,255,255), TAG_DONE); - } - else - { - screen->DrawTexture(tex, x, y, DTA_CleanNoMove, true, DTA_Alpha, BackbuttonAlpha, TAG_DONE); - } - } -} - - -DEFINE_ACTION_FUNCTION(DMenu, Drawer) -{ - PARAM_SELF_PROLOGUE(DMenu); - self->Drawer(); - return 0; -} - void DMenu::CallDrawer() { IFVIRTUAL(DMenu, Drawer) @@ -436,14 +262,6 @@ void DMenu::CallDrawer() VMValue params[] = { (DObject*)this }; GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); } - else Drawer(); -} - -DEFINE_ACTION_FUNCTION(DMenu, Close) -{ - PARAM_SELF_PROLOGUE(DMenu); - self->Close(); - return 0; } bool DMenu::TranslateKeyboardEvents() @@ -500,7 +318,11 @@ void M_StartControlPanel (bool makeSound) void M_ActivateMenu(DMenu *menu) { if (menuactive == MENU_Off) menuactive = MENU_On; - if (CurrentMenu != nullptr) CurrentMenu->ReleaseCapture(); + if (CurrentMenu != nullptr && CurrentMenu->mMouseCapture) + { + CurrentMenu->mMouseCapture = false; + I_ReleaseMouseCapture(); + } CurrentMenu = menu; GC::WriteBarrier(CurrentMenu); } diff --git a/src/menu/menu.h b/src/menu/menu.h index 7d1236ccf..1b4b22255 100644 --- a/src/menu/menu.h +++ b/src/menu/menu.h @@ -263,42 +263,19 @@ public: MOUSE_Release }; - enum - { - BACKBUTTON_TIME = 4*TICRATE - }; - TObjPtr mParentMenu; bool mMouseCapture; bool mBackbuttonSelected; bool DontDim; DMenu(DMenu *parent = NULL); - virtual bool Responder (event_t *ev); - virtual bool MenuEvent (int mkey, bool fromcontroller); - virtual void Ticker (); - virtual void Drawer (); bool TranslateKeyboardEvents(); virtual void Close(); - virtual bool MouseEvent(int type, int x, int y); - - virtual void SetFocus(DMenuItemBase *fc) {} - virtual bool CheckFocus(DMenuItemBase *fc) { return false; } - virtual void ReleaseFocus() {} bool CallResponder(event_t *ev); bool CallMenuEvent(int mkey, bool fromcontroller); - bool CallMouseEvent(int type, int x, int y); void CallTicker(); void CallDrawer(); - - bool MouseEventBack(int type, int x, int y); - void SetCapture(); - void ReleaseCapture(); - bool HasCapture() - { - return mMouseCapture; - } }; //============================================================================= diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 1abd0bc4c..0f5647005 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -63,6 +63,8 @@ static TArray properties; static TArray AFTable; static TArray FieldTable; +extern int BackbuttonTime; +extern float BackbuttonAlpha; //========================================================================== // @@ -912,6 +914,12 @@ void InitThingdef() fieldptr = new PField("demoplayback", TypeSInt32, VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&demoplayback); Namespaces.GlobalNamespace->Symbols.AddSymbol(fieldptr); + fieldptr = new PField("BackbuttonTime", TypeSInt32, VARF_Native | VARF_Static, (intptr_t)&BackbuttonTime); + Namespaces.GlobalNamespace->Symbols.AddSymbol(fieldptr); + + fieldptr = new PField("BackbuttonAlpha", TypeFloat32, VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&BackbuttonAlpha); + Namespaces.GlobalNamespace->Symbols.AddSymbol(fieldptr); + // Argh. It sucks when bad hacks need to be supported. WP_NOCHANGE is just a bogus pointer but it used everywhere as a special flag. // It cannot be defined as constant because constants can either be numbers or strings but nothing else, so the only 'solution' diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index 500fe3abc..e9a89b0ab 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -300,6 +300,7 @@ struct GameInfoStruct native native int gametype; native bool norandomplayerclass; native Array infoPages; + native String mBackButton; } class Object native diff --git a/wadsrc/static/zscript/menu/menu.txt b/wadsrc/static/zscript/menu/menu.txt index 7d0c030df..dda75a739 100644 --- a/wadsrc/static/zscript/menu/menu.txt +++ b/wadsrc/static/zscript/menu/menu.txt @@ -91,31 +91,190 @@ class Menu : Object native native bool mBackbuttonSelected; native bool DontDim; - void Init(Menu parent) - { - mParentMenu = parent; - } - native static int MenuTime(); native static void SetVideoMode(); native static Menu GetCurrentMenu(); native static void SetMenu(Name mnu, int param = 0); native static void StartMessage(String msg, int mode = 0, Name command = 'none'); + native static void SetMouseCapture(bool on); + native void Close(); + native void ActivateMenu(); + //============================================================================= + // + // + // + //============================================================================= + + void Init(Menu parent) + { + mParentMenu = parent; + mMouseCapture = false; + mBackbuttonSelected = false; + DontDim = false; + } + + //============================================================================= + // + // + // + //============================================================================= + + virtual bool MenuEvent (int mkey, bool fromcontroller) + { + switch (mkey) + { + case MKEY_Back: + Close(); + MenuSound (GetCurrentMenu() != null? "menu/backup" : "menu/clear"); + return true; + } + return false; + } + + + //============================================================================= + // + // + // + //============================================================================= + + protected bool MouseEventBack(int type, int x, int y) + { + if (m_show_backbutton >= 0) + { + let tex = TexMan.CheckForTexture(gameinfo.mBackButton, TexMan.Type_MiscPatch); + if (tex.IsValid()) + { + Vector2 v = TexMan.GetScaledSize(tex); + int w = int(v.X + 0.5) * CleanXfac; + int h = int(v.Y + 0.5) * CleanYfac; + if (m_show_backbutton&1) x -= screen.GetWidth() - w; + if (m_show_backbutton&2) y -= screen.GetHeight() - h; + mBackbuttonSelected = ( x >= 0 && x < w && y >= 0 && y < h); + if (mBackbuttonSelected && type == MOUSE_Release) + { + if (m_use_mouse == 2) mBackbuttonSelected = false; + MenuEvent(MKEY_Back, true); + } + return mBackbuttonSelected; + } + } + return false; + } + + //============================================================================= + // + // + // + //============================================================================= + + virtual bool Responder(InputEventData ev) + { + bool res = false; + if (ev.type == InputEventData.GUI_Event) + { + if (ev.subtype == InputEventData.GUI_LButtonDown) + { + res = MouseEventBack(MOUSE_Click, ev.data1, ev.data2); + // make the menu's mouse handler believe that the current coordinate is outside the valid range + if (res) ev.data2 = -1; + res |= MouseEvent(MOUSE_Click, ev.data1, ev.data2); + if (res) + { + SetCapture(true); + } + + } + else if (ev.subtype == InputEventData.GUI_MouseMove) + { + BackbuttonTime = 4*Thinker.TICRATE; + if (mMouseCapture || m_use_mouse == 1) + { + res = MouseEventBack(MOUSE_Move, ev.data1, ev.data2); + if (res) ev.data2 = -1; + res |= MouseEvent(MOUSE_Move, ev.data1, ev.data2); + } + } + else if (ev.subtype == InputEventData.GUI_LButtonUp) + { + if (mMouseCapture) + { + SetCapture(false); + res = MouseEventBack(MOUSE_Release, ev.data1, ev.data2); + if (res) ev.data2 = -1; + res |= MouseEvent(MOUSE_Release, ev.data1, ev.data2); + } + } + } + return false; + } + + //============================================================================= + // + // + // + //============================================================================= + + virtual void Drawer () + { + if (self == GetCurrentMenu() && BackbuttonAlpha > 0 && m_show_backbutton >= 0 && m_use_mouse) + { + let tex = TexMan.CheckForTexture(gameinfo.mBackButton, TexMan.Type_MiscPatch); + if (tex.IsValid()) + { + Vector2 v = TexMan.GetScaledSize(tex); + int w = int(v.X + 0.5) * CleanXfac; + int h = int(v.Y + 0.5) * CleanYfac; + int x = (!(m_show_backbutton&1))? 0:screen.GetWidth() - w; + int y = (!(m_show_backbutton&2))? 0:screen.GetHeight() - h; + if (mBackbuttonSelected && (mMouseCapture || m_use_mouse == 1)) + { + screen.DrawTexture(tex, true, x, y, DTA_CleanNoMove, true, DTA_ColorOverlay, Color(40, 255,255,255)); + } + else + { + screen.DrawTexture(tex, true, x, y, DTA_CleanNoMove, true, DTA_Alpha, BackbuttonAlpha); + } + } + } + } + + //============================================================================= + // + // + // + //============================================================================= + + void SetCapture(bool on) + { + if (mMouseCapture != on) + { + mMouseCapture = on; + SetMouseCapture(on); + } + } + + //============================================================================= + // + // + // + //============================================================================= + virtual bool TranslateKeyboardEvents() { return true; } virtual void SetFocus(MenuItemBase fc) {} virtual bool CheckFocus(MenuItemBase fc) { return false; } virtual void ReleaseFocus() {} virtual void ResetColor() {} + virtual bool MouseEvent(int type, int mx, int my) { return false; } + virtual void Ticker() {} + + //============================================================================= + // + // + // + //============================================================================= - native virtual bool Responder(InputEventData ev); - native virtual bool MenuEvent (int mkey, bool fromcontroller); - native virtual bool MouseEvent(int type, int mx, int my); - native virtual void Ticker(); - native virtual void Drawer(); - native void Close(); - native void ActivateMenu(); - static void MenuSound(Sound snd) { S_Sound (snd, CHAN_VOICE | CHAN_UI, snd_menuvolume, ATTN_NONE); From fb52b034b0242b393cef3d5c4f44c1221a2865ba Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 19 Feb 2017 15:35:28 +0100 Subject: [PATCH 06/12] - added a GenericMenu class, so that all menus can be given a virtual Init method. Doing this to Menu itself would not work because the different menus require different parameters. This also means that all menus that are routed through menu items must inherit from either ListMenu, OptionMenu or GenericMenu. All other types can only be used internally. This should complete the menu scriptification. --- src/menu/menu.cpp | 9 +++++++-- wadsrc/static/zscript/menu/menu.txt | 8 ++++++++ wadsrc/static/zscript/menu/readthis.txt | 15 ++++++++------- 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/src/menu/menu.cpp b/src/menu/menu.cpp index c64b05711..b2ceffc7a 100644 --- a/src/menu/menu.cpp +++ b/src/menu/menu.cpp @@ -469,10 +469,15 @@ void M_SetMenu(FName menu, int param) const PClass *menuclass = PClass::FindClass(menu); if (menuclass != nullptr) { - if (menuclass->IsDescendantOf(RUNTIME_CLASS(DMenu))) + if (menuclass->IsDescendantOf("GenericMenu")) { DMenu *newmenu = (DMenu*)menuclass->CreateNew(); - newmenu->mParentMenu = CurrentMenu; + + IFVIRTUALPTRNAME(newmenu, "GenericMenu", Init) + { + VMValue params[3] = { newmenu, CurrentMenu }; + GlobalVMStack.Call(func, params, 2, nullptr, 0); + } M_ActivateMenu(newmenu); return; } diff --git a/wadsrc/static/zscript/menu/menu.txt b/wadsrc/static/zscript/menu/menu.txt index dda75a739..84478ba81 100644 --- a/wadsrc/static/zscript/menu/menu.txt +++ b/wadsrc/static/zscript/menu/menu.txt @@ -296,3 +296,11 @@ class MenuDescriptor : Object native native static MenuDescriptor GetDescriptor(Name n); } +// This class is only needed to give it a virtual Init method that doesn't belong to Menu itself +class GenericMenu : Menu +{ + virtual void Init(Menu parent) + { + Super.Init(parent); + } +} \ No newline at end of file diff --git a/wadsrc/static/zscript/menu/readthis.txt b/wadsrc/static/zscript/menu/readthis.txt index a3db8a8a7..604fb489e 100644 --- a/wadsrc/static/zscript/menu/readthis.txt +++ b/wadsrc/static/zscript/menu/readthis.txt @@ -33,7 +33,7 @@ ** */ -class ReadThisMenu : Menu +class ReadThisMenu : GenericMenu { int mScreen; int mInfoTic; @@ -43,18 +43,19 @@ class ReadThisMenu : Menu // // //============================================================================= + + override void Init(Menu parent) + { + Super.Init(parent); + mScreen = 1; + mInfoTic = gametic; + } override void Drawer() { double alpha; TextureID tex, prevpic; - if (mScreen == 0) - { - mScreen = 1; - mInfoTic = gametic; - } - // Did the mapper choose a custom help page via MAPINFO? if (level.F1Pic.Length() != 0) { From c0f588e234bd6516103a0c8ab79d8ad0622bdc59 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 19 Feb 2017 16:08:10 +0100 Subject: [PATCH 07/12] - let M_ClearMenus destroy all open menus so that they can properly deinitialize. --- src/menu/menu.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/menu/menu.cpp b/src/menu/menu.cpp index b2ceffc7a..9a8860510 100644 --- a/src/menu/menu.cpp +++ b/src/menu/menu.cpp @@ -766,13 +766,14 @@ void M_Drawer (void) // //============================================================================= -void M_ClearMenus () +void M_ClearMenus() { M_DemoNoPlay = false; - if (CurrentMenu != nullptr) + while (CurrentMenu != nullptr) { + DMenu* parent = CurrentMenu->mParentMenu; CurrentMenu->Destroy(); - CurrentMenu = nullptr; + CurrentMenu = parent; } V_SetBorderNeedRefresh(); menuactive = MENU_Off; From f3b6343e53f3cc846f12af182572abd3413db665 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 19 Feb 2017 17:24:30 +0100 Subject: [PATCH 08/12] - use floats for menu item coordinates. This only has an effect in the ListMenu because the OptionMenu uses fixed offsets which work differently. --- src/menu/menu.cpp | 4 +-- src/menu/menu.h | 14 ++++---- src/menu/menudef.cpp | 32 +++++++++---------- wadsrc/static/zscript/menu/listmenu.txt | 14 ++++---- wadsrc/static/zscript/menu/listmenuitems.txt | 30 ++++++++--------- wadsrc/static/zscript/menu/menuitembase.txt | 12 +++---- wadsrc/static/zscript/menu/playercontrols.txt | 24 +++++++------- wadsrc/static/zscript/menu/playerdisplay.txt | 4 +-- 8 files changed, 68 insertions(+), 66 deletions(-) diff --git a/src/menu/menu.cpp b/src/menu/menu.cpp index 9a8860510..fe5af6268 100644 --- a/src/menu/menu.cpp +++ b/src/menu/menu.cpp @@ -1117,7 +1117,7 @@ DMenuItemBase * CreateOptionMenuItemControl(const char *label, FName cmd, FKeyBi return (DMenuItemBase*)p; } -DMenuItemBase * CreateListMenuItemPatch(int x, int y, int height, int hotkey, FTextureID tex, FName command, int param) +DMenuItemBase * CreateListMenuItemPatch(double x, double y, int height, int hotkey, FTextureID tex, FName command, int param) { auto c = PClass::FindClass("ListMenuItemPatchItem"); auto p = c->CreateNew(); @@ -1127,7 +1127,7 @@ DMenuItemBase * CreateListMenuItemPatch(int x, int y, int height, int hotkey, FT return (DMenuItemBase*)p; } -DMenuItemBase * CreateListMenuItemText(int x, int y, int height, int hotkey, const char *text, FFont *font, PalEntry color1, PalEntry color2, FName command, int param) +DMenuItemBase * CreateListMenuItemText(double x, double y, int height, int hotkey, const char *text, FFont *font, PalEntry color1, PalEntry color2, FName command, int param) { auto c = PClass::FindClass("ListMenuItemTextItem"); auto p = c->CreateNew(); diff --git a/src/menu/menu.h b/src/menu/menu.h index 1b4b22255..8922147e1 100644 --- a/src/menu/menu.h +++ b/src/menu/menu.h @@ -138,11 +138,11 @@ class DListMenuDescriptor : public DMenuDescriptor public: TArray mItems; int mSelectedItem; - int mSelectOfsX; - int mSelectOfsY; + double mSelectOfsX; + double mSelectOfsY; FTextureID mSelector; int mDisplayTop; - int mXpos, mYpos; + double mXpos, mYpos; int mWLeft, mWRight; int mLinespacing; // needs to be stored for dynamically created menus int mAutoselect; // this can only be set by internal menu creation functions @@ -288,7 +288,7 @@ class DMenuItemBase : public DObject { DECLARE_CLASS(DMenuItemBase, DObject) public: - int mXpos, mYpos; + double mXpos, mYpos; FNameNoInit mAction; bool mEnabled; @@ -298,7 +298,7 @@ public: bool SetValue(int i, int value); bool GetValue(int i, int *pvalue); void OffsetPositionY(int ydelta) { mYpos += ydelta; } - int GetY() { return mYpos; } + double GetY() { return mYpos; } }; //============================================================================= @@ -355,7 +355,7 @@ DMenuItemBase * CreateOptionMenuItemStaticText(const char *name, bool v); DMenuItemBase * CreateOptionMenuItemSubmenu(const char *label, FName cmd, int center); DMenuItemBase * CreateOptionMenuItemControl(const char *label, FName cmd, FKeyBindings *bindings); DMenuItemBase * CreateOptionMenuItemJoyConfigMenu(const char *label, IJoystickConfig *joy); -DMenuItemBase * CreateListMenuItemPatch(int x, int y, int height, int hotkey, FTextureID tex, FName command, int param); -DMenuItemBase * CreateListMenuItemText(int x, int y, int height, int hotkey, const char *text, FFont *font, PalEntry color1, PalEntry color2, FName command, int param); +DMenuItemBase * CreateListMenuItemPatch(double x, double y, int height, int hotkey, FTextureID tex, FName command, int param); +DMenuItemBase * CreateListMenuItemText(double x, double y, int height, int hotkey, const char *text, FFont *font, PalEntry color1, PalEntry color2, FName command, int param); #endif diff --git a/src/menu/menudef.cpp b/src/menu/menudef.cpp index f9ecbd808..cf986ee58 100644 --- a/src/menu/menudef.cpp +++ b/src/menu/menudef.cpp @@ -305,11 +305,11 @@ static void ParseListMenuBody(FScanner &sc, DListMenuDescriptor *desc) sc.MustGetString(); desc->mSelector = GetMenuTexture(sc.String); sc.MustGetStringName(","); - sc.MustGetNumber(); - desc->mSelectOfsX = sc.Number; + sc.MustGetFloat(); + desc->mSelectOfsX = sc.Float; sc.MustGetStringName(","); - sc.MustGetNumber(); - desc->mSelectOfsY = sc.Number; + sc.MustGetFloat(); + desc->mSelectOfsY = sc.Float; } else if (sc.Compare("Linespacing")) { @@ -318,11 +318,11 @@ static void ParseListMenuBody(FScanner &sc, DListMenuDescriptor *desc) } else if (sc.Compare("Position")) { - sc.MustGetNumber(); - desc->mXpos = sc.Number; + sc.MustGetFloat(); + desc->mXpos = sc.Float; sc.MustGetStringName(","); - sc.MustGetNumber(); - desc->mYpos = sc.Number; + sc.MustGetFloat(); + desc->mYpos = sc.Float; } else if (sc.Compare("Centermenu")) { @@ -973,13 +973,13 @@ static void BuildEpisodeMenu() if ((*desc)->IsKindOf(RUNTIME_CLASS(DListMenuDescriptor))) { DListMenuDescriptor *ld = static_cast(*desc); - int posy = ld->mYpos; + int posy = (int)ld->mYpos; int topy = posy; // Get lowest y coordinate of any static item in the menu for(unsigned i = 0; i < ld->mItems.Size(); i++) { - int y = ld->mItems[i]->GetY(); + int y = (int)ld->mItems[i]->GetY(); if (y < topy) topy = y; } @@ -1073,13 +1073,13 @@ static void BuildPlayerclassMenu() // add player display ld->mSelectedItem = ld->mItems.Size(); - int posy = ld->mYpos; + int posy = (int)ld->mYpos; int topy = posy; // Get lowest y coordinate of any static item in the menu for(unsigned i = 0; i < ld->mItems.Size(); i++) { - int y = ld->mItems[i]->GetY(); + int y = (int)ld->mItems[i]->GetY(); if (y < topy) topy = y; } @@ -1333,8 +1333,8 @@ void M_StartupSkillMenu(FGameStartup *gs) if ((*desc)->IsKindOf(RUNTIME_CLASS(DListMenuDescriptor))) { DListMenuDescriptor *ld = static_cast(*desc); - int x = ld->mXpos; - int y = ld->mYpos; + int x = (int)ld->mXpos; + int y = (int)ld->mYpos; // Delete previous contents for(unsigned i=0; imItems.Size(); i++) @@ -1363,7 +1363,7 @@ void M_StartupSkillMenu(FGameStartup *gs) // Get lowest y coordinate of any static item in the menu for(unsigned i = 0; i < ld->mItems.Size(); i++) { - int y = ld->mItems[i]->GetY(); + int y = (int)ld->mItems[i]->GetY(); if (y < topy) topy = y; } @@ -1380,7 +1380,7 @@ void M_StartupSkillMenu(FGameStartup *gs) { ld->mItems[i]->OffsetPositionY(topdelta); } - y = ld->mYpos = posy - topdelta; + ld->mYpos = y = posy - topdelta; } } else diff --git a/wadsrc/static/zscript/menu/listmenu.txt b/wadsrc/static/zscript/menu/listmenu.txt index 5821d0323..a7a9f71ae 100644 --- a/wadsrc/static/zscript/menu/listmenu.txt +++ b/wadsrc/static/zscript/menu/listmenu.txt @@ -4,11 +4,11 @@ class ListMenuDescriptor : MenuDescriptor native { native Array mItems; native int mSelectedItem; - native int mSelectOfsX; - native int mSelectOfsY; + native double mSelectOfsX; + native double mSelectOfsY; native TextureID mSelector; native int mDisplayTop; - native int mXpos, mYpos; + native double mXpos, mYpos; native int mWLeft, mWRight; native int mLinespacing; // needs to be stored for dynamically created menus native int mAutoselect; // this can only be set by internal menu creation functions @@ -51,16 +51,16 @@ class ListMenu : Menu mDesc = desc; if (desc.mCenter) { - int center = 160; + double center = 160; for(int i=0; i < mDesc.mItems.Size(); i++) { - int xpos = mDesc.mItems[i].GetX(); + double xpos = mDesc.mItems[i].GetX(); int width = mDesc.mItems[i].GetWidth(); - int curx = mDesc.mSelectOfsX; + double curx = mDesc.mSelectOfsX; if (width > 0 && mDesc.mItems[i].Selectable()) { - int left = 160 - (width - curx) / 2 - curx; + double left = 160 - (width - curx) / 2 - curx; if (left < center) center = left; } } diff --git a/wadsrc/static/zscript/menu/listmenuitems.txt b/wadsrc/static/zscript/menu/listmenuitems.txt index e3eec6dd1..c1bafeaf9 100644 --- a/wadsrc/static/zscript/menu/listmenuitems.txt +++ b/wadsrc/static/zscript/menu/listmenuitems.txt @@ -35,7 +35,7 @@ class ListMenuItem : MenuItemBase { - void DrawSelector(int xofs, int yofs, TextureID tex) + void DrawSelector(double xofs, double yofs, TextureID tex) { if (tex.isNull()) { @@ -68,7 +68,7 @@ class ListMenuItemStaticPatch : ListMenuItem TextureID mTexture; bool mCentered; - void Init(int x, int y, TextureID patch, bool centered = false) + void Init(double x, double y, TextureID patch, bool centered = false) { Super.Init(x, y); mTexture = patch; @@ -82,17 +82,17 @@ class ListMenuItemStaticPatch : ListMenuItem return; } - int x = mXpos; + double x = mXpos; Vector2 vec = TexMan.GetScaledSize(mTexture); if (mYpos >= 0) { - if (mCentered) x -= int(vec.X) / 2; + if (mCentered) x -= vec.X / 2; screen.DrawTexture (mTexture, true, x, mYpos, DTA_Clean, true); } else { - int x = (mXpos - 160) * CleanXfac + (Screen.GetWidth()>>1); - if (mCentered) x -= (int(vec.X) * CleanXfac)/2; + x = (mXpos - 160) * CleanXfac + (Screen.GetWidth()>>1); + if (mCentered) x -= (vec.X * CleanXfac)/2; screen.DrawTexture (mTexture, true, x, -mYpos*CleanYfac, DTA_CleanNoMove, true); } } @@ -100,7 +100,7 @@ class ListMenuItemStaticPatch : ListMenuItem class ListMenuItemStaticPatchCentered : ListMenuItemStaticPatch { - void Init(int x, int y, TextureID patch) + void Init(double x, double y, TextureID patch) { Super.Init(x, y, patch, true); } @@ -119,7 +119,7 @@ class ListMenuItemStaticText : ListMenuItem int mColor; bool mCentered; - void Init(ListMenuDescriptor desc, int x, int y, String text, int color = Font.CR_UNTRANSLATED) + void Init(ListMenuDescriptor desc, double x, double y, String text, int color = Font.CR_UNTRANSLATED) { Super.Init(x, y); mText = text; @@ -128,7 +128,7 @@ class ListMenuItemStaticText : ListMenuItem mCentered = false; } - void InitDirect(int x, int y, String text, Font font, int color = Font.CR_UNTRANSLATED, bool centered = false) + void InitDirect(double x, double y, String text, Font font, int color = Font.CR_UNTRANSLATED, bool centered = false) { Super.Init(x, y); mText = text; @@ -144,13 +144,13 @@ class ListMenuItemStaticText : ListMenuItem String text = Stringtable.Localize(mText); if (mYpos >= 0) { - int x = mXpos; + double x = mXpos; if (mCentered) x -= mFont.StringWidth(text)/2; screen.DrawText(mFont, mColor, x, mYpos, text, DTA_Clean, true); } else { - int x = (mXpos - 160) * CleanXfac + (Screen.GetWidth() >> 1); + double x = (mXpos - 160) * CleanXfac + (Screen.GetWidth() >> 1); if (mCentered) x -= (mFont.StringWidth(text) * CleanXfac)/2; screen.DrawText (mFont, mColor, x, -mYpos*CleanYfac, text, DTA_CleanNoMove, true); } @@ -160,7 +160,7 @@ class ListMenuItemStaticText : ListMenuItem class ListMenuItemStaticTextCentered : ListMenuItemStaticText { - void Init(ListMenuDescriptor desc, int x, int y, String text, int color = -1) + void Init(ListMenuDescriptor desc, double x, double y, String text, int color = -1) { Super.Init(desc, x, y, text, color); mCentered = true; @@ -179,7 +179,7 @@ class ListMenuItemSelectable : ListMenuItem int mHeight; int mParam; - protected void Init(int x, int y, int height, Name childmenu, int param = -1) + protected void Init(double x, double y, int height, Name childmenu, int param = -1) { Super.Init(x, y, childmenu); mHeight = height; @@ -250,7 +250,7 @@ class ListMenuItemTextItem : ListMenuItemSelectable mHotkey = hotkey.CharCodeAt(0); } - void InitDirect(int x, int y, int height, String hotkey, String text, Font font, int color, int color2, Name child, int param = 0) + void InitDirect(double x, double y, int height, String hotkey, String text, Font font, int color, int color2, Name child, int param = 0) { Super.Init(x, y, height, child, param); mText = text; @@ -288,7 +288,7 @@ class ListMenuItemPatchItem : ListMenuItemSelectable mTexture = patch; } - void InitDirect(int x, int y, int height, TextureID patch, String hotkey, Name child, int param = 0) + void InitDirect(double x, double y, int height, TextureID patch, String hotkey, Name child, int param = 0) { Super.Init(x, y, height, child, param); mHotkey = hotkey.CharCodeAt(0); diff --git a/wadsrc/static/zscript/menu/menuitembase.txt b/wadsrc/static/zscript/menu/menuitembase.txt index de5f05a42..35663d8b2 100644 --- a/wadsrc/static/zscript/menu/menuitembase.txt +++ b/wadsrc/static/zscript/menu/menuitembase.txt @@ -6,11 +6,11 @@ class MenuItemBase : Object native { - protected native int mXpos, mYpos; + protected native double mXpos, mYpos; protected native Name mAction; native bool mEnabled; - void Init(int xpos = 0, int ypos = 0, Name actionname = 'None') + void Init(double xpos = 0, double ypos = 0, Name actionname = 'None') { mXpos = xpos; mYpos = ypos; @@ -36,10 +36,10 @@ class MenuItemBase : Object native virtual int GetIndent() { return 0; } virtual int Draw(OptionMenuDescriptor desc, int y, int indent, bool selected) { return indent; } - void OffsetPositionY(int ydelta) { mYpos += ydelta; } - int GetY() { return mYpos; } - int GetX() { return mXpos; } - void SetX(int x) { mXpos = x; } + void OffsetPositionY(double ydelta) { mYpos += ydelta; } + double GetY() { return mYpos; } + double GetX() { return mXpos; } + void SetX(double x) { mXpos = x; } } // this is only used to parse font color ranges in MENUDEF diff --git a/wadsrc/static/zscript/menu/playercontrols.txt b/wadsrc/static/zscript/menu/playercontrols.txt index 389c34043..b7b4f05f4 100644 --- a/wadsrc/static/zscript/menu/playercontrols.txt +++ b/wadsrc/static/zscript/menu/playercontrols.txt @@ -71,7 +71,7 @@ class ListMenuItemPlayerNameBox : ListMenuItemSelectable // //============================================================================= - void InitDirect(int x, int y, int height, int frameofs, String text, Font font, int color, Name command) + void InitDirect(double x, double y, int height, int frameofs, String text, Font font, int color, Name command) { Super.Init(x, y, height, command); mText = text; @@ -113,7 +113,7 @@ class ListMenuItemPlayerNameBox : ListMenuItemSelectable // //============================================================================= - protected void DrawBorder (int x, int y, int len) + protected void DrawBorder (double x, double y, int len) { let left = TexMan.CheckForTexture("M_LSLEFT", TexMan.Type_MiscPatch); let mid = TexMan.CheckForTexture("M_LSCNTR", TexMan.Type_MiscPatch); @@ -141,7 +141,9 @@ class ListMenuItemPlayerNameBox : ListMenuItemSelectable } else { - screen.Clear(x, y, x + len, y + SmallFont.GetHeight() * 3/2, 0); + int xx = int(x - 160) * CleanXfac + screen.GetWidth()/2; + int yy = int(y - 100) * CleanXfac + screen.GetHeight()/2; + screen.Clear(xx, yy, xx + len*CleanXfac, yy + SmallFont.GetHeight() * CleanYfac * 3/2, 0); } } } @@ -161,7 +163,7 @@ class ListMenuItemPlayerNameBox : ListMenuItemSelectable } // Draw player name box - int x = mXpos + mFont.StringWidth(text) + 16 + mFrameSize; + double x = mXpos + mFont.StringWidth(text) + 16 + mFrameSize; DrawBorder (x, mYpos - mFrameSize, MAXPLAYERNAME+1); if (!mEnter) { @@ -246,7 +248,7 @@ class ListMenuItemValueText : ListMenuItemSelectable // //============================================================================= - void InitDirect(int x, int y, int height, String text, Font font, int color, int valuecolor, Name command, Name values) + void InitDirect(double x, double y, int height, String text, Font font, int color, int valuecolor, Name command, Name values) { Super.Init(x, y, height, command); mText = text; @@ -337,7 +339,7 @@ class ListMenuItemValueText : ListMenuItemSelectable String text = Stringtable.Localize(mText); screen.DrawText(mFont, selected? OptionMenuSettings.mFontColorSelection : mFontColor, mXpos, mYpos, text, DTA_Clean, true); - int x = mXpos + mFont.StringWidth(text) + 8; + double x = mXpos + mFont.StringWidth(text) + 8; if (mSelections.Size() > 0) { screen.DrawText(mFont, mFontColor2, x, mYpos, mSelections[mSelection], DTA_Clean, true); @@ -385,7 +387,7 @@ class ListMenuItemSlider : ListMenuItemSelectable // //============================================================================= - void InitDirect(int x, int y, int height, String text, Font font, int color, Name command, int min, int max, int step) + void InitDirect(double x, double y, int height, String text, Font font, int color, Name command, int min, int max, int step) { Super.Init(x, y, height, command); mText = text; @@ -463,7 +465,7 @@ class ListMenuItemSlider : ListMenuItemSelectable lm.ReleaseFocus(); } - int slide_left = SmallFont.StringWidth ("Green") + 8 + mXpos; + int slide_left = SmallFont.StringWidth ("Green") + 8 + int(mXpos); int slide_right = slide_left + 12*8; // 12 char cells with 8 pixels each. if (type == Menu.MOUSE_Click) @@ -491,7 +493,7 @@ class ListMenuItemSlider : ListMenuItemSelectable // //============================================================================= - protected void DrawSlider (int x, int y) + protected void DrawSlider (double x, double y) { int range = mMaxrange - mMinrange; int cur = mSelection - mMinrange; @@ -515,8 +517,8 @@ class ListMenuItemSlider : ListMenuItemSelectable screen.DrawText(mFont, selected? OptionMenuSettings.mFontColorSelection : mFontColor, mXpos, mYpos, text, DTA_Clean, true); - int x = SmallFont.StringWidth ("Green") + 8 + mXpos; - int x2 = SmallFont.StringWidth (text) + 8 + mXpos; + double x = SmallFont.StringWidth ("Green") + 8 + mXpos; + double x2 = SmallFont.StringWidth (text) + 8 + mXpos; DrawSlider (MAX(x2, x), mYpos); } } \ No newline at end of file diff --git a/wadsrc/static/zscript/menu/playerdisplay.txt b/wadsrc/static/zscript/menu/playerdisplay.txt index 492ba978c..da64559c8 100644 --- a/wadsrc/static/zscript/menu/playerdisplay.txt +++ b/wadsrc/static/zscript/menu/playerdisplay.txt @@ -252,8 +252,8 @@ class ListMenuItemPlayerDisplay : ListMenuItem } else { - int x = (mXpos - 160) * CleanXfac + (screen.GetWidth() >> 1); - int y = (mYpos - 100) * CleanYfac + (screen.GetHeight() >> 1); + int x = int(mXpos - 160) * CleanXfac + (screen.GetWidth() >> 1); + int y = int(mYpos - 100) * CleanYfac + (screen.GetHeight() >> 1); screen.DrawTexture(mBackdrop, false, x, y - 1, DTA_DestWidth, 72 * CleanXfac, From fa0be4d4a93f580d968ecd50168b28498c04c035 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 19 Feb 2017 17:30:02 +0100 Subject: [PATCH 09/12] - fixed keycodes for confirmation menu. --- wadsrc/static/zscript/menu/messagebox.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wadsrc/static/zscript/menu/messagebox.txt b/wadsrc/static/zscript/menu/messagebox.txt index d95298546..b7b611f41 100644 --- a/wadsrc/static/zscript/menu/messagebox.txt +++ b/wadsrc/static/zscript/menu/messagebox.txt @@ -181,12 +181,12 @@ class MessageBoxMenu : Menu int ch = ev.data1; ch = ch >= 65 && ch <91? ch + 32 : ch; - if (ch == 78 /*'n'*/ || ch == 32) + if (ch == 110 /*'n'*/ || ch == 32) { HandleResult(false); return true; } - else if (ch == 89 /*'y'*/) + else if (ch == 121 /*'y'*/) { HandleResult(true); return true; From 68b47d81de98ec3674f1fa8f7d642b9cd3e86b32 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 19 Feb 2017 17:58:54 +0100 Subject: [PATCH 10/12] - fixed WP_NOCHANGE changes with a restart, so this must be taken into account for the script variable holding it. --- src/scripting/thingdef_data.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 0f5647005..378c6c927 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -65,6 +65,7 @@ static TArray AFTable; static TArray FieldTable; extern int BackbuttonTime; extern float BackbuttonAlpha; +static AWeapon *wpnochg; //========================================================================== // @@ -924,7 +925,7 @@ void InitThingdef() // Argh. It sucks when bad hacks need to be supported. WP_NOCHANGE is just a bogus pointer but it used everywhere as a special flag. // It cannot be defined as constant because constants can either be numbers or strings but nothing else, so the only 'solution' // is to create a static variable from it and reference that in the script. Yuck!!! - static AWeapon *wpnochg = WP_NOCHANGE; + wpnochg = WP_NOCHANGE; fieldptr = new PField("WP_NOCHANGE", NewPointer(RUNTIME_CLASS(AWeapon), false), VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&wpnochg); Namespaces.GlobalNamespace->Symbols.AddSymbol(fieldptr); From 6c9558459d941a072ffd3fb4f281200be24c5a68 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 19 Feb 2017 18:15:40 +0100 Subject: [PATCH 11/12] - allow menu items to inherit their parent's Init method for MENUDEFS. --- src/menu/menudef.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/menu/menudef.cpp b/src/menu/menudef.cpp index cf986ee58..16b567166 100644 --- a/src/menu/menudef.cpp +++ b/src/menu/menudef.cpp @@ -369,7 +369,7 @@ static void ParseListMenuBody(FScanner &sc, DListMenuDescriptor *desc) PClass *cls = PClass::FindClass(buildname); if (cls != nullptr && cls->IsDescendantOf("ListMenuItem")) { - auto func = dyn_cast(cls->Symbols.FindSymbol("Init", false)); + auto func = dyn_cast(cls->Symbols.FindSymbol("Init", true)); if (func != nullptr && !(func->Variants[0].Flags & (VARF_Protected | VARF_Private))) // skip internal classes which have a protexted init method. { auto &args = func->Variants[0].Proto->ArgumentTypes; @@ -741,7 +741,7 @@ static void ParseOptionMenuBody(FScanner &sc, DOptionMenuDescriptor *desc) PClass *cls = PClass::FindClass(buildname); if (cls != nullptr && cls->IsDescendantOf("OptionMenuItem")) { - auto func = dyn_cast(cls->Symbols.FindSymbol("Init", false)); + auto func = dyn_cast(cls->Symbols.FindSymbol("Init", true)); if (func != nullptr && !(func->Variants[0].Flags & (VARF_Protected | VARF_Private))) // skip internal classes which have a protexted init method. { auto &args = func->Variants[0].Proto->ArgumentTypes; From 65f2433ac727682520ecb4be1b285b5031c23d68 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 19 Feb 2017 18:27:29 +0100 Subject: [PATCH 12/12] - fixed: The text enter screen must be activated if it should be displayed. --- wadsrc/static/zscript/menu/optionmenuitems.txt | 1 + wadsrc/static/zscript/menu/playercontrols.txt | 1 + 2 files changed, 2 insertions(+) diff --git a/wadsrc/static/zscript/menu/optionmenuitems.txt b/wadsrc/static/zscript/menu/optionmenuitems.txt index 9ac308372..404ce5b36 100644 --- a/wadsrc/static/zscript/menu/optionmenuitems.txt +++ b/wadsrc/static/zscript/menu/optionmenuitems.txt @@ -1129,6 +1129,7 @@ class OptionMenuItemTextField : OptionMenuFieldBase { Menu.MenuSound("menu/choose"); mEnter = TextEnterMenu.Open(Menu.GetCurrentMenu(), GetCVarString(), -1, 2, fromcontroller); + mEnter.ActivateMenu(); return true; } else if (mkey == Menu.MKEY_Input) diff --git a/wadsrc/static/zscript/menu/playercontrols.txt b/wadsrc/static/zscript/menu/playercontrols.txt index b7b4f05f4..b0f97cdbc 100644 --- a/wadsrc/static/zscript/menu/playercontrols.txt +++ b/wadsrc/static/zscript/menu/playercontrols.txt @@ -188,6 +188,7 @@ class ListMenuItemPlayerNameBox : ListMenuItemSelectable { Menu.MenuSound ("menu/choose"); mEnter = TextEnterMenu.Open(Menu.GetCurrentMenu(), mPlayerName, MAXPLAYERNAME, 2, fromcontroller); + mEnter.ActivateMenu(); return true; } else if (mkey == Menu.MKEY_Input)