[Scummvm-git-logs] scummvm master -> 1679f1018984eadc65c569613b56c9d3bf25b1ba

djsrv dservilla at gmail.com
Fri Jun 26 17:23:05 UTC 2020


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

Summary:
1679f10189 DIRECTOR: LINGO: Implement event passing


Commit: 1679f1018984eadc65c569613b56c9d3bf25b1ba
    https://github.com/scummvm/scummvm/commit/1679f1018984eadc65c569613b56c9d3bf25b1ba
Author: djsrv (dservilla at gmail.com)
Date: 2020-06-26T13:22:15-04:00

Commit Message:
DIRECTOR: LINGO: Implement event passing

Changed paths:
    engines/director/lingo/lingo-builtins.cpp
    engines/director/lingo/lingo-events.cpp
    engines/director/lingo/lingo.cpp
    engines/director/lingo/lingo.h


diff --git a/engines/director/lingo/lingo-builtins.cpp b/engines/director/lingo/lingo-builtins.cpp
index 5c7a6b5802..c320961647 100644
--- a/engines/director/lingo/lingo-builtins.cpp
+++ b/engines/director/lingo/lingo-builtins.cpp
@@ -1095,7 +1095,7 @@ void LB::b_continue(int nargs) {
 }
 
 void LB::b_dontPassEvent(int nargs) {
-	g_lingo->_dontPassEvent = true;
+	g_lingo->_passEvent = false;
 	warning("dontPassEvent raised");
 }
 
@@ -1181,9 +1181,8 @@ void LB::b_halt(int nargs) {
 }
 
 void LB::b_pass(int nargs) {
-	g_lingo->printSTUBWithArglist("b_pass", nargs);
-
-	g_lingo->dropStack(nargs);
+	g_lingo->_passEvent = true;
+	warning("pass raised");
 }
 
 void LB::b_pause(int nargs) {
diff --git a/engines/director/lingo/lingo-events.cpp b/engines/director/lingo/lingo-events.cpp
index 187e7d95a8..59b089f3f7 100644
--- a/engines/director/lingo/lingo-events.cpp
+++ b/engines/director/lingo/lingo-events.cpp
@@ -107,33 +107,7 @@ void Lingo::setPrimaryEventHandler(LEvent event, const Common::String &code) {
 	addCode(code.c_str(), kArchMain, kGlobalScript, event);
 }
 
-void Lingo::primaryEventHandler(LEvent event) {
-	/* When an event occurs the message [...] is first sent to a
-	 * primary event handler: [... if exists it is executed] and the
-	 * event is passed on to other objects unless you explicitly stop
-	 * the message by including the dontPassEventCommand in the script
-	 * [D4 docs page 77]
-	 */
-	/* N.B.: No primary event handlers for events other than
-	 * keyup, keydown, mouseup, mousedown, timeout
-	 * [see: www.columbia.edu/itc/visualarts/r4110/s2001/handouts
-	 * /03_03_Event_Hierarchy.pdf]
-	 */
-	switch (event) {
-	case kEventMouseDown:
-	case kEventMouseUp:
-	case kEventKeyUp:
-	case kEventKeyDown:
-	case kEventTimeout:
-		debugC(3, kDebugLingoExec, "calling primary event handler (%s)", _eventHandlerTypes[event]);
-		executeScript(kGlobalScript, event);
-		break;
-	default:
-		break;
-	}
-}
-
-void Lingo::registerSpriteEvent(LEvent event, int spriteId) {
+void Lingo::queueSpriteEvent(LEvent event, int eventId, int spriteId) {
 	/* When the mouseDown or mouseUp occurs over a sprite, the message
 	 * goes first to the sprite script, then to the script of the cast
 	 * member, to the frame script and finally to the movie scripts.
@@ -156,14 +130,12 @@ void Lingo::registerSpriteEvent(LEvent event, int spriteId) {
 			// If sprite is immediate, its script is run on mouseDown, otherwise on mouseUp
 			if ((event == kEventMouseDown && sprite->_immediate)
 					|| (event == kEventMouseUp && !sprite->_immediate)) {
-				_eventQueue.push(LingoEvent(kEventNone, kArchMain, kScoreScript, sprite->_scriptId, spriteId));
-				return;
+				_eventQueue.push(LingoEvent(kEventNone, eventId, kArchMain, kScoreScript, sprite->_scriptId, false, spriteId));
 			}
 		} else {
 			ScriptContext *script = getScriptContext(kArchMain, kScoreScript, sprite->_scriptId);
 			if (script && script->_eventHandlers.contains(event)) {
-				_eventQueue.push(LingoEvent(event, kArchMain, kScoreScript, sprite->_scriptId, spriteId));
-				return;
+				_eventQueue.push(LingoEvent(event, eventId, kArchMain, kScoreScript, sprite->_scriptId, false, spriteId));
 			}
 		}
 	}
@@ -176,15 +148,11 @@ void Lingo::registerSpriteEvent(LEvent event, int spriteId) {
 		script = getScriptContext(archiveIndex, kCastScript, sprite->_castId);
 	}
 	if (script && script->_eventHandlers.contains(event)) {
-		_eventQueue.push(LingoEvent(event, archiveIndex, kCastScript, sprite->_castId, spriteId));
-		return;
+		_eventQueue.push(LingoEvent(event, eventId, archiveIndex, kCastScript, sprite->_castId, false, spriteId));
 	}
-
-	// Delegate to the frame
-	registerFrameEvent(event);	
 }
 
-void Lingo::registerFrameEvent(LEvent event) {
+void Lingo::queueFrameEvent(LEvent event, int eventId) {
 	/* [in D4] the enterFrame, exitFrame, idle and timeout messages
 	 * are sent to a frame script and then a movie script.	If the
 	 * current frame has no frame script when the event occurs, the
@@ -202,15 +170,11 @@ void Lingo::registerFrameEvent(LEvent event) {
 	int scriptId = score->_frames[score->getCurrentFrame()]->_actionId;
 
 	if (scriptId) {
-		_eventQueue.push(LingoEvent(event, kArchMain, kScoreScript, scriptId));
-		return;
+		_eventQueue.push(LingoEvent(event, eventId, kArchMain, kScoreScript, scriptId, false));
 	}
-
-	// Delegate to the movie
-	registerMovieEvent(event);
 }
 
-void Lingo::registerMovieEvent(LEvent event) {
+void Lingo::queueMovieEvent(LEvent event, int eventId) {
 	/* If more than one movie script handles the same message, Lingo
 	 * searches the movie scripts according to their order in the cast
 	 * window [p.81 of D4 docs]
@@ -223,59 +187,89 @@ void Lingo::registerMovieEvent(LEvent event) {
 	for (ScriptContextHash::iterator it = _archives[kArchMain].scriptContexts[kMovieScript].begin();
 			it != _archives[kArchMain].scriptContexts[kMovieScript].end(); ++it) {
 		if (it->_value->_eventHandlers.contains(event)) {
-			_eventQueue.push(LingoEvent(event, kArchMain, kMovieScript, it->_key));
+			_eventQueue.push(LingoEvent(event, eventId, kArchMain, kMovieScript, it->_key, false));
 			return;
 		}
 	}
 	for (ScriptContextHash::iterator it = _archives[kArchShared].scriptContexts[kMovieScript].begin();
 			it != _archives[kArchShared].scriptContexts[kMovieScript].end(); ++it) {
 		if (it->_value->_eventHandlers.contains(event)) {
-			_eventQueue.push(LingoEvent(event, kArchShared, kMovieScript, it->_key));
+			_eventQueue.push(LingoEvent(event, eventId, kArchShared, kMovieScript, it->_key, false));
 			return;
 		}
 	}
-
-	debugC(9, kDebugEvents, "Lingo::registerEvent(%s): no handler", _eventHandlerTypes[event]);
 }
 
 void Lingo::registerEvent(LEvent event, int spriteId) {
-	primaryEventHandler(event);
+	int eventId = _nextEventId++;
+	if (_nextEventId < 0)
+		_nextEventId = 0;
 
-	if (_dontPassEvent) {
-		_dontPassEvent = false;
-		return;
+	int oldQueueSize = _eventQueue.size();
+
+	/* When an event occurs the message [...] is first sent to a
+	 * primary event handler: [... if exists it is executed] and the
+	 * event is passed on to other objects unless you explicitly stop
+	 * the message by including the dontPassEvent command in the script
+	 * [D4 docs page 77]
+	 */
+	/* N.B.: No primary event handlers for events other than
+	 * keyup, keydown, mouseup, mousedown, timeout
+	 * [see: www.columbia.edu/itc/visualarts/r4110/s2001/handouts
+	 * /03_03_Event_Hierarchy.pdf]
+	 */
+	switch (event) {
+	case kEventMouseDown:
+	case kEventMouseUp:
+	case kEventKeyUp:
+	case kEventKeyDown:
+	case kEventTimeout:
+		if (getScriptContext(kArchMain, kGlobalScript, event)) {
+			_eventQueue.push(LingoEvent(kEventNone, eventId, kArchMain, kGlobalScript, event, true));
+		}
+		break;
+	default:
+		break;
 	}
 
+	/* Now queue any objects that responds to this event, in order of precedence.
+	 *   (Sprite -> Cast Member -> Frame -> Movie)
+	 * Once one of these objects handles the event, any event handlers queued
+	 * for the same event will be ignored unless the pass command was called.
+	 */
 	switch (event) {
-		case kEventKeyUp:
-		case kEventKeyDown:
-		case kEventMouseUp:
-		case kEventMouseDown:
-		case kEventBeginSprite:
-			if (spriteId) {
-				registerSpriteEvent(event, spriteId);
-				break;
-			}
-			// fall through
+	case kEventKeyUp:
+	case kEventKeyDown:
+	case kEventMouseUp:
+	case kEventMouseDown:
+	case kEventBeginSprite:
+		if (spriteId) {
+			queueSpriteEvent(event, eventId, spriteId);
+		}
+		// fall through
+
+	case kEventIdle:
+	case kEventEnterFrame:
+	case kEventExitFrame:
+	case kEventNone:
+		queueFrameEvent(event, eventId);
+		// fall through
+
+	case kEventStart:
+	case kEventStartUp:
+	case kEventStartMovie:
+	case kEventStopMovie:
+	case kEventTimeout:
+	case kEventPrepareMovie:
+		queueMovieEvent(event, eventId);
+		break;
 
-		case kEventIdle:
-		case kEventEnterFrame:
-		case kEventExitFrame:
-		case kEventNone:
-			registerFrameEvent(event);
-			break;
-
-		case kEventStart:
-		case kEventStartUp:
-		case kEventStartMovie:
-		case kEventStopMovie:
-		case kEventTimeout:
-		case kEventPrepareMovie:
-			registerMovieEvent(event);
-			break;
+	default:
+		warning("registerEvent: Unhandled event %s", _eventHandlerTypes[event]);
+	}
 
-		default:
-			warning("registerEvent: Unhandled event %s", _eventHandlerTypes[event]);
+	if (oldQueueSize == _eventQueue.size()) {
+		debugC(9, kDebugEvents, "Lingo::registerEvent(%s): no event handler", _eventHandlerTypes[event]);
 	}
 }
 
@@ -285,13 +279,20 @@ void Lingo::processEvent(LEvent event, int spriteId) {
 }
 
 void Lingo::processEvents() {
+	int lastEventId = -1;
+
 	while (!_eventQueue.empty()) {
 		LingoEvent el = _eventQueue.pop();
 
 		if (_vm->getCurrentScore()->_stopPlay && el.event != kEventStopMovie)
 			continue;
 
-		processEvent(el.event, el.archiveIndex, el.st, el.scriptId, el.channelId);
+		if (lastEventId == el.eventId && !_passEvent)
+			continue;
+
+		_passEvent = el.passByDefault;
+		processEvent(el.event, el.archiveIndex, el.scriptType, el.scriptId, el.channelId);
+		lastEventId = el.eventId;
 	}
 }
 
diff --git a/engines/director/lingo/lingo.cpp b/engines/director/lingo/lingo.cpp
index 7e41fc81df..dcb0752422 100644
--- a/engines/director/lingo/lingo.cpp
+++ b/engines/director/lingo/lingo.cpp
@@ -155,10 +155,11 @@ Lingo::Lingo(DirectorEngine *vm) : _vm(vm) {
 
 	_localvars = NULL;
 
-	_dontPassEvent = false;
-
 	_archiveIndex = kArchMain;
 
+	// events
+	_nextEventId = 0;
+	_passEvent = false;
 	_perFrameHook = Datum();
 
 	initEventHandlerTypes();
diff --git a/engines/director/lingo/lingo.h b/engines/director/lingo/lingo.h
index fc69d149bb..89231416ee 100644
--- a/engines/director/lingo/lingo.h
+++ b/engines/director/lingo/lingo.h
@@ -332,16 +332,20 @@ struct CFrame {	/* proc/func call stack frame */
 
 struct LingoEvent {
 	LEvent event;
+	int eventId;
 	int archiveIndex;
-	ScriptType st;
+	ScriptType scriptType;
 	int scriptId;
+	bool passByDefault;
 	int channelId;
 
-	LingoEvent (LEvent e, int ai, ScriptType s, int si, int ci = -1) {
+	LingoEvent (LEvent e, int ei, int ai, ScriptType st, int si, bool pass, int ci = -1) {
 		event = e;
+		eventId = ei;
 		archiveIndex = ai;
-		st = s;
+		scriptType = st;
 		scriptId = si;
+		passByDefault = pass;
 		channelId = ci;
 	}
 };
@@ -403,12 +407,12 @@ private:
 private:
 	void initEventHandlerTypes();
 	void setPrimaryEventHandler(LEvent event, const Common::String &code);
-	void primaryEventHandler(LEvent event);
-	void registerSpriteEvent(LEvent event, int spriteId);
-	void registerFrameEvent(LEvent event);
-	void registerMovieEvent(LEvent event);
+	void queueSpriteEvent(LEvent event, int eventId, int spriteId);
+	void queueFrameEvent(LEvent event, int eventId);
+	void queueMovieEvent(LEvent event, int eventId);
 	void processEvent(LEvent event, int archiveIndex, ScriptType st, int entityId, int channelId = -1);
 
+	int _nextEventId;
 	Common::Queue<LingoEvent> _eventQueue;
 
 public:
@@ -541,7 +545,6 @@ public:
 	Common::HashMap<Common::String, VarType, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> *_methodVarsStash;
 
 public:
-	uint16 _currentEntityId;
 	int _currentChannelId;
 	ScriptContext *_currentScriptContext;
 	ScriptData *_currentScript;
@@ -606,8 +609,8 @@ public:
 
 	int _floatPrecision;
 
-	bool _dontPassEvent;
-
+	// events
+	bool _passEvent;
 	Datum _perFrameHook;
 
 public:




More information about the Scummvm-git-logs mailing list