diff --git a/source/blood/src/d_menu.cpp b/source/blood/src/d_menu.cpp index 2ba91858a..44c8874dd 100644 --- a/source/blood/src/d_menu.cpp +++ b/source/blood/src/d_menu.cpp @@ -381,7 +381,7 @@ void GameInterface::DrawMenuCaption(const DVector2& origin, const char* text) int height; // font #1, tile #2038. viewGetFontInfo(1, NULL, NULL, &height); - rotatesprite(int(origin.X * 65536) + 320 << 15, 20 << 16, 65536, 0, 2038, -128, 0, 78, 0, 0, xdim - 1, ydim - 1); + rotatesprite(int(origin.X * 65536) + (320 << 15), 20 << 16, 65536, 0, 2038, -128, 0, 78, 0, 0, xdim - 1, ydim - 1); viewDrawText(1, text, 160, 20 - height / 2, -128, 0, 1, false); } diff --git a/source/common/menu/imagescroller.cpp b/source/common/menu/imagescroller.cpp index 8193ab80b..d0a50895b 100644 --- a/source/common/menu/imagescroller.cpp +++ b/source/common/menu/imagescroller.cpp @@ -43,24 +43,6 @@ #include "gamecontrol.h" #include "build.h" -//============================================================================= -// -// Show a fullscreen image / centered text screen for an image scroller -// -//============================================================================= - -class ImageScreen : public DMenu // Todo: This should be global -{ - const FImageScrollerDescriptor::ScrollerItem* mDesc; -public: - ImageScreen(const FImageScrollerDescriptor::ScrollerItem* it) - { - mDesc = it; - } - void Drawer() override; -}; - - //============================================================================= // // Fullscreen image drawer (move to its own source file!) @@ -93,15 +75,19 @@ void ImageScreen::Drawer() } } - -DImageScrollerMenu::DImageScrollerMenu(DMenu* parent, FImageScrollerDescriptor* desc) - : DMenu(parent) +ImageScreen* DImageScrollerMenu::newImageScreen(FImageScrollerDescriptor::ScrollerItem* desc) { + return new ImageScreen(desc); +} + +void DImageScrollerMenu::Init(DMenu* parent, FImageScrollerDescriptor* desc) +{ + mParentMenu = parent; index = 0; mDesc = desc; canAnimate = !!(mDesc->mFlags & LMF_Animate); - mCurrent = new ImageScreen(&mDesc->mItems[0]); + mCurrent = newImageScreen(&mDesc->mItems[0]); mCurrent->canAnimate = canAnimate; } @@ -119,7 +105,7 @@ bool DImageScrollerMenu::MenuEvent(int mkey, bool fromcontroller) if (pageTransition.previous == nullptr) { if (--index < 0) index = mDesc->mItems.Size() - 1; - auto next = new ImageScreen(&mDesc->mItems[index]); + auto next = newImageScreen(&mDesc->mItems[index]); next->canAnimate = canAnimate; if (!pageTransition.StartTransition(mCurrent, next, MA_Return)) { @@ -135,7 +121,7 @@ bool DImageScrollerMenu::MenuEvent(int mkey, bool fromcontroller) if (pageTransition.previous == nullptr) { if (++index >= (int)mDesc->mItems.Size()) index = 0; - auto next = new ImageScreen(&mDesc->mItems[index]); + auto next = newImageScreen(&mDesc->mItems[index]); next->canAnimate = canAnimate; if (!pageTransition.StartTransition(mCurrent, next, MA_Advance)) { diff --git a/source/common/menu/menu.cpp b/source/common/menu/menu.cpp index 525fe4ccf..6a4b2aff9 100644 --- a/source/common/menu/menu.cpp +++ b/source/common/menu/menu.cpp @@ -534,7 +534,6 @@ bool M_SetMenu(FName menu, int param, FName caller) } newmenu->Init(DMenu::CurrentMenu, ld); M_ActivateMenu(newmenu); - return true; } } else if ((*desc)->mType == MDESC_OptionsMenu) @@ -549,11 +548,25 @@ bool M_SetMenu(FName menu, int param, FName caller) else if ((*desc)->mType == MDESC_ImageScroller) { FImageScrollerDescriptor* ld = static_cast(*desc); - if (ld->mItems.Size() > 0) // only open the submenu if it isn't empty. + DImageScrollerMenu* newmenu; + if (ld->mClass != NAME_None) { - DImageScrollerMenu* newmenu = new DImageScrollerMenu(DMenu::CurrentMenu, ld); - M_ActivateMenu(newmenu); + auto ndx = menuClasses.FindEx([=](const auto p) { return p->mName == ld->mClass; }); + if (ndx == menuClasses.Size()) + { + I_Error("Bad menu class %s\n", ld->mClass.GetChars()); + } + else + { + newmenu = (DImageScrollerMenu*)menuClasses[ndx]->CreateNew(); + } } + else + { + newmenu = new DImageScrollerMenu; + } + newmenu->Init(DMenu::CurrentMenu, ld); + M_ActivateMenu(newmenu); } return true; } diff --git a/source/common/menu/menu.h b/source/common/menu/menu.h index 6cf842a1c..3ab844da5 100644 --- a/source/common/menu/menu.h +++ b/source/common/menu/menu.h @@ -669,16 +669,19 @@ void DrawOptionText(int x, int y, int color, const char *text, bool grayed = fal // ImageScroller // //============================================================================= +class ImageScreen; class DImageScrollerMenu : public DMenu { - DMenu* mCurrent; - FImageScrollerDescriptor* mDesc; - int index; + DMenu* mCurrent = nullptr; + FImageScrollerDescriptor* mDesc = nullptr; + int index = 0; MenuTransition pageTransition = {}; + virtual ImageScreen* newImageScreen(FImageScrollerDescriptor::ScrollerItem* desc); + public: - DImageScrollerMenu(DMenu* parent = nullptr, FImageScrollerDescriptor* desc = nullptr); + void Init(DMenu* parent = nullptr, FImageScrollerDescriptor* desc = nullptr); bool MenuEvent(int mkey, bool fromcontroller); bool MouseEvent(int type, int x, int y); void Ticker(); @@ -722,6 +725,23 @@ public: }; +//============================================================================= +// +// Show a fullscreen image / centered text screen for an image scroller +// +//============================================================================= + +class ImageScreen : public DMenu +{ +protected: + const FImageScrollerDescriptor::ScrollerItem* mDesc; +public: + ImageScreen(const FImageScrollerDescriptor::ScrollerItem* it) + { + mDesc = it; + } + void Drawer() override; +}; diff --git a/source/common/menu/menudef.cpp b/source/common/menu/menudef.cpp index 0cdc2eb59..4af11fb44 100644 --- a/source/common/menu/menudef.cpp +++ b/source/common/menu/menudef.cpp @@ -580,6 +580,11 @@ static void ParseImageScrollerBody(FScanner &sc, FImageScrollerDescriptor *desc) ParseImageScrollerBody(sc, desc); } } + else if (sc.Compare("Class")) + { + sc.MustGetString(); + desc->mClass = sc.String; + } else if (sc.Compare("TextItem") || sc.Compare("ImageItem")) { FImageScrollerDescriptor::ScrollerItem item; diff --git a/source/duke3d/src/d_menu.cpp b/source/duke3d/src/d_menu.cpp index ab7b8e8b4..e210eb205 100644 --- a/source/duke3d/src/d_menu.cpp +++ b/source/duke3d/src/d_menu.cpp @@ -330,7 +330,7 @@ protected: void PreDraw() override { - CallScript(CurrentMenu == this ? EVENT_DISPLAYMENU : EVENT_DISPLAYMENUREST, true); + CallScript(CurrentMenu == this ? EVENT_DISPLAYMENU : EVENT_DISPLAYINACTIVEMENU, true); Super::PreDraw(); } @@ -364,6 +364,56 @@ class DukeMainMenu : public DukeListMenu } }; +//---------------------------------------------------------------------------- +// +// Hack to display Ion Fury's credits screens +// +//---------------------------------------------------------------------------- + +class DukeImageScreen : public ImageScreen +{ +public: + DukeImageScreen(FImageScrollerDescriptor::ScrollerItem* desc) + : ImageScreen(desc) + {} + + void CallScript(int event, bool getorigin = false) + { + ud.returnvar[0] = int(origin.X * 65536); + ud.returnvar[1] = int(origin.Y * 65536); + ud.returnvar[2] = 0; + VM_OnEventWithReturn(event, g_player[screenpeek].ps->i, screenpeek, mDesc->scriptID); + if (getorigin) + { + origin.X = ud.returnvar[0] / 65536.; + origin.Y = ud.returnvar[1] / 65536.; + } + } + + void Drawer() override + { + // Hack alert: The Ion Fury scripts - being true to the entire design here, take the current menu value + // not from the passed variable but instead from the global current_menu, so we have to temporarily alter that here. + // Ugh. (Talk about "broken by design"...) + auto cm = g_currentMenu; + g_currentMenu = mDesc->scriptID; + auto o = origin; + CallScript(EVENT_DISPLAYMENU, true); + ImageScreen::Drawer(); + CallScript(EVENT_DISPLAYMENUREST, false); + g_currentMenu = cm; + origin = o; + } +}; + +class DDukeImageScrollerMenu : public DImageScrollerMenu +{ + ImageScreen* newImageScreen(FImageScrollerDescriptor::ScrollerItem* desc) override + { + return new DukeImageScreen(desc); + } +}; + //---------------------------------------------------------------------------- // // Menu related game interface functions @@ -390,7 +440,7 @@ void GameInterface::DrawNativeMenuText(int fontnum, int state, double xpos, doub int32_t const height = font.get_yline(); status |= MT_YCenter; - int32_t const y_internal = ypos + ((height >> 17) << 16);// -menu->scrollPos; + int32_t const y_internal = int(ypos * 65536) + ((height >> 17) << 16);// -menu->scrollPos; vec2_t textsize; if (dodraw) @@ -720,10 +770,12 @@ END_DUKE_NS static TMenuClassDescriptor _mm("Duke.MainMenu"); static TMenuClassDescriptor _lm("Duke.ListMenu"); static TMenuClassDescriptor _ngcsm("Duke.NewGameCustomSubMenu"); +static TMenuClassDescriptor _ism("Duke.ImageScrollerMenu"); void RegisterDukeMenus() { menuClasses.Push(&_mm); menuClasses.Push(&_lm); menuClasses.Push(&_ngcsm); + menuClasses.Push(&_ism); } diff --git a/wadsrc/static/demolition/menudef.txt b/wadsrc/static/demolition/menudef.txt index 9489d87ec..05f71287d 100644 --- a/wadsrc/static/demolition/menudef.txt +++ b/wadsrc/static/demolition/menudef.txt @@ -397,21 +397,26 @@ LISTMENU "MultiMenu" ImageScroller "HelpMenu" { - ifgame(Duke, Nam, WW2GI, Redneck, RedneckRides) + ifgame(Duke, Nam, WW2GI, Fury) { ImageItem "TEXTSTORY", 400 ImageItem "F1HELP", 401 + class "Duke.ImageScrollerMenu" + ifgame(Duke, Nam, WW2GI) + { + animatedtransition + } + } + ifgame(Redneck, RedneckRides) + { + ImageItem "TEXTSTORY" + ImageItem "F1HELP" ifgame(RedneckRides) { ImageItem "RRTILE1636" } animatedtransition } - ifgame(fury) - { - ImageItem "TEXTSTORY", 400 - ImageItem "F1HELP", 401 - } ifgame(blood) { // The duplication here is to integrate the alternating versions of HELP3 @@ -452,12 +457,14 @@ ImageScroller "CreditsMenu" ImageItem "CREDITSTEXT2", 991 ImageItem "CREDITSTEXT3", 992 animatedtransition + class "Duke.ImageScrollerMenu" } ifgame(fury) { // Ion Fury does not have a separate credits menu, so if someone tries to open it anyway, use the same screens as "Help" but start on the one for the credits. ImageItem "F1HELP", 401 ImageItem "TEXTSTORY", 400 + class "Duke.ImageScrollerMenu" } ifgame(Redneck) {