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

mgerhardy noreply at scummvm.org
Sun Jul 5 08:58:41 UTC 2026


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

Summary:
ee699988c6 MACS2: fixed wrong main menu conditions and switching scenes when actor x coordinate is negative
d65c1fbe08 MACS2: revert "fixed center of mouse cursor sprite"
e8cfe46d21 MACS2: convert imgui debugger into a window to ensure that the top can get clicked to trigger scene switches


Commit: ee699988c61586703d37419ddb095160fbcfdc3f
    https://github.com/scummvm/scummvm/commit/ee699988c61586703d37419ddb095160fbcfdc3f
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2026-07-05T10:54:47+02:00

Commit Message:
MACS2: fixed wrong main menu conditions and switching scenes when actor x coordinate is negative

Changed paths:
    engines/macs2/scriptexecutor.cpp
    engines/macs2/view1.cpp


diff --git a/engines/macs2/scriptexecutor.cpp b/engines/macs2/scriptexecutor.cpp
index da5990d9ea5..bedff69742b 100644
--- a/engines/macs2/scriptexecutor.cpp
+++ b/engines/macs2/scriptexecutor.cpp
@@ -1042,6 +1042,21 @@ void Script::ScriptExecutor::scriptMoveObject() {
 		_stream->seek(0, SEEK_END);
 	}
 
+	// Binary (1008:aa83): when runtime data exists, sync target/finalDest to the new
+	// object position so a subsequent waitForWalk completes immediately.
+	if (object->_dataOffset != 0) {
+		GameObject::StoredWalkRuntime &s = object->_storedWalkRuntime;
+		s.valid = true;
+		s.targetPosition = object->_position;
+		s.pathFinalDestination = object->_position;
+		s.currentPathIndex = 0;
+		s.path.clear();
+		s.stepDeltaX = 0;
+		s.stepDeltaY = 0;
+		s.stepError = 0;
+		s.stepDirectionSet = false;
+	}
+
 	currentView->rebuildCharacterLookupTable();
 }
 
@@ -1314,16 +1329,15 @@ ExecutionResult Script::ScriptExecutor::scriptWaitForWalk() {
 		endBuffering(_lastOpcodeTriggeredSkip);
 		return ExecutionResult::ScriptFinished;
 	}
-	// Original checks runtime+0x231 (frozen/attached flag) -> error 0x1F
-	if (walkObject->_hasBoundsAttachment) {
-		setScriptError(0x1F);
+	// Binary (1008:db56 opcode 0x11): object+0x0A runtime must exist; no on-screen Character required.
+	if (walkObject->_dataOffset == 0) {
+		setScriptError(2);
 		endBuffering(_lastOpcodeTriggeredSkip);
 		return ExecutionResult::ScriptFinished;
 	}
-	View1 *currentView = (View1 *)_engine->findView("View1");
-	Character *c = currentView->getCharacterByIndex(objectID);
-	if (c == nullptr) {
-		setScriptError(2);
+	// Original checks runtime+0x231 (frozen/attached flag) -> error 0x1F
+	if (walkObject->_hasBoundsAttachment) {
+		setScriptError(0x1F);
 		endBuffering(_lastOpcodeTriggeredSkip);
 		return ExecutionResult::ScriptFinished;
 	}
diff --git a/engines/macs2/view1.cpp b/engines/macs2/view1.cpp
index 5abf0a7c2b3..65b3371cc81 100644
--- a/engines/macs2/view1.cpp
+++ b/engines/macs2/view1.cpp
@@ -1663,14 +1663,21 @@ bool View1::handleInput(const MouseDownMessage &msg) {
 					_savedCursorMode = g_engine->_scriptExecutor->_cursorMode;
 					openOriginalSaveLoadPanel();
 				} else {
+					// Binary save/load path saves cursor then sets PanelCursor (0x19).
+					_savedCursorMode = g_engine->_scriptExecutor->_cursorMode;
+					g_engine->setCursorMode(Script::MouseMode::PanelCursor);
 					g_engine->openMainMenuDialog();
+					updateCursor();
 				}
 			}
 			return true;
 		}
 
-		// From handleInput (1008:e8bf): right-click when not executing
+		// From handleInput (1008:e8bf): right-click when not executing and cursor != Disabled
 		// opens the action bar at the mouse position.
+		if (g_engine->_scriptExecutor->_cursorMode == Script::MouseMode::Disabled) {
+			return true;
+		}
 		if (_uiPanelState != kUiPanelActionBar) {
 			openMainMenu(msg._pos);
 		} else {
@@ -1712,6 +1719,14 @@ bool View1::handlePanelRelease(const MouseUpMessage &msg) {
 		return false;
 	}
 
+	// Binary handleInput (1008:e8bf): action bar/inventory panel release is only handled
+	// when g_wScriptIsExecuting==0 and g_wCursorMode!=0x1A. Save/load (state 4) still
+	// closes during script execution.
+	if (g_engine->_scriptExecutor->isExecuting() &&
+		_uiPanelState != kUiPanelSaveLoad) {
+		return true;
+	}
+
 	const UiPanelState previousState = _uiPanelState;
 	bool shouldClose = false;
 
@@ -1823,6 +1838,15 @@ bool View1::msgAction(const ActionMessage &msg) {
 		debug("Game speed mode: %u", g_engine->_gameSpeedMode);
 		return true;
 	case Macs2::kMacs2ActionOpenGMM:
+		// Binary has no GMM; mirror save/load panel cursor handling when a script wait is active.
+		if (g_engine->_scriptExecutor->isExecuting()) {
+			if (g_engine->_scriptExecutor->_cursorMode == Script::MouseMode::Disabled) {
+				_savedCursorMode = g_engine->_scriptExecutor->_cursorMode;
+				g_engine->setCursorMode(Script::MouseMode::PanelCursor);
+			}
+		} else if (g_engine->_scriptExecutor->_cursorMode == Script::MouseMode::Disabled) {
+			return true;
+		}
 		g_engine->openMainMenuDialog();
 		updateCursor();
 		return true;
@@ -2158,6 +2182,7 @@ bool View1::tick() {
 					executor->_walkTargetObjectIndex = 0;
 				} else {
 					Character *c = getCharacterByIndex(walkTarget);
+					bool walkComplete = false;
 					if (c != nullptr) {
 						Common::Point pos = c->getPosition();
 						// Binary: walkAlongPath guarantees pos == finalDest on arrival.
@@ -2169,20 +2194,31 @@ bool View1::tick() {
 								c->_motionProgress == 0) {
 								c->_motionTargetVerticalOffset = walkObject->_verticalOffsetScale;
 							}
-							bool verticalOk = !c->hasPendingVerticalMotion();
-							if (verticalOk) {
-								if (!executor->_pickupInProgress) {
-									executor->_walkTargetObjectIndex = 0;
-									g_engine->runScriptExecutor();
-								} else if (c->_gameObject->_orientation != 0x11) {
-									// Binary: pickup in progress, trigger pickup animation.
-									// Save current orientation so it can be restored after pickup.
-									c->_previousOrientation = c->_gameObject->_orientation;
-									c->_gameObject->_orientation = 0x11;
-								}
+							walkComplete = !c->hasPendingVerticalMotion();
+						}
+					} else if (walkObject->_storedWalkRuntime.valid) {
+						// Binary gameTick (1008:e752): polls object table pos vs runtime finalDest;
+						// no on-screen Character is required (e.g. after moveObject to another scene).
+						const GameObject::StoredWalkRuntime &rt = walkObject->_storedWalkRuntime;
+						if (walkObject->_position.x == rt.pathFinalDestination.x &&
+							walkObject->_position.y == rt.pathFinalDestination.y) {
+							if ((int16)rt.motionTargetVerticalOffset < 0 ||
+								rt.motionTargetVerticalOffset == walkObject->_verticalOffsetScale) {
+								walkComplete = true;
 							}
 						}
 					}
+					if (walkComplete) {
+						if (!executor->_pickupInProgress) {
+							executor->_walkTargetObjectIndex = 0;
+							g_engine->runScriptExecutor();
+						} else if (c != nullptr && c->_gameObject->_orientation != 0x11) {
+							// Binary: pickup in progress, trigger pickup animation.
+							// Save current orientation so it can be restored after pickup.
+							c->_previousOrientation = c->_gameObject->_orientation;
+							c->_gameObject->_orientation = 0x11;
+						}
+					}
 				}
 			} else if (executor->_waitForPcmSound) {
 				drawSceneUpdate();


Commit: d65c1fbe086e65a378bfc51939e13119a4d7d09c
    https://github.com/scummvm/scummvm/commit/d65c1fbe086e65a378bfc51939e13119a4d7d09c
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2026-07-05T10:57:42+02:00

Commit Message:
MACS2: revert "fixed center of mouse cursor sprite"

This reverts commit ddb9646d8c505331034ed627688e8e39f1cc8e0d.

This was in fact an error elsewhere: see 641e3d987e70009cb6b3d02fbb431ad00fc9ef0f

Changed paths:
    engines/macs2/macs2.cpp
    engines/macs2/view1.cpp


diff --git a/engines/macs2/macs2.cpp b/engines/macs2/macs2.cpp
index 56cf79321f5..1904014ce66 100644
--- a/engines/macs2/macs2.cpp
+++ b/engines/macs2/macs2.cpp
@@ -1120,10 +1120,38 @@ int Macs2Engine::computeMinCostToReachable(int nodeIndex, int prevNode, uint16 a
 }
 
 void Macs2Engine::setCursorMode(Script::MouseMode newMode) {
-	// setCursorMode (1008:3ea5): binary adjusts top-left by old/new half-extents.
+	// setCursorMode (1008:3ea5): when the cursor image changes, keep the hotspot
+	// fixed on screen by compensating for the old/new image half-extents, clamp,
+	// refresh the cursor graphic, and flag the clip rect dirty.
+	const Script::MouseMode oldMode = _scriptExecutor->_cursorMode;
 	const bool cursorVisible = CursorMan.isVisible();
 
+	auto cursorHalfSize = [this](Script::MouseMode mode, uint16 &halfW, uint16 &halfH) {
+		halfW = halfH = 0;
+		const int index = (int)mode - 1;
+		if (index < 0 || index >= (int)_imageResources.size())
+			return;
+		halfW = _imageResources[index]._width / 2;
+		halfH = _imageResources[index]._height / 2;
+	};
+
+	uint16 oldHalfW = 0, oldHalfH = 0, newHalfW = 0, newHalfH = 0;
+	cursorHalfSize(oldMode, oldHalfW, oldHalfH);
+
+	Common::Point mouse = g_system->getEventManager()->getMousePos();
+	mouse.x += oldHalfW;
+	mouse.y += oldHalfH;
+
 	_scriptExecutor->_cursorMode = newMode;
+
+	cursorHalfSize(newMode, newHalfW, newHalfH);
+	mouse.x -= newHalfW;
+	mouse.y -= newHalfH;
+
+	mouse.x = CLIP<int>(mouse.x, (int)newHalfW, 319 - (int)newHalfW);
+	mouse.y = CLIP<int>(mouse.y, (int)newHalfH, 199 - (int)newHalfH);
+	g_system->warpMouse(mouse.x, mouse.y);
+
 	_clipRectDirty = true;
 
 	if (View1 *view = (View1 *)findView("View1"))
diff --git a/engines/macs2/view1.cpp b/engines/macs2/view1.cpp
index 65b3371cc81..0f509a4aa3f 100644
--- a/engines/macs2/view1.cpp
+++ b/engines/macs2/view1.cpp
@@ -28,7 +28,6 @@
 #include "engines/enhancements.h"
 #include "graphics/cursorman.h"
 #include "graphics/paletteman.h"
-#include "graphics/scaler/aspect.h"
 #include "macs2/debugtools.h"
 #include "macs2/detection.h"
 #include "macs2/gameobjects.h"
@@ -118,28 +117,6 @@ void buildFadedPalette(byte *colors, const byte *sourcePalette, int fadeValue) {
 	}
 }
 
-static Common::Point cursorReplaceHotspot(uint16 width, uint16 height) {
-	const uint scale = MAX(1u, g_system->getScaleFactor());
-	const int hotX = (int)width / (2 * (int)scale);
-	int hotY = (int)height / (2 * (int)scale);
-
-	if (g_system->getFeatureState(OSystem::kFeatureAspectRatioCorrection)) {
-		const int target = (int)height / 2;
-		int bestHotY = hotY;
-		int bestErr = ABS(real2Aspect(bestHotY * (int)scale) - target);
-		for (int candidate = 0; candidate <= (int)height; candidate++) {
-			const int err = ABS(real2Aspect(candidate * (int)scale) - target);
-			if (err < bestErr) {
-				bestErr = err;
-				bestHotY = candidate;
-			}
-		}
-		hotY = bestHotY;
-	}
-
-	return Common::Point(hotX, hotY);
-}
-
 } // namespace
 
 const View1::BorderStyle View1::kBorderRaised = {0x1010, 0x1012, 0x1011};
@@ -385,10 +362,7 @@ void View1::updateCursor(const byte *palette) {
 		rgbaCursor[i] = rgbaCursorFormat.RGBToColor(paletteEntry[0], paletteEntry[1], paletteEntry[2]);
 	}
 
-	// adjustViewportToMouse (1008:3de3): interaction center = mouse; draw at center - half.
-	// getMousePos() is the center; compensate hotspot for SurfaceSdl rHot scaling (see above).
-	const Common::Point hotspot = cursorReplaceHotspot(width, height);
-	CursorMan.replaceCursor(rgbaCursor.data(), width, height, hotspot.x, hotspot.y, 0, &rgbaCursorFormat);
+	CursorMan.replaceCursor(rgbaCursor.data(), width, height, width >> 1, height >> 1, 0, &rgbaCursorFormat);
 	// Enable a cursor palette so the backend won't re-blit the cursor on
 	// every screen palette change. The macs2 engine uses RGBA cursors with
 	// baked-in palette colors, so the cursor palette content is irrelevant -


Commit: e8cfe46d2156238f170f10fbc68c39d53db7adb2
    https://github.com/scummvm/scummvm/commit/e8cfe46d2156238f170f10fbc68c39d53db7adb2
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2026-07-05T10:58:28+02:00

Commit Message:
MACS2: convert imgui debugger into a window to ensure that the top can get clicked to trigger scene switches

Changed paths:
    engines/macs2/debugtools.cpp


diff --git a/engines/macs2/debugtools.cpp b/engines/macs2/debugtools.cpp
index 387905dbfa0..a1e6c29dc05 100644
--- a/engines/macs2/debugtools.cpp
+++ b/engines/macs2/debugtools.cpp
@@ -1988,6 +1988,7 @@ static void showObjectScriptsWindow() {
 }
 
 static void showSoundWindow();
+static void showDebugToolbarWindow();
 
 bool shouldDrawPathfindingOverlay() {
 	return _showPathfindingOverlay;
@@ -2012,7 +2013,34 @@ void onImGuiRender() {
 	}
 	ImGui::GetIO().ConfigFlags &= ~(ImGuiConfigFlags_NoMouseCursorChange | ImGuiConfigFlags_NoMouse);
 
-	if (ImGui::BeginMainMenuBar()) {
+	showDebugToolbarWindow();
+	showScriptWindow();
+	showObjectScriptsWindow();
+	showBreakpointsWindow();
+	showVariablesWindow();
+	showCharactersWindow();
+	drawHoveredObjectOverlay();
+	showAnimViewerWindow();
+	showInventoryWindow();
+	showAnimationsWindow();
+	showSceneMapsWindow();
+	showImageResourcesWindow();
+	showDebugOutputWindow();
+	showTextLogWindow();
+	showSoundWindow();
+}
+
+static void showDebugToolbarWindow() {
+	// Movable toolbar window instead of BeginMainMenuBar(), which reserves the full
+	// viewport width and intercepts clicks along the top edge of the game view.
+	ImGui::SetNextWindowPos(ImVec2(8.0f, 8.0f), ImGuiCond_FirstUseEver);
+	const ImGuiWindowFlags flags = ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse;
+	if (!ImGui::Begin("MACS2 Debug", nullptr, flags)) {
+		ImGui::End();
+		return;
+	}
+
+	if (ImGui::BeginMenuBar()) {
 		if (ImGui::BeginMenu("Debug")) {
 			ImGui::MenuItem("Script", NULL, &_showScript);
 			ImGui::MenuItem("Object Scripts", NULL, &_showObjectScripts);
@@ -2047,21 +2075,25 @@ void onImGuiRender() {
 			for (const auto &ch : channels) {
 				bool enabled = debugChannelSet(-1, ch.flag);
 				if (ImGui::MenuItem(ch.name, NULL, enabled)) {
-					if (enabled)
+					if (enabled) {
 						DebugMan.disableDebugChannel(ch.flag);
-					else
+					} else {
 						DebugMan.enableDebugChannel(ch.flag);
+					}
 				}
 			}
 			ImGui::EndMenu();
 		}
 		if (ImGui::BeginMenu("Speed")) {
-			if (ImGui::MenuItem("Normal", NULL, g_engine->_gameSpeedMode == 0))
+			if (ImGui::MenuItem("Normal", NULL, g_engine->_gameSpeedMode == 0)) {
 				g_engine->_gameSpeedMode = 0;
-			if (ImGui::MenuItem("Fast", NULL, g_engine->_gameSpeedMode == 1))
+			}
+			if (ImGui::MenuItem("Fast", NULL, g_engine->_gameSpeedMode == 1)) {
 				g_engine->_gameSpeedMode = 1;
-			if (ImGui::MenuItem("Slow", NULL, g_engine->_gameSpeedMode == 2))
+			}
+			if (ImGui::MenuItem("Slow", NULL, g_engine->_gameSpeedMode == 2)) {
 				g_engine->_gameSpeedMode = 2;
+			}
 			ImGui::EndMenu();
 		}
 		if (ImGui::BeginMenu("Tools")) {
@@ -2070,50 +2102,58 @@ void onImGuiRender() {
 				ImGui::MenuItem("Auto-click (simulate repeated clicks)", NULL, &toolsView->_autoclickActive);
 			}
 			ImGui::Separator();
-			if (ImGui::MenuItem("Quick Start (Scene 6)"))
+			if (ImGui::MenuItem("Quick Start (Scene 6)")) {
 				g_engine->changeScene(0x6);
+			}
 			ImGui::Separator();
 			static int sceneInput = 1;
 			ImGui::SetNextItemWidth(60);
 			ImGui::InputInt("##scn", &sceneInput, 1, 10);
 			ImGui::SameLine();
 			if (ImGui::MenuItem("Change Scene")) {
-				if (sceneInput > 0 && sceneInput <= 512)
+				if (sceneInput > 0 && sceneInput <= 512) {
 					g_engine->changeScene((uint32)sceneInput);
+				}
 			}
 			ImGui::Separator();
-			if (ImGui::MenuItem("Run Script Executor"))
+			if (ImGui::MenuItem("Run Script Executor")) {
 				g_engine->runScriptExecutor(true);
+			}
 			static int dosSaveSlot = 0;
 			ImGui::SetNextItemWidth(60);
 			ImGui::InputInt("##dosslot", &dosSaveSlot, 1, 1);
-			if (dosSaveSlot < 0)
+			if (dosSaveSlot < 0) {
 				dosSaveSlot = 0;
-			if (dosSaveSlot > 9)
+			}
+			if (dosSaveSlot > 9) {
 				dosSaveSlot = 9;
+			}
 			ImGui::SameLine();
 			if (ImGui::MenuItem("Save to original DOS slot (SAVEGAME.N)")) {
 				Common::Error err = g_engine->saveOriginalGameState(dosSaveSlot);
-				if (err.getCode() != Common::kNoError)
+				if (err.getCode() != Common::kNoError) {
 					warning("Failed to write original DOS save SAVEGAME.%d", dosSaveSlot);
-				else
+				} else {
 					debug("Wrote original DOS save SAVEGAME.%d", dosSaveSlot);
+				}
 			}
 			static int dosLoadSlot = 0;
 			ImGui::SetNextItemWidth(60);
 			ImGui::InputInt("##dosloadslot", &dosLoadSlot, 1, 1);
-			if (dosLoadSlot < 0)
+			if (dosLoadSlot < 0) {
 				dosLoadSlot = 0;
-			if (dosLoadSlot > 9)
+			}
+			if (dosLoadSlot > 9) {
 				dosLoadSlot = 9;
+			}
 			ImGui::SameLine();
 			if (ImGui::MenuItem("Load original DOS slot (SAVEGAME.N)")) {
-				// loadGameState slots 100..109 map to original DOS SAVEGAME.0..9
 				Common::Error err = g_engine->loadGameState(100 + dosLoadSlot);
-				if (err.getCode() != Common::kNoError)
+				if (err.getCode() != Common::kNoError) {
 					warning("Failed to load original DOS save SAVEGAME.%d", dosLoadSlot);
-				else
+				} else {
 					debug("Loaded original DOS save SAVEGAME.%d", dosLoadSlot);
+				}
 			}
 			if (ImGui::MenuItem("Reset Background + Fade")) {
 				View1 *view = (View1 *)g_engine->findView("View1");
@@ -2129,12 +2169,15 @@ void onImGuiRender() {
 					if (view->isInventorySourceProtagonist()) {
 						const uint16 currentScene = Scenes::instance()._currentSceneIndex;
 						for (GameObject *obj : GameObjects::instance()._objects) {
-							if (obj == nullptr)
+							if (obj == nullptr) {
 								continue;
-							if ((int16)obj->_sceneIndex < 0 || obj->_sceneIndex != currentScene)
+							}
+							if ((int16)obj->_sceneIndex < 0 || obj->_sceneIndex != currentScene) {
 								continue;
-							if (0x13 >= obj->_blobs.size() || obj->_blobs[0x13].empty())
+							}
+							if (0x13 >= obj->_blobs.size() || obj->_blobs[0x13].empty()) {
 								continue;
+							}
 							view->transferInventoryItem(view->_activeInventoryItem, obj);
 							view->_activeInventoryItem = nullptr;
 							view->setInventorySource(view->_inventorySource);
@@ -2149,25 +2192,13 @@ void onImGuiRender() {
 			}
 			ImGui::EndMenu();
 		}
-		ImGui::Text("| Scene: %d | Speed: %s", Scenes::instance()._currentSceneIndex,
+		ImGui::Separator();
+		ImGui::Text("Scene: %d | Speed: %s", Scenes::instance()._currentSceneIndex,
 					g_engine->_gameSpeedMode == 0 ? "Normal" : (g_engine->_gameSpeedMode == 1 ? "Fast" : "Slow"));
-		ImGui::EndMainMenuBar();
+		ImGui::EndMenuBar();
 	}
 
-	showScriptWindow();
-	showObjectScriptsWindow();
-	showBreakpointsWindow();
-	showVariablesWindow();
-	showCharactersWindow();
-	drawHoveredObjectOverlay();
-	showAnimViewerWindow();
-	showInventoryWindow();
-	showAnimationsWindow();
-	showSceneMapsWindow();
-	showImageResourcesWindow();
-	showDebugOutputWindow();
-	showTextLogWindow();
-	showSoundWindow();
+	ImGui::End();
 }
 
 static void showSoundWindow() {




More information about the Scummvm-git-logs mailing list