[Scummvm-git-logs] scummvm master -> db7fca93b744d21782a6f6163983efda03a524f2

bluegr noreply at scummvm.org
Mon Mar 9 20:06:11 UTC 2026


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

Summary:
db7fca93b7 SCUMM: MI1 SEGA CD - Add the option to use the original 'wait' cursor on the pause menu


Commit: db7fca93b744d21782a6f6163983efda03a524f2
    https://github.com/scummvm/scummvm/commit/db7fca93b744d21782a6f6163983efda03a524f2
Author: Robert Megone (robert.megone at gmail.com)
Date: 2026-03-09T22:06:06+02:00

Commit Message:
SCUMM: MI1 SEGA CD - Add the option to use the original 'wait' cursor on the pause menu

Changed paths:
    engines/scumm/cursor.cpp
    engines/scumm/dialogs.cpp
    engines/scumm/dialogs.h


diff --git a/engines/scumm/cursor.cpp b/engines/scumm/cursor.cpp
index b9a1b90cb55..5ddbb08c7f0 100644
--- a/engines/scumm/cursor.cpp
+++ b/engines/scumm/cursor.cpp
@@ -19,6 +19,7 @@
  *
  */
 
+#include "common/config-manager.h"
 #include "common/system.h"
 #include "common/macresman.h"
 #include "common/util.h"
@@ -217,6 +218,75 @@ static const byte segacd_cross_cursor[256] = {
 	0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
 };
 
+// Sega CD Monkey Island wait cursor
+static const byte segacd_wait_cursor_frames[4][160] = {
+	{ // frame 0
+		0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x01, 0x01, 0x0F, 0xFF, 0xFF, 0xFF,
+		0xFF, 0xFF, 0xFF, 0x0F, 0x01, 0x01, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x01, 0x01, 0x01, 0xFF, 0xFF, 0xFF,
+		0xFF, 0xFF, 0x01, 0x0F, 0x0F, 0x0F, 0x0F, 0x01, 0xFF, 0xFF, 0xFF, 0x01, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x01, 0xFF,
+		0x01, 0x0F, 0x0F, 0x01, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x01, 0x01, 0x0F, 0x0F, 0x0F, 0x01, 0x01, 0x01, 0x01, 0x0F, 0x01,
+		0x01, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x01, 0x01, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x01,
+		0xFF, 0x01, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x01, 0xFF, 0xFF, 0xFF, 0x01, 0x0F, 0x0F, 0x0F, 0x0F, 0x01, 0xFF, 0xFF,
+		0xFF, 0xFF, 0xFF, 0x01, 0x01, 0x01, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x01, 0x01, 0x0F, 0xFF, 0xFF, 0xFF,
+		0xFF, 0xFF, 0xFF, 0x0F, 0x01, 0x01, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF
+	},
+	{ // frame 1
+		0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x01, 0x01, 0x0F, 0xFF, 0xFF, 0xFF,
+		0xFF, 0xFF, 0xFF, 0x0F, 0x01, 0x01, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x01, 0x01, 0x01, 0xFF, 0xFF, 0xFF,
+		0xFF, 0xFF, 0x01, 0x0F, 0x0F, 0x0F, 0x0F, 0x01, 0xFF, 0xFF, 0xFF, 0x01, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x01, 0xFF,
+		0x01, 0x0F, 0x0F, 0x01, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x01, 0x01, 0x0F, 0x0F, 0x0F, 0x01, 0x0F, 0x0F, 0x0F, 0x0F, 0x01,
+		0x01, 0x0F, 0x0F, 0x0F, 0x0F, 0x01, 0x0F, 0x0F, 0x0F, 0x01, 0x01, 0x0F, 0x0F, 0x0F, 0x0F, 0x01, 0x0F, 0x0F, 0x0F, 0x01,
+		0xFF, 0x01, 0x0F, 0x0F, 0x0F, 0x01, 0x0F, 0x0F, 0x01, 0xFF, 0xFF, 0xFF, 0x01, 0x0F, 0x0F, 0x0F, 0x0F, 0x01, 0xFF, 0xFF,
+		0xFF, 0xFF, 0xFF, 0x01, 0x01, 0x01, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x01, 0x01, 0x0F, 0xFF, 0xFF, 0xFF,
+		0xFF, 0xFF, 0xFF, 0x0F, 0x01, 0x01, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF
+	},
+	{ // frame 2
+		0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x01, 0x01, 0x0F, 0xFF, 0xFF, 0xFF,
+		0xFF, 0xFF, 0xFF, 0x0F, 0x01, 0x01, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x01, 0x01, 0x01, 0xFF, 0xFF, 0xFF,
+		0xFF, 0xFF, 0x01, 0x0F, 0x0F, 0x0F, 0x0F, 0x01, 0xFF, 0xFF, 0xFF, 0x01, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x01, 0xFF,
+		0x01, 0x0F, 0x0F, 0x01, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x01, 0x01, 0x0F, 0x0F, 0x0F, 0x01, 0x0F, 0x0F, 0x0F, 0x0F, 0x01,
+		0x01, 0x0F, 0x01, 0x01, 0x01, 0x0F, 0x0F, 0x0F, 0x0F, 0x01, 0x01, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x01,
+		0xFF, 0x01, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x01, 0xFF, 0xFF, 0xFF, 0x01, 0x0F, 0x0F, 0x0F, 0x0F, 0x01, 0xFF, 0xFF,
+		0xFF, 0xFF, 0xFF, 0x01, 0x01, 0x01, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x01, 0x01, 0x0F, 0xFF, 0xFF, 0xFF,
+		0xFF, 0xFF, 0xFF, 0x0F, 0x01, 0x01, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF
+	},
+	{ // frame 3
+		0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x01, 0x01, 0x0F, 0xFF, 0xFF, 0xFF,
+		0xFF, 0xFF, 0xFF, 0x0F, 0x01, 0x01, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x01, 0x01, 0x01, 0xFF, 0xFF, 0xFF,
+		0xFF, 0xFF, 0x01, 0x0F, 0x0F, 0x0F, 0x0F, 0x01, 0xFF, 0xFF, 0xFF, 0x01, 0x0F, 0x0F, 0x0F, 0x01, 0x0F, 0x0F, 0x01, 0xFF,
+		0x01, 0x0F, 0x0F, 0x01, 0x0F, 0x01, 0x0F, 0x0F, 0x0F, 0x01, 0x01, 0x0F, 0x0F, 0x0F, 0x01, 0x01, 0x0F, 0x0F, 0x0F, 0x01,
+		0x01, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x01, 0x01, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x01,
+		0xFF, 0x01, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x01, 0xFF, 0xFF, 0xFF, 0x01, 0x0F, 0x0F, 0x0F, 0x0F, 0x01, 0xFF, 0xFF,
+		0xFF, 0xFF, 0xFF, 0x01, 0x01, 0x01, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x01, 0x01, 0x0F, 0xFF, 0xFF, 0xFF,
+		0xFF, 0xFF, 0xFF, 0x0F, 0x01, 0x01, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF
+	},
+};
+
+static void buildSegaCdMonkeyPauseCursorFrame(byte *dst16x16, int frame) {
+	const int kOutW = 16;
+	const int kOutH = 16;
+	const int kSrcW = 10;
+	const int kSrcH = 16;
+	const int kXOff = (kOutW - kSrcW) / 2;
+	const int kYOff = 0;
+
+	if (frame < 0)
+		frame = 0;
+	frame &= 3;
+
+	memset(dst16x16, 0xFF, kOutW * kOutH);
+
+	for (int y = 0; y < kSrcH; y++) {
+		for (int x = 0; x < kSrcW; x++) {
+			const byte v = segacd_wait_cursor_frames[frame][y * kSrcW + x];
+
+			if (v != 0xFF) {
+				dst16x16[(y + kYOff) * kOutW + (x + kXOff)] = v;
+			}
+		}
+	}
+}
+
 #ifdef ENABLE_SCUMM_7_8
 static const byte default_v7_cursor[] = {
 	0x01,0x01,0x01,0x01, 0x00,0x0F,0x00, 0x01,0x01,0x01,0x01,
@@ -258,6 +328,57 @@ static const byte default_v8_cursor[] = {
 #endif
 
 void ScummEngine_v5::animateCursor() {
+	const bool isSegaCdMonkey = (_game.platform == Common::kPlatformSegaCD && _game.id == GID_MONKEY);
+	const bool wantPauseWaitCursor = isSegaCdMonkey && isUsingOriginalGUI() && _mainMenuIsActive && ConfMan.getBool("sega_cd_wait_cursor_when_paused");
+
+	if (wantPauseWaitCursor) {
+		if (_cursor.animate != 2) {
+			_cursor.width = 16;
+			_cursor.height = 16;
+			_cursor.hotspotX = 7;
+			_cursor.hotspotY = 7;
+
+			_cursor.animate = 2;
+			_cursor.animateIndex = 0;
+
+			buildSegaCdMonkeyPauseCursorFrame(_grabbedCursor, 0);
+			updateCursor();
+			return;
+		}
+	} else if (_cursor.animate == 2 && isSegaCdMonkey) {
+		_cursor.animate = 0;
+		_cursor.animateIndex = 0;
+		setBuiltinCursor(0);
+		return;
+	}
+
+
+if (_cursor.animate == 2) {
+	static uint32 sNextTick = 0;
+	static uint8 sFrame = 0;
+	static const uint32 kFrameMs = 200;
+
+	const uint32 now = _system->getMillis();
+
+	if (_cursor.animateIndex == 0) {
+		sFrame = 0;
+		sNextTick = now + kFrameMs;
+		buildSegaCdMonkeyPauseCursorFrame(_grabbedCursor, sFrame);
+		updateCursor();
+		_cursor.animateIndex = 1;
+		return;
+	}
+
+	if ((int32)(now - sNextTick) >= 0) {
+		sFrame = (sFrame + 1) & 3;
+		sNextTick = now + kFrameMs;
+		buildSegaCdMonkeyPauseCursorFrame(_grabbedCursor, sFrame);
+		updateCursor();
+	}
+
+	return;
+}
+
 	if (_cursor.animate) {
 		if (!(_cursor.animateIndex & 0x1)) {
 			setBuiltinCursor((_cursor.animateIndex >> 1) & 3);
@@ -976,6 +1097,25 @@ void ScummEngine_v2::setSnailCursor() {
 	if (_macGui)
 		return;
 
+	// Monkey Island (Sega CD) has an animated wait cursor for the original pause menu.
+	// Only enable it when enabled from the game options dialog.
+	if (_game.platform == Common::kPlatformSegaCD && _game.id == GID_MONKEY &&
+			isUsingOriginalGUI() && _mainMenuIsActive &&
+			ConfMan.getBool("sega_cd_wait_cursor_when_paused")) {
+
+		_cursor.width = 16;
+		_cursor.height = 16;
+		_cursor.hotspotX = 7;
+		_cursor.hotspotY = 7;
+
+		_cursor.animate = 2;
+		_cursor.animateIndex = 0;
+
+		buildSegaCdMonkeyPauseCursorFrame(_grabbedCursor, 0);
+		updateCursor();
+		return;
+	}
+
 	byte color;
 	if (_game.platform == Common::kPlatformC64 || _game.platform == Common::kPlatformApple2GS)
 		color = default_v0_cursor_colors[1];
@@ -1091,24 +1231,28 @@ void ScummEngine_v5::setBuiltinCursor(int idx) {
 	}
 
 	if (_game.platform == Common::kPlatformSegaCD) {
-		//_cursor.animate = 0;
-		_cursor.width = 16;
-		_cursor.height = 16;
-		_cursor.hotspotX = 7;
-		_cursor.hotspotY = 7;
-		byte arr[256];
-		for (int i = 0; i < 256; i++) {
-			if (segacd_cross_cursor[i] != 0x00)
-				arr[i] = segacd_cross_cursor[i];
-			else
-				arr[i] = 0x01; // TODO: Brown during cutscenes or dialogs (or something else?)
-		}
-
+	if (_cursor.animate == 2) {
+		_cursor.animate = 0;
+		_cursor.animateIndex = 0;
+	}
 
-		CursorMan.replaceCursor(arr, 16, 16, 7, 7, 0xFF);
-		return;
+	_cursor.width = 16;
+	_cursor.height = 16;
+	_cursor.hotspotX = 7;
+	_cursor.hotspotY = 7;
+
+	byte arr[256];
+	for (int i = 0; i < 256; i++) {
+		if (segacd_cross_cursor[i] != 0x00)
+			arr[i] = segacd_cross_cursor[i];
+		else
+			arr[i] = 0x01; // TODO: Brown during cutscenes or dialogs (or something else?)
 	}
 
+	CursorMan.replaceCursor(arr, 16, 16, 7, 7, 0xFF);
+	return;
+}
+
 	int i, j;
 	uint16 color;
 	const uint16 *src = _cursorImages[_currentCursor];
diff --git a/engines/scumm/dialogs.cpp b/engines/scumm/dialogs.cpp
index b15c11a04d2..852d6773531 100644
--- a/engines/scumm/dialogs.cpp
+++ b/engines/scumm/dialogs.cpp
@@ -1221,6 +1221,13 @@ GUI::CheckboxWidget *ScummOptionsContainerWidget::createSegaShadowModeCheckbox(G
 	);
 }
 
+GUI::CheckboxWidget *ScummOptionsContainerWidget::createSegaCdWaitCursorWhenPausedCheckbox(GuiObject *boss, const Common::String &name) {
+	return new GUI::CheckboxWidget(boss, name,
+		_("Show wait cursor when paused"),
+		_("When paused, show the animated wait cursor from the original Sega CD version.")
+	);
+}
+
 GUI::CheckboxWidget *ScummOptionsContainerWidget::createCopyProtectionCheckbox(GuiObject *boss, const Common::String &name) {
 	return new GUI::CheckboxWidget(boss, name,
 		_("Enable copy protection"),
@@ -1694,6 +1701,9 @@ MI1CdGameOptionsWidget::MI1CdGameOptionsWidget(GuiObject *boss, const Common::St
 	if (platform == Common::kPlatformSegaCD)
 		_enableSegaShadowModeCheckbox = createSegaShadowModeCheckbox(widgetsBoss(), "MI1CdGameOptionsDialog.EnableSegaShadowMode");
 
+	if (platform == Common::kPlatformSegaCD)
+		_enableSegaCdWaitCursorWhenPausedCheckbox = createSegaCdWaitCursorWhenPausedCheckbox(widgetsBoss(), "MI1CdGameOptionsDialog.EnableSegaCdWaitCursorWhenPaused");
+
 	GUI::StaticTextWidget *text = new GUI::StaticTextWidget(widgetsBoss(), "MI1CdGameOptionsDialog.IntroAdjustmentLabel", _("Intro Adjust:"));
 
 	text->setAlign(Graphics::TextAlign::kTextAlignEnd);
@@ -1729,6 +1739,13 @@ void MI1CdGameOptionsWidget::load() {
 	if (_enableSegaShadowModeCheckbox)
 		_enableSegaShadowModeCheckbox->setState(ConfMan.getBool("enable_sega_shadow_mode", _domain));
 
+	if (_enableSegaCdWaitCursorWhenPausedCheckbox) {
+		bool enabled = false;
+		if (ConfMan.hasKey("sega_cd_wait_cursor_when_paused", _domain))
+			enabled = ConfMan.getBool("sega_cd_wait_cursor_when_paused", _domain);
+		_enableSegaCdWaitCursorWhenPausedCheckbox->setState(enabled);
+	}
+
 	int introAdjustment = 0;
 	int outlookAdjustment = 0;
 
@@ -1755,6 +1772,9 @@ bool MI1CdGameOptionsWidget::save() {
 	if (_enableSegaShadowModeCheckbox)
 		ConfMan.setBool("enable_sega_shadow_mode", _enableSegaShadowModeCheckbox->getState(), _domain);
 
+	if (_enableSegaCdWaitCursorWhenPausedCheckbox)
+		ConfMan.setBool("sega_cd_wait_cursor_when_paused", _enableSegaCdWaitCursorWhenPausedCheckbox->getState(), _domain);
+
 	ConfMan.setInt("mi1_intro_adjustment", _introAdjustmentSlider->getValue(), _domain);
 	ConfMan.setInt("mi1_outlook_adjustment", _outlookAdjustmentSlider->getValue(), _domain);
 	ConfMan.setBool("original_gui", _enableOriginalGUICheckbox->getState(), _domain);
@@ -1777,6 +1797,9 @@ void MI1CdGameOptionsWidget::defineLayout(GUI::ThemeEval &layouts, const Common:
 	if (platform == Common::kPlatformSegaCD)
 		layouts.addWidget("EnableSegaShadowMode", "Checkbox");
 
+	if (platform == Common::kPlatformSegaCD)
+		layouts.addWidget("EnableSegaCdWaitCursorWhenPaused", "Checkbox");
+
 #ifdef USE_TTS
 	layouts.addWidget("EnableTTS", "Checkbox");
 #endif
diff --git a/engines/scumm/dialogs.h b/engines/scumm/dialogs.h
index 094288a1cf9..f0a2ef98c1c 100644
--- a/engines/scumm/dialogs.h
+++ b/engines/scumm/dialogs.h
@@ -241,6 +241,7 @@ protected:
 	GUI::CheckboxWidget *createOriginalGUICheckbox(GuiObject *boss, const Common::String &name);
 	GUI::CheckboxWidget *createGammaCorrectionCheckbox(GuiObject *boss, const Common::String &name);
 	GUI::CheckboxWidget *createSegaShadowModeCheckbox(GuiObject *boss, const Common::String &name);
+	GUI::CheckboxWidget *createSegaCdWaitCursorWhenPausedCheckbox(GuiObject *boss, const Common::String &name);
 	GUI::CheckboxWidget *createCopyProtectionCheckbox(GuiObject *boss, const Common::String &name);
 #ifdef USE_TTS
 	GUI::CheckboxWidget *createEnableTTSCheckbox(GuiObject *boss, const Common::String &name);
@@ -388,6 +389,7 @@ private:
 
 	GUI::CheckboxWidget *_enableOriginalGUICheckbox = nullptr;
 	GUI::CheckboxWidget *_enableSegaShadowModeCheckbox = nullptr;
+	GUI::CheckboxWidget *_enableSegaCdWaitCursorWhenPausedCheckbox = nullptr;
 #ifdef USE_TTS
 	GUI::CheckboxWidget *_enableTTSCheckbox = nullptr;
 #endif




More information about the Scummvm-git-logs mailing list