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

sev- noreply at scummvm.org
Fri Aug 14 16:46:37 UTC 2026


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

Summary:
609c7d127f MACVENTURE: Do not pop the calling script when a called function is missing
526f3b6018 MACVENTURE: Fix double delete of the dialog when asking the user for text
962fd07289 MACVENTURE: Implement shift click to select several objects at once
75e982f71f MACVENTURE: Return the documented range from the random opcode
67b63cf754 MACVENTURE: Let a command target the object it was invoked on
678d781680 MACVENTURE: Do not drop object updates while a window is queued
a5f5989f92 MACVENTURE: Give dialog buttons the press feedback of the original


Commit: 609c7d127f543637c5a40c0c69aa8541beec24ef
    https://github.com/scummvm/scummvm/commit/609c7d127f543637c5a40c0c69aa8541beec24ef
Author: Ion Andrei Cristian (lecturatul2017 at gmail.com)
Date: 2026-08-14T18:46:30+02:00

Commit Message:
MACVENTURE: Do not pop the calling script when a called function is missing

The CALL opcode popped the script list unconditionally after running the
callee, but loadScript() only pushes a ScriptAsset when the function
actually exists (getItemByteSize() > 0). Calling a missing function
therefore popped the caller itself, leaving the reference held by
runFunc() dangling, and the following assignment to it freed the
instruction array a second time.

The original engine reserves the slot before the call and always removes
that same slot, so the list stays balanced either way. Pop and rebind
only when loadScript() has really pushed a script.

This crashed Deja Vu II when using Hit on an object without a hit
handler.

Changed paths:
    engines/macventure/script.cpp


diff --git a/engines/macventure/script.cpp b/engines/macventure/script.cpp
index c48cc49b213..c54d52ede63 100644
--- a/engines/macventure/script.cpp
+++ b/engines/macventure/script.cpp
@@ -966,10 +966,13 @@ bool ScriptEngine::opbcCALL(EngineState *state, EngineFrame *frame, ScriptAsset
 	ScriptAsset newfun = ScriptAsset(id, _scripts);
 	ScriptAsset current = script;
 	debugC(2, kMVDebugScript, "Call function: %d", id);
+	uint32 depth = frame->scripts.size();
 	if (loadScript(frame, id))
 		return true;
-	frame->scripts.pop_front();
-	script = frame->scripts.front();
+	if (frame->scripts.size() > depth) {
+		frame->scripts.pop_front();
+		script = frame->scripts.front();
+	}
 	debugC(2, kMVDebugScript, "Return from fuction %d", id);
 	return false;
 }


Commit: 526f3b601882a3c145313a0e70dce7800cf2f6c3
    https://github.com/scummvm/scummvm/commit/526f3b601882a3c145313a0e70dce7800cf2f6c3
Author: Ion Andrei Cristian (lecturatul2017 at gmail.com)
Date: 2026-08-14T18:46:30+02:00

Commit Message:
MACVENTURE: Fix double delete of the dialog when asking the user for text

getTextFromUser() deleted the open dialog without clearing the pointer,
and then called showPrebuiltDialog(), which starts with closeDialog() and
deletes the very same pointer again. Leave the cleanup to closeDialog().

Changed paths:
    engines/macventure/gui.cpp


diff --git a/engines/macventure/gui.cpp b/engines/macventure/gui.cpp
index 10d3d600483..fcde154fae9 100644
--- a/engines/macventure/gui.cpp
+++ b/engines/macventure/gui.cpp
@@ -1212,9 +1212,6 @@ void Gui::closeDialog() {
 }
 
 void Gui::getTextFromUser(Common::String &title) {
-	if (_dialog) {
-		delete _dialog;
-	}
 	showPrebuiltDialog(kSpeakDialog, title);
 }
 


Commit: 962fd072895e6ca0d5a42c7676120d261b3a9a19
    https://github.com/scummvm/scummvm/commit/962fd072895e6ca0d5a42c7676120d261b3a9a19
Author: Ion Andrei Cristian (lecturatul2017 at gmail.com)
Date: 2026-08-14T18:46:30+02:00

Commit Message:
MACVENTURE: Implement shift click to select several objects at once

Shift clicking toggles an object in and out of the selection instead of
replacing it, as the original does, so several objects can be picked and
then dragged together. Dragging already handled groups: selectDraggable()
builds a proxy for every selected object and handleObjectDrop() moves
whatever is in the current selection. Only the selecting was missing.

Three things stood in the way. The shift state never reached the engine,
because Cursor always passed false; it is now read from the event manager
when the button goes down. Gui::select() passed the last two arguments to
checkSelect() in the wrong order, so the flag arrived as isDoubleClick.
And handleObjectSelect() had the shift branch left as a stub.

Correcting the argument order exposed the select() call in kCursorDCStart,
which runs on the release of every single click. It used to land in the
empty shift branch and do nothing, but with the flags the right way round
it activated the object instead. It has no other effect, since the
selectDraggable() it also reached returns early while an object is being
dragged, so the call is gone.

Shift now also keeps clicks from starting a drag and from clearing the
selection in inventory windows, which would otherwise undo the selection
being built.

Changed paths:
    engines/macventure/cursor.cpp
    engines/macventure/gui.cpp
    engines/macventure/gui.h
    engines/macventure/macventure.cpp


diff --git a/engines/macventure/cursor.cpp b/engines/macventure/cursor.cpp
index 9c43df9098c..e2227dd99ef 100644
--- a/engines/macventure/cursor.cpp
+++ b/engines/macventure/cursor.cpp
@@ -46,6 +46,7 @@ static const ClickState _transitionTable[kCursorStateCount][kCursorInputCount] =
 Cursor::Cursor(Gui *gui) {
 	_gui = gui;
 	_state = kCursorIdle;
+	_shiftPressed = false;
 }
 Cursor::~Cursor() {}
 
@@ -59,6 +60,7 @@ bool Cursor::processEvent(const Common::Event &event) {
 		return true;
 	}
 	if (event.type == Common::EVENT_LBUTTONDOWN) {
+		_shiftPressed = (g_system->getEventManager()->getModifierState() & Common::KBD_SHIFT) != 0;
 		changeState(kButtonDownCol);
 		return true;
 	}
@@ -91,11 +93,10 @@ void Cursor::executeStateIn() {
 	switch (_state) {
 	case kCursorSCStart:
 		g_system->getTimerManager()->installTimerProc(&cursorTimerHandler, 300000, this, "macVentureCursor");
-		_gui->select(_pos, false, false);
+		_gui->select(_pos, _shiftPressed, false);
 		break;
 	case kCursorDCStart:
 		g_system->getTimerManager()->installTimerProc(&cursorTimerHandler, 300000, this, "macVentureCursor");
-		_gui->select(_pos, false, true);
 		break;
 	case kCursorSCSink:
 		_gui->handleSingleClick();
diff --git a/engines/macventure/gui.cpp b/engines/macventure/gui.cpp
index fcde154fae9..c0faef912ea 100644
--- a/engines/macventure/gui.cpp
+++ b/engines/macventure/gui.cpp
@@ -1372,7 +1372,7 @@ void Gui::checkSelect(const WindowData &data, Common::Point pos, const Common::R
 		}
 	}
 	if (child != 0 || data.refcon == kMainGameWindow) {
-		if (!isDoubleClick)
+		if (!isDoubleClick && !shiftPressed)
 			selectDraggable(child, ref, pos);
 		_engine->handleObjectSelect(child, ref, shiftPressed, isDoubleClick);
 		bringToFront(ref);
@@ -1934,8 +1934,10 @@ bool Gui::processInventoryEvents(WindowReference ref, WindowClick click, Common:
 		WindowData &data = findWindowData((WindowReference)ref);
 
 		if (click == kBorderInner && !_draggedObjects.size()) {
-			_engine->unselectAll();
-			_engine->getSelectedObjects().clear();
+			if (!(g_system->getEventManager()->getModifierState() & Common::KBD_SHIFT)) {
+				_engine->unselectAll();
+				_engine->getSelectedObjects().clear();
+			}
 
 			_lassoStart = event.mouse;
 			_lassoEnd = _lassoStart;
@@ -2012,7 +2014,7 @@ void Gui::select(Common::Point cursorPosition, bool shiftPressed, bool isDoubleC
 	WindowData &data = findWindowData((WindowReference)ref);
 
 	Common::Rect clickRect = calculateClickRect(cursorPosition + data.scrollPos, win->getInnerDimensions());
-	checkSelect(data, cursorPosition, clickRect, (WindowReference)ref, isDoubleClick, shiftPressed);
+	checkSelect(data, cursorPosition, clickRect, (WindowReference)ref, shiftPressed, isDoubleClick);
 }
 
 void Gui::handleSingleClick() {
diff --git a/engines/macventure/gui.h b/engines/macventure/gui.h
index 93193afff2c..2bb88a5ea5c 100644
--- a/engines/macventure/gui.h
+++ b/engines/macventure/gui.h
@@ -344,6 +344,7 @@ private:
 
 	Common::Point _pos;
 	ClickState _state;
+	bool _shiftPressed;
 };
 
 
diff --git a/engines/macventure/macventure.cpp b/engines/macventure/macventure.cpp
index c4bc3f862d6..41615b197b3 100644
--- a/engines/macventure/macventure.cpp
+++ b/engines/macventure/macventure.cpp
@@ -401,7 +401,25 @@ void MacVentureEngine::handleObjectSelect(ObjID objID, WindowReference win, bool
 	const WindowData &windata = _gui->getWindowData(win);
 
 	if (shiftPressed) {
-		// TODO: Implement shift functionality.
+		if (objID == 0) {
+			objID = windata.objRef;
+		}
+		if (objID > 0) {
+			int selectedIndex = findObjectInArray(objID, _selectedObjs);
+			if (findObjectInArray(objID, _currentSelection) != -1) {
+				unselectObject(objID);
+				if (selectedIndex != -1) {
+					_selectedObjs.remove_at(selectedIndex);
+				}
+			} else {
+				selectObject(objID);
+				if (selectedIndex == -1) {
+					_selectedObjs.push_back(objID);
+				}
+			}
+			refreshReady();
+			preparedToRun();
+		}
 	} else {
 		if (_selectedControl && _currentSelection.size() > 0 && getInvolvedObjects() > 1) {
 			if (objID == 0) {


Commit: 75e982f71f10cb69114cb992a1d55c7bf1777552
    https://github.com/scummvm/scummvm/commit/75e982f71f10cb69114cb992a1d55c7bf1777552
Author: Ion Andrei Cristian (lecturatul2017 at gmail.com)
Date: 2026-08-14T18:46:30+02:00

Commit Message:
MACVENTURE: Return the documented range from the random opcode

The random opcode pushed a value between 0 and the popped maximum, but
the original returns a value below that maximum. Values equal to the
maximum are one past the end of whatever table or list the script indexes
with them.

Guard against a maximum of zero as well, since randBetween() takes
unsigned arguments and would otherwise be handed a huge range.

Changed paths:
    engines/macventure/script.cpp


diff --git a/engines/macventure/script.cpp b/engines/macventure/script.cpp
index c54d52ede63..b6484715709 100644
--- a/engines/macventure/script.cpp
+++ b/engines/macventure/script.cpp
@@ -604,7 +604,7 @@ void ScriptEngine::op8bSGLO(EngineState *state, EngineFrame *frame) {
 
 void ScriptEngine::op8cRAND(EngineState *state, EngineFrame *frame) {
 	int16 max = state->pop();
-	state->push(_engine->randBetween(0, max));
+	state->push(max > 0 ? _engine->randBetween(0, max - 1) : 0);
 }
 
 void ScriptEngine::op8dCOPY(EngineState *state, EngineFrame *frame) {


Commit: 67b63cf754075907849a90b85d906453da772eb1
    https://github.com/scummvm/scummvm/commit/67b63cf754075907849a90b85d906453da772eb1
Author: Ion Andrei Cristian (lecturatul2017 at gmail.com)
Date: 2026-08-14T18:46:30+02:00

Commit Message:
MACVENTURE: Let a command target the object it was invoked on

The destination object was pushed into the selection queue, so every
two-object command also ran on its own destination.  That was worked
around by skipping the destination while running the queue, which made
commands whose target is the source itself, such as operating the
flashlight in Deja Vu II, do nothing at all.

Keep the destination out of the queue and track it in the highlight
list instead, the way the original engine does.

Changed paths:
    engines/macventure/macventure.cpp


diff --git a/engines/macventure/macventure.cpp b/engines/macventure/macventure.cpp
index 41615b197b3..6b480dfbd33 100644
--- a/engines/macventure/macventure.cpp
+++ b/engines/macventure/macventure.cpp
@@ -405,17 +405,10 @@ void MacVentureEngine::handleObjectSelect(ObjID objID, WindowReference win, bool
 			objID = windata.objRef;
 		}
 		if (objID > 0) {
-			int selectedIndex = findObjectInArray(objID, _selectedObjs);
 			if (findObjectInArray(objID, _currentSelection) != -1) {
 				unselectObject(objID);
-				if (selectedIndex != -1) {
-					_selectedObjs.remove_at(selectedIndex);
-				}
 			} else {
 				selectObject(objID);
-				if (selectedIndex == -1) {
-					_selectedObjs.push_back(objID);
-				}
 			}
 			refreshReady();
 			preparedToRun();
@@ -582,9 +575,6 @@ bool MacVenture::MacVentureEngine::runScriptEngine() {
 	while (!_currentSelection.empty()) {
 		ObjID obj = _currentSelection.front();
 		_currentSelection.remove_at(0);
-		if (getInvolvedObjects() > 1 && obj == _destObject) {
-			continue;
-		}
 		if (isGameRunning() && _world->isObjActive(obj)) {
 			if (_scriptEngine->runControl(_selectedControl, obj, _destObject, _deltaPoint)) {
 				_haltedInSelection = true;
@@ -939,14 +929,20 @@ void MacVentureEngine::selectObject(ObjID objID) {
 	}
 	if (findObjectInArray(objID, _currentSelection) == -1) {
 		_currentSelection.push_back(objID);
+	}
+	if (findObjectInArray(objID, _selectedObjs) == -1) {
+		_selectedObjs.push_back(objID);
 		highlightExit(objID);
 	}
 }
 
 void MacVentureEngine::unselectObject(ObjID objID) {
-	int idxCur = findObjectInArray(objID, _currentSelection);
-	if (idxCur != -1) {
-		_currentSelection.remove_at(idxCur);
+	int idx = findObjectInArray(objID, _currentSelection);
+	if (idx != -1) {
+		_currentSelection.remove_at(idx);
+	}
+	if ((idx = findObjectInArray(objID, _selectedObjs)) != -1) {
+		_selectedObjs.remove_at(idx);
 		highlightExit(objID);
 	}
 }
@@ -1015,12 +1011,15 @@ void MacVentureEngine::selectPrimaryObject(ObjID objID) {
 	int idx;
 	debugC(4, kMVDebugMain, "Select primary object (%d)", objID);
 	if (_destObject > 0 &&
-		(idx = findObjectInArray(_destObject, _currentSelection)) != -1) {
-		unselectAll();
+		(idx = findObjectInArray(_destObject, _selectedObjs)) != -1 &&
+		findObjectInArray(_destObject, _currentSelection) == -1) {
+		_selectedObjs.remove_at(idx);
+		highlightExit(_destObject);
 	}
 	_destObject = objID;
-	if (findObjectInArray(_destObject, _currentSelection) == -1) {
-		selectObject(_destObject);
+	if (findObjectInArray(_destObject, _selectedObjs) == -1) {
+		_selectedObjs.push_back(_destObject);
+		highlightExit(_destObject);
 	}
 
 	_cmdReady = true;
@@ -1153,10 +1152,9 @@ void MacVentureEngine::reflectSwap(ObjID fromID, ObjID toID) {
 }
 
 void MacVentureEngine::toggleExits() {
-	Common::Array<ObjID> exits = _currentSelection;
-	while (!exits.empty()) {
-		ObjID obj = exits.front();
-		exits.remove_at(0);
+	while (!_selectedObjs.empty()) {
+		ObjID obj = _selectedObjs.back();
+		_selectedObjs.pop_back();
 		highlightExit(obj);
 		updateWindow(findParentWindow(obj));
 	}
@@ -1258,7 +1256,7 @@ bool MacVentureEngine::isObjDraggable(ObjID objID) {
 }
 
 bool MacVentureEngine::isObjSelected(ObjID objID) {
-	int idx = findObjectInArray(objID, _currentSelection);
+	int idx = findObjectInArray(objID, _selectedObjs);
 	return idx != -1;
 }
 


Commit: 678d78168011891067806b240c3adf8e0ba1b956
    https://github.com/scummvm/scummvm/commit/678d78168011891067806b240c3adf8e0ba1b956
Author: Ion Andrei Cristian (lecturatul2017 at gmail.com)
Date: 2026-08-14T18:46:30+02:00

Commit Message:
MACVENTURE: Do not drop object updates while a window is queued

Object updates were skipped when the object already had any entry in the
queue, but the queue also holds window entries, which are dispatched
after the updates.  While one of those was pending, the object could
change again without the world ever telling its window, so the object
only showed up once the room was entered anew.

Changed paths:
    engines/macventure/macventure.cpp


diff --git a/engines/macventure/macventure.cpp b/engines/macventure/macventure.cpp
index 6b480dfbd33..9bbbbf1f9c0 100644
--- a/engines/macventure/macventure.cpp
+++ b/engines/macventure/macventure.cpp
@@ -1167,7 +1167,7 @@ void MacVentureEngine::zoomObject(ObjID objID) {
 bool MacVentureEngine::isObjEnqueued(ObjID objID) {
 	Common::Array<QueuedObject>::const_iterator it;
 	for (it = _objQueue.begin(); it != _objQueue.end(); it++) {
-		if ((*it).object == objID) {
+		if ((*it).id == kUpdateObject && (*it).object == objID) {
 			return true;
 		}
 	}


Commit: a5f5989f921626bbd4c38f53cf108e06bab70cd4
    https://github.com/scummvm/scummvm/commit/a5f5989f921626bbd4c38f53cf108e06bab70cd4
Author: Ion Andrei Cristian (lecturatul2017 at gmail.com)
Date: 2026-08-14T18:46:30+02:00

Commit Message:
MACVENTURE: Give dialog buttons the press feedback of the original

A dialog button ran its action as soon as the mouse went down on it, and
never showed that it was being held.  The original inverts the button
while it is pressed, de-inverts it when the pointer leaves it, and only
acts once the button is released inside its bounds, so a misplaced press
can still be taken back by dragging away before letting go.

The action is tied to a press that started on the same button, so that a
release left over from whatever opened the dialog cannot trigger one.

Changed paths:
    engines/macventure/dialog.cpp
    engines/macventure/dialog.h


diff --git a/engines/macventure/dialog.cpp b/engines/macventure/dialog.cpp
index a0e44b4beb9..f73ca8751e0 100644
--- a/engines/macventure/dialog.cpp
+++ b/engines/macventure/dialog.cpp
@@ -280,15 +280,30 @@ const Common::String &DialogElement::doGetText() {
 // CONCRETE DIALOG ELEMENTS
 
 DialogButton::DialogButton(Dialog *dialog, Common::String title, DialogAction action, Common::Point position, uint width, uint height):
-	DialogElement(dialog, title, action, position, width, height, Graphics::kTextAlignCenter) {}
+	DialogElement(dialog, title, action, position, width, height, Graphics::kTextAlignCenter),
+	_pressed(false), _mouseOverPressed(false) {}
 
 bool DialogButton::doProcessEvent(MacVenture::Dialog *dialog, Common::Event event) {
 	Common::Point mouse = event.mouse;
+	dialog->localize(mouse);
+
 	if (event.type == Common::EVENT_LBUTTONDOWN) {
-		dialog->localize(mouse);
 		if (_bounds.contains(mouse)) {
-			debugC(2, kMVDebugGUI, "Click! Button: %s", _text.c_str());
-			dialog->handleDialogAction(this, _action);
+			_pressed = true;
+			_mouseOverPressed = true;
+			return true;
+		}
+	} else if (event.type == Common::EVENT_MOUSEMOVE) {
+		if (_pressed) {
+			_mouseOverPressed = _bounds.contains(mouse);
+		}
+	} else if (event.type == Common::EVENT_LBUTTONUP) {
+		if (_pressed) {
+			_pressed = false;
+			if (_bounds.contains(mouse)) {
+				debugC(2, kMVDebugGUI, "Click! Button: %s", _text.c_str());
+				dialog->handleDialogAction(this, _action);
+			}
 			return true;
 		}
  	}
@@ -296,11 +311,13 @@ bool DialogButton::doProcessEvent(MacVenture::Dialog *dialog, Common::Event even
 }
 
 void DialogButton::doDraw(MacVenture::Dialog *dialog, Graphics::ManagedSurface &target) {
-	target.fillRect(_bounds, kColorWhite);
+	bool invert = _pressed && _mouseOverPressed;
+
+	target.fillRect(_bounds, invert ? kColorBlack : kColorWhite);
 	target.frameRect(_bounds, kColorBlack);
 	// Draw title
 	dialog->getFont().drawString(
-		&target, _text, _bounds.left, _bounds.top, _bounds.width(), kColorBlack, Graphics::kTextAlignCenter);
+		&target, _text, _bounds.left, _bounds.top, _bounds.width(), invert ? kColorWhite : kColorBlack, Graphics::kTextAlignCenter);
 }
 
 DialogPlainText::DialogPlainText(Dialog *dialog, Common::String content, Common::Point position, int width, int height, Graphics::TextAlign alignment) :
diff --git a/engines/macventure/dialog.h b/engines/macventure/dialog.h
index 9a88982b8fa..a6cee6c189d 100644
--- a/engines/macventure/dialog.h
+++ b/engines/macventure/dialog.h
@@ -113,6 +113,9 @@ public:
 private:
 	bool doProcessEvent(Dialog *dialog, Common::Event event) override;
 	void doDraw(MacVenture::Dialog *dialog, Graphics::ManagedSurface &target) override;
+
+	bool _pressed;
+	bool _mouseOverPressed;
 };
 
 class DialogPlainText : public DialogElement {




More information about the Scummvm-git-logs mailing list