[Scummvm-git-logs] scummvm master -> 07298a76da8e1c003c393f9de30d4a9c5778e3f7

dreammaster noreply at scummvm.org
Thu May 21 20:45:59 UTC 2026


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

Summary:
4eacb7d50d MADS: PHANTOM: Remove unused functions from main_menu.cpp
845f7a2b45 MADS: DRAGONSPHERE: Beginnings of main menu
1892a6850c MADS: DRAGONSPHERE: Main menu buttons showing
6a2f5bd733 MADS: DRAGONSPHERE: Added global_parser_code
07298a76da MADS: DRAGONSPHERE: Other global game functions


Commit: 4eacb7d50da1ab0c072022a8b25c5ed1a3f34404
    https://github.com/scummvm/scummvm/commit/4eacb7d50da1ab0c072022a8b25c5ed1a3f34404
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-05-22T06:20:41+10:00

Commit Message:
MADS: PHANTOM: Remove unused functions from main_menu.cpp

Changed paths:
    engines/mads/madsv2/phantom/main_menu.cpp


diff --git a/engines/mads/madsv2/phantom/main_menu.cpp b/engines/mads/madsv2/phantom/main_menu.cpp
index 727b1d769e5..12636a1df5b 100644
--- a/engines/mads/madsv2/phantom/main_menu.cpp
+++ b/engines/mads/madsv2/phantom/main_menu.cpp
@@ -152,7 +152,7 @@ Palette special_pal;                     /* Palette for fadeout */
 
 MenuItem menu_item[NUM_MENU_ITEMS+1];    /* Menu item array */
 
-void start_series() {
+static void start_series() {
 	int error_flag = true;
 	int count;
 	int handle;
@@ -180,7 +180,7 @@ done:
 	}
 }
 
-void stop_series(void) {
+static void stop_series(void) {
 	int count;
 
 	for (count = NUM_MENU_ITEMS - 1; count >= 0; count--) {
@@ -188,7 +188,7 @@ void stop_series(void) {
 	}
 }
 
-void start_hotspots(void) {
+static void start_hotspots(void) {
 	int count;
 	int x1, x2, y1, y2;
 	int xs, ys;
@@ -211,7 +211,7 @@ void start_hotspots(void) {
 	hspot_add(156, 77, 170, 83, 2, EYE_HOTSPOT + 1, mcga_mode);
 }
 
-void process_menu(void) {
+static void process_menu(void) {
 	int myspot;
 
 	myspot = hspot_which(mouse_x, mouse_y - viewing_at_y, mcga_mode);
@@ -236,7 +236,7 @@ void process_menu(void) {
 	}
 }
 
-void process_sprites(void) {
+static void process_sprites(void) {
 	int count;
 	int sprite;
 	int series;
@@ -309,7 +309,7 @@ done:
 	;
 }
 
-void process_messages(int anim) {
+static void process_messages(int anim) {
 	int total;
 	int count;
 	int id, x, y;
@@ -464,36 +464,9 @@ void menu_control(void) {
 		kernel.clock = now_clock;
 
 		if (now_clock >= menu_clock) {
-			switch (menu_mode) {
-			case MENU_APPEARING:
-				/*
-				menu_state -= 1;
-				if (menu_state <= 1) {
-				  menu_state         = MENU_HIGH_SPRITE;
-				  do {
-					menu_appear_state += 1;
-				  } while ((menu_appear_state < NUM_MENU_ITEMS) &&
-					   (!menu_item[menu_appear_state].active));
-				  if (menu_appear_state >= NUM_MENU_ITEMS) {
-					menu_mode          = MENU_ACCEPTING_COMMANDS;
-				  }
-				}
-				*/
-				break;
-
-			case MENU_ACCEPTING_COMMANDS:
-				break;
-
-			case MENU_DISAPPEARING:
+			if (menu_mode == MENU_DISAPPEARING)
 				going = false;
-				/*
-				menu_state += 1;
-				if (menu_state > MENU_HIGH_SPRITE + 1) {
-				  going = false;
-				}
-				*/
-				break;
-			}
+
 			menu_clock = now_clock + MENU_FRAME_RATE;
 		}
 
@@ -571,72 +544,6 @@ void menu_control(void) {
 	stop_series();
 }
 
-void add_parameter(char *parameter) {
-	if (command_line_size < COMMAND_LINE_MAX) {
-		Common::strcpy_s(command_line[command_line_size], parameter);
-		command_list[command_line_size] = command_line[command_line_size];
-		command_line_size++;
-	}
-}
-
-void add_sound_parameter(void) {
-	char temp_buf[80];
-	char work_buf[80];
-
-	Common::strcpy_s(temp_buf, "-c:n");
-	temp_buf[3] = sound_letter;
-
-	Common::strcat_s(temp_buf, ",");
-	Common::sprintf_s(work_buf, "%x", config_file.sound_card_address);
-	Common::strcat_s(temp_buf, work_buf);
-	Common::strcat_s(temp_buf, ",");
-	Common::sprintf_s(work_buf, "%x", config_file.sound_card_type);
-	Common::strcat_s(temp_buf, work_buf);
-
-	add_parameter(temp_buf);
-}
-
-void add_speech_parameter(void) {
-	char temp_buf[80];
-	char work_buf[80];
-
-	if (config_file.speech_card_type > 0) {
-		Common::strcpy_s(temp_buf, "-u:");
-
-		Common::sprintf_s(work_buf, "%x", config_file.speech_card_address);
-		Common::strcat_s(temp_buf, work_buf);
-		Common::strcat_s(temp_buf, ",");
-		Common::sprintf_s(work_buf, "%x", config_file.speech_card_type);
-		Common::strcat_s(temp_buf, work_buf);
-		Common::strcat_s(temp_buf, ",");
-		env_catint(temp_buf, config_file.speech_card_irq, 2);
-		Common::strcat_s(temp_buf, ",");
-		env_catint(temp_buf, config_file.speech_card_drq, 2);
-
-		add_parameter(temp_buf);
-	}
-}
-
-void add_chain_parameter(void) {
-	char temp_buf[80];
-	int added_dash = false;
-
-	Common::strcpy_s(temp_buf, "-a:\"mainmenu");
-
-	if (env_search_mode == ENV_SEARCH_CONCAT_FILES) {
-		Common::strcat_s(temp_buf, " -p");
-		added_dash = true;
-	}
-
-	if (use_mouse_cursor_fix) {
-		if (!added_dash) {
-			Common::strcat_s(temp_buf, " -");
-			added_dash = true;
-		}
-		Common::strcat_s(temp_buf, "u");
-	}
-}
-
 } // namespace Phantom
 } // namespace MADSV2
 } // namespace MADS


Commit: 845f7a2b45f994d941ad34f070e1079e2c369cc0
    https://github.com/scummvm/scummvm/commit/845f7a2b45f994d941ad34f070e1079e2c369cc0
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-05-22T06:20:41+10:00

Commit Message:
MADS: DRAGONSPHERE: Beginnings of main menu

Changed paths:
  A engines/mads/madsv2/dragonsphere/main.cpp
  A engines/mads/madsv2/dragonsphere/main.h
  A engines/mads/madsv2/dragonsphere/main_menu.cpp
  A engines/mads/madsv2/dragonsphere/main_menu.h
  A engines/mads/madsv2/dragonsphere/menus.cpp
  A engines/mads/madsv2/dragonsphere/menus.h
  A engines/mads/madsv2/dragonsphere/sound_dragonsphere.cpp
  A engines/mads/madsv2/dragonsphere/sound_dragonsphere.h
    engines/mads/madsv2/dragonsphere/dragonsphere.cpp
    engines/mads/madsv2/dragonsphere/mads/sounds.h
    engines/mads/module.mk


diff --git a/engines/mads/madsv2/dragonsphere/dragonsphere.cpp b/engines/mads/madsv2/dragonsphere/dragonsphere.cpp
index 370f905ee38..891c94915e4 100644
--- a/engines/mads/madsv2/dragonsphere/dragonsphere.cpp
+++ b/engines/mads/madsv2/dragonsphere/dragonsphere.cpp
@@ -27,6 +27,8 @@
 #include "mads/madsv2/core/screen.h"
 #include "mads/madsv2/dragonsphere/dragonsphere.h"
 #include "mads/madsv2/dragonsphere/global.h"
+#include "mads/madsv2/dragonsphere/main.h"
+#include "mads/madsv2/dragonsphere/sound_dragonsphere.h"
 
 namespace MADS {
 namespace MADSV2 {
@@ -41,12 +43,11 @@ Common::Error DragonsphereEngine::run() {
 	setDebugger(new Console());
 
 	// Set up sound manager
-	_soundManager = nullptr; // new DragonsphereSoundManager(_mixer, _soundFlag);
-	//_soundManager->validate();
+	_soundManager = new DragonSoundManager(_mixer, _soundFlag);
+	_soundManager->validate();
 
 	// Run the game
-	// TODO
-	Dragonsphere::global_section_constructor();	// Test call
+	Dragonsphere::dragonsphere_main();
 
 	return Common::kNoError;
 }
diff --git a/engines/mads/madsv2/dragonsphere/mads/sounds.h b/engines/mads/madsv2/dragonsphere/mads/sounds.h
index ecf9d31c787..2e7d9469e62 100644
--- a/engines/mads/madsv2/dragonsphere/mads/sounds.h
+++ b/engines/mads/madsv2/dragonsphere/mads/sounds.h
@@ -80,7 +80,10 @@ enum {
 	N_BigBirdCall        =  69,
 	N_JumpThwang         =  70,
 	N_StepOnFloatingDisk =  77,
-	N_004CryOfDismay     =  78
+	N_004CryOfDismay     =  78,
+
+	// Section 9
+	N_AllFade            =   1
 };
 
 } // namespace Dragonsphere
diff --git a/engines/mads/madsv2/dragonsphere/main.cpp b/engines/mads/madsv2/dragonsphere/main.cpp
new file mode 100644
index 00000000000..5d46d24113d
--- /dev/null
+++ b/engines/mads/madsv2/dragonsphere/main.cpp
@@ -0,0 +1,320 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "common/config-manager.h"
+#include "gui/saveload.h"
+#include "mads/madsv2/dragonsphere/main.h"
+#include "mads/madsv2/animview/animview.h"
+#include "mads/madsv2/textview/textview.h"
+#include "mads/madsv2/core/env.h"
+#include "mads/madsv2/core/error.h"
+#include "mads/madsv2/core/fileio.h"
+#include "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/himem.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/magic.h"
+#include "mads/madsv2/core/matte.h"
+#include "mads/madsv2/core/mcga.h"
+#include "mads/madsv2/core/mouse.h"
+#include "mads/madsv2/core/pal.h"
+#include "mads/madsv2/core/player.h"
+#include "mads/madsv2/core/quote.h"
+#include "mads/madsv2/core/speech.h"
+#include "mads/madsv2/dragonsphere/main_menu.h"
+#include "mads/madsv2/dragonsphere/menus.h"
+#include "mads/madsv2/engine.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Dragonsphere {
+
+constexpr bool SHOW_LINES = true;
+constexpr byte LINE_COLOR = 2;
+
+char *quotes;
+
+static void main_menu_main() {
+	auto &screen = *g_engine->getScreen();
+	Palette palette;
+
+	if (!kernel_game_startup(19, KERNEL_STARTUP_CURSOR | KERNEL_STARTUP_INTERRUPT | KERNEL_STARTUP_FONT,
+		nullptr, nullptr)) {
+		viewing_at_y = (200 - scr_work.y) >> 1;
+
+		mouse_cursor_sprite(cursor, 7);
+		mouse_show();
+		mouse_force(280, 126);
+		mouse_hide();
+
+		mouse_cursor_sprite(cursor, 1);
+		matte_init(0xFFFF);
+		kernel_seq_init();
+		kernel_message_init();
+		kernel_animation_init();
+		kernel_init_dynamic();
+
+		picture_view_x = 0;
+		picture_view_y = 0;
+
+		quotes = quote_load(0, 68, 69, 70, 71, 72, 73, 74, 75, 76,
+			77, 78, 79, 80, 81, 82, 83, 84, 85, 86,
+			87, 88, 89, 90, 91, 92, 93, 94, 95, 96,
+			97, 98, 99, 0);
+
+		global_speech_load(9);
+		bool valid = !kernel_room_startup(902, 0, nullptr, true, true);
+
+		master_palette[4].r = 63;
+		master_palette[4].g = 50;
+		master_palette[4].b = 0;
+		master_palette[5].r = 30;
+		master_palette[5].g = 15;
+		master_palette[5].b = 0;
+		mcga_setpal_range(&master_palette, 4, 2);
+
+		new_background = true;
+
+		if (valid) {
+			memset(&palette, 0, sizeof(palette));
+			mcga_setpal(&palette);
+			mouse_cursor_sprite(cursor, 1);
+
+			if (SHOW_LINES && viewing_at_y != 0) {
+				screen.hLine(0, viewing_at_y - 2, 319, LINE_COLOR);
+				screen.hLine(0, scr_work.y + viewing_at_y + 1, 319, LINE_COLOR);
+			}
+
+			kernel_load_sound_driver("*#SOUND.PH9", 'N', 544, 0, 49);
+
+			menu_control();
+
+			if (selected_item >= 0) {
+				// Zero out the first 3 entries of both magic color arrays
+				for (int i = 0; i < 3; i++) {
+					magic_color_values[i] = 0;
+					magic_color_flags[i] = 0;
+				}
+
+				mcga_getpal(&palette);
+
+				magic_fade_to_grey(palette, 0, 0x10, 1, 1, 0, 0, 0);
+			}
+		}
+
+		free(quotes);
+		kernel_unload_sound_driver();
+		kernel_game_shutdown();
+	}
+
+	mcga_reset();
+}
+
+static void main_cold_data_init() {
+	debugger_reset = game_debugger_reset;
+	debugger_update = game_debugger;
+	game_menu_routine = global_game_menu;
+	game_menu_init = global_menu_system_init;
+	game_menu_exit = global_menu_system_shutdown;
+	game_emergency_save = global_emergency_save;
+
+	Common::strcpy_s(config_file_name, "config.pha");
+	Common::strcpy_s(save_game_key, "phan");
+	Common::strcpy_s(restart_game_key, "phantom");
+
+	Common::strcpy_s(player.series_name, "RAL");
+	player.walker_must_reload = true;
+	player.walker_loads_first = false;
+	player.walker_visible = true;
+	player.scaling_velocity = true;
+
+	Common::strcpy_s(kernel_cheating_password, "WIDECHEW");
+	kernel_cheating_allowed = strlen(kernel_cheating_password);
+
+	kernel.cheating = gDebugLevel == 9 ? kernel_cheating_allowed : 0;
+}
+
+static void game_main(int argc, const char **argv) {
+	int count;
+	int mads_mode;
+	const char *scan;
+
+	pack_enable_pfab_explode();
+
+	mads_mode = env_verify();
+
+	new_section = 1;
+	new_room = 101;
+	player.x = 160;
+	player.y = 78;
+
+	player.target_facing = FACING_NORTH;
+
+	game_cold_data_init();
+	main_cold_data_init();
+	g_engine->readConfigFile();
+	global_load_config_parameters();
+
+	if (argc >= 2) {
+		for (count = 1; count < argc; count++) {
+			if (strchr("-/", argv[count][0]) != NULL) {
+				for (scan = argv[count] + 1; *scan != 0; scan++) {
+					flag_parse(&scan);
+				}
+			} else if (argv[count][0] == '?') {
+				show_logo();
+
+				if (!mads_mode) env_search_mode = ENV_SEARCH_CONCAT_FILES;
+				error_dump_file("*warn2.dat");
+				goto done;
+			}
+		}
+	}
+
+	if (report_version) {
+		show_version();
+		goto done;
+	}
+
+	if (fileio_exist("global.hag")) {
+		art_hags_are_on_hd = true;
+	} else {
+		art_hags_are_on_hd = false;
+	}
+
+#if 0
+	if (config_file.cd_version_installed) {
+		strcpy(temp_buf_2, "x:\\forest.exe");
+		temp_buf_2[0] = env_cd_drive;
+		if (!fileio_exist(temp_buf_2)) {
+			problem();
+			printf("Please throw the Once Upon A Forest CD into drive %c:\n", (char)env_cd_drive);
+			printf("and type 'OUAF'. If your CD-ROM drive letter has changed, run\n");
+			printf("INSTALL to reconfigure this option.\n\n");
+			goto done;
+		}
+	}
+
+	if (!fileio_exist("config.for")) {
+		problem();
+		printf("Before you can run Once Upon A Forest, you need to run 'INSTALL' to configure\n");
+		printf("the game for you your hardware.  Type 'INSTALL' and hit 'ENTER' when you have\n");
+		printf("finished reading this.\n\n");
+		goto done;
+	}
+
+	mem_you_got = mem_used + mem_avail_at_start;
+
+	if (mem_you_got < 569000) {
+		need_to_free = 569000 - mem_you_got;
+		problem();
+		printf("You need at least 588,000 bytes of conventional memory to play\n");
+		printf("Once Upon A Forest. You'll need to free up another %6ld bytes.\n\n", need_to_free);
+		/* printf("to play this game.\n\n"); */
+		goto done;
+	}
+#endif
+	himem_startup();
+
+	himem_shutdown();
+
+	if (!mads_mode && (env_search_mode == ENV_SEARCH_MADS_PATH))
+		error("false start");
+
+	game_control();
+
+done:
+	global_unload_config_parameters();
+
+	if (fileio_exist("config.for")) {
+		global_write_config_file();
+	}
+	if (chain_flag && (win_status || force_chain) && (key_abort_level < 2)) {
+		warning("TODO: chain_execute");
+	} else {
+		if (win_status) {
+			debug("(Ending: %d)", win_status);
+		}
+	}
+}
+
+void dragonsphere_main() {
+	static const char *CMD_LINE[] = { nullptr, "-p" };
+
+	pack_enable_pfab_explode();
+	if (!env_verify())
+		env_search_mode = ENV_SEARCH_CONCAT_FILES;
+
+	if (ConfMan.getBool("start_game") || ConfMan.hasKey("save_slot"))
+		selected_item = 0;
+	else if (ConfMan.getBool("start_intro"))
+		selected_item = 3;
+	else
+		selected_item = -1;
+
+	while (!g_engine->shouldQuit()) {
+		switch (selected_item) {
+		case -1:
+			main_menu_main();
+			break;
+
+		case 0:
+			game_main(2, CMD_LINE);
+			return;
+
+		case 1: {
+			// Resume savegame
+			// Get a list of saves and choose the last one
+			auto saves = g_engine->listSaves();
+			if (!saves.empty())
+				savegame_slot = saves.back().getSaveSlot();
+
+			// Start the game, which will also load the selected savegame
+			game_main(2, CMD_LINE);
+			return;
+		}
+
+		case 2:
+			// Restore savegame
+			game_restore_flag = 2;
+			game_main(2, CMD_LINE);
+			return;
+
+		case 3:
+			AnimView::animview_main("@phantom");
+			selected_item = -1;
+			break;
+
+		case 4:
+			// Exit
+			return;
+
+		default:
+			// Credits
+			TextView::textview_main("credits");
+			selected_item = -1;
+			break;
+		}
+	}
+}
+
+} // namespace Dragonspheree
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/dragonsphere/main.h b/engines/mads/madsv2/dragonsphere/main.h
new file mode 100644
index 00000000000..b2851a42dc7
--- /dev/null
+++ b/engines/mads/madsv2/dragonsphere/main.h
@@ -0,0 +1,37 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef MADS_DRAGONSPHERE_MAIN_H
+#define MADS_DRAGONSPHERE_MAIN_H
+
+#include "common/scummsys.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Dragonsphere {
+
+extern void dragonsphere_main();
+
+} // namespace Dragonsphere
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/dragonsphere/main_menu.cpp b/engines/mads/madsv2/dragonsphere/main_menu.cpp
new file mode 100644
index 00000000000..e2e22963e34
--- /dev/null
+++ b/engines/mads/madsv2/dragonsphere/main_menu.cpp
@@ -0,0 +1,440 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "mads/madsv2/engine.h"
+#include "mads/madsv2/core/general.h"
+#include "mads/madsv2/core/config.h"
+#include "mads/madsv2/core/font.h"
+#include "mads/madsv2/core/speech.h"
+#include "mads/madsv2/core/matte.h"
+#include "mads/madsv2/core/sprite.h"
+#include "mads/madsv2/core/error.h"
+#include "mads/madsv2/core/room.h"
+#include "mads/madsv2/core/fileio.h"
+#include "mads/madsv2/core/env.h"
+#include "mads/madsv2/core/buffer.h"
+#include "mads/madsv2/core/mem.h"
+#include "mads/madsv2/core/pal.h"
+#include "mads/madsv2/core/timer.h"
+#include "mads/madsv2/core/mcga.h"
+#include "mads/madsv2/core/cycle.h"
+#include "mads/madsv2/core/mouse.h"
+#include "mads/madsv2/core/screen.h"
+#include "mads/madsv2/core/video.h"
+#include "mads/madsv2/core/lib.h"
+#include "mads/madsv2/core/keys.h"
+#include "mads/madsv2/core/sound.h"
+#include "mads/madsv2/core/btype.h"
+#include "mads/madsv2/core/hspot.h"
+#include "mads/madsv2/core/magic.h"
+#include "mads/madsv2/core/ems.h"
+#include "mads/madsv2/core/xms.h"
+#include "mads/madsv2/core/imath.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/pack.h"
+#include "mads/madsv2/core/quote.h"
+#include "mads/madsv2/dragonsphere/mads/sounds.h"
+#include "mads/madsv2/dragonsphere/main_menu.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Dragonsphere {
+
+#define CONFIG_FILE_NAME "CONFIG.PHA"
+
+#define EYE_QUOTES      16
+#define EYE_HOTSPOT     32
+#define EYE_MESSAGES    2
+
+#undef MESSAGE_COLOR
+#define MESSAGE_COLOR   1284
+
+
+ConfigFile config_file;
+
+int mads_mode = false;
+
+FontPtr font = NULL;
+int font_auto_spacing = -1;
+
+bool new_background   = false;
+int room_number       = 0;
+
+int win_status        = 0;
+
+bool force_opening    = false;
+bool dont_return      = false;
+bool white_bars       = true;
+byte white_border     = 2;
+
+char command_line[COMMAND_LINE_MAX][80];
+char *command_list[COMMAND_LINE_MAX+1];
+int  command_line_size = 0;
+
+int  use_mouse_cursor_fix = false;
+
+bool going;
+int  menu_mode;
+int  must_perform_matte;
+
+long frame_clock;
+long now_clock;
+long menu_clock;
+
+int menu_state;
+int menu_appear_state;
+
+int highest_y = -1;
+int next_x    = -1;
+
+char sound_file[80]    = "*#SOUND.PH9";
+char sound_letter      = 'N';
+
+int  sound_board_address = 0x220;              /* Default sound board address */
+int  sound_board_type    = sound_board_roland; /* Default sound board type    */
+
+int  swapping = false;                   /* Flag when swapping in new background */
+int  swap_line;                          /* Currently active swap line           */
+long swap_clock;                         /* Time for next swap */
+
+int  current_item;
+int  current_eye   = false;
+int  eye_latch     = false;
+int  selected_item = -1;
+
+#define LEFT_EYE   0
+#define RIGHT_EYE  1
+
+extern char *quotes;
+int  eye_message[2];
+int  eye_pokes   = 0;
+int  recent_eye  = 0;
+int  rebel_base  = 0;
+int  poke_count_message = -1;
+int  poke_count         = 0;
+int  poke_counting      = false;
+
+char poke_count_buf[2][20];
+
+char bonus_buf[80] = "";
+
+Palette special_pal;                     /* Palette for fadeout */
+
+
+MenuItem menu_item[NUM_MENU_ITEMS+1];    /* Menu item array */
+
+static void start_series() {
+	int error_flag = true;
+	int count;
+	int handle;
+	char temp_buf[80];
+
+	for (count = 0; count < NUM_MENU_ITEMS; count++) {
+		handle = -1;
+		Common::strcpy_s(temp_buf, "*MAIN0.SS");
+		temp_buf[5] = (char)('0' + count);
+
+		handle = matte_load_series(temp_buf, 0, 0);
+		if (handle < 0) goto done;
+
+		menu_item[count].handle = handle;
+		menu_item[count].active = count != 6;	// Quotes button was never implemented
+		menu_item[count].status = 0;
+	}
+
+	error_flag = false;
+
+done:
+	if (error_flag) {
+		Common::strcpy_s(error_string, temp_buf);
+		error_report(ERROR_SERIES_LOAD_FAILED, WARNING, MODULE_UNKNOWN, count, handle);
+	}
+}
+
+static void stop_series() {
+	int count;
+
+	for (count = NUM_MENU_ITEMS - 1; count >= 0; count--) {
+		matte_deallocate_series(menu_item[count].handle, true);
+	}
+}
+
+static void start_hotspots() {
+	int count;
+	int x1, x2, y1, y2;
+	int xs, ys;
+	SeriesPtr series;
+
+	numspots = 0;
+
+	for (count = 0; count < NUM_MENU_ITEMS; count++) {
+		series = series_list[menu_item[count].handle];
+		xs = series->index[0].xs;
+		ys = series->index[0].ys;
+		x1 = series->index[0].x - (xs >> 1);
+		y1 = series->index[0].y - (ys - 1);
+		x2 = x1 + xs - 1;
+		y2 = y1 + ys - 1;
+		hspot_add(x1, y1, x2, y2, 1, count, mcga_mode);
+	}
+}
+
+static void process_menu() {
+	int myspot;
+
+	myspot = hspot_which(mouse_x, mouse_y - viewing_at_y, mcga_mode);
+
+	current_eye = false;
+
+	if ((myspot > 0) && mouse_any_stroke && (menu_mode == MENU_ACCEPTING_COMMANDS)) {
+		current_item = spot[myspot].num;
+		if (current_item >= EYE_HOTSPOT) {
+			current_item = -1;
+			current_eye = true;
+		}
+	} else {
+		current_item = -1;
+	}
+
+	if (mouse_stop_stroke && (current_item >= 0) && (menu_mode == MENU_ACCEPTING_COMMANDS)) {
+		selected_item = current_item;
+		menu_mode = MENU_DISAPPEARING;
+		menu_state = 1;
+		sound_queue(N_AllFade);
+	}
+}
+
+static void process_sprites() {
+	int count;
+	int sprite;
+	int series;
+	int look, match;
+	Image image;
+
+	for (count = 0; count < (int)image_marker; count++) {
+		if ((image_list[count].segment_id < KERNEL_SEGMENT_ANIMATION) ||
+			(image_list[count].segment_id > KERNEL_SEGMENT_ANIMATION_HIGH)) {
+			if (image_list[count].flags >= IMAGE_STATIC) {
+				image_list[count].flags = IMAGE_ERASE;
+			}
+		}
+	}
+
+	if (menu_mode == MENU_APPEARING) goto done;
+
+	for (count = 0; count < NUM_MENU_ITEMS; count++) {
+		if (menu_item[count].active) {
+			image.flags = IMAGE_UPDATE;
+			image.segment_id = (byte)(count + 1);
+
+			series = count;
+			if (menu_mode == MENU_ACCEPTING_COMMANDS) {
+				if (count != current_item) {
+					sprite = 1;
+				} else {
+					sprite = 2;
+				}
+			} else {
+				sprite = 1;
+				/*
+				if (count != selected_item) {
+				  sprite = 1;
+				} else {
+				  sprite = 2;
+				}
+				*/
+			}
+
+			image.series_id = (byte)menu_item[series].handle;
+			image.sprite_id = sprite;
+
+			image.x = series_list[series]->index[sprite - 1].x;
+			image.y = series_list[series]->index[sprite - 1].y;
+
+			image.depth = 0;
+			image.scale = 100;
+
+			match = !(sprite <= MENU_HIGH_SPRITE);
+
+			for (look = 0; !match && (look < (int)image_marker); look++) {
+				if (image_list[look].segment_id == image.segment_id) {
+					if (memcmp(&image_list[look].series_id,
+						&image.series_id, 9) == 0) {
+						image_list[look].flags = IMAGE_STATIC;
+						match = true;
+					}
+				}
+			}
+
+			if (!match) {
+				image_list[image_marker] = image;
+				image_marker++;
+			}
+		}
+	}
+
+done:
+	;
+}
+
+void menu_control() {
+	int fx;
+	int mykey;
+	int last_frame = -1;
+	int now_frame;
+	int reset_frame;
+	int anim;
+	int initial_reset = false;
+
+	menu_mode = MENU_APPEARING;
+	menu_state = MENU_HIGH_SPRITE;
+	menu_appear_state = 0;
+	menu_clock = 999999999;
+
+	going = true;
+	must_perform_matte = false;
+
+	frame_clock = 0;
+
+	start_series();
+	start_hotspots();
+
+	anim = kernel_run_animation("*RM902A.AA", 0);
+
+	mouse_init_cycle();
+
+	while (going && !g_engine->shouldQuit()) {
+		if (keys_any()) {
+			mykey = keys_get();
+			switch (toupper(mykey)) {
+			case esc_key:
+				selected_item = 4;
+				going = false;
+				break;
+
+			case alt_x_key:
+			case alt_q_key:
+			case ctrl_x_key:
+			case ctrl_q_key:
+				going = false;
+				break;
+
+			case 'S':
+				menu_mode = MENU_APPEARING;
+				menu_state = MENU_HIGH_SPRITE;
+				menu_appear_state = 0;
+				break;
+
+			default:
+				if (menu_mode == MENU_APPEARING) {
+					menu_mode = MENU_ACCEPTING_COMMANDS;
+					kernel_reset_animation(anim, 105);
+					kernel_anim[anim].next_clock = kernel.clock;
+				}
+				break;
+			}
+		}
+
+		mouse_begin_cycle(false);
+
+		if (mouse_stroke_going) {
+			if (menu_mode == MENU_APPEARING) {
+				menu_mode = MENU_ACCEPTING_COMMANDS;
+				kernel_reset_animation(anim, 105);
+				kernel_anim[anim].next_clock = kernel.clock;
+				mouse_init_cycle();
+			}
+		}
+
+		if (menu_mode != MENU_APPEARING) {
+			mouse_show();
+		}
+
+		now_clock = timer_read();
+		kernel.clock = now_clock;
+
+		if (now_clock >= menu_clock) {
+			if (menu_mode == MENU_DISAPPEARING)
+				going = false;
+
+			menu_clock = now_clock + MENU_FRAME_RATE;
+		}
+
+		process_menu();
+		kernel_message_update_all();
+		kernel_process_all_animations();
+
+		reset_frame = -1;
+		now_frame = kernel_anim[anim].frame;
+		if (now_frame != last_frame) {
+			last_frame = now_frame;
+
+			if (now_frame < 105) {
+				if (menu_mode != MENU_APPEARING) {
+					if (!initial_reset) {
+						reset_frame = 105;
+						initial_reset = true;
+					}
+				}
+			}
+
+			if (now_frame >= 109) {
+				if (menu_mode == MENU_APPEARING)
+					menu_mode = MENU_ACCEPTING_COMMANDS;
+
+				reset_frame = 105;
+			}
+
+			if (reset_frame >= 0) {
+				kernel_reset_animation(anim, reset_frame);
+				last_frame = reset_frame;
+			}
+		}
+
+		if (now_clock >= frame_clock) {
+			process_sprites();
+
+			fx = new_background ? 1 : 0;
+			matte_frame(fx, false);
+
+			if (fx) {
+				now_clock = timer_read();
+				menu_clock = now_clock + MENU_FRAME_RATE;
+			}
+
+			must_perform_matte = false;
+			new_background = false;
+
+			frame_clock = now_clock + FRAME_RATE;
+		}
+
+		mouse_end_cycle(false, going);
+	}
+
+	kernel_abort_animation(anim);
+
+	stop_series();
+}
+
+} // namespace Dragonsphere
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/dragonsphere/main_menu.h b/engines/mads/madsv2/dragonsphere/main_menu.h
new file mode 100644
index 00000000000..cc895fb0896
--- /dev/null
+++ b/engines/mads/madsv2/dragonsphere/main_menu.h
@@ -0,0 +1,59 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef MADS_DRAGONSPHERE_MAIN_MENU_H
+#define MADS_DRAGONSPHERE_MAIN_MENU_H
+
+#include "common/str.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Dragonsphere {
+
+#define COMMAND_LINE_MAX        10
+
+#define FRAME_RATE              1
+#define MENU_FRAME_RATE         3
+
+#define NUM_MENU_ITEMS          6
+
+#define MENU_APPEARING          0
+#define MENU_ACCEPTING_COMMANDS 1
+#define MENU_DISAPPEARING       2
+
+#define MENU_HIGH_SPRITE        15
+
+typedef struct {
+	int handle;           /* Sprite series handle */
+	int active;           /* Menu item is active  */
+	int status;           /* Current status       */
+} MenuItem;
+
+extern bool new_background;
+extern int selected_item;
+
+extern void menu_control();
+
+} // namespace Dragonsphere
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/dragonsphere/menus.cpp b/engines/mads/madsv2/dragonsphere/menus.cpp
new file mode 100644
index 00000000000..9fe53d0397f
--- /dev/null
+++ b/engines/mads/madsv2/dragonsphere/menus.cpp
@@ -0,0 +1,615 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "mads/madsv2/core/config.h"
+#include "mads/madsv2/core/echo.h"
+#include "mads/madsv2/core/game.h"
+#include "mads/madsv2/core/global.h"
+#include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/keys.h"
+#include "mads/madsv2/core/matte.h"
+#include "mads/madsv2/core/mem.h"
+#include "mads/madsv2/core/speech.h"
+#include "mads/madsv2/core/quote.h"
+#include "mads/madsv2/core/text.h"
+#include "mads/madsv2/dragonsphere/menus.h"
+#include "mads/madsv2/dragonsphere/global.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Dragonsphere {
+
+#define SAVE_MENU_PIXEL_WIDTH           200
+#define MAX_SAVES_ON_SCREEN             10
+
+#define SPACE_BETWEEN                   -1
+
+#define MAIN_MENU_ITEM_WIDTH            140
+#define MAIN_MENU_FORCE_WIDTH           160
+
+#define DIFFICULTY_MENU_FORCE_WIDTH     140
+
+#define OPTIONS_MENU_ITEM_WIDTH         160
+#define OPTIONS_MENU_FORCE_WIDTH        170
+#define OPTIONS_MENU_OFF_CENTER         10
+
+
+#define SAVE_SUCCESSFUL                 1
+#define RESTORE_SUCCESSFUL              2
+#define SAVE_FAILED                     3
+#define RESTORE_FAILED                  4
+
+
+int global_menu_direct_jump;
+int global_menu_force_restart;
+
+char *menu_quotes = NULL;
+
+
+static int global_save(int id, const char *save_game_name) {
+	int status;
+
+	game_save_name(id + 1);
+
+	if (g_engine->saveGameState(id + 1, save_game_name).getCode() == Common::kNoError)
+		status = SAVE_SUCCESSFUL;
+	else
+		status = SAVE_FAILED;
+
+	return status;
+}
+
+static int global_restore(int id) {
+	int status;
+
+	if (g_engine->loadGameState(id + 1).getCode() == Common::kNoError)
+		status = RESTORE_SUCCESSFUL;
+	else
+		status = RESTORE_FAILED;
+
+	WRITE_LE_UINT32(&global[walker_timing], 0);
+
+	return status;
+}
+
+void global_menu_system_init() {
+}
+
+void global_menu_system_shutdown() {
+	if (menu_quotes != NULL)
+		mem_free(menu_quotes);
+}
+
+static char *menu_quote(int id) {
+	return quote_string(menu_quotes, id);
+}
+
+void global_emergency_save() {
+	game_save_name(0);
+
+	if (scr_orig.data != NULL) mem_free(scr_orig.data);
+
+	g_engine->saveAutosaveIfEnabled();
+}
+
+static void global_alert(int status) {
+}
+
+static void global_menu_score() {
+}
+
+static void global_menu_save_restore(int save) {
+#if 0
+	int status = -1;
+	int selection;
+	char *save_game_name;
+	PopupItem *save_list;
+	PopupItem *go_button;
+	PopupItem *clear_button;
+	PopupItem *cancel_button;
+	PopupItem *result;
+
+	popup_dialog_create(game_menu_popup, GAME_DIALOG_HEAP, 20);
+
+	if (save) {
+		popup_message(menu_quote(quote_save_title), POPUP_CENTER, POPUP_FILL);
+	} else {
+		popup_message(menu_quote(quote_restore_title), POPUP_CENTER, POPUP_FILL);
+	}
+	popup_blank(4);
+
+	save_list = popup_savelist(game_save_directory, menu_quote(quote_menu_empty),
+		GAME_MAX_SAVE_SLOTS,
+		GAME_MAX_SAVE_LENGTH + 1,
+		GAME_MAX_SAVE_LENGTH,
+		SAVE_MENU_PIXEL_WIDTH,
+		MAX_SAVES_ON_SCREEN,
+		save, game.last_save);
+
+	if (save) {
+		go_button = popup_button(menu_quote(quote_menu_save), POPUP_BUTTON_LEFT);
+		clear_button = popup_button(menu_quote(quote_menu_clear), POPUP_CENTER);
+		game_menu_popup->clear_item = clear_button;
+	} else {
+		go_button = popup_button(menu_quote(quote_menu_restore), POPUP_BUTTON_LEFT);
+	}
+	cancel_button = popup_cancel_button(menu_quote(quote_menu_cancel));
+
+	result = popup_execute();
+
+	if (result == cancel_button) {
+		switch (game_menu_popup->key) {
+		case alt_x_key:
+		case ctrl_x_key:
+		case alt_q_key:
+		case ctrl_q_key:
+			game.going = false;
+			kernel.activate_menu = GAME_NO_MENU;
+			break;
+
+		case f1_key:
+			kernel.activate_menu = GAME_MAIN_MENU;
+			break;
+
+		case f2_key:
+			if (save) {
+				kernel.activate_menu = GAME_MAIN_MENU;
+			} else {
+				kernel.activate_menu = GAME_SAVE_MENU;
+			}
+			break;
+
+		case f3_key:
+			if (!save) {
+				kernel.activate_menu = GAME_MAIN_MENU;
+			} else {
+				kernel.activate_menu = GAME_RESTORE_MENU;
+			}
+			break;
+
+		case f4_key:
+			kernel.activate_menu = GAME_SCORE_MENU;
+			break;
+
+		case f5_key:
+			kernel.activate_menu = GAME_OPTIONS_MENU;
+			break;
+
+		default:
+			kernel.activate_menu = GAME_MAIN_MENU;
+			break;
+		}
+	} else {
+		kernel.activate_menu = GAME_NO_MENU;
+	}
+
+	popup_dialog_destroy();
+
+	if (result == go_button) {
+		selection = save_list->list->picked_element;
+		game.last_save = selection;
+		if (save) {
+			save_game_name = game_save_directory + ((GAME_MAX_SAVE_LENGTH + 1) * selection);
+			if (!strlen(save_game_name)) {
+				Common::strcpy_s(save_game_name, GAME_MAX_SAVE_LENGTH, menu_quote(quote_menu_unnamed));
+			}
+			status = global_save(selection, save_game_name);
+
+		} else {
+			status = global_restore(selection);
+		}
+
+		if (status > 0)
+			// Dummy name to signal save/load went ok
+			Common::strcpy_s(save_game_buf, "OK");
+	}
+
+	if (status >= 0) {
+		global_alert(status);
+	}
+#endif
+}
+
+static void global_menu_options() {
+#if 0
+	int initial_1, initial_2, initial_3;
+	int initial_4, initial_5, initial_6;
+	int former_music;
+	int former_sound;
+	PopupItem *music_item;
+	PopupItem *sound_item;
+	PopupItem *interface_item;
+	PopupItem *fade_item;
+	PopupItem *panning_item;
+	PopupItem *speech_item;
+	PopupItem *done_button;
+	PopupItem *cancel_button;
+	PopupItem *result;
+
+	global_unload_config_parameters();
+
+	popup_dialog_create(game_menu_popup, GAME_DIALOG_HEAP, 20);
+
+	popup_sprite(box_param.logo, 1, POPUP_CENTER, POPUP_FILL);
+	popup_blank(2);
+
+	former_music = config_file.music_flag;
+	former_sound = config_file.sound_flag;
+
+	initial_1 = config_file.music_flag ? 0 : 1;
+	initial_2 = config_file.sound_flag ? 0 : 1;
+	initial_6 = config_file.speech_flag ? 0 : 1;
+	initial_3 = config_file.interface_hotspots;
+	initial_4 = config_file.screen_fade;
+	initial_5 = config_file.panning_speed;
+
+	music_item = popup_menu(menu_quote(quote_options_item1),
+		POPUP_CENTER, POPUP_FILL, OPTIONS_MENU_ITEM_WIDTH,
+		OPTIONS_MENU_OFF_CENTER,
+		2, 40, initial_1);
+	popup_menu_option(music_item, menu_quote(quote_options_item1a));
+	popup_menu_option(music_item, menu_quote(quote_options_item1b));
+
+	popup_blank(SPACE_BETWEEN);
+
+
+	sound_item = popup_menu(menu_quote(quote_options_item2),
+		POPUP_CENTER, POPUP_FILL, OPTIONS_MENU_ITEM_WIDTH,
+		OPTIONS_MENU_OFF_CENTER,
+		2, 40, initial_2);
+	popup_menu_option(sound_item, menu_quote(quote_options_item2a));
+	popup_menu_option(sound_item, menu_quote(quote_options_item2b));
+
+	popup_blank(SPACE_BETWEEN);
+
+
+	speech_item = popup_menu(menu_quote(quote_options_item6),
+		POPUP_CENTER, POPUP_FILL, OPTIONS_MENU_ITEM_WIDTH,
+		OPTIONS_MENU_OFF_CENTER,
+		2, 40, initial_6);
+	popup_menu_option(speech_item, menu_quote(quote_options_item6a));
+	popup_menu_option(speech_item, menu_quote(quote_options_item6b));
+
+	popup_blank(SPACE_BETWEEN);
+
+
+	interface_item = popup_menu(menu_quote(quote_options_item3),
+		POPUP_CENTER, POPUP_FILL, OPTIONS_MENU_ITEM_WIDTH,
+		OPTIONS_MENU_OFF_CENTER,
+		2, 40, initial_3);
+	popup_menu_option(interface_item, menu_quote(quote_options_item3a));
+	popup_menu_option(interface_item, menu_quote(quote_options_item3b));
+
+	popup_blank(SPACE_BETWEEN);
+
+
+	fade_item = popup_menu(menu_quote(quote_options_item4),
+		POPUP_CENTER, POPUP_FILL, OPTIONS_MENU_ITEM_WIDTH,
+		OPTIONS_MENU_OFF_CENTER,
+		3, 40, initial_4);
+	popup_menu_option(fade_item, menu_quote(quote_options_item4a));
+	popup_menu_option(fade_item, menu_quote(quote_options_item4b));
+	popup_menu_option(fade_item, menu_quote(quote_options_item4c));
+
+	popup_blank(SPACE_BETWEEN);
+
+
+	panning_item = popup_menu(menu_quote(quote_options_item5),
+		POPUP_CENTER, POPUP_FILL, OPTIONS_MENU_ITEM_WIDTH,
+		OPTIONS_MENU_OFF_CENTER,
+		3, 40, initial_5);
+	popup_menu_option(panning_item, menu_quote(quote_options_item5a));
+	popup_menu_option(panning_item, menu_quote(quote_options_item5b));
+	popup_menu_option(panning_item, menu_quote(quote_options_item5c));
+
+
+
+	done_button = popup_button(menu_quote(quote_menu_done), POPUP_LEFT);
+	cancel_button = popup_cancel_button(menu_quote(quote_menu_cancel));
+
+	popup_width_force(OPTIONS_MENU_FORCE_WIDTH);
+
+	result = popup_execute();
+
+	kernel.activate_menu = GAME_MAIN_MENU;
+
+	if (result == cancel_button) {
+		switch (game_menu_popup->key) {
+		case alt_x_key:
+		case ctrl_x_key:
+		case alt_q_key:
+		case ctrl_q_key:
+			game.going = false;
+			kernel.activate_menu = GAME_NO_MENU;
+			break;
+
+		case f1_key:
+			kernel.activate_menu = GAME_MAIN_MENU;
+			break;
+
+		case f2_key:
+			kernel.activate_menu = GAME_SAVE_MENU;
+			break;
+
+		case f3_key:
+			kernel.activate_menu = GAME_RESTORE_MENU;
+			break;
+
+		case f4_key:
+			kernel.activate_menu = GAME_SCORE_MENU;
+			break;
+
+		case f5_key:
+			kernel.activate_menu = GAME_MAIN_MENU;
+			break;
+
+		default:
+			kernel.activate_menu = GAME_MAIN_MENU;
+			break;
+		}
+	}
+
+	if (result == done_button) {
+		config_file.music_flag = !music_item->list->picked_element;
+		config_file.sound_flag = !sound_item->list->picked_element;
+		config_file.speech_flag = !speech_item->list->picked_element;
+		config_file.interface_hotspots = interface_item->list->picked_element;
+		config_file.screen_fade = fade_item->list->picked_element;
+		config_file.panning_speed = panning_item->list->picked_element;
+
+		global_write_config_file();
+		global_load_config_parameters();
+
+		kernel.activate_menu = GAME_NO_MENU;
+	}
+
+	if ((former_music != config_file.music_flag) ||
+		(former_sound != config_file.sound_flag)) {
+		game_exec_function(section_music_reset_pointer);
+	}
+
+	if (!config_file.speech_flag) {
+		if (speech_system_active)
+			speech_all_off();
+	}
+
+	popup_dialog_destroy();
+#endif
+}
+
+static void global_menu_difficulty() {
+#if 0
+	PopupItem *easy_item;
+	PopupItem *result;
+
+	popup_dialog_create(game_menu_popup, GAME_DIALOG_HEAP, 20);
+
+	popup_message(menu_quote(quote_difficulty_title), POPUP_CENTER, POPUP_FILL);
+	popup_blank(6);
+
+	easy_item = popup_menu(menu_quote(quote_difficulty_item1),
+		POPUP_CENTER, POPUP_FILL, MAIN_MENU_ITEM_WIDTH, 0,
+		0, 0, 0);
+
+	popup_blank(SPACE_BETWEEN);
+
+	(void)popup_menu(menu_quote(quote_difficulty_item2),
+		POPUP_CENTER, POPUP_FILL, MAIN_MENU_ITEM_WIDTH, 0,
+		0, 0, 0);
+
+
+	popup_width_force(DIFFICULTY_MENU_FORCE_WIDTH);
+
+	game_menu_popup->cancel_item = NULL;
+
+	result = popup_execute();
+
+	kernel.activate_menu = GAME_NO_MENU;
+
+	if (result == easy_item) {
+		game.difficulty = EASY_MODE;
+	} else {
+		game.difficulty = HARD_MODE;
+	}
+
+	if (result == NULL) {
+		game.going = false;
+	}
+
+	switch (game_menu_popup->key) {
+	case alt_x_key:
+	case ctrl_x_key:
+	case alt_q_key:
+	case ctrl_q_key:
+	case esc_key:
+		game.going = false;
+		break;
+	}
+
+	popup_dialog_destroy();
+#endif
+}
+
+static void global_menu_main() {
+#if 0
+	PopupItem *save_item;
+	PopupItem *restore_item;
+	PopupItem *score_item;
+	PopupItem *options_item;
+	PopupItem *resume_item;
+	PopupItem *quit_item;
+	PopupItem *result;
+
+	popup_dialog_create(game_menu_popup, GAME_DIALOG_HEAP, 20);
+
+	popup_sprite(box_param.logo, 1, POPUP_CENTER, POPUP_FILL);
+	popup_blank(6);
+
+	save_item = popup_menu(menu_quote(quote_main_item1),
+		POPUP_CENTER, POPUP_FILL, MAIN_MENU_ITEM_WIDTH, 0,
+		0, 0, 0);
+
+	popup_blank(SPACE_BETWEEN);
+
+	restore_item = popup_menu(menu_quote(quote_main_item2),
+		POPUP_CENTER, POPUP_FILL, MAIN_MENU_ITEM_WIDTH, 0,
+		0, 0, 0);
+
+	popup_blank(SPACE_BETWEEN);
+
+	score_item = popup_menu(menu_quote(quote_main_item6),
+		POPUP_CENTER, POPUP_FILL, MAIN_MENU_ITEM_WIDTH, 0,
+		0, 0, 0);
+
+	popup_blank(SPACE_BETWEEN);
+
+	options_item = popup_menu(menu_quote(quote_main_item3),
+		POPUP_CENTER, POPUP_FILL, MAIN_MENU_ITEM_WIDTH, 0,
+		0, 0, 0);
+
+	popup_blank(SPACE_BETWEEN);
+
+	resume_item = popup_menu(menu_quote(quote_main_item4),
+		POPUP_CENTER, POPUP_FILL, MAIN_MENU_ITEM_WIDTH, 0,
+		0, 0, 0);
+
+	popup_blank(SPACE_BETWEEN);
+
+	quit_item = popup_menu(menu_quote(quote_main_item5),
+		POPUP_CENTER, POPUP_FILL, MAIN_MENU_ITEM_WIDTH, 0,
+		0, 0, 0);
+
+	popup_width_force(MAIN_MENU_FORCE_WIDTH);
+	game_menu_popup->cancel_item = resume_item;
+
+	result = popup_execute();
+
+	if (result == save_item) {
+		kernel.activate_menu = GAME_SAVE_MENU;
+	} else if (result == restore_item) {
+		kernel.activate_menu = GAME_RESTORE_MENU;
+	} else if (result == options_item) {
+		kernel.activate_menu = GAME_OPTIONS_MENU;
+	} else if (result == score_item) {
+		kernel.activate_menu = GAME_SCORE_MENU;
+	} else {
+		kernel.activate_menu = GAME_NO_MENU;
+	}
+
+	if (result == quit_item)
+		game.going = false;
+
+	switch (game_menu_popup->key) {
+	case alt_q_key:
+	case alt_x_key:
+	case ctrl_q_key:
+		game.going = false;
+		kernel.activate_menu = GAME_NO_MENU;
+		break;
+
+	case f5_key:
+		kernel.activate_menu = GAME_SAVE_MENU;
+		break;
+
+	case f7_key:
+		kernel.activate_menu = GAME_RESTORE_MENU;
+		break;
+
+	case f8_key:
+		kernel.activate_menu = GAME_SCORE_MENU;
+		break;
+
+	case f10_key:
+		kernel.activate_menu = GAME_OPTIONS_MENU;
+		break;
+
+	default:
+		break;
+	}
+#endif
+}
+
+void global_game_menu() {
+	bool loaded = false;
+
+	if (box_param.series == NULL) {
+		Common::strcpy_s(box_param.name, "*BOX");
+		if (popup_box_load())
+			goto done;
+		loaded = true;
+	}
+
+	game_menu_setup();
+	g_engine->flushKeys();
+
+	do {
+		switch (kernel.activate_menu) {
+		case GAME_MAIN_MENU:
+			global_menu_main();
+			break;
+		case GAME_SAVE_MENU:
+			if (config_file.original_save_load) {
+				global_menu_save_restore(true);
+			} else {
+				kernel.activate_menu = GAME_NO_MENU;
+				g_engine->saveGameDialog();
+			}
+			break;
+		case GAME_RESTORE_MENU:
+			if (config_file.original_save_load) {
+				global_menu_save_restore(false);
+			} else {
+				kernel.activate_menu = GAME_NO_MENU;
+				if (g_engine->loadGameDialog())
+					// Dummy name to flag that load was successful
+					Common::strcpy_s(save_game_buf, "OK");
+			}
+			break;
+		case GAME_OPTIONS_MENU:
+			global_menu_options();
+			break;
+		case GAME_DIFFICULTY_MENU:
+			global_menu_difficulty();
+			break;
+		case GAME_SCORE_MENU:
+			global_menu_score();
+			break;
+		default:
+			kernel.activate_menu = GAME_NO_MENU;
+			break;
+		}
+	} while (!g_engine->shouldQuit() && game.going && kernel.activate_menu != GAME_NO_MENU);
+
+	game_menu_shutdown();
+
+	if (loaded) {
+		sprite_free(&box_param.menu, true);
+		sprite_free(&box_param.logo, true);
+		sprite_free(&box_param.series, true);
+	}
+
+done:
+	;
+}
+
+} // namespace Dragonsphere
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/dragonsphere/menus.h b/engines/mads/madsv2/dragonsphere/menus.h
new file mode 100644
index 00000000000..5876ffa2af8
--- /dev/null
+++ b/engines/mads/madsv2/dragonsphere/menus.h
@@ -0,0 +1,40 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef MADS_DRAGONSPHERE_MENUS_H
+#define MADS_DRAGONSPHERE_MENUS_H
+
+#include "common/scummsys.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Dragonsphere {
+
+extern void global_menu_system_init();
+extern void global_menu_system_shutdown();
+extern void global_emergency_save();
+extern void global_game_menu();
+
+} // namespace Dragonsphere
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/madsv2/dragonsphere/sound_dragonsphere.cpp b/engines/mads/madsv2/dragonsphere/sound_dragonsphere.cpp
new file mode 100644
index 00000000000..5c449b0f56e
--- /dev/null
+++ b/engines/mads/madsv2/dragonsphere/sound_dragonsphere.cpp
@@ -0,0 +1,1573 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "common/endian.h"
+#include "common/file.h"
+#include "common/md5.h"
+#include "common/textconsole.h"
+#include "mads/madsv2/dragonsphere/sound_dragonsphere.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Dragonsphere {
+
+void DragonSoundManager::validate() {
+	Common::File f;
+	static const char *const MD5[] = {
+		"cac84f53ccf18ca56f4c03352037790f",
+		"2dcdbe18ca5225384cdb97ceb7f5642a",
+		"c6001b0dfe32cb9399ab60742b631c2e",
+		"1596b657c6171e13714eaf114bf94641",
+		"ecbb8bdf1e2e36fcacedce79761e625b",
+		"29639869e5faed1378dd2cdc1d132889",
+		nullptr,
+		nullptr,
+		"379fcc9af2142f15a3e7166eee6dd49d"
+	};
+
+	for (int i = 1; i <= 9; ++i) {
+		if (i == 7 || i == 8)
+			continue;
+		Common::Path filename(Common::String::format("asound.dr%d", i));
+		if (!f.open(filename))
+			error("Could not process - %s", filename.toString().c_str());
+		Common::String md5str = Common::computeStreamMD5AsString(f, 8192);
+		f.close();
+
+		if (md5str != MD5[i - 1])
+			error("Invalid sound file - %s", filename.toString().c_str());
+	}
+}
+
+void DragonSoundManager::loadDriver(int sectionNumber) {
+	switch (sectionNumber) {
+	case 1:
+		_driver = new ASound1(_mixer, _opl);
+		break;
+	case 2:
+		_driver = new ASound2(_mixer, _opl);
+		break;
+	case 3:
+		_driver = new ASound3(_mixer, _opl);
+		break;
+	case 4:
+		_driver = new ASound4(_mixer, _opl);
+		break;
+	case 5:
+		_driver = new ASound5(_mixer, _opl);
+		break;
+	case 9:
+		_driver = new ASound9(_mixer, _opl);
+		break;
+	default:
+		_driver = nullptr;
+		return;
+	}
+}
+
+/*-----------------------------------------------------------------------*/
+/* ASound1  (asound.dr1)                                                  *
+ *-----------------------------------------------------------------------*/
+
+const ASound1::CommandPtr ASound1::_commandList[40] = {
+	&ASound1::command0,  &ASound1::command1,  &ASound1::command2,  &ASound1::command3,
+	&ASound1::command4,  &ASound1::command5,  &ASound1::command6,  &ASound1::command7,
+	&ASound1::command8,  nullptr,             nullptr,             nullptr,
+	nullptr,             nullptr,             nullptr,             nullptr,
+	&ASound1::command16, nullptr,             nullptr,             nullptr,
+	nullptr,             nullptr,             nullptr,             nullptr,
+	&ASound1::command24, &ASound1::command25, &ASound1::command26, &ASound1::command27,
+	nullptr,             nullptr,             nullptr,             nullptr,
+	&ASound1::command32, &ASound1::command33, &ASound1::command34, &ASound1::command35,
+	&ASound1::command36, &ASound1::command37, &ASound1::command38, &ASound1::command39
+};
+
+ASound1::ASound1(Audio::Mixer *mixer, OPL::OPL *opl)
+		: ASound(mixer, opl, "asound.dr1", 0x21e0, 0x4d20) {
+	// Load sound samples
+	auto samplesStream = getDataStream(0x1d4);
+	for (int i = 0; i < 120; ++i)
+		_samples.push_back(AdlibSample(samplesStream));
+}
+
+int ASound1::command(int commandId, int param) {
+	if (commandId > 39 || !_commandList[commandId])
+		return 0;
+	
+	return (this->*_commandList[commandId])();
+}
+
+// commands 0-8: delegate to base ASound
+int ASound1::command0() { return ASound::command0(); }
+int ASound1::command1() { return ASound::command1(); }
+int ASound1::command2() { return ASound::command2(); }
+int ASound1::command3() { return ASound::command3(); }
+int ASound1::command4() { return ASound::command4(); }
+int ASound1::command5() { return ASound::command5(); }
+int ASound1::command6() { return ASound::command6(); }
+int ASound1::command7() { return ASound::command7(); }
+int ASound1::command8() { return ASound::command8(); }
+
+int ASound1::commandMusic0() {
+	ASound::command1();
+	_channels[0]->load(loadData(0x1ECA));
+	_channels[1]->load(loadData(0x1FBF));
+	_channels[2]->load(loadData(0x2037));
+	_channels[3]->load(loadData(0x20EE));
+	_channels[4]->load(loadData(0x219B));
+	_channels[5]->load(loadData(0x21AF));
+	return 0;
+}
+
+int ASound1::commandMusic1() {
+	ASound::command1();
+	_channels[0]->load(loadData(0x3418));
+	_channels[1]->load(loadData(0x34EB));
+	_channels[2]->load(loadData(0x359B));
+	_channels[3]->load(loadData(0x3658));
+	_channels[4]->load(loadData(0x3667));
+	_channels[5]->load(loadData(0x3677));
+	return 0;
+}
+
+int ASound1::commandMusic2() {
+	ASound::command1();
+	_channels[0]->load(loadData(0x3688));
+	_channels[1]->load(loadData(0x387B));
+	_channels[2]->load(loadData(0x3A01));
+	_channels[3]->load(loadData(0x3BC6));
+	_channels[4]->load(loadData(0x3D31));
+	_channels[5]->load(loadData(0x3D41));
+	return 0;
+}
+
+int ASound1::commandMusic3() {
+	ASound::command1();
+	_channels[0]->load(loadData(0x3D52));
+	_channels[1]->load(loadData(0x3FD3));
+	_channels[2]->load(loadData(0x41FF));
+	_channels[3]->load(loadData(0x420C));
+	_channels[4]->load(loadData(0x4219));
+	_channels[5]->load(loadData(0x4229));
+	return 0;
+}
+
+// ---------------------------------------------------------------------------
+// command16 - random background music
+//
+// If channel 0 is active and already playing one of the five known music
+// pieces (identified by their starting offset in field_17), leave it alone.
+// Otherwise pick a piece at random: the original uses getRandomNumber() & 7,
+// discarding 0 and indexing a four-entry table repeated twice (entries 1-3
+// -> pieces 1-3, entries 4-7 -> same pieces again with entry 4 wrapping to
+// piece 0).  We reproduce this with a modulo-4 on a non-zero value.
+// ---------------------------------------------------------------------------
+int ASound1::command16() {
+	if (_channels[0]->_activeCount) {
+		// Special offset checks
+		int f = _channels[0]->_loopStartPtr - &_soundData[0];
+
+		if (f == 0 || f == 0x1ECA || f == 0x21C4 ||
+		    f == 0x3418 || f == 0x3688 || f == 0x3D52)
+			return 0;
+	}
+
+	int idx;
+	do {
+		idx = getRandomNumber() & 3;
+	} while (idx == 0);
+	_musicIndex = idx;
+
+	typedef int (ASound1::*MusicPtr)();
+	static const MusicPtr musicTable[4] = {
+		&ASound1::commandMusic0,
+		&ASound1::commandMusic1,
+		&ASound1::commandMusic2,
+		&ASound1::commandMusic3
+	};
+	return (this->*musicTable[idx])();
+}
+
+// ---------------------------------------------------------------------------
+// commands 24-27 - upper channel pool
+// ---------------------------------------------------------------------------
+
+int ASound1::command24() {
+	playSound(0x173A);
+	playSound(0x176D);
+	return 0;
+}
+
+int ASound1::command25() {
+	playSound(0x179B);
+	playSound(0x17C7);
+	return 0;
+}
+
+int ASound1::command26() {
+	playSound(0x17F5);
+	return 0;
+}
+
+int ASound1::command27() {
+	playSound(0x1801);
+	return 0;
+}
+
+// ---------------------------------------------------------------------------
+// commands 32-39
+// ---------------------------------------------------------------------------
+
+// command32 - no guard, no fade, load ch0-5
+int ASound1::command32() {
+	_channels[0]->load(loadData(0x2522));
+	_channels[1]->load(loadData(0x255D));
+	_channels[2]->load(loadData(0x2591));
+	_channels[3]->load(loadData(0x25BB));
+	_channels[4]->load(loadData(0x25E7));
+	_channels[5]->load(loadData(0x2613));
+	return 0;
+}
+
+// command33 - isSoundActive guard, command1, load ch0-5
+int ASound1::command33() {
+	byte *pData = loadData(0x266C);
+	if (!isSoundActive(pData)) {
+		ASound::command1();
+		_channels[0]->load(pData);
+		_channels[1]->load(loadData(0x2929));
+		_channels[2]->load(loadData(0x2B1D));
+		_channels[3]->load(loadData(0x2D37));
+		_channels[4]->load(loadData(0x2EC3));
+		_channels[5]->load(loadData(0x3033));
+	}
+	return 0;
+}
+
+// command34 - isSoundActive guard, stop(), load ch0-5
+int ASound1::command34() {
+	byte *pData = loadData(0x1852);
+	if (!isSoundActive(pData)) {
+		stop();
+		_channels[0]->load(pData);
+		_channels[1]->load(loadData(0x1AA9));
+		_channels[2]->load(loadData(0x1BC4));
+		_channels[3]->load(loadData(0x1CF1));
+		_channels[4]->load(loadData(0x1DF2));
+		_channels[5]->load(loadData(0x1EBE));
+	}
+	return 0;
+}
+
+// command35 - isSoundActive guard, command2 (lower-bank fade),
+// load ch0-5
+int ASound1::command35() {
+	byte *pData = loadData(0x0C36);
+	if (!isSoundActive(pData)) {
+		ASound::command2();
+		_channels[0]->load(pData);
+		_channels[1]->load(loadData(0x0D7F));
+		_channels[2]->load(loadData(0x0E48));
+		_channels[3]->load(loadData(0x0F10));
+		_channels[4]->load(loadData(0x0FB2));
+		_channels[5]->load(loadData(0x1096));
+	}
+	return 0;
+}
+
+// command36 - isSoundActive guard, command2 (lower-bank fade),
+// load ch0-5
+int ASound1::command36() {
+	byte *pData = loadData(0x1190);
+	if (!isSoundActive(pData)) {
+		ASound::command2();
+		_channels[0]->load(pData);
+		_channels[1]->load(loadData(0x12D7));
+		_channels[2]->load(loadData(0x13AA));
+		_channels[3]->load(loadData(0x1476));
+		_channels[4]->load(loadData(0x1528));
+		_channels[5]->load(loadData(0x1614));
+	}
+	return 0;
+}
+
+// command37 - isSoundActive guard, command1, four loadAny
+// calls starting from channel 0
+int ASound1::command37() {
+	byte *pData = loadData(0x3220);
+	if (!isSoundActive(pData)) {
+		ASound::command1();
+		findFreeChannel(pData);
+		findFreeChannel(loadData(0x326A));
+		findFreeChannel(loadData(0x3293));
+		findFreeChannel(loadData(0x32AC));
+	}
+	return 0;
+}
+
+// command38 - alias for commandMusic0; also the direct dispatch
+// target for command 38.
+int ASound1::command38() {
+	return commandMusic0();
+}
+
+// command39 - isSoundActive guard, command1, load ch0-5
+int ASound1::command39() {
+	byte *pData = loadData(0x423A);
+	if (!isSoundActive(pData)) {
+		ASound::command1();
+		_channels[0]->load(pData);
+		_channels[1]->load(loadData(0x43DF));
+		_channels[2]->load(loadData(0x44F7));
+		_channels[3]->load(loadData(0x45ED));
+		_channels[4]->load(loadData(0x46F9));
+		_channels[5]->load(loadData(0x48AF));
+	}
+	return 0;
+}
+
+/*-----------------------------------------------------------------------*/
+
+/*-----------------------------------------------------------------------*/
+/* ASound2  (asound.dr2)                                                  *
+ *-----------------------------------------------------------------------*/
+
+const ASound2::CommandPtr ASound2::_commandList[73] = {
+	// commands 0-8  (asound_commands1)
+	&ASound2::command0,  &ASound2::command1,  &ASound2::command2,  &ASound2::command3,
+	&ASound2::command4,  &ASound2::command5,  &ASound2::command6,  &ASound2::command7,
+	&ASound2::command8,
+	// 9-15 absent
+	nullptr,             nullptr,             nullptr,
+	nullptr,             nullptr,             nullptr,             nullptr,
+	// command 16  (asound_commands2)
+	&ASound2::command16,
+	// 17-23 absent
+	nullptr,             nullptr,             nullptr,
+	nullptr,             nullptr,             nullptr,             nullptr,
+	// commands 24-27  (asound_commands3)
+	&ASound2::command24, &ASound2::command25, &ASound2::command26, &ASound2::command27,
+	// 28-31 absent
+	nullptr,             nullptr,             nullptr,             nullptr,
+	// commands 32-35  (asound_commands4)
+	&ASound2::command32, &ASound2::command33, &ASound2::command34, &ASound2::command35,
+	// 36-63 absent
+	nullptr,             nullptr,             nullptr,             nullptr,
+	nullptr,             nullptr,             nullptr,             nullptr,
+	nullptr,             nullptr,             nullptr,             nullptr,
+	nullptr,             nullptr,             nullptr,             nullptr,
+	nullptr,             nullptr,             nullptr,             nullptr,
+	nullptr,             nullptr,             nullptr,             nullptr,
+	nullptr,             nullptr,             nullptr,             nullptr,
+	// commands 64-72  (asound_commands5)
+	&ASound2::command64, &ASound2::command65, &ASound2::command66, &ASound2::command67,
+	&ASound2::command68, &ASound2::command69, &ASound2::command70, &ASound2::command71,
+	&ASound2::command72
+};
+
+ASound2::ASound2(Audio::Mixer *mixer, OPL::OPL *opl)
+		: ASound(mixer, opl, "asound.dr2", 0x2040, 0x2300) {
+	// Load sound samples
+	auto samplesStream = getDataStream(0x1d4);
+	for (int i = 0; i < 120; ++i)
+		_samples.push_back(AdlibSample(samplesStream));
+}
+
+int ASound2::command(int commandId, int param) {
+	if (commandId > 72 || !_commandList[commandId])
+		return 0;
+
+	return (this->*_commandList[commandId])();
+}
+
+// commands 0-8: delegate to base ASound
+int ASound2::command0() { return ASound::command0(); }
+int ASound2::command1() { return ASound::command1(); }
+int ASound2::command2() { return ASound::command2(); }
+int ASound2::command3() { return ASound::command3(); }
+int ASound2::command4() { return ASound::command4(); }
+int ASound2::command5() { return ASound::command5(); }
+int ASound2::command6() { return ASound::command6(); }
+int ASound2::command7() { return ASound::command7(); }
+int ASound2::command8() { return ASound::command8(); }
+
+// ---------------------------------------------------------------------------
+// command16 - isSoundActive guard, command1, load ch0-5
+// ---------------------------------------------------------------------------
+int ASound2::command16() {
+	byte *pData = loadData(0x0C36);
+	if (!isSoundActive(pData)) {
+		ASound::command1();
+		_channels[0]->load(pData);
+		_channels[1]->load(loadData(0x0C8E));
+		_channels[2]->load(loadData(0x0CF4));
+		_channels[3]->load(loadData(0x0D4E));
+		_channels[4]->load(loadData(0x0DA3));
+		_channels[5]->load(loadData(0x0DB1));
+	}
+	return 0;
+}
+
+// ---------------------------------------------------------------------------
+// commands 24-27 (asound_commands3) - upper channel pool
+// ---------------------------------------------------------------------------
+
+int ASound2::command24() {
+	playSound(0x1A4A);
+	playSound(0x1A7D);
+	return 0;
+}
+
+int ASound2::command25() {
+	playSound(0x1AAB);
+	playSound(0x1AD7);
+	return 0;
+}
+
+int ASound2::command26() {
+	playSound(0x1B05);
+	return 0;
+}
+
+int ASound2::command27() {
+	playSound(0x1B11);
+	return 0;
+}
+
+// ---------------------------------------------------------------------------
+// commands 32-35 (asound_commands4)
+// ---------------------------------------------------------------------------
+
+// command32 - command1, six loadAny calls from channel 0
+int ASound2::command32() {
+	ASound::command1();
+	findFreeChannel(loadData(0x1BE4));
+	findFreeChannel(loadData(0x1CB7));
+	findFreeChannel(loadData(0x1E1E));
+	findFreeChannel(loadData(0x1EC8));
+	findFreeChannel(loadData(0x1ED8));
+	findFreeChannel(loadData(0x1EEF));
+	return 0;
+}
+
+// command33 - isSoundActive guard, command1, load ch0-7
+int ASound2::command33() {
+	byte *pData = loadData(0x1B62);
+	if (!isSoundActive(pData)) {
+		ASound::command1();
+		_channels[0]->load(pData);
+		_channels[1]->load(loadData(0x1B97));
+		_channels[2]->load(loadData(0x1BA5));
+		_channels[3]->load(loadData(0x1BB3));
+		_channels[4]->load(loadData(0x1BC1));
+		_channels[5]->load(loadData(0x1BC5));
+		_channels[6]->load(loadData(0x1BC9));
+		_channels[7]->load(loadData(0x1BD5));
+	}
+	return 0;
+}
+
+// command34 - isSoundActive guard, command1, load ch0-6
+int ASound2::command34() {
+	byte *pData = loadData(0x0DC0);
+	if (!isSoundActive(pData)) {
+		ASound::command1();
+		_channels[0]->load(pData);
+		_channels[1]->load(loadData(0x0FAF));
+		_channels[2]->load(loadData(0x1206));
+		_channels[3]->load(loadData(0x139A));
+		_channels[4]->load(loadData(0x1565));
+		_channels[5]->load(loadData(0x1833));
+		_channels[6]->load(loadData(0x18CD));
+	}
+	return 0;
+}
+
+// command35 - isSoundActive guard, command1, load ch0-6
+int ASound2::command35() {
+	byte *pData = loadData(0x1F02);
+	if (!isSoundActive(pData)) {
+		ASound::command1();
+		_channels[0]->load(pData);
+		_channels[1]->load(loadData(0x1F66));
+		_channels[2]->load(loadData(0x1F70));
+		_channels[3]->load(loadData(0x1F8D));
+		_channels[4]->load(loadData(0x1FCE));
+		_channels[5]->load(loadData(0x1FF7));
+		_channels[6]->load(loadData(0x202E));
+	}
+	return 0;
+}
+
+// ---------------------------------------------------------------------------
+// commands 64-72 (asound_commands5) - upper channel pool
+// ---------------------------------------------------------------------------
+
+int ASound2::command64() {
+	playSound(0x1928);
+	return 0;
+}
+
+int ASound2::command65() {
+	playSound(0x193C);
+	return 0;
+}
+
+int ASound2::command66() {
+	playSound(0x1946);
+	playSound(0x195C);
+	return 0;
+}
+
+int ASound2::command67() {
+	playSound(0x196D);
+	return 0;
+}
+
+// no-op
+int ASound2::command68() {
+	return 0;
+}
+
+int ASound2::command69() {
+	playSound(0x197F);
+	playSound(0x19A5);
+	playSound(0x19CB);
+	return 0;
+}
+
+int ASound2::command70() {
+	playSound(0x19E5);
+	playSound(0x19F1);
+	return 0;
+}
+
+int ASound2::command71() {
+	playSound(0x19FF);
+	return 0;
+}
+
+int ASound2::command72() {
+	playSound(0x1A0D);
+	playSound(0x1A10);
+	return 0;
+}
+
+/*-----------------------------------------------------------------------*/
+
+/*-----------------------------------------------------------------------*/
+/* ASound3  (asound.dr3)                                                  *
+ *-----------------------------------------------------------------------*/
+
+const ASound3::CommandPtr ASound3::_commandList[77] = {
+	// commands 0-8  (asound_commands1)
+	&ASound3::command0,  &ASound3::command1,  &ASound3::command2,  &ASound3::command3,
+	&ASound3::command4,  &ASound3::command5,  &ASound3::command6,  &ASound3::command7,
+	&ASound3::command8,
+	// 9-15 absent
+	nullptr,             nullptr,             nullptr,
+	nullptr,             nullptr,             nullptr,             nullptr,
+	// command 16  (asound_commands2)
+	&ASound3::command16,
+	// 17-23 absent
+	nullptr,             nullptr,             nullptr,
+	nullptr,             nullptr,             nullptr,             nullptr,
+	// commands 24-27  (asound_commands3)
+	&ASound3::command24, &ASound3::command25, &ASound3::command26, &ASound3::command27,
+	// 28-31 absent
+	nullptr,             nullptr,             nullptr,             nullptr,
+	// commands 32-37  (asound_commands4)
+	&ASound3::command32, &ASound3::command33, &ASound3::command34, &ASound3::command35,
+	&ASound3::command36, &ASound3::command37,
+	// 38-63 absent
+	nullptr,             nullptr,             nullptr,             nullptr,
+	nullptr,             nullptr,             nullptr,             nullptr,
+	nullptr,             nullptr,             nullptr,             nullptr,
+	nullptr,             nullptr,             nullptr,             nullptr,
+	nullptr,             nullptr,             nullptr,             nullptr,
+	nullptr,             nullptr,             nullptr,             nullptr,
+	nullptr,             nullptr,
+	// commands 64-75  (asound_commands5)
+	&ASound3::command64, &ASound3::command65, &ASound3::command66, &ASound3::command67,
+	&ASound3::command68, &ASound3::command69, &ASound3::command70, &ASound3::command71,
+	&ASound3::command72, &ASound3::command73, &ASound3::command74, &ASound3::command75,
+	// command 76 = nullsub_8
+	nullptr
+};
+
+ASound3::ASound3(Audio::Mixer *mixer, OPL::OPL *opl)
+		: ASound(mixer, opl, "asound.dr3", 0x20c0, 0x31a0) {
+	// Load sound samples
+	auto samplesStream = getDataStream(0x1d4);
+	for (int i = 0; i < 120; ++i)
+		_samples.push_back(AdlibSample(samplesStream));
+}
+
+int ASound3::command(int commandId, int param) {
+	if (commandId > 76 || !_commandList[commandId])
+		return 0;
+	
+	return (this->*_commandList[commandId])();
+}
+
+// commands 0-8: delegate to base ASound
+int ASound3::command0() { return ASound::command0(); }
+int ASound3::command1() { return ASound::command1(); }
+int ASound3::command2() { return ASound::command2(); }
+int ASound3::command3() { return ASound::command3(); }
+int ASound3::command4() { return ASound::command4(); }
+int ASound3::command5() { return ASound::command5(); }
+int ASound3::command6() { return ASound::command6(); }
+int ASound3::command7() { return ASound::command7(); }
+int ASound3::command8() { return ASound::command8(); }
+
+// ---------------------------------------------------------------------------
+// sub_11CC6 - shared helper used by command34.
+// isSoundActive guard on 0xC36; if not active: command1, load ch0-7.
+// (The tiny ch6 and ch7 blocks - 4 bytes each - are very short sub-blocks
+// within the same composite sound.)
+// ---------------------------------------------------------------------------
+void ASound3::sub11CC6() {
+	byte *pData = loadData(0x0C36);
+	if (!isSoundActive(pData)) {
+		ASound::command1();
+		_channels[0]->load(pData);
+		_channels[1]->load(loadData(0x0C6B));
+		_channels[2]->load(loadData(0x0C79));
+		_channels[3]->load(loadData(0x0C87));
+		_channels[4]->load(loadData(0x0C95));
+		_channels[5]->load(loadData(0x0C99));
+		_channels[6]->load(loadData(0x0C9D));
+		_channels[7]->load(loadData(0x0CA9));
+	}
+}
+
+// ---------------------------------------------------------------------------
+// command16 - isSoundActive guard, command1, load ch0-5
+// ---------------------------------------------------------------------------
+int ASound3::command16() {
+	byte *pData = loadData(0x24F2);
+	if (!isSoundActive(pData)) {
+		ASound::command1();
+		_channels[0]->load(pData);
+		_channels[1]->load(loadData(0x259E));
+		_channels[2]->load(loadData(0x2627));
+		_channels[3]->load(loadData(0x26AE));
+		_channels[4]->load(loadData(0x2761));
+		_channels[5]->load(loadData(0x2810));
+	}
+	return 0;
+}
+
+// ---------------------------------------------------------------------------
+// commands 24-27 (asound_commands3) - upper channel pool
+// ---------------------------------------------------------------------------
+
+int ASound3::command24() {
+	playSound(0x2A7C);
+	playSound(0x2AAF);
+	return 0;
+}
+
+int ASound3::command25() {
+	playSound(0x2ADD);
+	playSound(0x2B09);
+	return 0;
+}
+
+int ASound3::command26() {
+	playSound(0x2B37);
+	return 0;
+}
+
+int ASound3::command27() {
+	playSound(0x2B43);
+	return 0;
+}
+
+// ---------------------------------------------------------------------------
+// commands 32-37 (asound_commands4)
+// ---------------------------------------------------------------------------
+
+// command32 - isSoundActive guard, command1, load ch0-7
+int ASound3::command32() {
+	byte *pData = loadData(0x2B94);
+	if (!isSoundActive(pData)) {
+		ASound::command1();
+		_channels[0]->load(pData);
+		_channels[1]->load(loadData(0x2C00));
+		_channels[2]->load(loadData(0x2C49));
+		_channels[3]->load(loadData(0x2C8C));
+		_channels[4]->load(loadData(0x2D23));
+		_channels[5]->load(loadData(0x2DCE));
+		_channels[6]->load(loadData(0x2E25));
+		_channels[7]->load(loadData(0x2E84));
+	}
+	return 0;
+}
+
+// command33 - isSoundActive guard, command1, load ch0-6
+int ASound3::command33() {
+	byte *pData = loadData(0x149E);
+	if (!isSoundActive(pData)) {
+		ASound::command1();
+		_channels[0]->load(pData);
+		_channels[1]->load(loadData(0x16AB));
+		_channels[2]->load(loadData(0x1933));
+		_channels[3]->load(loadData(0x1A2F));
+		_channels[4]->load(loadData(0x1C25));
+		_channels[5]->load(loadData(0x1ECD));
+		_channels[6]->load(loadData(0x206F));
+	}
+	return 0;
+}
+
+// command34 - calls sub11CC6 (loads ch0-7 if not active),
+// then unconditionally loads ch8 at 0x298E
+int ASound3::command34() {
+	sub11CC6();
+	_channels[8]->load(loadData(0x298E));
+	return 0;
+}
+
+// command35 - isSoundActive guard, command1, load ch0-5
+int ASound3::command35() {
+	byte *pData = loadData(0x0CB8);
+	if (!isSoundActive(pData)) {
+		ASound::command1();
+		_channels[0]->load(pData);
+		_channels[1]->load(loadData(0x0E55));
+		_channels[2]->load(loadData(0x0F63));
+		_channels[3]->load(loadData(0x1051));
+		_channels[4]->load(loadData(0x1159));
+		_channels[5]->load(loadData(0x130B));
+	}
+	return 0;
+}
+
+// command36 - isSoundActive guard, command1, load ch0-5
+int ASound3::command36() {
+	byte *pData = loadData(0x2072);
+	if (!isSoundActive(pData)) {
+		ASound::command1();
+		_channels[0]->load(pData);
+		_channels[1]->load(loadData(0x2136));
+		_channels[2]->load(loadData(0x23EA));
+		_channels[3]->load(loadData(0x243D));
+		_channels[4]->load(loadData(0x2455));
+		_channels[5]->load(loadData(0x24A3));
+	}
+	return 0;
+}
+
+// command37 - single upper-pool voice
+int ASound3::command37() {
+	playSound(0x298E);
+	return 0;
+}
+
+// ---------------------------------------------------------------------------
+// commands 64-75 (asound_commands5)
+// ---------------------------------------------------------------------------
+
+int ASound3::command64() {
+	_channels[6]->load(loadData(0x28CA));
+	_channels[8]->load(loadData(0x28FC));
+	return 0;
+}
+
+int ASound3::command65() {
+	_channels[6]->load(loadData(0x2919));
+	_channels[8]->load(loadData(0x292A));
+	return 0;
+}
+
+int ASound3::command66() {
+	_channels[6]->load(loadData(0x2937));
+	_channels[7]->load(loadData(0x2956));
+	_channels[8]->load(loadData(0x2965));
+	return 0;
+}
+
+int ASound3::command67() {
+	playSound(0x2984);
+	return 0;
+}
+
+int ASound3::command68() {
+	playSound(0x2998);
+	playSound(0x29AE);
+	playSound(0x29C2);
+	return 0;
+}
+
+int ASound3::command69() {
+	playSound(0x29D8);
+	return 0;
+}
+
+int ASound3::command70() {
+	playSound(0x2B4F);
+	return 0;
+}
+
+int ASound3::command71() {
+	playSound(0x2B5E);
+	return 0;
+}
+
+int ASound3::command72() {
+	_channels[7]->load(loadData(0x29EA));
+	_channels[8]->load(loadData(0x2A18));
+	return 0;
+}
+
+int ASound3::command73() {
+	playSound(0x2A44);
+	return 0;
+}
+
+int ASound3::command74() {
+	playSound(0x2A4E);
+	return 0;
+}
+
+int ASound3::command75() {
+	_channels[7]->load(loadData(0x29FB));
+	_channels[8]->load(loadData(0x2A29));
+	return 0;
+}
+
+/*-----------------------------------------------------------------------*/
+
+/*-----------------------------------------------------------------------*/
+/* ASound4  (asound.dr4)                                                  *
+ *-----------------------------------------------------------------------*/
+
+const ASound4::CommandPtr ASound4::_commandList[71] = {
+	// commands 0-8  (asound_commands1)
+	&ASound4::command0,  &ASound4::command1,  &ASound4::command2,  &ASound4::command3,
+	&ASound4::command4,  &ASound4::command5,  &ASound4::command6,  &ASound4::command7,
+	&ASound4::command8,
+	// 9-15 absent
+	nullptr,             nullptr,             nullptr,
+	nullptr,             nullptr,             nullptr,             nullptr,
+	// command 16  (asound_commands2)
+	&ASound4::command16,
+	// 17-23 absent
+	nullptr,             nullptr,             nullptr,
+	nullptr,             nullptr,             nullptr,             nullptr,
+	// commands 24-27  (asound_commands3)
+	&ASound4::command24, &ASound4::command25, &ASound4::command26, &ASound4::command27,
+	// 28-63 absent (the 0x20-range table has max=0, unreachable)
+	nullptr,             nullptr,             nullptr,             nullptr,
+	nullptr,             nullptr,             nullptr,             nullptr,
+	nullptr,             nullptr,             nullptr,             nullptr,
+	nullptr,             nullptr,             nullptr,             nullptr,
+	nullptr,             nullptr,             nullptr,             nullptr,
+	nullptr,             nullptr,             nullptr,             nullptr,
+	nullptr,             nullptr,             nullptr,             nullptr,
+	nullptr,             nullptr,             nullptr,             nullptr,
+	nullptr,             nullptr,             nullptr,             nullptr,
+	// commands 64-70  (asound_commands4)
+	&ASound4::command64, &ASound4::command65, &ASound4::command66, &ASound4::command67,
+	&ASound4::command68, &ASound4::command69, &ASound4::command70
+};
+
+ASound4::ASound4(Audio::Mixer *mixer, OPL::OPL *opl)
+		: ASound(mixer, opl, "asound.dr4", 0x1f90, 0x14d0) {
+	// Load sound samples
+	auto samplesStream = getDataStream(0x1d4);
+	for (int i = 0; i < 120; ++i)
+		_samples.push_back(AdlibSample(samplesStream));
+}
+
+int ASound4::command(int commandId, int param) {
+	if (commandId > 70 || !_commandList[commandId])
+		return 0;
+	
+	return (this->*_commandList[commandId])();
+}
+
+// commands 0-8: delegate to base ASound
+int ASound4::command0() { return ASound::command0(); }
+int ASound4::command1() { return ASound::command1(); }
+int ASound4::command2() { return ASound::command2(); }
+int ASound4::command3() { return ASound::command3(); }
+int ASound4::command4() { return ASound::command4(); }
+int ASound4::command5() { return ASound::command5(); }
+int ASound4::command6() { return ASound::command6(); }
+int ASound4::command7() { return ASound::command7(); }
+int ASound4::command8() { return ASound::command8(); }
+
+// ---------------------------------------------------------------------------
+// command16 - isSoundActive guard, command1, load ch0-6
+// ---------------------------------------------------------------------------
+int ASound4::command16() {
+	byte *pData = loadData(0x0C36);
+	if (!isSoundActive(pData)) {
+		ASound::command1();
+		_channels[0]->load(pData);
+		_channels[1]->load(loadData(0x0C75));
+		_channels[2]->load(loadData(0x0EF1));
+		_channels[3]->load(loadData(0x0F19));
+		_channels[4]->load(loadData(0x0F41));
+		_channels[5]->load(loadData(0x0F67));
+		_channels[6]->load(loadData(0x0F90));
+	}
+	return 0;
+}
+
+// ---------------------------------------------------------------------------
+// commands 24-27 (asound_commands3) - upper pool
+//
+// commands 24 and 25 are both wired to the same handler,
+// which loads two upper-pool sounds.
+// ---------------------------------------------------------------------------
+
+int ASound4::command24() {
+	playSound(0x0FFA);
+	playSound(0x100C);
+	return 0;
+}
+
+int ASound4::command25() {
+	return command24();
+}
+
+int ASound4::command26() {
+	playSound(0x119D);
+	return 0;
+}
+
+int ASound4::command27() {
+	playSound(0x11A9);
+	return 0;
+}
+
+// ---------------------------------------------------------------------------
+// commands 64-70 (asound_commands4, base 0x40)
+// All entries use the upper pool
+// ---------------------------------------------------------------------------
+
+int ASound4::command64() {
+	playSound(0x1017);
+	playSound(0x1031);
+	return 0;
+}
+
+int ASound4::command65() {
+	playSound(0x1042);
+	playSound(0x104B);
+	return 0;
+}
+
+int ASound4::command66() {
+	playSound(0x105F);
+	playSound(0x1068);
+	return 0;
+}
+
+int ASound4::command67() {
+	playSound(0x1078);
+	playSound(0x1081);
+	return 0;
+}
+
+int ASound4::command68() {
+	playSound(0x108F);
+	return 0;
+}
+
+int ASound4::command69() {
+	playSound(0x109B);
+	return 0;
+}
+
+int ASound4::command70() {
+	playSound(0x10A5);
+	playSound(0x10A8);
+	return 0;
+}
+
+/*-----------------------------------------------------------------------*/
+
+/*-----------------------------------------------------------------------*/
+/* ASound5  (asound.dr5)                                                  *
+ *-----------------------------------------------------------------------*/
+
+const ASound5::CommandPtr ASound5::_commandList[79] = {
+	// commands 0-8  (asound_commands1)
+	&ASound5::command0,  &ASound5::command1,  &ASound5::command2,  &ASound5::command3,
+	&ASound5::command4,  &ASound5::command5,  &ASound5::command6,  &ASound5::command7,
+	&ASound5::command8,
+	// 9-15 absent
+	nullptr,             nullptr,             nullptr,
+	nullptr,             nullptr,             nullptr,             nullptr,
+	// command 16  (asound_commands2)
+	&ASound5::command16,
+	// 17-23 absent
+	nullptr,             nullptr,             nullptr,
+	nullptr,             nullptr,             nullptr,             nullptr,
+	// commands 24-27  (asound_commands3)
+	&ASound5::command24, &ASound5::command25, &ASound5::command26, &ASound5::command27,
+	// 28-31 absent
+	nullptr,             nullptr,             nullptr,             nullptr,
+	// commands 32-39  (asound_commands4)
+	&ASound5::command32, &ASound5::command33, &ASound5::command34, &ASound5::command35,
+	&ASound5::command36, &ASound5::command37, &ASound5::command38, &ASound5::command39,
+	// 40-63 absent
+	nullptr,             nullptr,             nullptr,             nullptr,
+	nullptr,             nullptr,             nullptr,             nullptr,
+	nullptr,             nullptr,             nullptr,             nullptr,
+	nullptr,             nullptr,             nullptr,             nullptr,
+	nullptr,             nullptr,             nullptr,             nullptr,
+	nullptr,             nullptr,             nullptr,             nullptr,
+	// commands 64-78  (asound_commands5)
+	&ASound5::command64, &ASound5::command65, &ASound5::command66, &ASound5::command67,
+	&ASound5::command68, &ASound5::command69, &ASound5::command70, &ASound5::command71,
+	&ASound5::command72, &ASound5::command73, &ASound5::command74, &ASound5::command75,
+	&ASound5::command76, &ASound5::command77, &ASound5::command78
+};
+
+ASound5::ASound5(Audio::Mixer *mixer, OPL::OPL *opl)
+		: ASound(mixer, opl, "asound.dr5", 0x2140, 0x5cd0) {
+	// Load sound samples
+	auto samplesStream = getDataStream(0x1d4);
+	for (int i = 0; i < 120; ++i)
+		_samples.push_back(AdlibSample(samplesStream));
+}
+
+int ASound5::command(int commandId, int param) {
+	if (commandId > 78 || !_commandList[commandId])
+		return 0;
+	
+	return (this->*_commandList[commandId])();
+}
+
+// commands 0-8: delegate to base ASound
+int ASound5::command0() { return ASound::command0(); }
+int ASound5::command1() { return ASound::command1(); }
+int ASound5::command2() { return ASound::command2(); }
+int ASound5::command3() { return ASound::command3(); }
+int ASound5::command4() { return ASound::command4(); }
+int ASound5::command5() { return ASound::command5(); }
+int ASound5::command6() { return ASound::command6(); }
+int ASound5::command7() { return ASound::command7(); }
+int ASound5::command8() { return ASound::command8(); }
+
+// ---------------------------------------------------------------------------
+// command16 - isSoundActive guard, command1, load ch0-5
+// ---------------------------------------------------------------------------
+int ASound5::command16() {
+	byte *pData = loadData(0x4142);
+	if (!isSoundActive(pData)) {
+		ASound::command1();
+		_channels[0]->load(pData);
+		_channels[1]->load(loadData(0x41BA));
+		_channels[2]->load(loadData(0x424C));
+		_channels[3]->load(loadData(0x42D1));
+		_channels[4]->load(loadData(0x4316));
+		_channels[5]->load(loadData(0x43AE));
+	}
+	return 0;
+}
+
+// ---------------------------------------------------------------------------
+// commands 24-27 (asound_commands3) - upper pool
+// ---------------------------------------------------------------------------
+
+int ASound5::command24() {
+	playSound(0x51FA);
+	playSound(0x522D);
+	return 0;
+}
+
+int ASound5::command25() {
+	playSound(0x525B);
+	playSound(0x5287);
+	return 0;
+}
+
+int ASound5::command26() {
+	playSound(0x52B5);
+	return 0;
+}
+
+// three upper-pool voices
+int ASound5::command27() {
+	playSound(0x4040);
+	playSound(0x404A);
+	playSound(0x4061);
+	return 0;
+}
+
+// ---------------------------------------------------------------------------
+// commands 32-39 (asound_commands4)
+// ---------------------------------------------------------------------------
+
+// command1, eight loadAny (lower pool, AdlibChannel_loadAny)
+int ASound5::command32() {
+	ASound::command1();
+	findFreeChannel(loadData(0x43BC));
+	findFreeChannel(loadData(0x466D));
+	findFreeChannel(loadData(0x4773));
+	findFreeChannel(loadData(0x4953));
+	findFreeChannel(loadData(0x4B4B));
+	findFreeChannel(loadData(0x4D93));
+	findFreeChannel(loadData(0x4EC7));
+	findFreeChannel(loadData(0x5071));
+	return 0;
+}
+
+// isSoundActive guard, command1, load ch0-6
+int ASound5::command33() {
+	byte *pData = loadData(0x21C6);
+	if (!isSoundActive(pData)) {
+		ASound::command1();
+		_channels[0]->load(pData);
+		_channels[1]->load(loadData(0x2427));
+		_channels[2]->load(loadData(0x26B3));
+		_channels[3]->load(loadData(0x27C3));
+		_channels[4]->load(loadData(0x29F1));
+		_channels[5]->load(loadData(0x2CB9));
+		_channels[6]->load(loadData(0x2E89));
+	}
+	return 0;
+}
+
+// isSoundActive guard, command1, load ch0-5 (non-sequential)
+// ch1 and ch3 use data from the 0x4000 region; ch0/ch2/ch4 from 0x2E9E region
+int ASound5::command34() {
+	byte *pData = loadData(0x2E9E);
+	if (!isSoundActive(pData)) {
+		ASound::command1();
+		_channels[0]->load(pData);
+		_channels[1]->load(loadData(0x4003));
+		_channels[2]->load(loadData(0x348F));
+		_channels[3]->load(loadData(0x400A));
+		_channels[4]->load(loadData(0x3A1F));
+		_channels[5]->load(loadData(0x4011));
+	}
+	return 0;
+}
+
+// isSoundActive guard, command1, load ch0-5 (non-sequential)
+// ch1/ch3/ch5 use data from the 0x2196 region interleaved with ch0/ch2/ch4
+int ASound5::command35() {
+	byte *pData = loadData(0x1D0A);
+	if (!isSoundActive(pData)) {
+		ASound::command1();
+		_channels[0]->load(pData);
+		_channels[1]->load(loadData(0x2196));
+		_channels[2]->load(loadData(0x1E4A));
+		_channels[3]->load(loadData(0x21A8));
+		_channels[4]->load(loadData(0x1F7A));
+		_channels[5]->load(loadData(0x21BA));
+	}
+	return 0;
+}
+
+// isSoundActive guard, command1, load ch0-5 (non-sequential)
+// ch4 and ch5 reuse blocks at 0x15EC and 0x18D9 that precede ch0's data
+int ASound5::command36() {
+	byte *pData = loadData(0x15F5);
+	if (!isSoundActive(pData)) {
+		ASound::command1();
+		_channels[0]->load(pData);
+		_channels[1]->load(loadData(0x18E2));
+		_channels[2]->load(loadData(0x1A28));
+		_channels[3]->load(loadData(0x1C59));
+		_channels[4]->load(loadData(0x15EC));
+		_channels[5]->load(loadData(0x18D9));
+	}
+	return 0;
+}
+
+// isSoundActive guard, command1, load ch0-8
+int ASound5::command37() {
+	byte *pData = loadData(0x1190);
+	if (!isSoundActive(pData)) {
+		ASound::command1();
+		_channels[0]->load(pData);
+		_channels[1]->load(loadData(0x131D));
+		_channels[2]->load(loadData(0x1497));
+		_channels[3]->load(loadData(0x14D3));
+		_channels[4]->load(loadData(0x1513));
+		_channels[5]->load(loadData(0x153F));
+		_channels[6]->load(loadData(0x156B));
+		_channels[7]->load(loadData(0x159D));
+		_channels[8]->load(loadData(0x15D1));
+	}
+	return 0;
+}
+
+// isSoundActive guard, command2 (lower-bank fade), load ch0-5
+int ASound5::command38() {
+	byte *pData = loadData(0x0C36);
+	if (!isSoundActive(pData)) {
+		ASound::command2();
+		_channels[0]->load(pData);
+		_channels[1]->load(loadData(0x0D7F));
+		_channels[2]->load(loadData(0x0E48));
+		_channels[3]->load(loadData(0x0F10));
+		_channels[4]->load(loadData(0x0FB2));
+		_channels[5]->load(loadData(0x1096));
+	}
+	return 0;
+}
+
+// isSoundActive guard, command3 (lower-bank fade only), load ch0-5
+int ASound5::command39() {
+	byte *pData = loadData(0x5312);
+	if (!isSoundActive(pData)) {
+		ASound::command3();
+		_channels[0]->load(pData);
+		_channels[1]->load(loadData(0x5569));
+		_channels[2]->load(loadData(0x567C));
+		_channels[3]->load(loadData(0x579D));
+		_channels[4]->load(loadData(0x5890));
+		_channels[5]->load(loadData(0x5954));
+	}
+	return 0;
+}
+
+// ---------------------------------------------------------------------------
+// commands 64-78 (asound_commands5) - upper pool unless noted
+// ---------------------------------------------------------------------------
+
+int ASound5::command64() {
+	playSound(0x4101);
+	return 0;
+}
+
+int ASound5::command65() {
+	playSound(0x401A);
+	return 0;
+}
+
+int ASound5::command66() {
+	playSound(0x402C);
+	return 0;
+}
+
+int ASound5::command67() {
+	playSound(0x4036);
+	return 0;
+}
+
+int ASound5::command68() {
+	playSound(0x407A);
+	return 0;
+}
+
+int ASound5::command69() {
+	playSound(0x408C);
+	return 0;
+}
+
+// also shared by command77 and command78
+int ASound5::command70() {
+	playSound(0x40BA);
+	return 0;
+}
+
+int ASound5::command71() {
+	playSound(0x40C8);
+	return 0;
+}
+
+int ASound5::command72() {
+	playSound(0x40D2);
+	return 0;
+}
+
+int ASound5::command73() {
+	playSound(0x40DC);
+	playSound(0x40E7);
+	return 0;
+}
+
+int ASound5::command74() {
+	playSound(0x410B);
+	return 0;
+}
+
+int ASound5::command75() {
+	playSound(0x4129);
+	playSound(0x4134);
+	return 0;
+}
+
+// same block as command70
+int ASound5::command76() {
+	return command70();
+}
+
+// same block as command70
+int ASound5::command77() {
+	return command70();
+}
+
+int ASound5::command78() {
+	playSound(0x411F);
+	return 0;
+}
+
+/*-----------------------------------------------------------------------*/
+
+const ASound9::CommandPtr ASound9::_commandList[72] = {
+	&ASound9::command0,  &ASound9::command1,  &ASound9::command2,  &ASound9::command3,
+	&ASound9::command4,  &ASound9::command5,  &ASound9::command6,  &ASound9::command7,
+	&ASound9::command8,  nullptr,             nullptr,             nullptr,
+	nullptr,             nullptr,             nullptr,             nullptr,
+	&ASound9::command16, nullptr,             nullptr,             nullptr,
+	nullptr,             nullptr,             nullptr,             nullptr,
+	&ASound9::command24, &ASound9::command25, &ASound9::command26, &ASound9::command27,
+	nullptr,             nullptr,             nullptr,             nullptr,
+	&ASound9::command32, &ASound9::command33, &ASound9::command34, &ASound9::command35,
+	&ASound9::command36, &ASound9::command37, &ASound9::command38, &ASound9::command39,
+	nullptr,             nullptr,             nullptr,             nullptr,
+	nullptr,             nullptr,             nullptr,             nullptr,
+	nullptr,             nullptr,             nullptr,             nullptr,
+	nullptr,             nullptr,             nullptr,             nullptr,
+	nullptr,             nullptr,             nullptr,             nullptr,
+	nullptr,             nullptr,             nullptr,             nullptr,
+	&ASound9::command64, &ASound9::command65, &ASound9::command66, &ASound9::command67,
+	&ASound9::command68, &ASound9::command69, &ASound9::command70, &ASound9::command71
+};
+
+ASound9::ASound9(Audio::Mixer *mixer, OPL::OPL *opl) :
+		ASound(mixer, opl, "asound.dr9", 0x20c0, 0x3690) {
+	// Load sound samples
+	auto samplesStream = getDataStream(0x1d4);
+	for (int i = 0; i < 120; ++i)
+		_samples.push_back(AdlibSample(samplesStream));
+}
+
+int ASound9::command(int commandId, int param) {
+	if (commandId > 71 || !_commandList[commandId])
+		return 0;
+	
+	return (this->*_commandList[commandId])();
+}
+
+// commands 0-8: delegate to base ASound
+int ASound9::command0() {
+	return ASound::command0();
+}
+int ASound9::command1() {
+	return ASound::command1();
+}
+int ASound9::command2() {
+	return ASound::command2();
+}
+int ASound9::command3() {
+	return ASound::command3();
+}
+int ASound9::command4() {
+	return ASound::command4();
+}
+int ASound9::command5() {
+	return ASound::command5();
+}
+int ASound9::command6() {
+	return ASound::command6();
+}
+int ASound9::command7() {
+	return ASound::command7();
+}
+int ASound9::command8() {
+	return ASound::command8();
+}
+
+int ASound9::command24() {
+	playSound(0x203E);
+	playSound(0x2071);
+	return 0;
+}
+
+int ASound9::command25() {
+	playSound(0x209F);
+	playSound(0x20CB);
+	return 0;
+}
+
+int ASound9::command26() {
+	playSound(0x20F9);
+	return 0;
+}
+
+int ASound9::command27() {
+	playSound(0x2105);
+	return 0;
+}
+
+int ASound9::command32() {
+	ASound::command1();
+	findFreeChannel(loadData(0x2B16));
+	findFreeChannel(loadData(0x2B6C));
+	findFreeChannel(loadData(0x2BB6));
+	findFreeChannel(loadData(0x2E88));
+	findFreeChannel(loadData(0x2E98));
+	findFreeChannel(loadData(0x2EA3));
+	findFreeChannel(loadData(0x2EAE));
+	findFreeChannel(loadData(0x2EB7));
+	return 0;
+}
+
+int ASound9::command33() {
+	return 0;
+}
+
+int ASound9::command34() {
+	ASound::command1();
+	_channels[0]->load(loadData(0x31D0));
+	_channels[1]->load(loadData(0x3221));
+	_channels[2]->load(loadData(0x3282));
+	_channels[3]->load(loadData(0x32CB));
+	_channels[4]->load(loadData(0x331A));
+	_channels[5]->load(loadData(0x3369));
+	_channels[6]->load(loadData(0x33B0));
+	return 0;
+}
+
+int ASound9::command35() {
+	ASound::command1();
+	_channels[0]->load(loadData(0x295E));
+	_channels[1]->load(loadData(0x299E));
+	_channels[2]->load(loadData(0x29C3));
+	_channels[3]->load(loadData(0x29E8));
+	_channels[4]->load(loadData(0x2A46));
+	_channels[5]->load(loadData(0x2AA5));
+	_channels[6]->load(loadData(0x2AE0));
+	return 0;
+}
+
+int ASound9::command36() {
+	ASound::command1();
+	_channels[0]->load(loadData(0x30AA));
+	_channels[1]->load(loadData(0x30DD));
+	_channels[2]->load(loadData(0x3109));
+	_channels[3]->load(loadData(0x313D));
+	_channels[4]->load(loadData(0x3175));
+	_channels[5]->load(loadData(0x319B));
+	return 0;
+}
+
+int ASound9::command37() {
+	ASound::command1();
+	_channels[0]->load(loadData(0x2156));
+	_channels[1]->load(loadData(0x21A6));
+	_channels[2]->load(loadData(0x228E));
+	_channels[3]->load(loadData(0x22F7));
+	_channels[4]->load(loadData(0x2351));
+	_channels[5]->load(loadData(0x25A8));
+	_channels[6]->load(loadData(0x28BF));
+	return 0;
+}
+
+int ASound9::command38() {
+	byte *pData = loadData(0x11BC);
+	if (!isSoundActive(pData)) {
+		ASound::command1();
+		_channels[0]->load(pData);
+		_channels[1]->load(loadData(0x1477));
+		_channels[2]->load(loadData(0x158D));
+		_channels[3]->load(loadData(0x1777));
+		_channels[4]->load(loadData(0x1977));
+		_channels[5]->load(loadData(0x1BC5));
+		_channels[6]->load(loadData(0x1CFF));
+		_channels[7]->load(loadData(0x1EAF));
+	}
+	return 0;
+}
+
+int ASound9::command39() {
+	byte *pData = loadData(0x0C36);
+	if (!isSoundActive(pData)) {
+		ASound::command0();
+		_channels[0]->load(pData);
+		_channels[1]->load(loadData(0x0D7D));
+		_channels[2]->load(loadData(0x0E50));
+		_channels[3]->load(loadData(0x0F1C));
+		_channels[4]->load(loadData(0x0FCE));
+		_channels[5]->load(loadData(0x10BA));
+	}
+	return 0;
+}
+
+int ASound9::command64() {
+	playSound(0x2EC6);
+	return 0;
+}
+
+int ASound9::command65() {
+	playSound(0x2EDA);
+	return 0;
+}
+
+int ASound9::command66() {
+	_channels[0]->load(loadData(0x2EE4));
+	_channels[1]->load(loadData(0x2F0E));
+	_channels[2]->load(loadData(0x2F3E));
+	_channels[3]->load(loadData(0x2F6E));
+	_channels[4]->load(loadData(0x2EE4));
+	_channels[5]->load(loadData(0x2F0E));
+	_channels[6]->load(loadData(0x2F3E));
+	_channels[7]->load(loadData(0x2F6E));
+	return 0;
+}
+
+int ASound9::command67() {
+	_channels[6]->load(loadData(0x2F9E));
+	_channels[7]->load(loadData(0x2FBD));
+	_channels[8]->load(loadData(0x2FCC));
+	return 0;
+}
+
+int ASound9::command68() {
+	playSound(0x2FEB);
+	return 0;
+}
+
+int ASound9::command69() {
+	playSound(0x2FF5);
+	playSound(0x301B);
+	playSound(0x3041);
+	return 0;
+}
+
+int ASound9::command70() {
+	playSound(0x305B);
+	playSound(0x3064);
+	return 0;
+}
+
+int ASound9::command71() {
+	playSound(0x306D);
+	playSound(0x308A);
+	return 0;
+}
+
+} // namespace Dragonsphere
+} // namespace MADSV2
+} // namespace MADS
diff --git a/engines/mads/madsv2/dragonsphere/sound_dragonsphere.h b/engines/mads/madsv2/dragonsphere/sound_dragonsphere.h
new file mode 100644
index 00000000000..e0d63abed2c
--- /dev/null
+++ b/engines/mads/madsv2/dragonsphere/sound_dragonsphere.h
@@ -0,0 +1,392 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef MADS_DRAGONSPHERE_SOUND_H
+#define MADS_DRAGONSPHERE_SOUND_H
+
+#include "mads/madsv2/core/asound.h"
+
+namespace MADS {
+namespace MADSV2 {
+namespace Dragonsphere {
+
+class DragonSoundManager : public SoundManager {
+protected:
+	void loadDriver(int sectionNum) override;
+
+public:
+	DragonSoundManager(Audio::Mixer *mixer, bool &soundFlag) : SoundManager(mixer, soundFlag) {
+	}
+	~DragonSoundManager() override {
+	}
+
+	void validate() override;
+};
+
+/**
+ * ASound1  (asound.ph1, _dataOffset = 0x21e0)
+ *
+ * Dispatch table layout:
+ *   off_11C32: commands  0–8   (max=8,    base=0)
+ *   off_11C44: command   16    (max=0x10, base=0x10, 1 entry)
+ *   off_11C46: commands 24–27  (max=0x1B, base=0x18, 4 entries)
+ *   off_11C4E: commands 32–39  (max=0x27, base=0x20, 8 entries)
+ *
+ * A fifth table (unk_13C3E, commands 64–76) exists but is encoded as raw
+ * sound data bytes used as near-pointers — not reconstructible without the
+ * binary.  Those commands are silently ignored.
+ *
+ * command16 (sub_11F70): random background-music selector.  Checks whether
+ * channel 0 is already playing one of the five known music pieces; if not,
+ * randomly picks from four music loaders and plays it, storing the choice
+ * in _musicIndex (mirrors word_11F5E in the original).
+ */
+class ASound1 : public ASound {
+private:
+	typedef int (ASound1::*CommandPtr)();
+	static const CommandPtr _commandList[40];
+
+	// Mirrors word_11F5E: tracks which music piece was last selected.
+	int _musicIndex = 0;
+
+	// Background-music loaders (targets of the CS:0x1F60 indirect table).
+	int commandMusic0();   // sub_11D84  – starts at 0x1ECA
+	int commandMusic1();   // sub_11EE6  – starts at 0x3418
+	int commandMusic2();   // sub_11F0E  – starts at 0x3688
+	int commandMusic3();   // sub_11F36  – starts at 0x3D52
+
+	int command0();
+	int command1();
+	int command2();
+	int command3();
+	int command4();
+	int command5();
+	int command6();
+	int command7();
+	int command8();
+
+	int command16();
+
+	int command24();
+	int command25();
+	int command26();
+	int command27();
+
+	int command32();
+	int command33();
+	int command34();
+	int command35();
+	int command36();
+	int command37();
+	int command38();
+	int command39();
+
+public:
+	ASound1(Audio::Mixer *mixer, OPL::OPL *opl);
+	~ASound1() override {}
+	int command(int commandId, int param) override;
+};
+
+/**
+ * ASound2  (asound.ph2, _dataOffset = 0x2040)
+ *
+ * Dispatch table layout:
+ *   asound_commands1: commands  0–8   (max=8,    base=0)
+ *   asound_commands2: command   16    (max=0x10, base=0x10, 1 entry)
+ *   asound_commands3: commands 24–27  (max=0x1B, base=0x18, 4 entries)
+ *   asound_commands4: commands 32–35  (max=0x23, base=0x20, 4 entries)
+ *   asound_commands5: commands 64–72  (max=0x48, base=0x40, 9 entries)
+ */
+class ASound2 : public ASound {
+private:
+	typedef int (ASound2::*CommandPtr)();
+	static const CommandPtr _commandList[73];
+
+	int command0();
+	int command1();
+	int command2();
+	int command3();
+	int command4();
+	int command5();
+	int command6();
+	int command7();
+	int command8();
+
+	int command16();
+
+	int command24();
+	int command25();
+	int command26();
+	int command27();
+
+	int command32();
+	int command33();
+	int command34();
+	int command35();
+
+	int command64();
+	int command65();
+	int command66();
+	int command67();
+	int command68();
+	int command69();
+	int command70();
+	int command71();
+	int command72();
+
+public:
+	ASound2(Audio::Mixer *mixer, OPL::OPL *opl);
+	~ASound2() override {}
+	int command(int commandId, int param) override;
+};
+
+/**
+ * ASound3  (asound.ph3, _dataOffset = 0x20c0)
+ *
+ * Dispatch table layout:
+ *   asound_commands1: commands  0–8   (max=8,    base=0)
+ *   asound_commands2: command   16    (max=0x10, base=0x10, 1 entry)
+ *   asound_commands3: commands 24–27  (max=0x1B, base=0x18, 4 entries)
+ *   asound_commands4: commands 32–37  (max=0x25, base=0x20, 6 entries)
+ *   asound_commands5: commands 64–75  (max=0x4B, base=0x40, 12 entries)
+ *     (command 76 = nullsub_8, silently ignored by bounds check)
+ */
+class ASound3 : public ASound {
+private:
+	typedef int (ASound3::*CommandPtr)();
+	static const CommandPtr _commandList[77];
+
+	// Internal helper: isSoundActive guard on 0xC36, load ch0–7.
+	// Called by command34 which then adds ch8.
+	void sub11CC6();
+
+	int command0();
+	int command1();
+	int command2();
+	int command3();
+	int command4();
+	int command5();
+	int command6();
+	int command7();
+	int command8();
+
+	int command16();
+
+	int command24();
+	int command25();
+	int command26();
+	int command27();
+
+	int command32();
+	int command33();
+	int command34();
+	int command35();
+	int command36();
+	int command37();
+
+	int command64();
+	int command65();
+	int command66();
+	int command67();
+	int command68();
+	int command69();
+	int command70();
+	int command71();
+	int command72();
+	int command73();
+	int command74();
+	int command75();
+
+public:
+	ASound3(Audio::Mixer *mixer, OPL::OPL *opl);
+	~ASound3() override {}
+	int command(int commandId, int param) override;
+};
+
+/**
+ * ASound4  (asound.ph4, _dataOffset = 0x1f90)
+ *
+ * Dispatch table layout:
+ *   asound_commands1: commands  0–8   (max=8,    base=0)
+ *   asound_commands2: command   16    (max=0x10, base=0x10, 1 entry)
+ *   asound_commands3: commands 24–27  (max=0x1B, base=0x18, 4 entries)
+ *   asound_commands4: commands 64–70  (max=0x46, base=0x40, 7 entries)
+ *     (Commands 32–63 are unreachable: the 0x20-range max constant = 0)
+ *
+ * commands 24 and 25 share the same handler (sub_11D0A).
+ */
+class ASound4 : public ASound {
+private:
+	typedef int (ASound4::*CommandPtr)();
+	static const CommandPtr _commandList[71];
+
+	int command0();
+	int command1();
+	int command2();
+	int command3();
+	int command4();
+	int command5();
+	int command6();
+	int command7();
+	int command8();
+
+	int command16();
+
+	int command24();
+	int command25();
+	int command26();
+	int command27();
+
+	int command64();
+	int command65();
+	int command66();
+	int command67();
+	int command68();
+	int command69();
+	int command70();
+
+public:
+	ASound4(Audio::Mixer *mixer, OPL::OPL *opl);
+	~ASound4() override {}
+	int command(int commandId, int param) override;
+};
+
+/**
+ * ASound5  (asound.ph5, _dataOffset = 0x2140)
+ *
+ * Dispatch table layout:
+ *   asound_commands1: commands  0–8   (max=8,    base=0)
+ *   asound_commands2: command   16    (max=0x10, base=0x10, 1 entry)
+ *   asound_commands3: commands 24–27  (max=0x1B, base=0x18, 4 entries)
+ *   asound_commands4: commands 32–39  (max=0x27, base=0x20, 8 entries)
+ *   asound_commands5: commands 64–78  (max=0x4E, base=0x40, 15 entries)
+ *     (command 79 = nullsub_8, silently ignored by bounds check)
+ *
+ * commands 36/35/34 load channels in non-sequential data order.
+ * commands 70, 77, and 78 all play the same 0x40BA sound block.
+ */
+class ASound5 : public ASound {
+private:
+	typedef int (ASound5::*CommandPtr)();
+	static const CommandPtr _commandList[79];
+
+	int command0();
+	int command1();
+	int command2();
+	int command3();
+	int command4();
+	int command5();
+	int command6();
+	int command7();
+	int command8();
+
+	int command16();
+
+	int command24();
+	int command25();
+	int command26();
+	int command27();
+
+	int command32();
+	int command33();
+	int command34();
+	int command35();
+	int command36();
+	int command37();
+	int command38();
+	int command39();
+
+	int command64();
+	int command65();
+	int command66();
+	int command67();
+	int command68();
+	int command69();
+	int command70();
+	int command71();
+	int command72();
+	int command73();
+	int command74();
+	int command75();
+	int command76();
+	int command77();
+	int command78();
+
+public:
+	ASound5(Audio::Mixer *mixer, OPL::OPL *opl);
+	~ASound5() override {}
+	int command(int commandId, int param) override;
+};
+
+class ASound9 : public ASound {
+private:
+	typedef int (ASound9:: *CommandPtr)();
+	int command0();
+	int command1();
+	int command2();
+	int command3();
+	int command4();
+	int command5();
+	int command6();
+	int command7();
+	int command8();
+
+	int command16() {
+		return command24();
+	}
+
+	int command24();
+	int command25();
+	int command26();
+	int command27();
+
+	int command32();
+	int command33();
+	int command34();
+	int command35();
+	int command36();
+	int command37();
+	int command38();
+	int command39();
+
+	int command64();
+	int command65();
+	int command66();
+	int command67();
+	int command68();
+	int command69();
+	int command70();
+	int command71();
+
+	static const CommandPtr _commandList[72];
+
+public:
+	ASound9(Audio::Mixer *mixer, OPL::OPL *opl);
+	~ASound9() override {
+	}
+	int command(int commandId, int param) override;
+};
+
+} // namespace Dragonsphere
+} // namespace MADSV2
+} // namespace MADS
+
+#endif
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index 65e1e8a416b..27e8f8ec714 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -183,6 +183,10 @@ MODULE_OBJS += \
 	madsv2/phantom/sound_phantom.o \
 	madsv2/dragonsphere/dragonsphere.o \
 	madsv2/dragonsphere/global.o \
+	madsv2/dragonsphere/main.o \
+	madsv2/dragonsphere/main_menu.o \
+	madsv2/dragonsphere/menus.o \
+	madsv2/dragonsphere/sound_dragonsphere.o \
 	madsv2/dragonsphere/mads/mads.o \
 	madsv2/dragonsphere/rooms/section1.o \
 	madsv2/dragonsphere/rooms/room101.o \


Commit: 1892a6850c779a15d36ec5024ed6029eff365cb2
    https://github.com/scummvm/scummvm/commit/1892a6850c779a15d36ec5024ed6029eff365cb2
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-05-22T06:20:41+10:00

Commit Message:
MADS: DRAGONSPHERE: Main menu buttons showing

Changed paths:
    engines/mads/madsv2/dragonsphere/main.cpp
    engines/mads/madsv2/dragonsphere/main_menu.cpp


diff --git a/engines/mads/madsv2/dragonsphere/main.cpp b/engines/mads/madsv2/dragonsphere/main.cpp
index 5d46d24113d..8d6641fc972 100644
--- a/engines/mads/madsv2/dragonsphere/main.cpp
+++ b/engines/mads/madsv2/dragonsphere/main.cpp
@@ -57,6 +57,12 @@ static void main_menu_main() {
 
 	if (!kernel_game_startup(19, KERNEL_STARTUP_CURSOR | KERNEL_STARTUP_INTERRUPT | KERNEL_STARTUP_FONT,
 		nullptr, nullptr)) {
+		matte_init(0xFFFF);
+		bool valid = !kernel_room_startup(920, 0, nullptr, true, true);
+
+		// Setup scr_work to use the full surface of scr_main (i.e. 320x200).
+		// Because of this, viewing_at_y is actually == 0
+		scr_work.y = picture_map.viewport_y;
 		viewing_at_y = (200 - scr_work.y) >> 1;
 
 		mouse_cursor_sprite(cursor, 7);
@@ -65,7 +71,6 @@ static void main_menu_main() {
 		mouse_hide();
 
 		mouse_cursor_sprite(cursor, 1);
-		matte_init(0xFFFF);
 		kernel_seq_init();
 		kernel_message_init();
 		kernel_animation_init();
@@ -73,23 +78,6 @@ static void main_menu_main() {
 
 		picture_view_x = 0;
 		picture_view_y = 0;
-
-		quotes = quote_load(0, 68, 69, 70, 71, 72, 73, 74, 75, 76,
-			77, 78, 79, 80, 81, 82, 83, 84, 85, 86,
-			87, 88, 89, 90, 91, 92, 93, 94, 95, 96,
-			97, 98, 99, 0);
-
-		global_speech_load(9);
-		bool valid = !kernel_room_startup(902, 0, nullptr, true, true);
-
-		master_palette[4].r = 63;
-		master_palette[4].g = 50;
-		master_palette[4].b = 0;
-		master_palette[5].r = 30;
-		master_palette[5].g = 15;
-		master_palette[5].b = 0;
-		mcga_setpal_range(&master_palette, 4, 2);
-
 		new_background = true;
 
 		if (valid) {
@@ -102,7 +90,7 @@ static void main_menu_main() {
 				screen.hLine(0, scr_work.y + viewing_at_y + 1, 319, LINE_COLOR);
 			}
 
-			kernel_load_sound_driver("*#SOUND.PH9", 'N', 544, 0, 49);
+			kernel_load_sound_driver("*#SOUND.DR9", 'N', 544, 0, 49);
 
 			menu_control();
 
@@ -135,9 +123,9 @@ static void main_cold_data_init() {
 	game_menu_exit = global_menu_system_shutdown;
 	game_emergency_save = global_emergency_save;
 
-	Common::strcpy_s(config_file_name, "config.pha");
-	Common::strcpy_s(save_game_key, "phan");
-	Common::strcpy_s(restart_game_key, "phantom");
+	Common::strcpy_s(config_file_name, "config.dra");
+	Common::strcpy_s(save_game_key, "drag");
+	Common::strcpy_s(restart_game_key, "dragon");
 
 	Common::strcpy_s(player.series_name, "RAL");
 	player.walker_must_reload = true;
diff --git a/engines/mads/madsv2/dragonsphere/main_menu.cpp b/engines/mads/madsv2/dragonsphere/main_menu.cpp
index e2e22963e34..7ece6326494 100644
--- a/engines/mads/madsv2/dragonsphere/main_menu.cpp
+++ b/engines/mads/madsv2/dragonsphere/main_menu.cpp
@@ -192,6 +192,7 @@ static void start_hotspots() {
 		ys = series->index[0].ys;
 		x1 = series->index[0].x - (xs >> 1);
 		y1 = series->index[0].y - (ys - 1);
+
 		x2 = x1 + xs - 1;
 		y2 = y1 + ys - 1;
 		hspot_add(x1, y1, x2, y2, 1, count, mcga_mode);
@@ -255,13 +256,6 @@ static void process_sprites() {
 				}
 			} else {
 				sprite = 1;
-				/*
-				if (count != selected_item) {
-				  sprite = 1;
-				} else {
-				  sprite = 2;
-				}
-				*/
 			}
 
 			image.series_id = (byte)menu_item[series].handle;


Commit: 6a2f5bd733a547ea932cd109ac65e77a013ed2fa
    https://github.com/scummvm/scummvm/commit/6a2f5bd733a547ea932cd109ac65e77a013ed2fa
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-05-22T06:20:41+10:00

Commit Message:
MADS: DRAGONSPHERE: Added global_parser_code

Changed paths:
    engines/mads/madsv2/core/kernel.cpp
    engines/mads/madsv2/dragonsphere/dragonsphere.cpp
    engines/mads/madsv2/dragonsphere/dragonsphere.h
    engines/mads/madsv2/dragonsphere/mads/inventory.h
    engines/mads/madsv2/dragonsphere/mads/sounds.h
    engines/mads/madsv2/dragonsphere/mads/words.h


diff --git a/engines/mads/madsv2/core/kernel.cpp b/engines/mads/madsv2/core/kernel.cpp
index 71c16299c0a..3ebb60eed69 100644
--- a/engines/mads/madsv2/core/kernel.cpp
+++ b/engines/mads/madsv2/core/kernel.cpp
@@ -2552,7 +2552,7 @@ int kernel_load_sound_driver(const char *name, char sound_card_, int sound_board
 	// Get the section number from the end of the driver filename, and use it to initialize
 	// the sound system; we provide our own implementation of the drivers
 	int sectionNum = *(name + strlen(name) - 1) - '0';
-	assert((sectionNum >= 1 && sectionNum <= 5) || sectionNum == 9);
+	assert(sectionNum >= 1 && sectionNum <= 9);
 
 	g_engine->_soundManager->init(sectionNum);
 
diff --git a/engines/mads/madsv2/dragonsphere/dragonsphere.cpp b/engines/mads/madsv2/dragonsphere/dragonsphere.cpp
index 891c94915e4..9924c7cf1af 100644
--- a/engines/mads/madsv2/dragonsphere/dragonsphere.cpp
+++ b/engines/mads/madsv2/dragonsphere/dragonsphere.cpp
@@ -21,14 +21,30 @@
 
 #include "engines/util.h"
 #include "mads/madsv2/console.h"
+#include "mads/madsv2/core/conv.h"
+#include "mads/madsv2/core/env.h"
 #include "mads/madsv2/core/game.h"
 #include "mads/madsv2/core/imath.h"
+#include "mads/madsv2/core/inter.h"
 #include "mads/madsv2/core/kernel.h"
+#include "mads/madsv2/core/object.h"
 #include "mads/madsv2/core/screen.h"
+#include "mads/madsv2/core/sound.h"
+#include "mads/madsv2/core/text.h"
 #include "mads/madsv2/dragonsphere/dragonsphere.h"
 #include "mads/madsv2/dragonsphere/global.h"
 #include "mads/madsv2/dragonsphere/main.h"
 #include "mads/madsv2/dragonsphere/sound_dragonsphere.h"
+#include "mads/madsv2/dragonsphere/rooms/section1.h"
+#include "mads/madsv2/dragonsphere/rooms/section2.h"
+#include "mads/madsv2/dragonsphere/rooms/section3.h"
+#include "mads/madsv2/dragonsphere/rooms/section4.h"
+#include "mads/madsv2/dragonsphere/rooms/section5.h"
+#include "mads/madsv2/dragonsphere/rooms/section6.h"
+#include "mads/madsv2/dragonsphere/rooms/section9.h"
+#include "mads/madsv2/dragonsphere/mads/inventory.h"
+#include "mads/madsv2/dragonsphere/mads/sounds.h"
+#include "mads/madsv2/dragonsphere/mads/words.h"
 
 namespace MADS {
 namespace MADSV2 {
@@ -53,15 +69,202 @@ Common::Error DragonsphereEngine::run() {
 }
 
 void DragonsphereEngine::global_init_code() {
+	int count;
+
+	for (count = 0; count < GLOBAL_LIST_SIZE; count++) {
+		global[count] = 0;
+	}
+
+	/* initialize_grid (); */
+
+	global[grid_position] = 5;
+	global[grid_position + 1] = 4;
+	global[grid_position + 2] = 9;
+	global[grid_position + 3] = 10;
+	global[grid_position + 4] = 15;
+	global[grid_position + 5] = 20;
+	global[grid_position + 6] = 19;
+	global[grid_position + 7] = 24;
+	global[grid_position + 8] = 23;
+	global[grid_position + 9] = 18;
 
+	global[grid_position + 10] = 13;
+	global[grid_position + 11] = 8;
+	global[grid_position + 12] = 3;
+	global[grid_position + 13] = 2;
+	global[grid_position + 14] = 1;
+	global[grid_position + 15] = 6;
+	global[grid_position + 16] = 7;
+	global[grid_position + 17] = 12;
+
+	global[grid_position + 18] = 17;
+	global[grid_position + 19] = 22;
+	global[grid_position + 20] = 21;
+	global[grid_position + 21] = 16;
+	global[grid_position + 22] = 11;
+
+	global[max_grid_value] = grid_position + 22;
+
+	global[oasis] = imath_random(1, 11);
+	switch (global[oasis]) {
+	case 1:  global[oasis] = 7;  break;
+	case 2:  global[oasis] = 13; break;
+	case 3:  global[oasis] = 19; break;
+	case 4:  global[oasis] = 25; break;
+	case 5:  global[oasis] = 31; break;
+	case 6:  global[oasis] = 37; break;
+	case 7:  global[oasis] = 45; break;
+	case 8:  global[oasis] = 53; break;
+	case 9:  global[oasis] = 61; break;
+	case 10: global[oasis] = 69; break;
+	case 11: global[oasis] = 77; break;
+	}
+
+	do {
+		global[fire_holes] = imath_random(1, 11);
+		switch (global[fire_holes]) {
+		case 1:  global[fire_holes] = 7;  break;
+		case 2:  global[fire_holes] = 13; break;
+		case 3:  global[fire_holes] = 19; break;
+		case 4:  global[fire_holes] = 25; break;
+		case 5:  global[fire_holes] = 31; break;
+		case 6:  global[fire_holes] = 37; break;
+		case 7:  global[fire_holes] = 45; break;
+		case 8:  global[fire_holes] = 53; break;
+		case 9:  global[fire_holes] = 61; break;
+		case 10: global[fire_holes] = 69; break;
+		case 11: global[fire_holes] = 77; break;
+		}
+	} while (global[fire_holes] == global[oasis]);
+
+	/* Section 1 Initialization */
+
+	global[player_score] = 0;
+	global[player_score_flags] = 0;
+
+	global[dragon_high_scene] = 0;
+	global[dragon_my_scene] = 0;
+	global[player_persona] = PLAYER_IS_KING;
+	global[king_status] = KING_CAPTIVE;
+	global[ward_status] = WARD_PRESENT;
+	global[amulet_status] = AMULET_NOT_CORRECT_TIME;
+	global[books_status] = BOOKS_NOT_PRESENT;
+	global[tapestry_status] = TAPESTRY_CLOSED;
+	global[talked_to_status] = TALKED_TO_NONE;
+	global[guard_pid_status] = GUARD_NEVER_HEALED;
+
+	global[crawled_out_of_bed_101] = false;
+	global[statue_is_on_stairway_114] = false;
+	global[dog_is_asleep] = false;
+	global[crystal_ball_dead] = false;
+	global[threw_bone] = false;
+	global[no_load_walker] = false;
+	global[wooden_door_open] = false;
+	global[king_is_in_stairwell] = false;
+	global[llanie_status] = BEFORE_FALL;
+	global[no_talk_to_guard] = false;
+	global[sorceror_defeated] = false;
+	global[waterfall_diverted] = false;
+	global[shak_status] = SHAK_NEVER_MET;
+	global[move_direction_510] = true;
+	global[move_direction_409] = true;
+	global[shak_506_angry] = false;
+	global[monster_is_dead] = false;
+	global[done_talking_lani_502] = false;
+	global[found_lani_504] = false;
+	global[said_use_sword_shak] = false;
+	global[goblet_filled_soporific] = false;
+	global[been_in_504_as_pid] = false;
+	global[seen_lani_dead_1st_time] = false;
+	global[said_poem_in_504] = false;
+	global[tried_to_heal_llanie_504] = false;
+	global[put_bundle_on_llanie_504] = false;
+	global[mud_is_in_eye_603] = false;
+	global[rope_is_alive] = true;
+	global[make_504_empty] = false;
+	global[rat_cage_is_open] = false;
+	global[flask_on_plate] = NONE;
+	global[fluid_is_dripping] = false;
+	global[hole_is_in_607] = false;
+	global[rope_is_hanging_in_607] = false;
+	global[object_is_in_freezer_605] = NEVER_USED_FREEZER;
+	global[has_taken_mud] = false;
+	global[desert_room] = 42;
+	global[object_imitated] = -1;
+	global[has_red] = false;
+	global[has_yellow] = false;
+	global[has_blue] = false;
+	global[wizard_dead] = false;
+	global[vine_will_grab] = true;
+	global[desert_counter] = 0;
+	global[floor_is_cool] = false;
+	global[rat_melted] = false;
+	global[door_is_cool] = false;
+	global[used_elevator] = false;
+	global[been_on_top_floor] = false;
+	global[torch_is_in_609] = false;
+	global[platform_clicked_606] = false;
+	global[perform_displacements] = true;
+	global[had_spirit_bundle] = false;
+	global[heal_verbs_visible] = false;
+	global[pid_talk_shamon] = false;
+	global[talked_to_soptus] = false;
+	global[pid_just_died] = false;
+	global[grapes_have_grown] = GRAPES_NOT_THERE;
+	global[grapes_are_dead] = false;
+	global[roc_is_chewing_dates] = false;
+	global[wins_in_desert] = 0;
+	global[wins_till_prize] = 3;
+	global[game_points] = 0;
+	global[dance_points] = 0;
+	global[clue_points] = 0;
+	global[prizes_owed_to_player] = 0; /* for king */
+	global[pid_has_been_healed_sop] = false;
+	global[object_flags] = 0;
+	global[save_wins_in_desert] = 0;
+	global[object_given_201] = -1;
+	global[king_got_stabbed] = false;
+	global[given_object_before] = false;
+	global[guards_are_asleep] = false;
+	global[dome_up] = false;
+	global[talked_to_wise] = false;
+	global[talked_to_shifter] = false;
+	global[talked_to_merchant] = false;
+	global[doll_given] = false;
+	global[reset_conv] = -1;
+	global[reset_conv_2] = -1;
+	global[talked_to_greta] = false;
+	global[slime_healed] = false;
+	global[dance_music_on] = false;
+	global[bubbles_up_in_301] = true;
+	global[bubble_wont_attack] = false;
+	global[can_view_crown_hole] = false;
+	global[player_is_seal] = false;
+	global[vines_have_player] = false;
+	global[end_of_game] = false;
+	global[pid_looked_at_doll] = false;
+	global[invoked_from_111] = false;
+
+	player.facing = FACING_NORTH;
+	player.turn_to_facing = FACING_NORTH;
 }
 
 void DragonsphereEngine::section_music(int section_num) {
-
+	switch (section_num) {
+	case 1: Rooms::section_1_music(); break;
+	case 2: Rooms::section_2_music(); break;
+	case 3: Rooms::section_3_music(); break;
+	case 4: Rooms::section_4_music(); break;
+	case 5: Rooms::section_5_music(); break;
+	case 6: Rooms::section_6_music(); break;
+	case 9: Rooms::section_9_music(); break;
+	}
 }
 
 void DragonsphereEngine::global_object_sprite() {
-
+	Common::strcpy_s(inter_object_buf, "*OB");
+	env_catint(inter_object_buf, inter_object_id, 3);
+	Common::strcat_s(inter_object_buf, "I");
 }
 
 void DragonsphereEngine::stop_walker_basic() {
@@ -142,22 +345,807 @@ void DragonsphereEngine::stop_walker_tricks() {
 }
 
 void DragonsphereEngine::global_section_constructor() {
-
+	Dragonsphere::global_section_constructor();
 }
 
 void DragonsphereEngine::syncRoom(Common::Serializer &s) {
-
+	Dragonsphere::sync_room(s);
 }
 
 void DragonsphereEngine::global_daemon_code() {
+	int random;
+	int count;
+	int how_many;
+
+	if (player.walker_visible && (player.commands_allowed || (conv_control.running >= 0)) && !player.walking &&
+		(player.facing == player.turn_to_facing) && global[perform_displacements]) {
+
+		if (kernel.clock >= *((long *)&global[walker_timing])) {
+
+			if (!player.stop_walker_pointer) {
+
+				random = imath_random(1, 30000);
+
+				if (global[player_persona] == PLAYER_IS_KING) {
+					if (random < 500) {
+						switch (player.facing) {
+						case FACING_SOUTHEAST:
+						case FACING_SOUTHWEST:
+							how_many = imath_random(0, 3);
+							if (how_many <= 2) {
+								for (count = 0; count < imath_random(5, 7); count++) {
+									player_add_stop_walker(how_many, 0);
+								}
+							} else {
+								player_add_stop_walker(-3, 0);
+								for (count = 0; count < imath_random(5, 7); count++) {
+									player_add_stop_walker(4, 0);
+								}
+								player_add_stop_walker(3, 0);
+							}
+							break;
+
+						case FACING_NORTHEAST:
+						case FACING_NORTHWEST:
+							how_many = imath_random(0, 1);
+							for (count = 0; count < imath_random(5, 7); count++) {
+								player_add_stop_walker(how_many, 0);
+							}
+							break;
+
+						case FACING_SOUTH:
+							how_many = imath_random(0, 3);
+							if (how_many <= 2) {
+								for (count = 0; count < imath_random(5, 7); count++) {
+									player_add_stop_walker(how_many, 0);
+								}
+
+							} else {
+								player_add_stop_walker(-3, 0);
+								for (count = 0; count < imath_random(5, 7); count++) {
+									player_add_stop_walker(4, 0);
+								}
+								player_add_stop_walker(3, 0);
+							}
+							break;
+
+						case FACING_NORTH:
+							how_many = imath_random(0, 2);
+							for (count = 0; count < imath_random(5, 7); count++) {
+								player_add_stop_walker(how_many, 0);
+							}
+							break;
 
+						case FACING_EAST:
+						case FACING_WEST:
+						default:
+							how_many = imath_random(0, 2);
+							if (how_many <= 1) {
+								for (count = 0; count < imath_random(5, 7); count++) {
+									player_add_stop_walker(how_many, 0);
+								}
+							} else {
+								player_add_stop_walker(-2, 0);
+								for (count = 0; count < imath_random(5, 7); count++) {
+									player_add_stop_walker(3, 0);
+								}
+								player_add_stop_walker(2, 0);
+							}
+							break;
+						}
+					}
+
+				} else {  /* player is PID */
+
+					if (random < 500) {
+						switch (player.facing) {
+						case FACING_SOUTHEAST:
+						case FACING_SOUTHWEST:
+							how_many = imath_random(0, 3);
+							if (how_many <= 2) {
+								for (count = 0; count < imath_random(5, 7); count++) {
+									player_add_stop_walker(how_many, 0);
+								}
+							} else {
+								player_add_stop_walker(-3, 0);
+								for (count = 0; count < imath_random(5, 7); count++) {
+									player_add_stop_walker(4, 0);
+								}
+								player_add_stop_walker(3, 0);
+							}
+							break;
+
+						case FACING_NORTHEAST:
+						case FACING_NORTHWEST:
+							how_many = imath_random(0, 2);
+							for (count = 0; count < imath_random(5, 7); count++) {
+								player_add_stop_walker(how_many, 0);
+							}
+							break;
+
+						case FACING_SOUTH:
+							how_many = imath_random(0, 3);
+							if (how_many <= 2) {
+								for (count = 0; count < imath_random(5, 7); count++) {
+									player_add_stop_walker(how_many, 0);
+								}
+							} else {
+								player_add_stop_walker(-3, 0);
+								player_add_stop_walker(3, 0);
+							}
+							break;
+
+						case FACING_NORTH:
+							how_many = imath_random(0, 2);
+							for (count = 0; count < imath_random(5, 7); count++) {
+								player_add_stop_walker(how_many, 0);
+							}
+							break;
+
+						case FACING_EAST:
+						case FACING_WEST:
+						default:
+							how_many = imath_random(0, 2);
+							if (how_many <= 1) {
+								for (count = 0; count < imath_random(5, 7); count++) {
+									player_add_stop_walker(how_many, 0);
+								}
+							} else {
+								player_add_stop_walker(3, 0);
+								player_add_stop_walker(2, 0);
+							}
+							break;
+						}
+
+					} else if (random < 1000) {
+						WRITE_LE_UINT32(&global[walker_timing], kernel.clock);
+					}
+				}
+
+			}
+
+			WRITE_LE_UINT32(&global[walker_timing], READ_LE_UINT32(&global[walker_timing]) + 10);
+		}
+	}
 }
 
 void DragonsphereEngine::global_pre_parser_code() {
-
+	if (player_said_1(look) || player_said_1(throw)) {
+		player.need_to_walk = false;
+	}
 }
 
 void DragonsphereEngine::global_parser_code() {
+	int id;
+	int idd;
+
+	id = object_named(player_second_noun);
+	idd = object_named(player_main_noun);
+
+	if (player_said_1(revert) && idd == polystone) {
+		if (global[object_imitated] == -1 || global[object_imitated] == 9) {
+			text_show(708);
+
+		} else {
+			global[object_imitated] = 9;
+			inter_move_object(idd, NOWHERE);
+			inter_give_to_player(idd);
+			object_examine(polystone, 701, 0);
+		}
+		goto handled;
+	}
+
+	if (player_said_1(mimic)) {
+		if (player_has(id)) {
+			if (room_id == 614 && id == blue_powerstone) {
+				text_show(61422);
+			}
+
+			if ((id == 9 && idd == 9) && (global[object_imitated] == -1 || global[object_imitated] == 9)) {
+				text_show(708);
+
+			} else {
+				global[object_imitated] = id;
+				
+				inter_move_object(id, NOWHERE);
+				inter_give_to_player(id);
+				if (id == 9) {
+					object_examine(polystone, 701, 0);
+				} else {
+					object_examine(polystone, 933, 0);
+				}
+			}
+
+		} else {
+			text_show(707);
+		}
+		goto handled;
+	}
+
+	if (player_said_2(polish, signet_ring)) {
+		object_examine(signet_ring, 901, 0);
+		goto handled;
+	}
+
+	if (player_said_2(invoke, red_stone) ||
+		player_said_2(invoke, yellow_stone) ||
+		player_said_2(invoke, blue_stone)) {
+		text_show(705);
+		goto handled;
+	}
+
+	if (player_said_1(pour_contents_of)) {
+		if (id == flask_full_of_acid && idd == flask_full_of_acid) {
+			text_show(23);
+		} else {
+			text_show(958);
+		}
+		goto handled;
+	}
+
+	if (player_said_1(drink) && idd == flask_full_of_acid) {
+		text_show(957);
+		goto handled;
+	}
+
+	if (player_said_2(put_magic_into, partial_bundle)) {
+		if (player_has(partly_built_bundle)) {
+			if (global[had_spirit_bundle]) {
+				inter_move_object(partly_built_bundle, NOWHERE);
+				inter_give_to_player(new_bundle);
+				object_examine(new_bundle, 977, 0);
+
+			} else {
+				text_show(998);
+			}
+		}
+		goto handled;
+	}
+
+	if (player_said_1(put_magic_into)) {
+		text_show(978);
+		goto handled;
+	}
+
+	if (player_said_2(polish, red_stone)) {
+		object_examine(red_powerstone, 935, 0);
+		goto handled;
+	}
+
+	if (player_said_2(polish, yellow_stone)) {
+		object_examine(yellow_powerstone, 703, 0);
+		goto handled;
+	}
+
+	if (player_said_2(polish, blue_stone)) {
+		object_examine(blue_powerstone, 704, 0);
+		goto handled;
+	}
+
+	if (player_said_2(give, signet_ring)) {
+		if (player_said_1(king)) {
+			text_show(902);
+		} else {
+			text_show(917);
+		}
+		goto handled;
+	}
+
+	if (player_said_2(open, music_box)) {
+		sound_play(N_MusicBoxOn);
+		object_examine(magic_music_box, 843, 0);
+		sound_play(N_MusicBoxOff);
+		goto handled;
+	}
+
+	if (player_said_2(rub, bird_figurine)) {
+		object_examine(bird_figurine, 903, 0);
+		goto handled;
+	}
+
+	if (player_said_2(talk_to, bird_figurine)) {
+		object_examine(bird_figurine, 904, 0);
+		goto handled;
+	}
+
+	if (player_said_2(rub, birdcall)) {
+		object_examine(birdcall, 906, 0);
+		goto handled;
+	}
+
+	if (player_said_2(polish, shieldstone)) {
+		object_examine(shieldstone, 907, 0);
+		goto handled;
+	}
+
+	if (player_said_2(throw, shieldstone)) {
+		text_show(908);
+		goto handled;
+	}
+
+	if (player_said_1(heal)) {
+		if (player_said_1(Llanie) ||
+			player_said_1(MacMorn) ||
+			player_said_1(shak) ||
+			player_said_1(wise_shifter) ||
+			player_said_1(Roc) ||
+			player_said_1(shifting_monster)) {
+			text_show(927);
+			goto handled;
+		}
+	}
+
+	if (player_said_1(heal)) {
+		if (player_said_1(Queen_Mother) ||
+			player_said_1(stranger) ||
+			player_said_1(Ner_Tom) ||
+			player_said_1(hermit) ||
+			player_said_1(shifter)) {
+			text_show(927);
+			goto handled;
+		}
+	}
+
+	if (player_said_1(heal)) {
+		if (player_said_1(trader) ||
+			player_said_1(lizard) ||
+			player_said_1(faerie) ||
+			player_said_1(shaman) ||
+			player_said_1(guard) ||
+			player_said_1(shapechanger) ||
+			player_said_1(Soptus_Ecliptus) ||
+			player_said_1(merchant)) {
+			text_show(927);
+			goto handled;
+		}
+	}
+
+	if (player_said_1(heal)) {
+		if (player_said_1(rat) ||
+			player_said_1(Sanwe) ||
+			player_said_1(king) ||
+			player_said_1(guard_captain) ||
+			player_said_1(beast) ||
+			player_said_1(darkness_beast)) {
+			text_show(927);
+			goto handled;
+
+		} else {
+			text_show(928);
+			goto handled;
+		}
+	}
+
+	if (player_said_1(heal_self)) {
+		text_show(929);
+		goto handled;
+	}
+
+	if (player_said_2(fill, goblet)) {
+		if (player_said_1(soporific)) {
+			if (global[goblet_filled_soporific]) {
+				object_examine(goblet, 994, 0);
+			} else {
+				object_examine(goblet, 914, 0);
+				global[goblet_filled_soporific] = true;
+			}
+		} else if (player_said_1(flask_full_of_acid)) {
+			object_examine(flask_full_of_acid, 993, 0);
+		} else {
+			object_examine(goblet, 913, 0);
+		}
+		goto handled;
+	}
+
+	if (player_said_2(drink_from, goblet)) {
+		if (global[goblet_filled_soporific]) {
+			object_examine(goblet, 916, 0);
+		} else {
+			text_show(915);
+		}
+		goto handled;
+	}
+
+	if (player_said_2(gnaw, bone)) {
+		object_examine(bone, 918, 0);
+		goto handled;
+	}
+
+	if (player_said_2(eat, fruit)) {
+		object_examine(fruit, 919, 0);
+		goto handled;
+	}
+
+	if (player_said_2(throw, fruit)) {
+		object_examine(fruit, 921, 0);
+		goto handled;
+	}
+
+	if (player_said_2(play_with, doll)) {
+		object_examine(words_doll, 922, 0);
+		goto handled;
+	}
+
+	if (player_said_2(talk_to, doll)) {
+		object_examine(words_doll, 931, 0);
+		goto handled;
+	}
+
+	if (player_said_2(open, doll)) {
+		object_examine(words_doll, 932, 0);
+		goto handled;
+	}
+
+	if (player_said_1(polystone)) {
+		if (player_said_1(push) || player_said_1(pull)) {
+			object_examine(polystone, 934, 0);
+			goto handled;
+		}
+	}
+
+	if (player_said_2(wear, key_crown)) {
+		object_examine(key_crown, 936, 0);
+		goto handled;
+	}
+
+	if (player_said_2(eat, dates)) {
+		text_show(938);
+		goto handled;
+	}
+
+	if (player_said_2(polish, statue)) {
+		object_examine(statue, 939, 0);
+		goto handled;
+	}
+
+	if (player_said_2(listen_to, flies)) {
+		sound_play(N_ListenToFlies);
+		text_show(940);
+		goto handled;
+	}
+
+	if (player_said_2(open, flies)) {
+		text_show(941);
+		goto handled;
+	}
+
+	if (player_said_2(talk_to, flies)) {
+		text_show(942);
+		goto handled;
+	}
+
+	if (player_said_2(break, soul_egg)) {
+		object_examine(soul_egg, 943, 0);
+		goto handled;
+	}
+
+	if (player_said_2(adjust, magic_belt)) {
+		object_examine(magic_belt, 944, 0);
+		goto handled;
+	}
+
+	if (player_said_2(feel, mud)) {
+		text_show(947);
+		goto handled;
+	}
+
+	if (player_said_2(taste, mud)) {
+		text_show(948);
+		goto handled;
+	}
+
+	if (player_said_2(throw, mud)) {
+		text_show(949);
+		goto handled;
+	}
+
+	if (player_said_2(feel, feathers)) {
+		text_show(950);
+		goto handled;
+	}
+
+	if (player_said_3(put, feathers, bone)) {
+		if (player_has(feathers) && player_has(bone)) {
+			inter_move_object(feathers, NOWHERE);
+			inter_move_object(bone, NOWHERE);
+			inter_give_to_player(partly_built_bundle);
+			object_examine(partly_built_bundle, 952, 0);
+			goto handled;
+		}
+	}
+
+	if (player_said_2(wave, torch)) {
+		text_show(953);
+		goto handled;
+	}
+
+	if (player_said_2(throw, torch)) {
+		text_show(954);
+		goto handled;
+	}
+
+	if (player_said_2(polish, flask)) {
+		text_show(955);
+		goto handled;
+	}
+
+	if (player_said_2(open, flask_full_of_acid)) {
+		text_show(956);
+		goto handled;
+	}
+
+	if (player_said_2(drink, flask_full_of_acid)) {
+		text_show(957);
+		goto handled;
+	}
+
+	if (player_said_2(pour, flask_full_of_acid)) {
+		text_show(958);
+		goto handled;
+	}
+
+	if (player_said_2(throw, flask_full_of_acid)) {
+		text_show(959);
+		goto handled;
+	}
+
+	if (player_said_2(tie, rope)) {
+		text_show(960);
+		goto handled;
+	}
+
+	if (player_said_2(vortex_stone, take_magic_from)) {
+		if (player_said_1(signet_ring) ||
+			player_said_1(bird_figurine) ||
+			player_said_1(birdcall) ||
+			player_said_1(shieldstone) ||
+			player_said_1(key_crown) ||
+			player_said_1(polystone) ||
+			player_said_1(red_stone) ||
+			player_said_1(blue_stone) ||
+			player_said_1(yellow_stone) ||
+			player_said_1(soul_egg) ||
+			player_said_1(magic_belt) ||
+			player_said_1(crystal_ball) ||
+			player_said_1(shifter_ring)) {
+
+			text_show(962);
+			goto handled;
+			/* then what good would it do you */
+		}
+	}
+
+	if (player_said_2(vortex_stone, take_magic_from)) {
+		if (player_said_1(signet_ring) ||
+			player_said_1(doll) ||
+			player_said_1(door_frame) ||
+			player_said_1(new_bundle) ||
+			player_said_1(tower_door) ||
+			player_said_1(vortex_stone) ||
+			player_said_1(spirit_bundle) ||
+			player_said_1(freezer) ||
+			player_said_1(music_box) ||
+			player_said_1(amulet)) {
+
+			text_show(962);
+			goto handled;
+			/* then what good would it do you */
+		}
+	}
+
+
+	if (player_said_2(vortex_stone, take_magic_from)) {
+		if ((player_said_1(cave) && room_id == 203) ||
+			(player_said_1(torch) && player.second_object_source != STROKE_INTERFACE) ||
+			(player_said_1(torch) && room_id == 607) ||
+			(player_said_1(torch) && room_id == 609) ||
+			player_said_1(teleport_door)) {
+
+			text_show(962);
+			/* then what good would it do you */
+
+		} else if (player_said_1(eye) ||
+			player_said_1(floating_disk) ||
+			player_said_1(spirit_plane) ||
+			player_said_1(waterfall) ||
+			player_said_1(darkness_beast) ||
+			player_said_1(ward) ||
+			player_said_1(teleportal) ||
+			player_said_1(tangle) ||
+			player_said_1(Roc) ||
+			player_said_1(Dragonsphere) ||
+			player_said_1(spell_shield) ||
+			player_said_1(glowing_floor) ||
+			(player_said_1(pedestal) && room_id == 116) ||
+			player_said_1(circle_of_spheres)) {
+
+			text_show(963);
+			/* too strong it fails */
+
+		} else {
+			text_show(961);
+		}
+		goto handled;
+	}
+
+	if (player_said_2(pet, dead_rat)) {
+		object_examine(dead_rat, 964, 0);
+		goto handled;
+	}
+
+	if (player_said_2(open, dead_rat)) {
+		text_show(965);
+		goto handled;
+	}
+
+	if (player_said_2(fold, map)) {
+		text_show(966);
+		goto handled;
+	}
+
+	if (player_said_2(gaze_into, crystal_ball)) {
+		object_examine(crystal_ball, 967, 0);
+		goto handled;
+	}
+
+	if (player_said_2(talk_to, crystal_ball)) {
+		object_examine(crystal_ball, 971, 0);
+		goto handled;
+	}
+
+	if (player_said_2(polish, black_sphere)) {
+		object_examine(black_sphere, 972, 0);
+		goto handled;
+	}
+
+	if (player_said_2(drink, soporific)) {
+		text_show(973);
+		goto handled;
+	}
+
+	if (player_said_1(shake)) {
+		if (idd == partly_built_bundle) {
+			text_show(976);
+
+		} else if (idd == medicine_bundle ||
+			idd == new_bundle) {
+			if (game.difficulty == HARD_MODE) {
+				text_show(974);
+
+			} else {
+				text_show(975);
+			}
+		}
+		goto handled;
+	}
+
+	if (player_said_2(lick, ratsicle)) {
+		text_show(979);
+		goto handled;
+	}
+
+	if (player_said_2(chew, tentacle_parts)) {
+		text_show(980);
+		goto handled;
+	}
+
+	if (player_said_2(put, tentacle_parts)) {
+
+		if (id == tentacle_parts) {
+			text_show(23);
+
+		} else {
+			text_show(981);
+		}
+		goto handled;
+	}
+
+	if (player_said_2(unroll, teleport_door)) {
+		text_show(982);
+		goto handled;
+	}
+
+	if (player_said_1(admire)) {
+		text_show(984);
+		goto handled;
+	}
+
+
+	if (player_said_2(make_noise, birdcall)) {
+		if (global[shak_status] == SHAK_MET) {
+			sound_play(N_BlowBirdCall);
+			text_show(50621);
+		} else if (player_has_been_in_room(509)) {
+			sound_play(N_BlowBirdCall);
+			text_show(992);
+		} else if (global[player_persona] == PLAYER_IS_KING) {
+			sound_play(N_BlowBirdCall);
+			text_show(991);
+		} else {
+			sound_play(N_BlowBirdCall);
+			text_show(992);
+		}
+		goto handled;
+	}
+
+	if (player_said_2(look, new_bundle)) {
+		object_examine(new_bundle, 890, 0);
+		goto handled;
+	}
+
+	if (player_said_1(look) && player_has(object_named(player_main_noun))) {
+		global_object_examine();
+		goto handled;
+	}
+
+	if (player_said_2(invoke, amulet)) {
+		if (global[amulet_status] == AMULET_NOT_CORRECT_TIME) {
+			object_examine(amulet, 945, 0);
+		}
+		goto handled;
+	}
+
+	if (player_said_2(thrust, sword) ||
+		player_said_2(carve_up, sword) ||
+		player_said_2(attack, sword)) {
+
+		if (player_said_1(bird_figurine) && player_has(bird_figurine)) {
+
+			inter_move_object(bird_figurine, NOWHERE);
+			inter_give_to_player(birdcall);
+			object_examine(birdcall, 912, 0);
+
+		} else {
+			text_show(911);
+		}
+		goto handled;
+	}
+
+	if (player_said_1(shift_into_bear) || player_said_1(shift_into_seal) ||
+		player_said_1(shift_into_snake)) {
+		text_show(988);
+		goto handled;
+	}
+
+	if (player_said_1(revert)) {
+		text_show(989);
+		goto handled;
+	}
+
+	if (player_said_2(invoke, signet_ring)) {
+		if (room_id == 408 || room_id == 409 || room_id == 410 || room_id == 411) {
+			text_show(702);
+		} else if (room_id == 110) {
+			text_show(996);
+		} else {
+			text_show(900);
+			global[desert_counter] = 0;
+			global[move_direction_510] = true;
+			new_room = 110;
+		}
+		goto handled;
+	}
+
+	if (player_said_2(speak_words_on, parchment)) {
+		text_show(985);
+		goto handled;
+	}
+
+	if (player_said_2(invoke_power_of, crystal_ball)) {
+		object_examine(crystal_ball, 969, 0);
+		goto handled;
+	}
+
+	goto done;
+
+handled:
+	player.command_ready = false;
+
+done:
+	;
+}
+
+void DragonsphereEngine::global_object_examine() {
 
 }
 
diff --git a/engines/mads/madsv2/dragonsphere/dragonsphere.h b/engines/mads/madsv2/dragonsphere/dragonsphere.h
index 5a9233b2a23..f5a6e873c59 100644
--- a/engines/mads/madsv2/dragonsphere/dragonsphere.h
+++ b/engines/mads/madsv2/dragonsphere/dragonsphere.h
@@ -31,6 +31,7 @@ namespace Dragonsphere {
 class DragonsphereEngine : public MADSV2Engine {
 private:
 	static void global_object_sprite();
+	static void global_object_examine();
 	static void stop_walker_basic();
 	static void stop_walker_tricks();
 
diff --git a/engines/mads/madsv2/dragonsphere/mads/inventory.h b/engines/mads/madsv2/dragonsphere/mads/inventory.h
index c27759a7a40..85d4fc9bf2c 100644
--- a/engines/mads/madsv2/dragonsphere/mads/inventory.h
+++ b/engines/mads/madsv2/dragonsphere/mads/inventory.h
@@ -29,38 +29,44 @@ namespace MADSV2 {
 namespace Dragonsphere {
 
 enum {
-	bird_figurine    =  1,
-	shieldstone      =  3,
-	sword            =  4,
-	goblet           =  5,
-	bone             =  6,
-	fruit            =  7,
-	pid_doll         =  8,
-	polystone        =  9,
-	red_powerstone   = 10,
-	yellow_powerstone= 11,
-	blue_powerstone  = 12,
-	key_crown        = 13,
-	dates            = 14,
-	statue           = 15,
-	bottle_of_flies  = 16,
-	soul_egg         = 17,
-	magic_belt       = 18,
-	amulet           = 19,
-	crystal_ball     = 29,
-	black_sphere     = 30,
-	soptus_soporific = 31,
-	shifter_ring     = 32,
-	medicine_bundle  = 33,
-	tentacle_parts   = 36,
-	rare_coin        = 38,
-	crystal_flower   = 39,
-	ruby_ring        = 41,
-	gold_nugget      = 42,
-	magic_music_box  = 43,
-	emerald          = 44,
-	piece_of_paper   = 45,
-	new_bundle       = 48
+	signet_ring         =  0,
+	bird_figurine       =  1,
+	birdcall            =  2,
+	shieldstone         =  3,
+	sword               =  4,
+	goblet              =  5,
+	bone                =  6,
+	fruit               =  7,
+	pid_doll            =  8,
+	polystone           =  9,
+	red_powerstone      = 10,
+	yellow_powerstone   = 11,
+	blue_powerstone     = 12,
+	key_crown           = 13,
+	dates               = 14,
+	statue              = 15,
+	bottle_of_flies     = 16,
+	soul_egg            = 17,
+	magic_belt          = 18,
+	amulet              = 19,
+	feathers            = 21,
+	flask_full_of_acid  = 24,
+	dead_rat            = 27,
+	crystal_ball        = 29,
+	black_sphere        = 30,
+	soptus_soporific    = 31,
+	shifter_ring        = 32,
+	medicine_bundle     = 33,
+	partly_built_bundle = 34,
+	tentacle_parts      = 36,
+	rare_coin           = 38,
+	crystal_flower      = 39,
+	ruby_ring           = 41,
+	gold_nugget         = 42,
+	magic_music_box     = 43,
+	emerald             = 44,
+	piece_of_paper      = 45,
+	new_bundle          = 48
 };
 
 } // namespace Dragonsphere
diff --git a/engines/mads/madsv2/dragonsphere/mads/sounds.h b/engines/mads/madsv2/dragonsphere/mads/sounds.h
index 2e7d9469e62..02a14f9cc37 100644
--- a/engines/mads/madsv2/dragonsphere/mads/sounds.h
+++ b/engines/mads/madsv2/dragonsphere/mads/sounds.h
@@ -48,6 +48,7 @@ enum {
 	N_DogWhimper         =  79,
 	N_BeastSnd           =  80,
 	N_GrabKing           =  82,
+	N_WaterBubbles       =  86,
 	N_MagicDoorOpens     =  88,
 	N_MagicDoorUnlocked  =  89,
 	N_JumpDownWell       =  93,
@@ -82,8 +83,12 @@ enum {
 	N_StepOnFloatingDisk =  77,
 	N_004CryOfDismay     =  78,
 
-	// Section 9
-	N_AllFade            =   1
+	// Section 9/General
+	N_AllFade            =   1,
+	N_MusicBoxOn         =  17,
+	N_MusicBoxOff        =  18,
+	N_BlowBirdCall       =  30,
+	N_ListenToFlies      =  31
 };
 
 } // namespace Dragonsphere
diff --git a/engines/mads/madsv2/dragonsphere/mads/words.h b/engines/mads/madsv2/dragonsphere/mads/words.h
index a28974ecb45..64ebbdbe957 100644
--- a/engines/mads/madsv2/dragonsphere/mads/words.h
+++ b/engines/mads/madsv2/dragonsphere/mads/words.h
@@ -56,6 +56,7 @@ enum {
 	words_decoration           =  41,
 	words_signet_ring          =  46,
 	words_invoke               =  47,
+	words_polish               =  48,
 	words_bird_figurine        =  50,
 	words_rub                  =  51,
 	words_birdcall             =  52,
@@ -66,44 +67,71 @@ enum {
 	words_carve_up             =  58,
 	words_goblet               =  59,
 	words_fill                 =  60,
+	words_drink_from           =  61,
 	words_bone                 =  62,
+	words_gnaw                 =  63,
 	words_fruit                =  64,
+	words_eat                  =  65,
 	words_doll                 =  66,
+	words_play_with            =  67,
 	words_heal                 =  68,
 	words_heal_self            =  70,
+	words_polystone            =  71,
+	words_mimic                =  72,
 	words_key_crown            =  76,
 	words_wear                 =  77,
 	words_dates                =  78,
 	words_statue               =  79,
 	words_bottle_of_flies      =  80,
+	words_listen_to            =  81,
 	words_soul_egg             =  82,
-	N_WaterBubbles             =  86,
+	words_break                =  83,
+	words_magic_belt           =  84,
+	words_adjust               =  85,
+	words_amulet               =  86,
 	words_thrust               =  87,
 	words_mud                  =  88,
+	words_feel                 =  89,
+	words_taste                =  90,
+	words_feathers             =  91,
 	words_torch                =  93,
+	words_wave                 =  94,
+	words_flask                =  95,
 	words_flask_full_of_acid   =  96,
 	words_pour                 =  98,
 	words_pour_contents_of     =  99,
+	words_drink                = 100,
 	words_rope                 = 101,
 	words_tie                  = 102,
 	words_take_magic_from      = 104,
 	words_dead_rat             = 105,
+	words_pet                  = 106,
+	words_map                  = 107,
+	words_fold                 = 108,
 	words_crystal_ball         = 109,
 	words_gaze_into            = 110,
 	words_invoke_power_of      = 111,
 	words_black_sphere         = 112,
 	words_soptus_soporific     = 113,
+	words_shifter_ring         = 114,
 	words_shift_into_bear      = 116,
 	words_shift_into_seal      = 117,
 	words_shift_into_snake     = 118,
 	words_revert               = 119,
+	words_shake                = 121,
 	words_partly_built_bundle  = 122,
 	words_ratsicle             = 123,
+	words_lick                 = 124,
 	words_tentacle_parts       = 125,
+	words_chew                 = 126,
+	words_teleport_door        = 127,
+	words_unroll               = 128,
 	words_rare_coin            = 129,
+	words_admire               = 130,
 	words_crystal_flower       = 131,
 	words_emerald              = 136,
 	words_speak_words_on       = 138,
+	words_vortex_stone         = 139,
 	words_touch                = 146,
 	words_throne_room          = 147,
 	words_passageway_to_west   = 150,
@@ -155,6 +183,7 @@ enum {
 	words_bucket               = 225,
 	words_jump_down            = 226,
 	words_door_to_darkness     = 228,
+	words_pedestal             = 229,
 	words_door_to_north        = 230,
 	words_painting             = 231,
 	words_document             = 232,
@@ -179,6 +208,7 @@ enum {
 	words_scullery_maid        = 266,
 	words_ward                 = 268,
 	words_darkness_beast       = 269,
+	words_beast                = 270,
 	words_put_magic_into       = 271,
 	words_guard                = 272,
 	words_crown                = 273,
@@ -189,6 +219,7 @@ enum {
 	words_shapechanger         = 282,
 	words_red_stone            = 283,
 	words_yellow_stone         = 284,
+	words_blue_stone           = 285,
 	words_flies                = 286,
 	words_flask_of_acid        = 287,
 	words_partial_bundle       = 288,
@@ -202,6 +233,7 @@ enum {
 	words_firepit              = 303,
 	words_spirit_bundle        = 306,
 	words_path_to_east         = 313,
+	words_waterfall            = 314,
 	words_ledge                = 317,
 	words_sconce               = 329,
 	words_rock_tumble          = 321,
@@ -217,10 +249,23 @@ enum {
 	words_grotto               = 345,
 	words_climb_through        = 346,
 	words_Queen_Mother         = 347,
+	words_MacMorn              = 350,
+	words_Llanie               = 355,
+	words_hermit               = 357,
+	words_shak                 = 359,
 	words_moon                 = 361,
 	words_eye                  = 368,
 	words_sit_on               = 363,
+	words_stranger             = 364,
+	words_tower_door           = 365,
+	words_freezer              = 388,
+	words_Ner_Tom              = 399,
+	words_music_box            = 414,
+	words_circle_of_spheres    = 423,
+	words_rat                  = 426,
+	words_door_frame           = 431,
 	words_teleportal           = 440,
+	words_glowing_floor        = 443,
 	words_Soptus_Ecliptus      = 448,
 	words_Slathan_ni_Patan     = 453,
 	words_spirit_plane         = 457,
@@ -234,6 +279,8 @@ enum {
 	words_bones                = 480,
 	words_tent                 = 481,
 	words_bush                 = 482,
+	words_Sanwe                = 483,
+	words_tangle               = 484,
 	words_sand                 = 485,
 	words_magic_grapes         = 486,
 	words_grape_vine           = 488,


Commit: 07298a76da8e1c003c393f9de30d4a9c5778e3f7
    https://github.com/scummvm/scummvm/commit/07298a76da8e1c003c393f9de30d4a9c5778e3f7
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-05-22T06:45:45+10:00

Commit Message:
MADS: DRAGONSPHERE: Other global game functions

Changed paths:
    engines/mads/madsv2/dragonsphere/dragonsphere.cpp
    engines/mads/madsv2/dragonsphere/dragonsphere.h
    engines/mads/madsv2/dragonsphere/mads/words.h


diff --git a/engines/mads/madsv2/dragonsphere/dragonsphere.cpp b/engines/mads/madsv2/dragonsphere/dragonsphere.cpp
index 9924c7cf1af..0355372d3c8 100644
--- a/engines/mads/madsv2/dragonsphere/dragonsphere.cpp
+++ b/engines/mads/madsv2/dragonsphere/dragonsphere.cpp
@@ -28,6 +28,7 @@
 #include "mads/madsv2/core/inter.h"
 #include "mads/madsv2/core/kernel.h"
 #include "mads/madsv2/core/object.h"
+#include "mads/madsv2/core/pal.h"
 #include "mads/madsv2/core/screen.h"
 #include "mads/madsv2/core/sound.h"
 #include "mads/madsv2/core/text.h"
@@ -261,89 +262,6 @@ void DragonsphereEngine::section_music(int section_num) {
 	}
 }
 
-void DragonsphereEngine::global_object_sprite() {
-	Common::strcpy_s(inter_object_buf, "*OB");
-	env_catint(inter_object_buf, inter_object_id, 3);
-	Common::strcat_s(inter_object_buf, "I");
-}
-
-void DragonsphereEngine::stop_walker_basic() {
-	int random;
-	int count;
-	int how_many;
-
-	random = imath_random(1, 30000);
-
-	switch (player.facing) {
-	case FACING_SOUTH:
-		if (random < 500) {
-			how_many = imath_random(4, 10);
-			for (count = 0; count < how_many; count++) {
-				player_add_stop_walker((random < 250) ? 1 : 2, 0);
-			}
-		} else if (random < 750) {
-			for (count = 0; count < 4; count++) {
-				player_add_stop_walker(1, 0);
-			}
-
-			player_add_stop_walker(0, 0);
-
-			for (count = 0; count < 4; count++) {
-				player_add_stop_walker(2, 0);
-			}
-
-			player_add_stop_walker(0, 0);
-		}
-		break;
-
-	case FACING_SOUTHEAST:
-	case FACING_SOUTHWEST:
-	case FACING_NORTHEAST:
-	case FACING_NORTHWEST:
-		if (random < 150) {
-			player_add_stop_walker(-1, 0);
-			player_add_stop_walker(1, 0);
-			for (count = 0; count < 6; count++) {
-				player_add_stop_walker(0, 0);
-			}
-		}
-		break;
-
-	case FACING_EAST:
-	case FACING_WEST:
-		if (random < 250) {
-			player_add_stop_walker(-1, 0);
-			how_many = imath_random(2, 6);
-			for (count = 0; count < how_many; count++) {
-				player_add_stop_walker(2, 0);
-			}
-			player_add_stop_walker(1, 0);
-			player_add_stop_walker(0, 0);
-			player_add_stop_walker(0, 0);
-		} else if (random < 500) {
-			WRITE_LE_UINT32(&global[walker_timing], kernel.clock);
-		}
-		break;
-
-	case FACING_NORTH:
-		if (random < 250) {
-			player_add_stop_walker(-1, 0);
-			how_many = imath_random(3, 7);
-			for (count = 0; count < how_many; count++) {
-				player_add_stop_walker(2, 0);
-			}
-			player_add_stop_walker(1, 0);
-			player_add_stop_walker(0, 0);
-		}
-		break;
-
-	}
-}
-
-void DragonsphereEngine::stop_walker_tricks() {
-
-}
-
 void DragonsphereEngine::global_section_constructor() {
 	Dragonsphere::global_section_constructor();
 }
@@ -360,10 +278,8 @@ void DragonsphereEngine::global_daemon_code() {
 	if (player.walker_visible && (player.commands_allowed || (conv_control.running >= 0)) && !player.walking &&
 		(player.facing == player.turn_to_facing) && global[perform_displacements]) {
 
-		if (kernel.clock >= *((long *)&global[walker_timing])) {
-
+		if (kernel.clock >= READ_LE_INT32(&global[walker_timing])) {
 			if (!player.stop_walker_pointer) {
-
 				random = imath_random(1, 30000);
 
 				if (global[player_persona] == PLAYER_IS_KING) {
@@ -1146,19 +1062,235 @@ done:
 }
 
 void DragonsphereEngine::global_object_examine() {
+	int id;
+
+	id = object_named(player_main_noun);
+
+	/* exceptions here */
+
+	if (player_said_1(music_box)) {
+		sound_play(N_MusicBoxOn);
+	}
+
+	if (player_said_1(doll)) {
+		if (global[player_persona] == PLAYER_IS_KING) {
+			object_examine(pid_doll, 808, 0);
+
+		} else { /* pid */
+			if (game.difficulty == EASY_MODE) {
+				if (global[pid_looked_at_doll]) {
+					object_examine(pid_doll, 896, 0);
+				} else {
+					object_examine(pid_doll, 895, 0);
+					global[pid_looked_at_doll] = true;
+					global[heal_verbs_visible] = true;
+					inter_move_object(pid_doll, NOWHERE);
+					inter_give_to_player(pid_doll);
+				}
 
+			} else {
+				if (global[pid_looked_at_doll]) {
+					object_examine(pid_doll, 896, 0);
+				} else {
+					object_examine(pid_doll, 706, 0);
+					global[pid_looked_at_doll] = true;
+					global[heal_verbs_visible] = true;
+					inter_move_object(pid_doll, NOWHERE);
+					inter_give_to_player(pid_doll);
+				}
+			}
+		}
+
+	} else if (player_said_1(polystone) && global[object_imitated] == -1) {
+		object_examine(polystone, 809, 0);
+
+	} else if (player_said_1(polystone) && global[object_imitated] == 9) {
+		object_examine(polystone, 809, 0);
+
+	} else if (player_said_1(polystone) && global[object_imitated] >= 0) {
+		object_examine(polystone, 894, 0);
+
+	} else if (player_said_1(medicine_bundle)) {
+		object_examine(medicine_bundle, 890, 0);
+
+	} else {
+		object_examine(id, 800 + id, 0);
+	}
+
+	if (player_said_1(music_box)) {
+		sound_play(N_MusicBoxOff);
+	}
 }
 
 void DragonsphereEngine::global_error_code() {
+	int show_me = 0;
+	int item;
+	int random;
 
+	random = imath_random(1, 1000);
+
+	if (player_said_3(put, king, pedestal)) {
+		if (global[king_status] != KING_CAPTIVE) {
+			text_show(43);
+			goto done;
+		}
+	}
+
+	if (player_said_1(take)) {
+		item = object_named(player_main_noun);
+		if (player_has(item) && player.main_object_source != STROKE_INTERFACE) {
+			show_me = 25;
+			/* player already has it */
+
+		} else {
+			if (random <= 333) {
+				show_me = 1;
+			} else if (random <= 666) {
+				show_me = 2;
+			} else {
+				show_me = 3;
+			}
+		}
+		goto done;
+	}
+
+	if (player_said_1(push)) {
+		if (random < 750) {
+			show_me = 4;
+		} else {
+			show_me = 5;
+		}
+		goto done;
+	}
+
+	if (player_said_1(pull)) {
+		if (random < 750) {
+			show_me = 6;
+		} else {
+			show_me = 7;
+		}
+		goto done;
+	}
+
+	if (player_said_1(open)) {
+		if (random <= 500) {
+			show_me = 8;
+		} else if (random <= 750) {
+			show_me = 9;
+		} else {
+			show_me = 10;
+		}
+		goto done;
+	}
+
+	if (player_said_1(close)) {
+		if (random <= 500) {
+			show_me = 11;
+		} else if (random <= 750) {
+			show_me = 12;
+		} else {
+			show_me = 13;
+		}
+		goto done;
+	}
+
+	if (player_said_1(put)) {
+		item = object_named(player_main_noun);
+		if (player_has(item)) {
+			show_me = 26;
+
+		} else if (player.main_object_source == STROKE_INTERFACE &&
+			player.second_object_source == STROKE_INTERFACE) {
+			show_me = 28;
+
+		} else if (random < 500) {
+			show_me = 14;
+
+		} else {
+			show_me = 15;
+		}
+		goto done;
+	}
+
+	if (player_said_1(talk_to)) {
+		if (random <= 500) {
+			show_me = 16;
+		} else {
+			show_me = 17;
+		}
+		goto done;
+	}
+
+	if (player_said_1(give)) {
+		item = object_named(player_main_noun);
+		if (player_has(item)) {
+			show_me = 27;
+
+		} else if (player.main_object_source == STROKE_INTERFACE &&
+			player.second_object_source == STROKE_INTERFACE) {
+			show_me = 28;
+
+		} else {
+			show_me = 18;
+		}
+		goto done;
+	}
+
+	if (player_said_1(throw)) {
+		item = object_named(player_main_noun);
+		if (player_has(item)) {
+			show_me = 19;
+		} else {
+			show_me = 28;
+		}
+		goto done;
+	}
+
+	if (player_said_1(look)) {
+		item = object_named(player_main_noun);
+		if (random <= 333) {
+			show_me = 20;
+		} else if (random <= 666) {
+			show_me = 21;
+		} else {
+			show_me = 22;
+		}
+		goto done;
+	}
+
+	if (!player_said_1(walk_to) && !player_said_1(walk_across) &&
+		!player_said_1(walk_down) && !player_said_1(walk_behind) &&
+		!player_said_1(cross)) {
+		if (random < 500) {
+			show_me = 23;
+		} else {
+			show_me = 24;
+		}
+		goto done;
+	}
+
+done:
+	if (show_me) text_show(show_me);
 }
 
 void DragonsphereEngine::global_room_init() {
+	switch (global[player_persona]) {
+	case PLAYER_IS_KING:
+		pal_change_color(KERNEL_MESSAGE_COLOR_BASE, 63, 0, 0);
+		pal_change_color(KERNEL_MESSAGE_COLOR_BASE + 1, 45, 0, 0);
+		break;
 
+	case PLAYER_IS_PID:
+	default:
+		pal_change_color(KERNEL_MESSAGE_COLOR_BASE, 63, 50, 42);
+		pal_change_color(KERNEL_MESSAGE_COLOR_BASE + 1, 45, 30, 20);
+		break;
+	}
 }
 
 void DragonsphereEngine::global_sound_driver() {
-
+	Common::strcpy_s(kernel.sound_driver, "/");
+	env_catint(kernel.sound_driver, new_section, 1);
 }
 
 } // namespace Dragonsphere
diff --git a/engines/mads/madsv2/dragonsphere/dragonsphere.h b/engines/mads/madsv2/dragonsphere/dragonsphere.h
index f5a6e873c59..d5e3f721170 100644
--- a/engines/mads/madsv2/dragonsphere/dragonsphere.h
+++ b/engines/mads/madsv2/dragonsphere/dragonsphere.h
@@ -30,10 +30,7 @@ namespace Dragonsphere {
 
 class DragonsphereEngine : public MADSV2Engine {
 private:
-	static void global_object_sprite();
 	static void global_object_examine();
-	static void stop_walker_basic();
-	static void stop_walker_tricks();
 
 public:
 	DragonsphereEngine(OSystem *syst, const MADSGameDescription *gameDesc) :
diff --git a/engines/mads/madsv2/dragonsphere/mads/words.h b/engines/mads/madsv2/dragonsphere/mads/words.h
index 64ebbdbe957..4230d44e59d 100644
--- a/engines/mads/madsv2/dragonsphere/mads/words.h
+++ b/engines/mads/madsv2/dragonsphere/mads/words.h
@@ -48,6 +48,7 @@ enum {
 	words_wall                 =  20,
 	words_window               =  24,
 	words_tapestry             =  26,
+	words_walk_behind          =  28,
 	words_look_at              =  30,
 	words_fireplace            =  34,
 	words_fireplace_screen     =  35,
@@ -118,6 +119,7 @@ enum {
 	words_shift_into_seal      = 117,
 	words_shift_into_snake     = 118,
 	words_revert               = 119,
+	words_medicine_bundle      = 120,
 	words_shake                = 121,
 	words_partly_built_bundle  = 122,
 	words_ratsicle             = 123,




More information about the Scummvm-git-logs mailing list