[Scummvm-git-logs] scummvm master -> 3400b414ecd8613e41da26fd228e8601ff6214ec

dreammaster noreply at scummvm.org
Sun Feb 9 01:51:57 UTC 2025


This automated email contains information about 4 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
8df055c612 M4: RIDDLE: Shift MenuGlobals and related structures into M4::GUI
7463da8bac M4: RIDDLE: Move general menu methods to GUI
82ed622b9b M4: RIDDLE: More movement
3400b414ec M4: RIDDLE: Implemented room 850


Commit: 8df055c61213640ccad827216587d6c9e67ee6ce
    https://github.com/scummvm/scummvm/commit/8df055c61213640ccad827216587d6c9e67ee6ce
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2025-02-08T17:51:40-08:00

Commit Message:
M4: RIDDLE: Shift MenuGlobals and related structures into M4::GUI

Changed paths:
  A engines/m4/gui/gui_menu.cpp
  A engines/m4/gui/gui_menu.h
    engines/m4/burger/gui/game_menu.cpp
    engines/m4/burger/gui/game_menu.h
    engines/m4/burger/vars.h
    engines/m4/console.cpp
    engines/m4/module.mk
    engines/m4/vars.h


diff --git a/engines/m4/burger/gui/game_menu.cpp b/engines/m4/burger/gui/game_menu.cpp
index 185fdaff5a1..197b1556e87 100644
--- a/engines/m4/burger/gui/game_menu.cpp
+++ b/engines/m4/burger/gui/game_menu.cpp
@@ -45,7 +45,6 @@ namespace M4 {
 namespace Burger {
 namespace GUI {
 
-#define _GM(X) _G(menu).X
 #define LockMouseSprite mouse_lock_sprite
 #define UnlockMouseSprite mouse_unlock_sprite
 
diff --git a/engines/m4/burger/gui/game_menu.h b/engines/m4/burger/gui/game_menu.h
index 8e1ef57c8db..086a5cc625c 100644
--- a/engines/m4/burger/gui/game_menu.h
+++ b/engines/m4/burger/gui/game_menu.h
@@ -26,89 +26,18 @@
 #include "graphics/surface.h"
 #include "m4/m4_types.h"
 #include "m4/graphics/gr_buff.h"
+#include "m4/gui/gui_menu.h"
 #include "m4/gui/gui_univ.h"
 
 namespace M4 {
 namespace Burger {
 namespace GUI {
 
-typedef bool (*ItemHandlerFunction)(void *theItem, int32 eventType, int32 event, int32 x, int32 y, void **currItem);
-typedef void (*DrawFunction)(void *source, void *dest, int32 x1, int32 y1, int32 x2, int32 y2);
-typedef void (*DestroyFunction)(void *theItem);
-typedef M4CALLBACK CALLBACK;
-
-typedef M4sprite Sprite;
-//struct Sprite {};
-
-struct menuItem {
-	menuItem *next;
-	menuItem *prev;
-
-	void *myMenu;
-	int32 tag;
-
-	int32 x1, y1, x2, y2;
-
-	bool transparent;
-	GrBuff *background;
-
-	void *itemInfo;
-
-	CALLBACK callback;
-	DrawFunction redraw;
-	DestroyFunction destroy;
-	ItemHandlerFunction	itemEventHandler;
-};
-
-struct menuItemMsg {
-	int32 itemFlags;
-};
-
-struct menuItemButton {
-	int32 itemFlags;
-	int32 buttonType;
-	const char *prompt;
-	menuItem *assocItem;
-	int32 specialTag;
-};
-
-struct menuItemHSlider {
-	int32 itemFlags;
-
-	int32 thumbW, thumbH;
-	int32 thumbX, maxThumbX;
-
-	int32 percent;
-};
-
-struct menuItemVSlider {
-	int32 itemFlags;
-
-	int32 thumbW, thumbH;
-	int32 thumbY, minThumbY, maxThumbY;
-
-	int32 percent;
-};
-
-struct menuItemTextField {
-	int32 itemFlags;
-
-	int32 specialTag;
-	int32 pixWidth;
-
-	char prompt[80];
-	char *promptEnd;
-
-	char *cursor;
-};
-
-struct guiMenu {
-	GrBuff *menuBuffer;
-	menuItem *itemList;
-	CALLBACK cb_return;
-	CALLBACK cb_esc;
-	EventHandler menuEventHandler;
-};
+using M4::GUI::guiMenu;
+using M4::GUI::menuItem;
+using M4::GUI::Sprite;
+using M4::GUI::CALLBACK;
+using M4::GUI::ItemHandlerFunction;
 
 // GENERAL MENU FUNCTIONS
 bool menu_Initialize(RGB8 *myPalette);
@@ -461,59 +390,6 @@ enum error_menu_tags {
 #define EM_RETURN_H	  15
 
 
-struct MenuGlobals {
-	//GLOBAL VARS
-	bool menuSystemInitialized = false;
-	bool interfaceWasVisible = false;
-	RGB8 *menuPalette = nullptr;
-	bool dumpedCodes = false;
-	bool dumpedBackground = false;
-
-	menuItem *menuCurrItem = nullptr;
-
-	guiMenu *gameMenu = nullptr;
-	guiMenu *opMenu = nullptr;
-	guiMenu *slMenu = nullptr;
-	guiMenu *errMenu = nullptr;
-
-	//menu sprite series vars
-	char *menuSeriesResource = nullptr;
-	MemHandle menuSeriesHandle = nullptr;
-	int32 menuSeriesOffset = 0;
-	int32 menuSeriesPalOffset = 0;
-
-	Font *menuFont = nullptr;
-
-	// menu sprites array (used to hold all the sprites for the current menu, spriteCount is set tot he number of sprites in the series)
-	int32 spriteCount = 0;
-	Sprite **menuSprites = nullptr;
-
-	// VARS SPECIFIC TO THE GAME MENUS SYSTEM
-	// An array of slot titles used by the save/load menus
-	char **slotTitles = nullptr;
-	bool *slotInUse = nullptr;
-	int32 firstSlotIndex = 0;	// Slot at the top of the list on menu
-	int32 slotSelected = -1;	// Slot currently selected 
-	bool deleteSaveDesc = false;
-
-	Sprite **thumbNails = nullptr;
-	Sprite *saveLoadThumbNail = nullptr;	// Original used for menu display
-	Graphics::Surface _thumbnail;			// ScummVM version used for savegame
-	int32 sizeofThumbData = -1;
-	int32 thumbIndex = 0;
-
-	bool currMenuIsSave = true;			// Used to determine load or save menu
-	bool saveLoadFromHotkey = false;	// Come from hotkey, not through game menu
-	bool gameMenuFromMain = false;		// Come from main menu, not through escape
-
-	int32 remember_digi_volume = 0;		// For cancelling out of the options menu
-	int32 remember_digestability = 0;	// For cancelling out of the options menu
-
-	~MenuGlobals() {
-		_thumbnail.free();
-	}
-};
-
 void CreateGameMenuMain(RGB8 *myPalette);
 
 } // namespace GUI
diff --git a/engines/m4/burger/vars.h b/engines/m4/burger/vars.h
index 637d5a8880b..e318a5a2aa4 100644
--- a/engines/m4/burger/vars.h
+++ b/engines/m4/burger/vars.h
@@ -28,7 +28,6 @@
 #include "m4/burger/core/stream_break.h"
 #include "m4/burger/gui/gui.h"
 #include "m4/burger/gui/gui_gizmo.h"
-#include "m4/burger/gui/game_menu.h"
 #include "m4/burger/flags.h"
 #include "m4/burger/hotkeys.h"
 #include "m4/burger/inventory.h"
@@ -98,7 +97,6 @@ public:
 	GUI::Gizmo_Globals _gizmo;
 	GUI::Interface _interface;
 	Burger::Hotkeys _hotkeys;
-	GUI::MenuGlobals _menu;
 	SeriesPlayers _seriesPlayers;
 	ReleaseTrigger_Globals _releaseTrigger;
 	StreamBreak_Globals _streamBreak;
diff --git a/engines/m4/console.cpp b/engines/m4/console.cpp
index 268aa857fba..3bb2fc7af0c 100644
--- a/engines/m4/console.cpp
+++ b/engines/m4/console.cpp
@@ -26,7 +26,7 @@
 
 namespace M4 {
 
-Console::Console() : GUI::Debugger() {
+Console::Console() : ::GUI::Debugger() {
 	registerCmd("teleport",  WRAP_METHOD(Console, cmdTeleport));
 	registerCmd("item",      WRAP_METHOD(Console, cmdItem));
 	registerCmd("hyperwalk", WRAP_METHOD(Console, cmdHyperwalk));
diff --git a/engines/m4/gui/gui_menu.cpp b/engines/m4/gui/gui_menu.cpp
new file mode 100644
index 00000000000..4fdf244cd22
--- /dev/null
+++ b/engines/m4/gui/gui_menu.cpp
@@ -0,0 +1,47 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "graphics/thumbnail.h"
+#include "m4/gui/gui_menu.h"
+#include "m4/adv_r/other.h"
+#include "m4/adv_r/adv_background.h"
+#include "m4/adv_r/adv_control.h"
+#include "m4/adv_r/adv_player.h"
+#include "m4/core/errors.h"
+#include "m4/core/imath.h"
+#include "m4/gui/gui_event.h"
+#include "m4/gui/hotkeys.h"
+#include "m4/graphics/gr_line.h"
+#include "m4/graphics/gr_sprite.h"
+#include "m4/graphics/krn_pal.h"
+#include "m4/gui/gui_sys.h"
+#include "m4/gui/gui_vmng.h"
+#include "m4/mem/mem.h"
+#include "m4/platform/keys.h"
+#include "m4/vars.h"
+#include "m4/m4.h"
+
+namespace M4 {
+namespace GUI {
+
+
+} // namespace GUI
+} // namespace M4
diff --git a/engines/m4/gui/gui_menu.h b/engines/m4/gui/gui_menu.h
new file mode 100644
index 00000000000..123584496b6
--- /dev/null
+++ b/engines/m4/gui/gui_menu.h
@@ -0,0 +1,170 @@
+
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef M4_GUI_GUI_MENU_H
+#define M4_GUI_GUI_MENU_H
+
+#include "graphics/surface.h"
+#include "m4/m4_types.h"
+#include "m4/graphics/gr_buff.h"
+#include "m4/gui/gui_univ.h"
+
+namespace M4 {
+namespace GUI {
+
+#define _GM(X) _G(menu).X
+
+typedef bool (*ItemHandlerFunction)(void *theItem, int32 eventType, int32 event, int32 x, int32 y, void **currItem);
+typedef void (*DrawFunction)(void *source, void *dest, int32 x1, int32 y1, int32 x2, int32 y2);
+typedef void (*DestroyFunction)(void *theItem);
+typedef M4CALLBACK CALLBACK;
+
+typedef M4sprite Sprite;
+
+struct menuItem {
+	menuItem *next;
+	menuItem *prev;
+
+	void *myMenu;
+	int32 tag;
+
+	int32 x1, y1, x2, y2;
+
+	bool transparent;
+	GrBuff *background;
+
+	void *itemInfo;
+
+	CALLBACK callback;
+	DrawFunction redraw;
+	DestroyFunction destroy;
+	ItemHandlerFunction	itemEventHandler;
+};
+
+
+struct menuItemMsg {
+	int32 itemFlags;
+};
+
+struct menuItemButton {
+	int32 itemFlags;
+	int32 buttonType;
+	const char *prompt;
+	menuItem *assocItem;
+	int32 specialTag;
+};
+
+struct menuItemHSlider {
+	int32 itemFlags;
+
+	int32 thumbW, thumbH;
+	int32 thumbX, maxThumbX;
+
+	int32 percent;
+};
+
+struct menuItemVSlider {
+	int32 itemFlags;
+
+	int32 thumbW, thumbH;
+	int32 thumbY, minThumbY, maxThumbY;
+
+	int32 percent;
+};
+
+struct menuItemTextField {
+	int32 itemFlags;
+
+	int32 specialTag;
+	int32 pixWidth;
+
+	char prompt[80];
+	char *promptEnd;
+
+	char *cursor;
+};
+
+struct guiMenu {
+	GrBuff *menuBuffer;
+	menuItem *itemList;
+	CALLBACK cb_return;
+	CALLBACK cb_esc;
+	EventHandler menuEventHandler;
+};
+
+struct MenuGlobals {
+	//GLOBAL VARS
+	bool menuSystemInitialized = false;
+	bool interfaceWasVisible = false;
+	RGB8 *menuPalette = nullptr;
+	bool dumpedCodes = false;
+	bool dumpedBackground = false;
+
+	menuItem *menuCurrItem = nullptr;
+
+	guiMenu *gameMenu = nullptr;
+	guiMenu *opMenu = nullptr;
+	guiMenu *slMenu = nullptr;
+	guiMenu *errMenu = nullptr;
+
+	//menu sprite series vars
+	char *menuSeriesResource = nullptr;
+	MemHandle menuSeriesHandle = nullptr;
+	int32 menuSeriesOffset = 0;
+	int32 menuSeriesPalOffset = 0;
+
+	Font *menuFont = nullptr;
+
+	// menu sprites array (used to hold all the sprites for the current menu, spriteCount is set tot he number of sprites in the series)
+	int32 spriteCount = 0;
+	Sprite **menuSprites = nullptr;
+
+	// VARS SPECIFIC TO THE GAME MENUS SYSTEM
+	// An array of slot titles used by the save/load menus
+	char **slotTitles = nullptr;
+	bool *slotInUse = nullptr;
+	int32 firstSlotIndex = 0;	// Slot at the top of the list on menu
+	int32 slotSelected = -1;	// Slot currently selected 
+	bool deleteSaveDesc = false;
+
+	Sprite **thumbNails = nullptr;
+	Sprite *saveLoadThumbNail = nullptr;	// Original used for menu display
+	Graphics::Surface _thumbnail;			// ScummVM version used for savegame
+	int32 sizeofThumbData = -1;
+	int32 thumbIndex = 0;
+
+	bool currMenuIsSave = true;			// Used to determine load or save menu
+	bool saveLoadFromHotkey = false;	// Come from hotkey, not through game menu
+	bool gameMenuFromMain = false;		// Come from main menu, not through escape
+
+	int32 remember_digi_volume = 0;		// For cancelling out of the options menu
+	int32 remember_digestability = 0;	// For cancelling out of the options menu
+
+	~MenuGlobals() {
+		_thumbnail.free();
+	}
+};
+
+} // namespace GUI
+} // namespace M4
+
+#endif
diff --git a/engines/m4/module.mk b/engines/m4/module.mk
index d4557d0656b..463673b8678 100644
--- a/engines/m4/module.mk
+++ b/engines/m4/module.mk
@@ -52,6 +52,7 @@ MODULE_OBJS = \
 	gui/gui_cheapo.o \
 	gui/gui_dialog.o \
 	gui/gui_item.o \
+	gui/gui_menu.o \
 	gui/gui_mouse.o \
 	gui/gui_sys.o \
 	gui/gui_vmng_core.o \
diff --git a/engines/m4/vars.h b/engines/m4/vars.h
index 49cf7222898..30d9cde44de 100644
--- a/engines/m4/vars.h
+++ b/engines/m4/vars.h
@@ -47,6 +47,7 @@
 #include "m4/graphics/rend.h"
 #include "m4/gui/gui_dialog.h"
 #include "m4/gui/gui_item.h"
+#include "m4/gui/gui_menu.h"
 #include "m4/gui/gui_mouse.h"
 #include "m4/gui/gui_univ.h"
 #include "m4/gui/hotkeys.h"
@@ -116,6 +117,7 @@ public:
 	ADVScale_Globals _scale;
 	ConvDisplayData _cdd;
 	Rend_Globals _rend;
+	GUI::MenuGlobals _menu;
 
 	const bool _cheating_enabled = true;
 


Commit: 7463da8bacf1b9e803d26cc617d21d9acbc7c8f4
    https://github.com/scummvm/scummvm/commit/7463da8bacf1b9e803d26cc617d21d9acbc7c8f4
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2025-02-08T17:51:40-08:00

Commit Message:
M4: RIDDLE: Move general menu methods to GUI

Changed paths:
    engines/m4/burger/gui/game_menu.cpp
    engines/m4/burger/gui/game_menu.h
    engines/m4/burger/vars.h
    engines/m4/gui/gui_menu.cpp
    engines/m4/gui/gui_menu.h
    engines/m4/vars.h


diff --git a/engines/m4/burger/gui/game_menu.cpp b/engines/m4/burger/gui/game_menu.cpp
index 197b1556e87..54600b95f79 100644
--- a/engines/m4/burger/gui/game_menu.cpp
+++ b/engines/m4/burger/gui/game_menu.cpp
@@ -45,9 +45,6 @@ namespace M4 {
 namespace Burger {
 namespace GUI {
 
-#define LockMouseSprite mouse_lock_sprite
-#define UnlockMouseSprite mouse_unlock_sprite
-
 static bool buttonClosesDialog;
 
 void UpdateThumbNails(int32 firstSlot, guiMenu *myMenu);
@@ -2041,576 +2038,6 @@ void menu_UnloadSprites(void) {
 }
 
 
-bool menu_Initialize(RGB8 *myPalette) {
-	int32 i, memAvail;
-
-	// This procedure is called before *any* menu is created - the following global var is used
-	// By the menu_eventhandler() to trap events - it must be cleared.
-	_GM(menuCurrItem) = nullptr;
-
-	if (_G(menuSystemInitialized)) {
-		return true;
-	}
-
-	// Set this now to prevent re-entry into the menu system
-	_G(menuSystemInitialized) = true;
-
-	// Pause the game
-	game_pause(true);
-
-	// Hide the telegram window
-	// Hide_telegram_dialog(); // Ripley shit again!
-
-	// Hide the interface
-	if (INTERFACE_VISIBLE) {
-		_GM(interfaceWasVisible) = true;
-		interface_hide();
-	} else {
-		_GM(interfaceWasVisible) = false;
-	}
-
-	_GM(menuPalette) = myPalette;
-	krn_fade_to_grey(_GM(menuPalette), 5, 1);
-
-	_GM(dumpedCodes) = false;
-	_GM(dumpedBackground) = false;
-
-	// Make sure we have enough memory
-	PurgeMem();
-	CompactMem();
-	memAvail = mem_avail();
-
-	// Dump the screen codes if necessary
-	if (memAvail < MEMORY_NEEDED) {
-		adv_GetCodeMemory();
-		_GM(dumpedCodes) = true;
-		memAvail = mem_avail();
-	}
-
-	// Dump the background if necessary
-	if (memAvail < MEMORY_NEEDED) {
-		adv_GetBackgroundMemory();
-		_GM(dumpedBackground) = true;
-		memAvail = mem_avail();
-	}
-
-	// If we still don't have enough memory, we are hosed
-	if (memAvail < MEMORY_NEEDED) {
-		return false;
-	}
-
-	// Load in the font
-	_GM(menuFont) = gr_font_load("FONTMENU.FNT");
-
-	// Alloc space for the save/load tables
-	if ((_GM(slotTitles) = (char **)mem_alloc(sizeof(char *) * MAX_SLOTS, "slot desc array")) == nullptr) {
-		return false;
-	}
-	for (i = 0; i < MAX_SLOTS; i++) {
-		if ((_GM(slotTitles)[i] = (char *)mem_alloc(80, "slot title")) == nullptr) {
-			return false;
-		}
-	}
-	if ((_GM(slotInUse) = (bool *)mem_alloc(sizeof(bool) * MAX_SLOTS, "slotUnUse array")) == nullptr) {
-		return false;
-	}
-
-	// Allocate space for the thumnail sprites
-	if ((_GM(thumbNails) = (Sprite **)mem_alloc(sizeof(Sprite *) * MAX_SLOTS, "thumbNail array")) == nullptr) {
-		return false;
-	}
-	for (i = 0; i < MAX_SLOTS; i++) {
-		if ((_GM(thumbNails)[i] = (Sprite *)mem_alloc(sizeof(Sprite), "thumbNail")) == nullptr) {
-			return false;
-		}
-		_GM(thumbNails)[i]->sourceHandle = nullptr;
-	}
-
-	return true;
-}
-
-
-void menu_Shutdown(bool fadeToColor) {
-	int32 i;
-
-	// Verify that we need to shutdown
-	if (!_G(menuSystemInitialized)) {
-		return;
-	}
-
-	_GM(menuCurrItem) = nullptr;
-
-	// Turf the font
-	gr_font_dealloc(_GM(menuFont));
-	_GM(menuFont) = nullptr;
-
-	// Turf the slot arrays
-	for (i = 0; i < MAX_SLOTS; i++) {
-		if (_GM(slotTitles)[i]) {
-			mem_free((void *)_GM(slotTitles)[i]);
-		}
-	}
-	mem_free((void *)_GM(slotTitles));
-	mem_free((void *)_GM(slotInUse));
-
-	// Turf the thumbnail sprites
-	for (i = 0; i < MAX_SLOTS; i++) {
-		if (_GM(thumbNails)[i]) {
-			mem_free((void *)_GM(thumbNails)[i]);
-		}
-	}
-	mem_free((void *)_GM(thumbNails));
-
-	// Restore the background and codes if necessary
-	PurgeMem();
-	CompactMem();
-	if (_GM(dumpedBackground)) {
-		if (!adv_restoreBackground()) {
-			error_show(FL, 0, "unable to restore background");
-		}
-	}
-	if (_GM(dumpedCodes)) {
-		if (!adv_restoreCodes()) {
-			error_show(FL, 0, "unable to restore screen codes");
-		}
-	}
-
-	// Fade the screen - up to color if the game resumes, down to black if a new game was loaded
-	if (fadeToColor) {
-		krn_fade_from_grey(_GM(menuPalette), 5, 1, TO_COLOR);
-	} else {
-		krn_fade_from_grey(_GM(menuPalette), 5, 1, TO_BLACK);
-	}
-
-	// See if the interface needs to be restored
-	if (_GM(interfaceWasVisible)) {
-		interface_show();
-	}
-
-	// Allow the mouse to change from a clock
-	UnlockMouseSprite();
-
-	// Unpause the game
-	game_pause(false);
-
-	// Menu is now uninitialized
-	_G(menuSystemInitialized) = false;
-}
-
-
-bool menu_EventHandler(void *theMenu, int32 eventType, int32 parm1, int32 parm2, int32 parm3, bool *currScreen);
-
-
-GrBuff *menu_CopyBackground(guiMenu *myMenu, int32 x, int32 y, int32 w, int32 h) {
-	GrBuff *copyOfBackground;
-	Buffer *srcBuff, *destBuff;
-
-	// Verify params
-	if ((!myMenu) || (!myMenu->menuBuffer)) {
-		return nullptr;
-	}
-
-	// Create a new grbuff struct
-	copyOfBackground = new GrBuff(w, h);
-	if (!copyOfBackground) {
-		return nullptr;
-	}
-
-	// Get the source and destination buffers
-	srcBuff = myMenu->menuBuffer->get_buffer();
-	destBuff = copyOfBackground->get_buffer();
-	if ((!srcBuff) || (!destBuff)) {
-		delete copyOfBackground;
-
-		return nullptr;
-	}
-
-	// Copy the rect
-	gr_buffer_rect_copy_2(srcBuff, destBuff, x, y, 0, 0, w, h);
-
-	// Now release the buffers
-	myMenu->menuBuffer->release();
-	copyOfBackground->release();
-
-	return copyOfBackground;
-}
-
-
-void menu_Show(void *s, void *r, void *b, int32 destX, int32 destY) {
-	ScreenContext *myScreen = (ScreenContext *)s;
-	RectList *myRectList = (RectList *)r;
-	Buffer *destBuffer = (Buffer *)b;
-	guiMenu *myMenu;
-	GrBuff *myMenuBuffer;
-	Buffer *myBuffer;
-	RectList *myRect;
-
-	// Parameter verification
-	if (!myScreen) {
-		return;
-	}
-	myMenu = (guiMenu *)(myScreen->scrnContent);
-	if (!myMenu) {
-		return;
-	}
-	myMenuBuffer = myMenu->menuBuffer;
-	if (!myMenuBuffer) {
-		return;
-	}
-	myBuffer = myMenuBuffer->get_buffer();
-	if (!myBuffer) {
-		return;
-	}
-
-	// If no destBuffer, then draw directly to video
-	if (!destBuffer) {
-		myRect = myRectList;
-		while (myRect) {
-			vmng_refresh_video(myRect->x1, myRect->y1, myRect->x1 - myScreen->x1, myRect->y1 - myScreen->y1,
-				myRect->x2 - myScreen->x1, myRect->y2 - myScreen->y1, myBuffer);
-			myRect = myRect->next;
-		}
-	}
-
-	// Else draw to the dest buffer
-	else {
-		myRect = myRectList;
-		while (myRect) {
-			gr_buffer_rect_copy_2(myBuffer, destBuffer, myRect->x1 - myScreen->x1, myRect->y1 - myScreen->y1,
-				destX, destY, myRect->x2 - myRect->x1 + 1, myRect->y2 - myRect->y1 + 1);
-			myRect = myRect->next;
-		}
-	}
-
-	// Release myBuffer
-	myMenuBuffer->release();
-}
-
-
-guiMenu *menu_Create(Sprite *backgroundSprite, int32 x1, int32 y1, int32 scrnFlags) {
-	guiMenu *newMenu;
-	Buffer *tempBuff, drawSpriteBuff;
-	DrawRequest			spriteDrawReq;
-
-	// Verify params
-	if (!backgroundSprite) {
-		return nullptr;
-	}
-
-	if ((newMenu = (guiMenu *)mem_alloc(sizeof(guiMenu), "gui menu")) == nullptr) {
-		return nullptr;
-	}
-	newMenu->menuBuffer = new GrBuff(backgroundSprite->w, backgroundSprite->h);
-	newMenu->itemList = nullptr;
-	newMenu->cb_return = nullptr;
-	newMenu->cb_esc = nullptr;
-	newMenu->menuEventHandler = menu_EventHandler;
-
-	// Draw the background in to the menuBuffer
-	tempBuff = newMenu->menuBuffer->get_buffer();
-
-	// Copy background into menu-buffer because it is not rectangular (matte ink effect)
-	Buffer *matte = _G(gameDrawBuff)->get_buffer(); // get a pointer to the game background buffer
-	if (tempBuff->h > (_G(gameDrawBuff)->h - y1)) {  // if temp buffer is going to hang off the bottom of the game buffer
-		gr_buffer_rect_copy_2(matte, tempBuff, x1, y1, 0, 0, tempBuff->w, _G(gameDrawBuff)->h - y1);	// copy the differnce
-	} else {
-		gr_buffer_rect_copy_2(matte, tempBuff, x1, y1, 0, 0, tempBuff->w, tempBuff->h);			  // copy all of it
-	}
-	_G(gameDrawBuff)->release();	 // Release the buffer so it can be moved if nesessary
-
-	// draw the sprite
-	if (backgroundSprite->sourceHandle) {
-		HLock(backgroundSprite->sourceHandle);
-		backgroundSprite->data = (uint8 *)((intptr)*(backgroundSprite->sourceHandle) + backgroundSprite->sourceOffset);
-
-		drawSpriteBuff.w = backgroundSprite->w;
-		drawSpriteBuff.stride = backgroundSprite->w;
-		drawSpriteBuff.h = backgroundSprite->h;
-		drawSpriteBuff.encoding = (backgroundSprite->encoding) & (uint8)0x7f;
-		drawSpriteBuff.data = backgroundSprite->data;
-
-		spriteDrawReq.Src = &drawSpriteBuff;
-		spriteDrawReq.Dest = tempBuff;
-		spriteDrawReq.x = 0;
-		spriteDrawReq.y = 0;
-		spriteDrawReq.scaleX = 100;
-		spriteDrawReq.scaleY = 100;
-		spriteDrawReq.srcDepth = 0;
-		spriteDrawReq.depthCode = nullptr;
-		spriteDrawReq.Pal = nullptr;
-		spriteDrawReq.ICT = nullptr;
-
-		gr_sprite_draw(&spriteDrawReq);
-
-		// Unlock the handle
-		HUnLock(backgroundSprite->sourceHandle);
-	}
-	// Release the tempBuffer
-	newMenu->menuBuffer->release();
-
-	if (!vmng_screen_create(x1, y1, x1 + backgroundSprite->w - 1, y1 + backgroundSprite->h - 1, 69, scrnFlags, (void *)newMenu,
-		(RefreshFunc)menu_Show, menu_EventHandler)) {
-		return nullptr;
-	}
-
-	return newMenu;
-}
-
-
-void menu_Destroy(guiMenu *myMenu) {
-	menuItem *myItem;
-
-	// Verify params
-	if (!myMenu) {
-		return;
-	}
-
-	// Destroy the items
-	myItem = myMenu->itemList;
-	while (myItem) {
-		myMenu->itemList = myItem->next;
-		(myItem->destroy)((void *)myItem);
-		myItem = myMenu->itemList;
-	}
-
-	// Destroy the buffer
-	delete myMenu->menuBuffer;
-
-	// Destroy the menu
-	mem_free((void *)myMenu);
-}
-
-void menu_Configure(guiMenu *myMenu, CALLBACK cb_return, CALLBACK cb_esc) {
-	if (!myMenu) {
-		return;
-	}
-	myMenu->cb_return = cb_return;
-	myMenu->cb_esc = cb_esc;
-}
-
-bool menu_EventHandler(void *theMenu, int32 eventType, int32 parm1, int32 parm2, int32 parm3, bool *currScreen) {
-	ScreenContext *myScreen;
-	guiMenu *myMenu = (guiMenu *)theMenu;
-	menuItem *myItem;
-	int32 status, menuX, menuY;
-	bool handled;
-	static int32 movingX;
-	static int32 movingY;
-	static bool movingScreen = false;
-
-	// Initialize the vars
-	handled = false;
-	if (currScreen)
-		*currScreen = false;
-
-	// Make sure the screen exists and is active
-	myScreen = vmng_screen_find(theMenu, &status);
-	if ((!myScreen) || (status != SCRN_ACTIVE)) {
-		return false;
-	}
-
-	// If the escape key was pressed, it takes priority over items handling the event
-	if ((eventType == EVENT_KEY) && (parm1 == KEY_ESCAPE)) {
-		if (myMenu->cb_esc) {
-			_GM(menuCurrItem) = nullptr;
-			(myMenu->cb_esc)(nullptr, theMenu);
-			return true;
-		}
-	}
-
-	// If the return key was pressed, it takes priority over items handling the event
-	if ((eventType == EVENT_KEY) && (parm1 == KEY_RETURN)) {
-		if (myMenu->cb_return) {
-			_GM(menuCurrItem) = nullptr;
-			(myMenu->cb_return)(nullptr, theMenu);
-			return true;
-		}
-	}
-
-	// Convert the global coordinates to coords relative to the menu
-	menuX = parm2 - myScreen->x1;
-	menuY = parm3 - myScreen->y1;
-
-	// If we are currently handling the events for an item, continue until that item releases control
-	if (_GM(menuCurrItem)) {
-		handled = (_GM(menuCurrItem)->itemEventHandler)(_GM(menuCurrItem), eventType, parm1, menuX, menuY, (void **)&_GM(menuCurrItem));
-		if (_GM(menuCurrItem)) {
-			*currScreen = true;
-		}
-		if (handled) {
-			return true;
-		}
-	}
-
-	// See what kind of event we have
-	if (eventType == EVENT_MOUSE) {
-		// Scroll through the list of items until we find one that the cursor is on top of
-		myItem = myMenu->itemList;
-		while (myItem && (!((menuX >= myItem->x1) && (menuX <= myItem->x2) &&
-			(menuY >= myItem->y1) && (menuY <= myItem->y2)))) {
-			myItem = myItem->next;
-		}
-
-		// If an item is found, then if it has an event handler, handle the event and return true
-		if (myItem) {
-			if (myItem->itemEventHandler) {
-				(myItem->itemEventHandler)(myItem, eventType, parm1, menuX, menuY, (void **)&_GM(menuCurrItem));
-				if (_GM(menuCurrItem)) {
-					*currScreen = true;
-				}
-				return true;
-			}
-		}
-	}
-
-	else if (eventType == EVENT_KEY) {
-		// Else the event is a key event - loop through - see if anyone grabs it
-		myItem = myMenu->itemList;
-		while (myItem && (!handled)) {
-			if (myItem->itemEventHandler) {
-				handled = (myItem->itemEventHandler)(myItem, eventType, parm1, -1, -1, nullptr);
-			}
-			myItem = myItem->next;
-		}
-		return handled;
-	}
-
-	//otherwise the event is not handled by any of the menu items.  Let the menu screen itself handle the event
-
-	switch (parm1) {
-	case _ME_L_click:
-	case _ME_doubleclick:
-		if (!(myScreen->scrnFlags & SF_IMMOVABLE)) {
-			*currScreen = true;
-			movingScreen = true;
-			movingX = parm2;
-			movingY = parm3;
-		}
-		break;
-
-	case _ME_L_drag:
-	case _ME_doubleclick_drag:
-		if (movingScreen) {
-			MoveScreenDelta(myScreen, parm2 - movingX, parm3 - movingY);
-			movingX = parm2;
-			movingY = parm3;
-		}
-		break;
-
-	case _ME_L_release:
-	case _ME_doubleclick_release:
-		*currScreen = false;
-		movingScreen = false;
-		break;
-
-	case _ME_move:
-	case _ME_L_hold:
-	case _ME_doubleclick_hold:
-		break;
-	}
-	return true;
-}
-
-menuItem *menu_GetItem(int32 tag, guiMenu *myMenu) {
-	menuItem *myItem;
-
-	// Verify params
-	if (!myMenu) {
-		return nullptr;
-	}
-
-	myItem = myMenu->itemList;
-	while (myItem && (myItem->tag != tag)) {
-		myItem = myItem->next;
-	}
-
-	return myItem;
-}
-
-
-void menu_ItemDelete(menuItem *myItem, int32 tag, guiMenu *myMenu) {
-
-	Buffer *myBuff, *backgroundBuff;
-
-	// Verify params
-	if (!myMenu) {
-		return;
-	}
-
-	if (!myItem) {
-		myItem = menu_GetItem(tag, myMenu);
-	}
-	if (!myItem) {
-		return;
-	}
-
-	// Remove myItem from the item list
-	if (myItem->next) {
-		myItem->next->prev = myItem->prev;
-	}
-	if (myItem->prev) {
-		myItem->prev->next = myItem->next;
-	} else {
-		myMenu->itemList = myItem->next;
-	}
-
-	// If the item is marked transparent, we can remove it from the menu
-	if (myItem->transparent) {
-		if (!myItem->background) {
-			return;
-		}
-		backgroundBuff = myItem->background->get_buffer();
-		if (!backgroundBuff) {
-			return;
-		}
-
-		// Get the menu buffer and draw the sprite to it
-		myBuff = myMenu->menuBuffer->get_buffer();
-		if (!myBuff) {
-			return;
-		}
-
-		// Copy the clean piece of the background to the menu buffer
-		gr_buffer_rect_copy_2(backgroundBuff, myBuff, 0, 0, myItem->x1, myItem->y1, backgroundBuff->w, backgroundBuff->h);
-
-		// Release both buffers
-		myMenu->menuBuffer->release();
-		myItem->background->release();
-	}
-
-	// Destroy the item;
-	if (myItem->destroy) {
-		myItem->destroy((void *)myItem);
-	}
-}
-
-void menu_ItemRefresh(menuItem *myItem, int32 tag, guiMenu *myMenu) {
-	ScreenContext *myScreen;
-	int32 status;
-
-	// Verify params
-	if (!myMenu) {
-		return;
-	}
-
-	if (!myItem) {
-		myItem = menu_GetItem(tag, myMenu);
-	}
-	if (!myItem) {
-		return;
-	}
-
-	// Draw myItem
-	(myItem->redraw)(myItem, (void *)myItem->myMenu, myItem->x1, myItem->y1, 0, 0);
-
-	// Update the video
-	myScreen = vmng_screen_find((void *)myItem->myMenu, &status);
-	if (myScreen && (status == SCRN_ACTIVE)) {
-		RestoreScreens(myScreen->x1 + myItem->x1, myScreen->y1 + myItem->y1,
-			myScreen->x1 + myItem->x2, myScreen->y1 + myItem->y2);
-	}
-}
-
 //-------------------------------------   GAME MENU   -------------------------------------//
 
 void cb_Game_Quit(void *, void *) {
diff --git a/engines/m4/burger/gui/game_menu.h b/engines/m4/burger/gui/game_menu.h
index 086a5cc625c..91d11b3f974 100644
--- a/engines/m4/burger/gui/game_menu.h
+++ b/engines/m4/burger/gui/game_menu.h
@@ -39,16 +39,6 @@ using M4::GUI::Sprite;
 using M4::GUI::CALLBACK;
 using M4::GUI::ItemHandlerFunction;
 
-// GENERAL MENU FUNCTIONS
-bool menu_Initialize(RGB8 *myPalette);
-guiMenu *menu_Create(Sprite *backgroundSprite, int32 x1, int32 y1, int32 scrnFlags);
-void menu_Destroy(guiMenu *myMenu);
-void menu_Configure(guiMenu *myMenu, CALLBACK cb_return, CALLBACK cb_esc);
-GrBuff *menu_CopyBackground(guiMenu *myMenu, int32 x, int32 y, int32 w, int32 h);
-menuItem *menu_GetItem(int32 tag, guiMenu *myMenu);
-void menu_ItemDelete(menuItem *myItem, int32 tag, guiMenu *myMenu);
-void menu_ItemRefresh(menuItem *myItem, int32 tag, guiMenu *myMenu);
-
 // SPECIFIC ITEM FUNCTIONS
 
 // Messages
@@ -94,10 +84,6 @@ void CreateGameMenuFromMain(RGB8 *myPalette);
 //
 //		gamemenu module defines
 //
-#define MEMORY_NEEDED		0	// bytes needed for menus to work
-#define MENU_DEPTH 			9 	// video depth for menu popup boxes
-#define MAX_SLOTS				99	// number of save games you can have
-#define MAX_SLOTS_SHOWN 	8	// number of slots in the scrolling field
 
 // 128 very light green
 // 129 light green
diff --git a/engines/m4/burger/vars.h b/engines/m4/burger/vars.h
index e318a5a2aa4..45d6469bed5 100644
--- a/engines/m4/burger/vars.h
+++ b/engines/m4/burger/vars.h
@@ -103,7 +103,6 @@ public:
 	Burger::Walker _walker;
 
 	int _wilburTerm = 2;
-	bool _menuSystemInitialized = false;
 	bool _gameMenuFromMain = false;
 	int _room902Flag = 0;
 	int _roomVal3 = 0;
diff --git a/engines/m4/gui/gui_menu.cpp b/engines/m4/gui/gui_menu.cpp
index 4fdf244cd22..5baf14ff6c1 100644
--- a/engines/m4/gui/gui_menu.cpp
+++ b/engines/m4/gui/gui_menu.cpp
@@ -42,6 +42,568 @@
 namespace M4 {
 namespace GUI {
 
+bool menu_Initialize(RGB8 *myPalette) {
+	int32 i, memAvail;
+
+	// This procedure is called before *any* menu is created - the following global var is used
+	// By the menu_eventhandler() to trap events - it must be cleared.
+	_GM(menuCurrItem) = nullptr;
+
+	if (_G(menuSystemInitialized)) {
+		return true;
+	}
+
+	// Set this now to prevent re-entry into the menu system
+	_G(menuSystemInitialized) = true;
+
+	// Pause the game
+	game_pause(true);
+
+	// Hide the telegram window
+	// Hide_telegram_dialog(); // Ripley shit again!
+
+	// Hide the interface
+	if (INTERFACE_VISIBLE) {
+		_GM(interfaceWasVisible) = true;
+		interface_hide();
+	} else {
+		_GM(interfaceWasVisible) = false;
+	}
+
+	_GM(menuPalette) = myPalette;
+	krn_fade_to_grey(_GM(menuPalette), 5, 1);
+
+	_GM(dumpedCodes) = false;
+	_GM(dumpedBackground) = false;
+
+	// Make sure we have enough memory
+	PurgeMem();
+	CompactMem();
+	memAvail = mem_avail();
+
+	// Dump the screen codes if necessary
+	if (memAvail < MEMORY_NEEDED) {
+		adv_GetCodeMemory();
+		_GM(dumpedCodes) = true;
+		memAvail = mem_avail();
+	}
+
+	// Dump the background if necessary
+	if (memAvail < MEMORY_NEEDED) {
+		adv_GetBackgroundMemory();
+		_GM(dumpedBackground) = true;
+		memAvail = mem_avail();
+	}
+
+	// If we still don't have enough memory, we are hosed
+	if (memAvail < MEMORY_NEEDED) {
+		return false;
+	}
+
+	// Load in the font
+	_GM(menuFont) = gr_font_load("FONTMENU.FNT");
+
+	// Alloc space for the save/load tables
+	if ((_GM(slotTitles) = (char **)mem_alloc(sizeof(char *) * MAX_SLOTS, "slot desc array")) == nullptr) {
+		return false;
+	}
+	for (i = 0; i < MAX_SLOTS; i++) {
+		if ((_GM(slotTitles)[i] = (char *)mem_alloc(80, "slot title")) == nullptr) {
+			return false;
+		}
+	}
+	if ((_GM(slotInUse) = (bool *)mem_alloc(sizeof(bool) * MAX_SLOTS, "slotUnUse array")) == nullptr) {
+		return false;
+	}
+
+	// Allocate space for the thumnail sprites
+	if ((_GM(thumbNails) = (Sprite **)mem_alloc(sizeof(Sprite *) * MAX_SLOTS, "thumbNail array")) == nullptr) {
+		return false;
+	}
+	for (i = 0; i < MAX_SLOTS; i++) {
+		if ((_GM(thumbNails)[i] = (Sprite *)mem_alloc(sizeof(Sprite), "thumbNail")) == nullptr) {
+			return false;
+		}
+		_GM(thumbNails)[i]->sourceHandle = nullptr;
+	}
+
+	return true;
+}
+
+void menu_Shutdown(bool fadeToColor) {
+	int32 i;
+
+	// Verify that we need to shutdown
+	if (!_G(menuSystemInitialized)) {
+		return;
+	}
+
+	_GM(menuCurrItem) = nullptr;
+
+	// Turf the font
+	gr_font_dealloc(_GM(menuFont));
+	_GM(menuFont) = nullptr;
+
+	// Turf the slot arrays
+	for (i = 0; i < MAX_SLOTS; i++) {
+		if (_GM(slotTitles)[i]) {
+			mem_free((void *)_GM(slotTitles)[i]);
+		}
+	}
+	mem_free((void *)_GM(slotTitles));
+	mem_free((void *)_GM(slotInUse));
+
+	// Turf the thumbnail sprites
+	for (i = 0; i < MAX_SLOTS; i++) {
+		if (_GM(thumbNails)[i]) {
+			mem_free((void *)_GM(thumbNails)[i]);
+		}
+	}
+	mem_free((void *)_GM(thumbNails));
+
+	// Restore the background and codes if necessary
+	PurgeMem();
+	CompactMem();
+	if (_GM(dumpedBackground)) {
+		if (!adv_restoreBackground()) {
+			error_show(FL, 0, "unable to restore background");
+		}
+	}
+	if (_GM(dumpedCodes)) {
+		if (!adv_restoreCodes()) {
+			error_show(FL, 0, "unable to restore screen codes");
+		}
+	}
+
+	// Fade the screen - up to color if the game resumes, down to black if a new game was loaded
+	if (fadeToColor) {
+		krn_fade_from_grey(_GM(menuPalette), 5, 1, TO_COLOR);
+	} else {
+		krn_fade_from_grey(_GM(menuPalette), 5, 1, TO_BLACK);
+	}
+
+	// See if the interface needs to be restored
+	if (_GM(interfaceWasVisible)) {
+		interface_show();
+	}
+
+	// Allow the mouse to change from a clock
+	UnlockMouseSprite();
+
+	// Unpause the game
+	game_pause(false);
+
+	// Menu is now uninitialized
+	_G(menuSystemInitialized) = false;
+}
+
+bool menu_EventHandler(void *theMenu, int32 eventType, int32 parm1, int32 parm2, int32 parm3, bool *currScreen);
+
+GrBuff *menu_CopyBackground(guiMenu *myMenu, int32 x, int32 y, int32 w, int32 h) {
+	GrBuff *copyOfBackground;
+	Buffer *srcBuff, *destBuff;
+
+	// Verify params
+	if ((!myMenu) || (!myMenu->menuBuffer)) {
+		return nullptr;
+	}
+
+	// Create a new grbuff struct
+	copyOfBackground = new GrBuff(w, h);
+	if (!copyOfBackground) {
+		return nullptr;
+	}
+
+	// Get the source and destination buffers
+	srcBuff = myMenu->menuBuffer->get_buffer();
+	destBuff = copyOfBackground->get_buffer();
+	if ((!srcBuff) || (!destBuff)) {
+		delete copyOfBackground;
+
+		return nullptr;
+	}
+
+	// Copy the rect
+	gr_buffer_rect_copy_2(srcBuff, destBuff, x, y, 0, 0, w, h);
+
+	// Now release the buffers
+	myMenu->menuBuffer->release();
+	copyOfBackground->release();
+
+	return copyOfBackground;
+}
+
+void menu_Show(void *s, void *r, void *b, int32 destX, int32 destY) {
+	ScreenContext *myScreen = (ScreenContext *)s;
+	RectList *myRectList = (RectList *)r;
+	Buffer *destBuffer = (Buffer *)b;
+	guiMenu *myMenu;
+	GrBuff *myMenuBuffer;
+	Buffer *myBuffer;
+	RectList *myRect;
+
+	// Parameter verification
+	if (!myScreen) {
+		return;
+	}
+	myMenu = (guiMenu *)(myScreen->scrnContent);
+	if (!myMenu) {
+		return;
+	}
+	myMenuBuffer = myMenu->menuBuffer;
+	if (!myMenuBuffer) {
+		return;
+	}
+	myBuffer = myMenuBuffer->get_buffer();
+	if (!myBuffer) {
+		return;
+	}
+
+	// If no destBuffer, then draw directly to video
+	if (!destBuffer) {
+		myRect = myRectList;
+		while (myRect) {
+			vmng_refresh_video(myRect->x1, myRect->y1, myRect->x1 - myScreen->x1, myRect->y1 - myScreen->y1,
+				myRect->x2 - myScreen->x1, myRect->y2 - myScreen->y1, myBuffer);
+			myRect = myRect->next;
+		}
+	}
+
+	// Else draw to the dest buffer
+	else {
+		myRect = myRectList;
+		while (myRect) {
+			gr_buffer_rect_copy_2(myBuffer, destBuffer, myRect->x1 - myScreen->x1, myRect->y1 - myScreen->y1,
+				destX, destY, myRect->x2 - myRect->x1 + 1, myRect->y2 - myRect->y1 + 1);
+			myRect = myRect->next;
+		}
+	}
+
+	// Release myBuffer
+	myMenuBuffer->release();
+}
+
+guiMenu *menu_Create(Sprite *backgroundSprite, int32 x1, int32 y1, int32 scrnFlags) {
+	guiMenu *newMenu;
+	Buffer *tempBuff, drawSpriteBuff;
+	DrawRequest			spriteDrawReq;
+
+	// Verify params
+	if (!backgroundSprite) {
+		return nullptr;
+	}
+
+	if ((newMenu = (guiMenu *)mem_alloc(sizeof(guiMenu), "gui menu")) == nullptr) {
+		return nullptr;
+	}
+	newMenu->menuBuffer = new GrBuff(backgroundSprite->w, backgroundSprite->h);
+	newMenu->itemList = nullptr;
+	newMenu->cb_return = nullptr;
+	newMenu->cb_esc = nullptr;
+	newMenu->menuEventHandler = menu_EventHandler;
+
+	// Draw the background in to the menuBuffer
+	tempBuff = newMenu->menuBuffer->get_buffer();
+
+	// Copy background into menu-buffer because it is not rectangular (matte ink effect)
+	Buffer *matte = _G(gameDrawBuff)->get_buffer(); // get a pointer to the game background buffer
+	if (tempBuff->h > (_G(gameDrawBuff)->h - y1)) {  // if temp buffer is going to hang off the bottom of the game buffer
+		gr_buffer_rect_copy_2(matte, tempBuff, x1, y1, 0, 0, tempBuff->w, _G(gameDrawBuff)->h - y1);	// copy the differnce
+	} else {
+		gr_buffer_rect_copy_2(matte, tempBuff, x1, y1, 0, 0, tempBuff->w, tempBuff->h);			  // copy all of it
+	}
+	_G(gameDrawBuff)->release();	 // Release the buffer so it can be moved if nesessary
+
+	// draw the sprite
+	if (backgroundSprite->sourceHandle) {
+		HLock(backgroundSprite->sourceHandle);
+		backgroundSprite->data = (uint8 *)((intptr) * (backgroundSprite->sourceHandle) + backgroundSprite->sourceOffset);
+
+		drawSpriteBuff.w = backgroundSprite->w;
+		drawSpriteBuff.stride = backgroundSprite->w;
+		drawSpriteBuff.h = backgroundSprite->h;
+		drawSpriteBuff.encoding = (backgroundSprite->encoding) & (uint8)0x7f;
+		drawSpriteBuff.data = backgroundSprite->data;
+
+		spriteDrawReq.Src = &drawSpriteBuff;
+		spriteDrawReq.Dest = tempBuff;
+		spriteDrawReq.x = 0;
+		spriteDrawReq.y = 0;
+		spriteDrawReq.scaleX = 100;
+		spriteDrawReq.scaleY = 100;
+		spriteDrawReq.srcDepth = 0;
+		spriteDrawReq.depthCode = nullptr;
+		spriteDrawReq.Pal = nullptr;
+		spriteDrawReq.ICT = nullptr;
+
+		gr_sprite_draw(&spriteDrawReq);
+
+		// Unlock the handle
+		HUnLock(backgroundSprite->sourceHandle);
+	}
+	// Release the tempBuffer
+	newMenu->menuBuffer->release();
+
+	if (!vmng_screen_create(x1, y1, x1 + backgroundSprite->w - 1, y1 + backgroundSprite->h - 1, 69, scrnFlags, (void *)newMenu,
+		(RefreshFunc)menu_Show, menu_EventHandler)) {
+		return nullptr;
+	}
+
+	return newMenu;
+}
+
+void menu_Destroy(guiMenu *myMenu) {
+	menuItem *myItem;
+
+	// Verify params
+	if (!myMenu) {
+		return;
+	}
+
+	// Destroy the items
+	myItem = myMenu->itemList;
+	while (myItem) {
+		myMenu->itemList = myItem->next;
+		(myItem->destroy)((void *)myItem);
+		myItem = myMenu->itemList;
+	}
+
+	// Destroy the buffer
+	delete myMenu->menuBuffer;
+
+	// Destroy the menu
+	mem_free((void *)myMenu);
+}
+
+void menu_Configure(guiMenu *myMenu, CALLBACK cb_return, CALLBACK cb_esc) {
+	if (!myMenu) {
+		return;
+	}
+	myMenu->cb_return = cb_return;
+	myMenu->cb_esc = cb_esc;
+}
+
+bool menu_EventHandler(void *theMenu, int32 eventType, int32 parm1, int32 parm2, int32 parm3, bool *currScreen) {
+	ScreenContext *myScreen;
+	guiMenu *myMenu = (guiMenu *)theMenu;
+	menuItem *myItem;
+	int32 status, menuX, menuY;
+	bool handled;
+	static int32 movingX;
+	static int32 movingY;
+	static bool movingScreen = false;
+
+	// Initialize the vars
+	handled = false;
+	if (currScreen)
+		*currScreen = false;
+
+	// Make sure the screen exists and is active
+	myScreen = vmng_screen_find(theMenu, &status);
+	if ((!myScreen) || (status != SCRN_ACTIVE)) {
+		return false;
+	}
+
+	// If the escape key was pressed, it takes priority over items handling the event
+	if ((eventType == EVENT_KEY) && (parm1 == KEY_ESCAPE)) {
+		if (myMenu->cb_esc) {
+			_GM(menuCurrItem) = nullptr;
+			(myMenu->cb_esc)(nullptr, theMenu);
+			return true;
+		}
+	}
+
+	// If the return key was pressed, it takes priority over items handling the event
+	if ((eventType == EVENT_KEY) && (parm1 == KEY_RETURN)) {
+		if (myMenu->cb_return) {
+			_GM(menuCurrItem) = nullptr;
+			(myMenu->cb_return)(nullptr, theMenu);
+			return true;
+		}
+	}
+
+	// Convert the global coordinates to coords relative to the menu
+	menuX = parm2 - myScreen->x1;
+	menuY = parm3 - myScreen->y1;
+
+	// If we are currently handling the events for an item, continue until that item releases control
+	if (_GM(menuCurrItem)) {
+		handled = (_GM(menuCurrItem)->itemEventHandler)(_GM(menuCurrItem), eventType, parm1, menuX, menuY, (void **)&_GM(menuCurrItem));
+		if (_GM(menuCurrItem)) {
+			*currScreen = true;
+		}
+		if (handled) {
+			return true;
+		}
+	}
+
+	// See what kind of event we have
+	if (eventType == EVENT_MOUSE) {
+		// Scroll through the list of items until we find one that the cursor is on top of
+		myItem = myMenu->itemList;
+		while (myItem && (!((menuX >= myItem->x1) && (menuX <= myItem->x2) &&
+			(menuY >= myItem->y1) && (menuY <= myItem->y2)))) {
+			myItem = myItem->next;
+		}
+
+		// If an item is found, then if it has an event handler, handle the event and return true
+		if (myItem) {
+			if (myItem->itemEventHandler) {
+				(myItem->itemEventHandler)(myItem, eventType, parm1, menuX, menuY, (void **)&_GM(menuCurrItem));
+				if (_GM(menuCurrItem)) {
+					*currScreen = true;
+				}
+				return true;
+			}
+		}
+	}
+
+	else if (eventType == EVENT_KEY) {
+		// Else the event is a key event - loop through - see if anyone grabs it
+		myItem = myMenu->itemList;
+		while (myItem && (!handled)) {
+			if (myItem->itemEventHandler) {
+				handled = (myItem->itemEventHandler)(myItem, eventType, parm1, -1, -1, nullptr);
+			}
+			myItem = myItem->next;
+		}
+		return handled;
+	}
+
+	// Otherwise the event is not handled by any of the menu items.  Let the menu screen itself handle the event
+
+	switch (parm1) {
+	case _ME_L_click:
+	case _ME_doubleclick:
+		if (!(myScreen->scrnFlags & SF_IMMOVABLE)) {
+			*currScreen = true;
+			movingScreen = true;
+			movingX = parm2;
+			movingY = parm3;
+		}
+		break;
+
+	case _ME_L_drag:
+	case _ME_doubleclick_drag:
+		if (movingScreen) {
+			MoveScreenDelta(myScreen, parm2 - movingX, parm3 - movingY);
+			movingX = parm2;
+			movingY = parm3;
+		}
+		break;
+
+	case _ME_L_release:
+	case _ME_doubleclick_release:
+		*currScreen = false;
+		movingScreen = false;
+		break;
+
+	case _ME_move:
+	case _ME_L_hold:
+	case _ME_doubleclick_hold:
+		break;
+	}
+	return true;
+}
+
+menuItem *menu_GetItem(int32 tag, guiMenu *myMenu) {
+	menuItem *myItem;
+
+	// Verify params
+	if (!myMenu) {
+		return nullptr;
+	}
+
+	myItem = myMenu->itemList;
+	while (myItem && (myItem->tag != tag)) {
+		myItem = myItem->next;
+	}
+
+	return myItem;
+}
+
+
+void menu_ItemDelete(menuItem *myItem, int32 tag, guiMenu *myMenu) {
+	Buffer *myBuff, *backgroundBuff;
+
+	// Verify params
+	if (!myMenu) {
+		return;
+	}
+
+	if (!myItem) {
+		myItem = menu_GetItem(tag, myMenu);
+	}
+	if (!myItem) {
+		return;
+	}
+
+	// Remove myItem from the item list
+	if (myItem->next) {
+		myItem->next->prev = myItem->prev;
+	}
+	if (myItem->prev) {
+		myItem->prev->next = myItem->next;
+	} else {
+		myMenu->itemList = myItem->next;
+	}
+
+	// If the item is marked transparent, we can remove it from the menu
+	if (myItem->transparent) {
+		if (!myItem->background) {
+			return;
+		}
+		backgroundBuff = myItem->background->get_buffer();
+		if (!backgroundBuff) {
+			return;
+		}
+
+		// Get the menu buffer and draw the sprite to it
+		myBuff = myMenu->menuBuffer->get_buffer();
+		if (!myBuff) {
+			return;
+		}
+
+		// Copy the clean piece of the background to the menu buffer
+		gr_buffer_rect_copy_2(backgroundBuff, myBuff, 0, 0, myItem->x1, myItem->y1, backgroundBuff->w, backgroundBuff->h);
+
+		// Release both buffers
+		myMenu->menuBuffer->release();
+		myItem->background->release();
+	}
+
+	// Destroy the item;
+	if (myItem->destroy) {
+		myItem->destroy((void *)myItem);
+	}
+}
+
+void menu_ItemRefresh(menuItem *myItem, int32 tag, guiMenu *myMenu) {
+	ScreenContext *myScreen;
+	int32 status;
+
+	// Verify params
+	if (!myMenu) {
+		return;
+	}
+
+	if (!myItem) {
+		myItem = menu_GetItem(tag, myMenu);
+	}
+	if (!myItem) {
+		return;
+	}
+
+	// Draw myItem
+	(myItem->redraw)(myItem, (void *)myItem->myMenu, myItem->x1, myItem->y1, 0, 0);
+
+	// Update the video
+	myScreen = vmng_screen_find((void *)myItem->myMenu, &status);
+	if (myScreen && (status == SCRN_ACTIVE)) {
+		RestoreScreens(myScreen->x1 + myItem->x1, myScreen->y1 + myItem->y1,
+			myScreen->x1 + myItem->x2, myScreen->y1 + myItem->y2);
+	}
+}
 
 } // namespace GUI
 } // namespace M4
diff --git a/engines/m4/gui/gui_menu.h b/engines/m4/gui/gui_menu.h
index 123584496b6..a05014eb594 100644
--- a/engines/m4/gui/gui_menu.h
+++ b/engines/m4/gui/gui_menu.h
@@ -32,6 +32,8 @@ namespace M4 {
 namespace GUI {
 
 #define _GM(X) _G(menu).X
+#define LockMouseSprite mouse_lock_sprite
+#define UnlockMouseSprite mouse_unlock_sprite
 
 typedef bool (*ItemHandlerFunction)(void *theItem, int32 eventType, int32 event, int32 x, int32 y, void **currItem);
 typedef void (*DrawFunction)(void *source, void *dest, int32 x1, int32 y1, int32 x2, int32 y2);
@@ -164,6 +166,26 @@ struct MenuGlobals {
 	}
 };
 
+//======================================
+//
+//		gamemenu module defines
+//
+#define MEMORY_NEEDED		0	// bytes needed for menus to work
+#define MENU_DEPTH 			9 	// video depth for menu popup boxes
+#define MAX_SLOTS			99	// number of save games you can have
+#define MAX_SLOTS_SHOWN 	8	// number of slots in the scrolling field
+
+// GENERAL MENU FUNCTIONS
+extern bool menu_Initialize(RGB8 *myPalette);
+extern void menu_Shutdown(bool fadeToColor);
+extern guiMenu *menu_Create(Sprite *backgroundSprite, int32 x1, int32 y1, int32 scrnFlags);
+extern void menu_Destroy(guiMenu *myMenu);
+extern void menu_Configure(guiMenu *myMenu, CALLBACK cb_return, CALLBACK cb_esc);
+extern GrBuff *menu_CopyBackground(guiMenu *myMenu, int32 x, int32 y, int32 w, int32 h);
+extern menuItem *menu_GetItem(int32 tag, guiMenu *myMenu);
+extern void menu_ItemDelete(menuItem *myItem, int32 tag, guiMenu *myMenu);
+extern void menu_ItemRefresh(menuItem *myItem, int32 tag, guiMenu *myMenu);
+
 } // namespace GUI
 } // namespace M4
 
diff --git a/engines/m4/vars.h b/engines/m4/vars.h
index 30d9cde44de..16d682969f2 100644
--- a/engines/m4/vars.h
+++ b/engines/m4/vars.h
@@ -118,6 +118,7 @@ public:
 	ConvDisplayData _cdd;
 	Rend_Globals _rend;
 	GUI::MenuGlobals _menu;
+	bool _menuSystemInitialized = false;
 
 	const bool _cheating_enabled = true;
 


Commit: 82ed622b9b84fe815da8d95612cdfcbd19cf2750
    https://github.com/scummvm/scummvm/commit/82ed622b9b84fe815da8d95612cdfcbd19cf2750
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2025-02-08T17:51:40-08:00

Commit Message:
M4: RIDDLE: More movement

Changed paths:
    engines/m4/burger/gui/game_menu.cpp
    engines/m4/burger/gui/game_menu.h
    engines/m4/gui/gui_menu.cpp
    engines/m4/gui/gui_menu.h
    engines/m4/m4.h
    engines/m4/riddle/gui/game_menu.cpp
    engines/m4/riddle/gui/game_menu.h


diff --git a/engines/m4/burger/gui/game_menu.cpp b/engines/m4/burger/gui/game_menu.cpp
index 54600b95f79..8c782770187 100644
--- a/engines/m4/burger/gui/game_menu.cpp
+++ b/engines/m4/burger/gui/game_menu.cpp
@@ -1976,70 +1976,11 @@ menuItem *menu_TextFieldAdd(guiMenu *myMenu, int32 tag, int32 x, int32 y, int32
 	return newItem;
 }
 
-//-----------------------------    GAME MENU FUNCTIONS    ---------------------------------//
-
-void DestroyGameMenu();
-
-bool menu_LoadSprites(const char *series, int32 numSprites) {
-	int32 i;
-
-	// Load in the game menu series
-	if (LoadSpriteSeries(series, &_GM(menuSeriesHandle), &_GM(menuSeriesOffset),
-		&_GM(menuSeriesPalOffset), _GM(menuPalette)) <= 0) {
-		return false;
-	}
-	_GM(menuSeriesResource) = mem_strdup(series);
-
-	// Update the palette for the menu
-	gr_pal_set_range(_GM(menuPalette), 59, 197);  // Rid
-
-	_GM(spriteCount) = numSprites;
-
-	// Create the _GM(menuSprites) array
-	if ((_GM(menuSprites) = (Sprite **)mem_alloc(sizeof(Sprite *) * _GM(spriteCount), "sprites array")) == nullptr) {
-		return false;
-	}
-
-	// Create the menu sprites
-	for (i = 0; i < _GM(spriteCount); i++) {
-		if ((_GM(menuSprites)[i] = CreateSprite(_GM(menuSeriesHandle), _GM(menuSeriesOffset), i, nullptr, nullptr)) == nullptr) {
-			return false;
-		}
-	}
-
-	return true;
-}
-
-
-void menu_UnloadSprites(void) {
-	int32 i;
-
-	if (!_GM(menuSeriesResource)) {
-		return;
-	}
-
-	// Unload the sprites from memory
-	rtoss(_GM(menuSeriesResource));
-	mem_free(_GM(menuSeriesResource));
-	_GM(menuSeriesResource) = nullptr;
-	_GM(menuSeriesHandle) = nullptr;
-	_GM(menuSeriesOffset) = -1;
-	_GM(menuSeriesPalOffset) = -1;
-
-	// Turf the sprites
-	for (i = 0; i < _GM(spriteCount); i++) {
-		mem_free((void *)_GM(menuSprites)[i]);
-	}
-
-	// Turf the sprites array
-	mem_free((void *)_GM(menuSprites));
-	_GM(menuSprites) = nullptr;
-	_GM(spriteCount) = 0;
-}
-
 
 //-------------------------------------   GAME MENU   -------------------------------------//
 
+static void DestroyGameMenu();
+
 void cb_Game_Quit(void *, void *) {
 	// Destroy the game menu
 	DestroyGameMenu();
diff --git a/engines/m4/burger/gui/game_menu.h b/engines/m4/burger/gui/game_menu.h
index 91d11b3f974..5b36c0befda 100644
--- a/engines/m4/burger/gui/game_menu.h
+++ b/engines/m4/burger/gui/game_menu.h
@@ -125,17 +125,6 @@ void CreateGameMenuFromMain(RGB8 *myPalette);
 #define GAME_MENU_W		260
 #define GAME_MENU_H		198
 
-enum game_menu_sprites {
-	GM_DIALOG_BOX,
-
-	GM_BUTTON_GREY,
-	GM_BUTTON_NORM,
-	GM_BUTTON_OVER,
-	GM_BUTTON_PRESS,
-
-	GM_TOTAL_SPRITES
-};
-
 enum game_menu_button_tags {
 	GM_TAG_QUIT = 1,
 	GM_TAG_OPTIONS = 2,
diff --git a/engines/m4/gui/gui_menu.cpp b/engines/m4/gui/gui_menu.cpp
index 5baf14ff6c1..849b4e6a2ad 100644
--- a/engines/m4/gui/gui_menu.cpp
+++ b/engines/m4/gui/gui_menu.cpp
@@ -605,5 +605,67 @@ void menu_ItemRefresh(menuItem *myItem, int32 tag, guiMenu *myMenu) {
 	}
 }
 
+
+//-----------------------------    GAME MENU FUNCTIONS    ---------------------------------//
+
+bool menu_LoadSprites(const char *series, int32 numSprites) {
+	int32 i;
+
+	// Load in the game menu series
+	if (LoadSpriteSeries(series, &_GM(menuSeriesHandle), &_GM(menuSeriesOffset),
+		&_GM(menuSeriesPalOffset), _GM(menuPalette)) <= 0) {
+		return false;
+	}
+	_GM(menuSeriesResource) = mem_strdup(series);
+
+	// Update the palette for the menu
+	if (IS_BURGER)
+		gr_pal_set_range(_GM(menuPalette), 59, 197);
+	else
+		gr_pal_set_range(_GM(menuPalette), 128, 128);
+
+	_GM(spriteCount) = numSprites;
+
+	// Create the _GM(menuSprites) array
+	if ((_GM(menuSprites) = (Sprite **)mem_alloc(sizeof(Sprite *) * _GM(spriteCount), "sprites array")) == nullptr) {
+		return false;
+	}
+
+	// Create the menu sprites
+	for (i = 0; i < _GM(spriteCount); i++) {
+		if ((_GM(menuSprites)[i] = CreateSprite(_GM(menuSeriesHandle), _GM(menuSeriesOffset), i, nullptr, nullptr)) == nullptr) {
+			return false;
+		}
+	}
+
+	return true;
+}
+
+void menu_UnloadSprites() {
+	int32 i;
+
+	if (!_GM(menuSeriesResource)) {
+		return;
+	}
+
+	// Unload the sprites from memory
+	rtoss(_GM(menuSeriesResource));
+	mem_free(_GM(menuSeriesResource));
+	_GM(menuSeriesResource) = nullptr;
+	_GM(menuSeriesHandle) = nullptr;
+	_GM(menuSeriesOffset) = -1;
+	_GM(menuSeriesPalOffset) = -1;
+
+	// Turf the sprites
+	for (i = 0; i < _GM(spriteCount); i++) {
+		mem_free((void *)_GM(menuSprites)[i]);
+	}
+
+	// Turf the sprites array
+	mem_free((void *)_GM(menuSprites));
+	_GM(menuSprites) = nullptr;
+	_GM(spriteCount) = 0;
+}
+
 } // namespace GUI
 } // namespace M4
diff --git a/engines/m4/gui/gui_menu.h b/engines/m4/gui/gui_menu.h
index a05014eb594..261d22a74dc 100644
--- a/engines/m4/gui/gui_menu.h
+++ b/engines/m4/gui/gui_menu.h
@@ -42,6 +42,18 @@ typedef M4CALLBACK CALLBACK;
 
 typedef M4sprite Sprite;
 
+enum game_menu_sprites {
+	GM_DIALOG_BOX,
+
+	GM_BUTTON_GREY,
+	GM_BUTTON_NORM,
+	GM_BUTTON_OVER,
+	GM_BUTTON_PRESS,
+
+	GM_TOTAL_SPRITES
+};
+
+
 struct menuItem {
 	menuItem *next;
 	menuItem *prev;
@@ -186,6 +198,9 @@ extern menuItem *menu_GetItem(int32 tag, guiMenu *myMenu);
 extern void menu_ItemDelete(menuItem *myItem, int32 tag, guiMenu *myMenu);
 extern void menu_ItemRefresh(menuItem *myItem, int32 tag, guiMenu *myMenu);
 
+extern bool menu_LoadSprites(const char *series, int32 numSprites);
+extern void menu_UnloadSprites();
+
 } // namespace GUI
 } // namespace M4
 
diff --git a/engines/m4/m4.h b/engines/m4/m4.h
index c33df99e0be..807fda94b1b 100644
--- a/engines/m4/m4.h
+++ b/engines/m4/m4.h
@@ -182,6 +182,8 @@ public:
 
 extern M4Engine *g_engine;
 #define SHOULD_QUIT ::M4::g_engine->shouldQuit()
+#define IS_BURGER g_engine->getGameType() == GType_Burger
+#define IS_RIDDLE g_engine->getGameType() == GType_Riddle
 
 } // End of namespace M4
 
diff --git a/engines/m4/riddle/gui/game_menu.cpp b/engines/m4/riddle/gui/game_menu.cpp
index 0783d5c7339..40bdfe7080e 100644
--- a/engines/m4/riddle/gui/game_menu.cpp
+++ b/engines/m4/riddle/gui/game_menu.cpp
@@ -43,13 +43,60 @@ namespace M4 {
 namespace Riddle {
 namespace GUI {
 
+static void CreateGameMenuMain(RGB8 *myPalette);
+
 void CreateGameMenu(RGB8 *myPalette) {
 	if ((!player_commands_allowed()) || (!INTERFACE_VISIBLE) ||
 		_G(pal_fade_in_progress) || _G(menuSystemInitialized)) {
 		return;
 	}
 
-	warning("TODO: Create game menu");
+	CreateGameMenuMain(myPalette);
+}
+
+void CreateGameMenuMain(RGB8 *myPalette) {
+	if (!_G(menuSystemInitialized)) {
+		menu_Initialize(myPalette);
+	}
+
+	// Keep the memory tidy
+	PurgeMem();
+	CompactMem();
+
+	// Load in the game menu sprites
+	if (!menu_LoadSprites("gamemenu", GM_TOTAL_SPRITES)) {
+		return;
+	}
+
+	_GM(gameMenu) = menu_Create(_GM(menuSprites)[GM_DIALOG_BOX], GAME_MENU_X, GAME_MENU_Y, MENU_DEPTH | SF_GET_ALL | SF_BLOCK_ALL | SF_IMMOVABLE);
+	if (!_GM(gameMenu)) {
+		return;
+	}
+#if 0
+	menu_ButtonAdd(_GM(gameMenu), GM_TAG_MAIN, GM_MAIN_X, GM_MAIN_Y, GM_MAIN_W, GM_MAIN_H, cb_Game_Main);
+	menu_ButtonAdd(_GM(gameMenu), GM_TAG_OPTIONS, GM_OPTIONS_X, GM_OPTIONS_Y, GM_OPTIONS_W, GM_OPTIONS_H, cb_Game_Options);
+	menu_ButtonAdd(_GM(gameMenu), GM_TAG_RESUME, GM_RESUME_X, GM_RESUME_Y, GM_RESUME_W, GM_RESUME_H, cb_Game_Resume);
+	menu_ButtonAdd(_GM(gameMenu), GM_TAG_QUIT, GM_QUIT_X, GM_QUIT_Y, GM_QUIT_W, GM_QUIT_H, cb_Game_Quit);
+
+	if (!_GM(gameMenuFromMain)) {
+		menu_ButtonAdd(_GM(gameMenu), GM_TAG_SAVE, GM_SAVE_X, GM_SAVE_Y, GM_SAVE_W, GM_SAVE_H, cb_Game_Save);
+	} else {
+		menu_ButtonAdd(_GM(gameMenu), GM_TAG_SAVE, GM_SAVE_X, GM_SAVE_Y, GM_SAVE_W, GM_SAVE_H, cb_Game_Save, BTN_TYPE_GM_GENERIC, true);
+	}
+
+	// See if there are any games to load
+	if (g_engine->savesExist()) {
+		menu_ButtonAdd(_GM(gameMenu), GM_TAG_LOAD, GM_LOAD_X, GM_LOAD_Y, GM_LOAD_W, GM_LOAD_H, cb_Game_Load);
+	} else {
+		menu_ButtonAdd(_GM(gameMenu), GM_TAG_LOAD, GM_LOAD_X, GM_LOAD_Y, GM_LOAD_W, GM_LOAD_H, cb_Game_Load, BTN_TYPE_GM_GENERIC, true);
+	}
+
+	// Configure the game so pressing <esc> will cause the menu to disappear and the game to resume
+	menu_Configure(_GM(gameMenu), cb_Game_Resume, cb_Game_Resume);
+
+	vmng_screen_show((void *)_GM(gameMenu));
+	LockMouseSprite(0);
+#endif
 }
 
 } // namespace GUI
diff --git a/engines/m4/riddle/gui/game_menu.h b/engines/m4/riddle/gui/game_menu.h
index 663c2596fd2..7b26136cbea 100644
--- a/engines/m4/riddle/gui/game_menu.h
+++ b/engines/m4/riddle/gui/game_menu.h
@@ -29,6 +29,9 @@ namespace M4 {
 namespace Riddle {
 namespace GUI {
 
+#define GAME_MENU_X 190
+#define GAME_MENU_Y 100
+
 extern void CreateGameMenu(RGB8 *myPalette);
 
 } // namespace GUI


Commit: 3400b414ecd8613e41da26fd228e8601ff6214ec
    https://github.com/scummvm/scummvm/commit/3400b414ecd8613e41da26fd228e8601ff6214ec
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2025-02-08T17:51:40-08:00

Commit Message:
M4: RIDDLE: Implemented room 850

Changed paths:
    engines/m4/riddle/rooms/section8/room850.cpp
    engines/m4/riddle/rooms/section8/room850.h


diff --git a/engines/m4/riddle/rooms/section8/room850.cpp b/engines/m4/riddle/rooms/section8/room850.cpp
index de67b04c4ce..1505194b374 100644
--- a/engines/m4/riddle/rooms/section8/room850.cpp
+++ b/engines/m4/riddle/rooms/section8/room850.cpp
@@ -27,10 +27,86 @@ namespace M4 {
 namespace Riddle {
 namespace Rooms {
 
+void Room850::preload() {
+	Room::preload();
+	_G(player).walker_in_this_scene = false;
+}
+
 void Room850::init() {
+	player_set_commands_allowed(false);
+
+	static const char *const PRELOADS[8] = {
+		"850_s01", "850_s02", "850_s03", "850_s04", "850_s05",
+		"850_s06", "603_s02c", "801_s02"
+	};
+	for (int i = 0; i < 8; ++i)
+		digi_preload(PRELOADS[i]);
+
+	_allStuff = series_load("850 ALL STUFF");
+	digi_play_loop("603_s02c", 2, 100, -1, 603);
+	_allStuffMach = TriggerMachineByHash(1, 1, 0, 0, 0, 0, 0, 0, 100, 0x100, false,
+		triggerMachineByHashCallback, "850 all");
+	sendWSMessage_10000(1, _allStuffMach, _allStuff, 1, 1, 1, _allStuff, 1, 15, 4);
 }
 
 void Room850::daemon() {
+	switch (_G(kernel).trigger) {
+	case 1:
+		kernel_timing_trigger(110, 10);
+		break;
+
+	case 10:
+		digi_play("850_s01", 1);
+		kernel_timing_trigger(360, 15);
+		break;
+
+	case 15:
+		digi_stop(2);
+		digi_play("850_s03", 2, 255, 20);
+		break;
+
+	case 20:
+		sendWSMessage_10000(1, _allStuffMach, _allStuff, 16, 20, 25, _allStuff, 20, 20, 0);
+		digi_play("850_s07", 3);
+		break;
+
+	case 25:
+		sendWSMessage_10000(1, _allStuffMach, _allStuff, 20, 29, 30, _allStuff, 29, 29, 0);
+		digi_play("850_s05", 2);
+		break;
+
+	case 30:
+		digi_play("850_s05", 2, 255, 40);
+		break;
+
+	case 40:
+		digi_play("850_s02", 1);
+		kernel_timing_trigger(60, 50);
+		break;
+
+	case 50:
+		digi_play("850r01", 2, 255, 60);
+		break;
+
+	case 60:
+		digi_play_loop("801_s02", 3, 100);
+		kernel_timing_trigger(15, 100);
+		break;
+
+
+	case 100:
+		player_set_commands_allowed(false);
+		disable_player_commands_and_fade_init(110);
+		break;
+
+	case 110:
+		adv_kill_digi_between_rooms(false);
+		_G(game).setRoom(801);
+		break;
+
+	default:
+		break;
+	}
 }
 
 } // namespace Rooms
diff --git a/engines/m4/riddle/rooms/section8/room850.h b/engines/m4/riddle/rooms/section8/room850.h
index 0ac509995d3..c4cd39e98ad 100644
--- a/engines/m4/riddle/rooms/section8/room850.h
+++ b/engines/m4/riddle/rooms/section8/room850.h
@@ -29,10 +29,15 @@ namespace Riddle {
 namespace Rooms {
 
 class Room850 : public Room {
+private:
+	int _allStuff = 0;
+	machine *_allStuffMach = nullptr;
+
 public:
 	Room850() : Room() {}
 	~Room850() override {}
 
+	void preload() override;
 	void init() override;
 	void daemon() override;
 };




More information about the Scummvm-git-logs mailing list