[Scummvm-git-logs] scummvm master -> 71efbea57e9727fb3a228bcc15379cc33b3634f1

dreammaster noreply at scummvm.org
Mon Jun 22 08:20:52 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:
68ab7092cd MADS: FOREST: Workaround for crash using invalid series_id
d2dbf7c0df MADS: FOREST: Implementing custom Forest interface
71efbea57e NEWS: Added MM engine section for Scorp's PRs that was previously missing


Commit: 68ab7092cdf3363d2b242104cda5063d5230e6ea
    https://github.com/scummvm/scummvm/commit/68ab7092cdf3363d2b242104cda5063d5230e6ea
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-06-22T18:20:23+10:00

Commit Message:
MADS: FOREST: Workaround for crash using invalid series_id

Changed paths:
    engines/mads/madsv2/core/matte.cpp


diff --git a/engines/mads/madsv2/core/matte.cpp b/engines/mads/madsv2/core/matte.cpp
index 06dc11664e6..fc302390d8c 100644
--- a/engines/mads/madsv2/core/matte.cpp
+++ b/engines/mads/madsv2/core/matte.cpp
@@ -889,10 +889,13 @@ void matte_frame(int special_effect, int full_screen) {
 	// Now, run through our depth list, and for each entry, draw the
 	// indicated sprite into the work buffer.
 	for (id = 0; id < depth_size; id++) {
-
 		// Get the index for the series for this depth list entry
 		id2 = depth_list_id[id];
 
+		// WORKAROUND: Invalid series_id
+		if (image_list[id2].series_id == (byte)-1)
+			continue;
+
 		// Draw the sprite into the work buffer at the appropriate depth
 		if (image_list[id2].scale >= 100) {
 			if (image_list[id2].scale == IMAGE_UNSCALED) {


Commit: d2dbf7c0df11ddc3123f8bec4d50ae7374961837
    https://github.com/scummvm/scummvm/commit/d2dbf7c0df11ddc3123f8bec4d50ae7374961837
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-06-22T18:20:23+10:00

Commit Message:
MADS: FOREST: Implementing custom Forest interface

Changed paths:
    engines/mads/madsv2/core/anim.cpp
    engines/mads/madsv2/core/anim.h
    engines/mads/madsv2/core/game.cpp
    engines/mads/madsv2/core/game.h
    engines/mads/madsv2/engine.cpp
    engines/mads/madsv2/forest/extra.cpp
    engines/mads/madsv2/forest/extra.h
    engines/mads/madsv2/forest/global.cpp


diff --git a/engines/mads/madsv2/core/anim.cpp b/engines/mads/madsv2/core/anim.cpp
index 6463112d948..f4d7a792ea0 100644
--- a/engines/mads/madsv2/core/anim.cpp
+++ b/engines/mads/madsv2/core/anim.cpp
@@ -78,7 +78,11 @@ void Speech::load(Common::SeekableReadStream *src) {
 }
 
 void ImageInter::load(Common::SeekableReadStream *src) {
-	src->readMultipleLE(flags, segment_id, series_id, sprite_id, x, y);
+	src->readMultipleLE(flags, segment_id, series_id, sprite_id);
+	src->skip(1);
+	x = src->readSint16LE();
+	y = src->readByte();
+	src->skip(1);
 }
 
 void Frame::load(Common::SeekableReadStream *src) {
diff --git a/engines/mads/madsv2/core/anim.h b/engines/mads/madsv2/core/anim.h
index 2385b8bba9a..453fccf6e40 100644
--- a/engines/mads/madsv2/core/anim.h
+++ b/engines/mads/madsv2/core/anim.h
@@ -237,10 +237,12 @@ struct ImageInter {
 	byte segment_id;
 	byte series_id;
 	byte sprite_id;
+	// byte padding
 	int16 x;
 	byte y;
+	// byte padding
 
-	static constexpr int SIZE = 2 + 1 + 1 + 1 + 2 + 1;
+	static constexpr int SIZE = 2 + 1 + 1 + 1 + 1 + 2 + 1 + 1;
 	void load(Common::SeekableReadStream *src);
 };
 typedef ImageInter *ImageInterPtr;
diff --git a/engines/mads/madsv2/core/game.cpp b/engines/mads/madsv2/core/game.cpp
index 9e2118ef213..610549274bb 100644
--- a/engines/mads/madsv2/core/game.cpp
+++ b/engines/mads/madsv2/core/game.cpp
@@ -109,7 +109,6 @@ int debugger_memory_all = false;    /* Not showing ALL memory  */
 int debugger_memory_keywait = false;    /* Not waiting for memory  */
 void (*debugger_reset)() = NULL;     /* Debugger reset routine  */
 void (*debugger_update)() = NULL;     /* Debugger update routine */
-int int_sprite[6];
 int selected_intro = false;
 long correction_clock;
 
@@ -1286,7 +1285,8 @@ void game_control() {
 	}
 
 	// Game level control loop
-	int_sprite[fx_int_journal] = -1;
+	if (g_engine->getGameID() == GType_Forest)
+		Forest::int_sprite[Forest::fx_int_journal] = -1;
 
 	while (game.going) {
 
@@ -1371,32 +1371,21 @@ void game_control() {
 				if (player.walker_is_loaded) {
 					player_dump_walker();
 				}
-#if 0
-				if (int_sprite[fx_int_journal] != -1 && room_id != KERNEL_RESTORING_GAME) {
-					matte_deallocate_series(int_sprite[fx_int_candle_on], true);
-					matte_deallocate_series(int_sprite[fx_int_dooropen], true);
-					matte_deallocate_series(int_sprite[fx_int_exit], true);
-					matte_deallocate_series(int_sprite[fx_int_candle], true);
-					matte_deallocate_series(int_sprite[fx_int_backpack], true);
-					matte_deallocate_series(int_sprite[fx_int_journal], true);
-					int_sprite[fx_int_journal] = -1;
+
+				if (g_engine->getGameID() == GType_Forest) {
+					if (room_id != KERNEL_RESTORING_GAME)
+						Forest::unload_interface();
+
+					g_engine->section_music(section_id);
 				}
 
-				g_engine->section_music(section_id);
-#endif
 				pal_init(KERNEL_RESERVED_LOW_COLORS, KERNEL_RESERVED_HIGH_COLORS);
 
 				matte_init(true);
-#if 0
-				if (!player.walker_is_loaded) {
-					int_sprite[fx_int_journal] = kernel_load_series("*journal", false);
-					int_sprite[fx_int_backpack] = kernel_load_series("*backpack", false);
-					int_sprite[fx_int_candle] = kernel_load_series("*candle", false);
-					int_sprite[fx_int_exit] = kernel_load_series("*door", false);
-					int_sprite[fx_int_dooropen] = kernel_load_series("*dooropen", false);
-					int_sprite[fx_int_candle_on] = kernel_load_series("*candleon", false);
-				}
-#endif
+
+				if (!player.walker_is_loaded && g_engine->getGameID() == GType_Forest)
+					Forest::load_interface();
+
 			} else {
 				player_preserve_palette();
 #if 0
@@ -1492,20 +1481,10 @@ void game_control() {
 				kernel_set_interface_mode(INTER_LIMITED_SENTENCES);
 
 			game_exec_function(room_init_code_pointer);
-#if 0
-			// paul - oh no! magic numbers!
-			stamp_sprite_to_interface(BP_X, BP_Y, 1, int_sprite[fx_int_backpack]);
-			if (global[5]) {  // candle_is_on
-				stamp_sprite_to_interface(CANDLE_X, CANDLE_Y, 1, int_sprite[fx_int_candle_on]);
-			} else {
-				stamp_sprite_to_interface(CANDLE_X, CANDLE_Y, 1, int_sprite[fx_int_candle]);
-			}
-			stamp_sprite_to_interface(DOOR_X, DOOR_Y, 1, int_sprite[fx_int_exit]);
 
-			if (room_id != 199) {  // Taranjeet, if this is not journal room
-				stamp_sprite_to_interface(JOURNAL_X, JOURNAL_Y, 1, int_sprite[fx_int_journal]);
-			}
-#endif
+			if (g_engine->getGameID() == GType_Forest)
+				Forest::draw_interface();
+
 			scr_work.data = buffer_pointer(&scr_main, 0, viewing_at_y);
 			if (viewing_at_y) {
 				buffer_rect_fill(scr_main, 0, 0, video_x, viewing_at_y, 0);
@@ -1612,17 +1591,8 @@ emergency:
 			kernel_unload_all_series();
 		}
 
-		if (room_id != KERNEL_RESTORING_GAME && g_engine->getGameID() == GType_Forest) {
-			if (int_sprite[fx_int_journal] != -1) {
-				matte_deallocate_series(int_sprite[fx_int_candle_on], true);
-				matte_deallocate_series(int_sprite[fx_int_dooropen], true);
-				matte_deallocate_series(int_sprite[fx_int_exit], true);
-				matte_deallocate_series(int_sprite[fx_int_candle], true);
-				matte_deallocate_series(int_sprite[fx_int_backpack], true);
-				matte_deallocate_series(int_sprite[fx_int_journal], true);
-				int_sprite[fx_int_journal] = -1;
-			}
-		}
+		if (room_id != KERNEL_RESTORING_GAME && g_engine->getGameID() == GType_Forest)
+			Forest::unload_interface();
 
 		pal_unlock();
 
@@ -3004,7 +2974,6 @@ void init_game() {
 	debugger_memory_keywait = false;
 	debugger_reset = NULL;
 	debugger_update = NULL;
-	memset(int_sprite, 0, sizeof(int_sprite));
 	selected_intro = false;
 	correction_clock = 0;
 	memset(save_game_key, 0, sizeof(save_game_key));
diff --git a/engines/mads/madsv2/core/game.h b/engines/mads/madsv2/core/game.h
index eaf730a697f..2755de20a9c 100644
--- a/engines/mads/madsv2/core/game.h
+++ b/engines/mads/madsv2/core/game.h
@@ -95,18 +95,8 @@ namespace MADSV2 {
 #define DEBUGGER_MAX_WATCH      12
 
 
-extern int int_sprite[6];
-
 extern int selected_intro;
 
-#define fx_int_journal          0
-#define fx_int_backpack         1
-#define fx_int_candle           2
-#define fx_int_exit             3
-#define fx_int_dooropen         4
-#define fx_int_candle_on        5
-
-
 #define EXTRA_MAX_INV_OBJECTS 18   /* 16, + background, + open backpack */
 
 /* int inven_ss[EXTRA_MAX_INV_OBJECTS]; */
diff --git a/engines/mads/madsv2/engine.cpp b/engines/mads/madsv2/engine.cpp
index e7fe891fcb9..22b7879d63b 100644
--- a/engines/mads/madsv2/engine.cpp
+++ b/engines/mads/madsv2/engine.cpp
@@ -53,6 +53,7 @@
 #include "mads/madsv2/core/timer.h"
 #include "mads/madsv2/core/vocab.h"
 #include "mads/madsv2/phantom/main.h"
+#include "mads/madsv2/forest/extra.h"
 #include "mads/core/sound_manager.h"
 
 namespace MADS {
@@ -114,6 +115,7 @@ void MADSV2Engine::initGlobals() {
 	init_sprite();
 	init_timer();
 	init_vocab();
+	Forest::init_extra();
 }
 
 void MADSV2Engine::readConfigFile() {
diff --git a/engines/mads/madsv2/forest/extra.cpp b/engines/mads/madsv2/forest/extra.cpp
index b222cf4d01d..25d8a625a6f 100644
--- a/engines/mads/madsv2/forest/extra.cpp
+++ b/engines/mads/madsv2/forest/extra.cpp
@@ -34,6 +34,12 @@ namespace MADS {
 namespace MADSV2 {
 namespace Forest {
 
+int int_sprite[6];
+
+void init_extra() {
+	Common::fill(int_sprite, int_sprite + 6, 0);
+}
+
 void display_interface() {
 	error("TODO: display_interface");
 }
@@ -63,7 +69,14 @@ void extra_spinning_object(void) {
 }
 
 void stamp_sprite_to_interface(int x, int y, int sprite, int series) {
-	error("TODO: stamp_sprite_to_interface");
+	ImageInter &ii = image_inter_list[image_inter_marker++];
+
+	ii.flags = IMAGE_UPDATE;
+	ii.segment_id = 200;
+	ii.sprite_id = sprite;
+	ii.series_id = series;
+	ii.x = x;
+	ii.y = y;
 }
 
 void delete_sprite_in_interface(int series) {
@@ -82,7 +95,44 @@ void extra_blank_knothole(void) {
 	error("TODO: extra_blank_knothole");
 }
 
-void do_interface_for_ouaf() {
+void load_interface() {
+	int_sprite[fx_int_journal] = kernel_load_series("*journal", false);
+	int_sprite[fx_int_backpack] = kernel_load_series("*backpack", false);
+	int_sprite[fx_int_candle] = kernel_load_series("*candle", false);
+	int_sprite[fx_int_exit] = kernel_load_series("*door", false);
+	int_sprite[fx_int_dooropen] = kernel_load_series("*dooropen", false);
+	int_sprite[fx_int_candle_on] = kernel_load_series("*candleon", false);
+}
+
+void unload_interface() {
+	if (int_sprite[fx_int_journal] != -1) {
+		matte_deallocate_series(int_sprite[fx_int_candle_on], true);
+		matte_deallocate_series(int_sprite[fx_int_dooropen], true);
+		matte_deallocate_series(int_sprite[fx_int_exit], true);
+		matte_deallocate_series(int_sprite[fx_int_candle], true);
+		matte_deallocate_series(int_sprite[fx_int_backpack], true);
+		matte_deallocate_series(int_sprite[fx_int_journal], true);
+		int_sprite[fx_int_journal] = -1;
+	}
+}
+
+void draw_interface() {
+	// Once Upon a Forest uses a custom interface
+	stamp_sprite_to_interface(BP_X, BP_Y, 1, int_sprite[fx_int_backpack]);
+	if (global[Forest::walker_converse_state]) {  // candle_is_on
+		stamp_sprite_to_interface(CANDLE_X, CANDLE_Y, 1, int_sprite[fx_int_candle_on]);
+	} else {
+		stamp_sprite_to_interface(CANDLE_X, CANDLE_Y, 1, int_sprite[fx_int_candle]);
+	}
+	stamp_sprite_to_interface(DOOR_X, DOOR_Y, 1, int_sprite[fx_int_exit]);
+
+	if (room_id != 199) {  // Taranjeet, if this is not journal room
+		stamp_sprite_to_interface(JOURNAL_X, JOURNAL_Y, 1, int_sprite[fx_int_journal]);
+	}
+
+}
+
+void do_interface() {
 	if (mouse_y > 156 &&
 		mouse_stop_stroke &&
 		player.commands_allowed &&
diff --git a/engines/mads/madsv2/forest/extra.h b/engines/mads/madsv2/forest/extra.h
index 8639da8addb..2fa56c6d0ad 100644
--- a/engines/mads/madsv2/forest/extra.h
+++ b/engines/mads/madsv2/forest/extra.h
@@ -28,6 +28,16 @@ namespace MADS {
 namespace MADSV2 {
 namespace Forest {
 
+// Interface sprites
+enum {
+	fx_int_journal          = 0,
+	fx_int_backpack         = 1,
+	fx_int_candle           = 2,
+	fx_int_exit             = 3,
+	fx_int_dooropen         = 4,
+	fx_int_candle_on        = 5
+};
+
 #define JOURNAL_FLY            1 
 #define BP_FLY                 2
 #define CANDLE_FLY             3
@@ -45,6 +55,10 @@ namespace Forest {
 #define DOOR_X                 264   /* X for top left corner of DOOR    */
 #define DOOR_Y                 2     /* Y for top left corner of DOOR    */
 
+extern int int_sprite[6];
+
+extern void init_extra();
+
 extern void fly_on_screen(int flying_object);
 extern void fly_off_screen(int flying_object);
 
@@ -53,7 +67,10 @@ extern void display_inventory(void);
 extern void solve_me_selected(void);
 extern void door_selected(void);
 
-extern void do_interface_for_ouaf();
+extern void load_interface();
+extern void unload_interface();
+extern void draw_interface();
+extern void do_interface();
 
 extern void extra_spinning_object(void);
 extern void extra_inven_preserve_palette(void);
diff --git a/engines/mads/madsv2/forest/global.cpp b/engines/mads/madsv2/forest/global.cpp
index d5bae9788be..9c4c62e91c5 100644
--- a/engines/mads/madsv2/forest/global.cpp
+++ b/engines/mads/madsv2/forest/global.cpp
@@ -1002,10 +1002,11 @@ void global_daemon_code() {
 
 	digi_read_another_chunk();
 
-	if (global[9]) midi_loop();  // please loop the damn music
+	if (global[9])
+		midi_loop();
 
 	if (section_id != 9) {
-		do_interface_for_ouaf();
+		do_interface();
 	}
 }
 


Commit: 71efbea57e9727fb3a228bcc15379cc33b3634f1
    https://github.com/scummvm/scummvm/commit/71efbea57e9727fb3a228bcc15379cc33b3634f1
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-06-22T18:20:23+10:00

Commit Message:
NEWS: Added MM engine section for Scorp's PRs that was previously missing

Changed paths:
    NEWS.md


diff --git a/NEWS.md b/NEWS.md
index 8e5dfbc53ab..cef4ab8ba29 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -11,6 +11,12 @@ For a more comprehensive changelog of the latest experimental code, see:
  Atari port:
    - Added integration with nFM library.
 
+ MM:
+   - Fix multiple M&M1 classic combat crashes
+   - Implement M&M1 classic PC speaker sound
+   - Fix stale view close handling causing crash.
+   - Fix M&M1 spelling mistakes
+   - Improved M&M1 Enhanced mouse support, character generation, and general in-game UI
 
 #### 2026.3.0 "Carousels & Killer Whales" (2026-06-20)
 




More information about the Scummvm-git-logs mailing list