[Scummvm-git-logs] scummvm master -> 246d7e7532bfd98b08017b9cfd8d9a5001cd3717

dreammaster noreply at scummvm.org
Sat Oct 10 05:47:33 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:
246d7e7532 MADS: Fix Phantom/Dragonsphere engine lifecycle


Commit: 246d7e7532bfd98b08017b9cfd8d9a5001cd3717
    https://github.com/scummvm/scummvm/commit/246d7e7532bfd98b08017b9cfd8d9a5001cd3717
Author: fusefib (fibofuse at gmail.com)
Date: 2026-10-10T16:43:13+11:00

Commit Message:
MADS: Fix Phantom/Dragonsphere engine lifecycle

Fixes #17306

Changed paths:
    engines/mads/core/game.cpp
    engines/mads/core/kernel.cpp
    engines/mads/core/kernel.h


diff --git a/engines/mads/core/game.cpp b/engines/mads/core/game.cpp
index b59a4634bf5..928f51e7aca 100644
--- a/engines/mads/core/game.cpp
+++ b/engines/mads/core/game.cpp
@@ -1546,6 +1546,7 @@ static void game_system_maintenance() {
  * Calls, in proper order, all daemon code for this framing round.
  */
 static void game_daemon_code() {
+	kernel_animations_begin_daemon();
 	kernel.trigger_setup_mode = KERNEL_TRIGGER_DAEMON;
 
 	game_exec_function(room_daemon_code_pointer);
@@ -1815,8 +1816,11 @@ static void game_main_loop() {
 	// Update any active graphics sequences
 	kernel_seq_update_all();
 
-	// Update any active animations
-	kernel_process_all_animations();
+	// Phantom and Dragonsphere scripts use daemon-observed frames for holds and handoffs.
+	// Preserve each newly exposed frame until that daemon can observe it.
+	// Otherwise, update any active animations as before.
+	kernel_process_all_animations(g_engine->getGameID() == GType_Phantom ||
+		g_engine->getGameID() == GType_Dragonsphere);
 
 	// Special mouse cursor update mode
 	if (kernel.mouse_cursor_point) {
diff --git a/engines/mads/core/kernel.cpp b/engines/mads/core/kernel.cpp
index 1e602b4d4ff..2c65d57a372 100644
--- a/engines/mads/core/kernel.cpp
+++ b/engines/mads/core/kernel.cpp
@@ -1313,9 +1313,17 @@ void kernel_animation_init() {
 		kernel_anim[count].anim = NULL;
 		kernel_anim[count].cycled = false;
 		kernel_anim[count].repeat = false;
+		kernel_anim[count].awaiting_daemon = false;
 	}
 }
 
+void kernel_animations_begin_daemon() {
+	// Clear before calling room code, not after: an explicit update from that
+	// code may expose another frame that still needs the next daemon pass.
+	for (int count = 0; count < KERNEL_MAX_ANIMATIONS; ++count)
+		kernel_anim[count].awaiting_daemon = false;
+}
+
 int kernel_run_animation(const char *name, int trigger_code) {
 	int found = -1;
 	int error_flag = true;
@@ -1395,6 +1403,8 @@ int kernel_run_animation(const char *name, int trigger_code) {
 	error_flag = false;
 
 	kernel_anim[found].last_frame = -1;
+	// A new animation may render its initial frame, including during a fade.
+	kernel_anim[found].awaiting_daemon = false;
 
 done:
 	if (error_flag) {
@@ -1496,6 +1506,9 @@ void kernel_reset_animation(int handle, int frame) {
 		kernel_anim[handle].frame = frame;
 		kernel_anim[handle].image = 0;
 		kernel_anim[handle].doomed = false;
+		// A script-selected frame is an explicit transition, not an unobserved
+		// automatic advance. Preserve parser releases and cross-actor handoffs.
+		kernel_anim[handle].awaiting_daemon = false;
 	}
 }
 
@@ -1734,6 +1747,9 @@ static void kernel_process_animation(int handle, int asynchronous) {
 	kernel_anim[handle].frame++;
 
 	if (!asynchronous) {
+		// Screen reconstruction uses the asynchronous path and must not create
+		// or consume a daemon observation for the live animation.
+		kernel_anim[handle].awaiting_daemon = true;
 		if (kernel_anim[handle].frame == kernel_anim[handle].anim->num_frames) {
 			if (kernel_anim[handle].trigger_code) {
 				kernel.trigger = kernel_anim[handle].trigger_code;
@@ -1754,12 +1770,18 @@ done:
 	;
 }
 
-void kernel_process_all_animations() {
+void kernel_process_all_animations(bool require_daemon) {
 	int count;
 	int ok_to_update;
 
 	for (count = 0; count < KERNEL_MAX_ANIMATIONS; count++) {
 		if (kernel_anim[count].anim != NULL) {
+			// Do not cross two automatic frame boundaries without giving the
+			// room its daemon pass. FX may bypass trigger delivery restrictions,
+			// but must not bypass this per-animation observation requirement.
+			if (require_daemon && kernel_anim[count].awaiting_daemon)
+				continue;
+
 			ok_to_update = (kernel.fx || !kernel.trigger ||
 				(kernel_anim[count].frame != kernel_anim[count].anim->num_frames - 1));
 			if (ok_to_update) {
@@ -1841,6 +1863,7 @@ void kernel_abort_animation(int handle) {
 	}
 
 	kernel_anim[handle].doomed = false;
+	kernel_anim[handle].awaiting_daemon = false;
 
 	go_ahead_and_frag_the_palette();
 }
diff --git a/engines/mads/core/kernel.h b/engines/mads/core/kernel.h
index 391d3c16dac..1308d359ded 100644
--- a/engines/mads/core/kernel.h
+++ b/engines/mads/core/kernel.h
@@ -243,7 +243,7 @@ struct Animation {
 	int     repeat;                     /* Animation should repeat continuously */
 	int     cycled;                     /* Animation has cycled back to start   */
 	int     sprite_loaded;              /* Current sprite loaded (for streamers)*/
-	byte *buffer[2];                /* Double buffering pointers (streamers)*/
+	byte    *buffer[2];                 /* Double buffering pointers (streamers)*/
 	int     buffer_id;                  /* Double buffering index    (streamers)*/
 	int     messages;                   /* Messages currently active from anim  */
 	int     frame;                      /* Current frame                        */
@@ -261,6 +261,8 @@ struct Animation {
 	int     dynamic_hotspot;            /* Attached dynamic hotspot             */
 
 	int     last_frame;                 /* Most recent frame viewed             */
+
+	bool    awaiting_daemon;            /* Current frame still needs daemon pass*/
 };
 
 
@@ -531,7 +533,17 @@ extern void kernel_abort_animation(int handle);
 extern void kernel_abort_all_animations();
 extern void kernel_doom_all_animations();
 extern void kernel_abort_doomed_animations();
-extern void kernel_process_all_animations();
+
+/**
+ * A daemon pass observes frames that were pending before the pass began.
+ */
+extern void kernel_animations_begin_daemon();
+
+/**
+ * Explicit updates (menus and in-daemon handoffs) retain their old behavior.
+ * Phantom/Dragonsphere game loops require daemon observation between automatic steps.
+ */
+extern void kernel_process_all_animations(bool require_daemon = false);
 extern void kernel_message_init();
 extern int  kernel_message_add(char *text, int x, int y, int color,
 	long time_on_screen, int trigger_code, int flags);




More information about the Scummvm-git-logs mailing list