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

dreammaster noreply at scummvm.org
Mon May 25 11:03:39 UTC 2026


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

Summary:
3b64511f7d MADS: DRAGONSPHERE: Fixes for room 105 dining room
b3022cdfdc MADS: DRAGONSPHERE: Room 106 cleanups
26ae7b4418 MADS: DRAGONSPHERE: Room 107 cleanup
dd7f87c3bd MADS: DRAGONSPHERE: Implemented remaining sound drivers


Commit: 3b64511f7d038ef9d98fc1ea1ff0a7f6b3e2bb98
    https://github.com/scummvm/scummvm/commit/3b64511f7d038ef9d98fc1ea1ff0a7f6b3e2bb98
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-05-25T21:03:26+10:00

Commit Message:
MADS: DRAGONSPHERE: Fixes for room 105 dining room

Changed paths:
    engines/mads/madsv2/dragonsphere/rooms/room104.cpp
    engines/mads/madsv2/dragonsphere/rooms/room105.cpp


diff --git a/engines/mads/madsv2/dragonsphere/rooms/room104.cpp b/engines/mads/madsv2/dragonsphere/rooms/room104.cpp
index e83a6026f70..aac03dd953e 100644
--- a/engines/mads/madsv2/dragonsphere/rooms/room104.cpp
+++ b/engines/mads/madsv2/dragonsphere/rooms/room104.cpp
@@ -47,44 +47,44 @@ namespace Dragonsphere {
 namespace Rooms {
 
 struct Scratch {
-	int16 sprite[16];            // ss[]  — series handles
-	int16 sequence[16];          // seq[] — sequence handles
-	int16 animation[6];          // aa[]  — animation handles
-	int16 doorway_id;            // 0x4C — dynamic hotspot handle for open doorway
-	int16 wall_panel_id;         // 0x4E — dynamic hotspot handle for wall panel
-	int16 secret_door_id;        // 0x50 — dynamic hotspot handle for secret door
-	int16 tapestry_frame;        // 0x52 — last anim frame seen (tapestry sequence)
-	int16 animation_running;     // 0x54 — which tapestry animation is running
-	int16 king_frame;            // 0x56 — last anim frame seen (King)
-	int16 king_action;           // 0x58 — current King animation state
-	int16 king_talk_count;       // 0x5A — King talking counter
-	int16 anim_0_running;        // 0x5C — King animation active flag
-	int16 mac_frame;             // 0x5E — last anim frame seen (MacMorn)
-	int16 mac_action;            // 0x60 — current MacMorn animation state
-	int16 mac_talk_count;        // 0x62 — MacMorn talking counter
-	int16 anim_1_running;        // 0x64 — MacMorn animation active flag
-	int16 queen_frame;           // 0x66 — last anim frame seen (Queen)
-	int16 queen_action;          // 0x68 — current Queen animation state
-	int16 queen_talk_count;      // 0x6A — Queen talking counter
-	int16 anim_2_running;        // 0x6C — Queen animation active flag
-	int16 twinkles_frame;        // 0x6E — last anim frame seen (Twinkles)
-	int16 twinkles_action;       // 0x70 — current Twinkles animation state
-	int16 twinkles_talk_count;   // 0x72 — Twinkles freeze counter
-	int16 anim_3_running;        // 0x74 — Twinkles animation active flag
-	int16 pid_frame;             // 0x76 — last anim frame seen (Pid)
-	int16 pid_action;            // 0x78 — current Pid animation state
-	int16 pid_talk_count;        // 0x7A — Pid freeze counter
-	int16 anim_4_running;        // 0x7C — Pid animation active flag
-	int32 clock;                 // 0x7E — general timer (long in original)
-	int32 death_timer;           // 0x82 — counts to 8 sec to kill Pid (long in original)
-	int16 activate_timer;        // 0x86 — T = start counting death_timer
-	int16 has_been_bear;         // 0x88 — Pid has completed bear transformation
-	int16 mac_2_frame;           // 0x8A — last anim frame seen (MacMorn death)
-	int16 anim_5_running;        // 0x8C — MacMorn death animation active flag
-	int16 amulet_works;          // 0x8E — amulet is functional
-	int16 pid_drawn_sword;       // 0x90 — Pid has drawn his sword
-	int16 death_frame;           // 0x92 — last anim frame seen (death sequence)
-	int16 anim_6_running;        // 0x94 — death animation active flag
+	int16 sprite[16];
+	int16 sequence[16];
+	int16 animation[6];
+	int16 doorway_id;
+	int16 wall_panel_id;
+	int16 secret_door_id;
+	int16 tapestry_frame;
+	int16 animation_running;
+	int16 king_frame;
+	int16 king_action;
+	int16 king_talk_count;
+	int16 anim_0_running;
+	int16 mac_frame;
+	int16 mac_action;
+	int16 mac_talk_count;
+	int16 anim_1_running;
+	int16 queen_frame;
+	int16 queen_action;
+	int16 queen_talk_count;
+	int16 anim_2_running;
+	int16 twinkles_frame;
+	int16 twinkles_action;
+	int16 twinkles_talk_count;
+	int16 anim_3_running;
+	int16 pid_frame;
+	int16 pid_action;
+	int16 pid_talk_count;
+	int16 anim_4_running;
+	int32 clock;
+	int32 death_timer;
+	int16 activate_timer;
+	int16 has_been_bear;
+	int16 mac_2_frame;
+	int16 anim_5_running;
+	int16 amulet_works;
+	int16 pid_drawn_sword;
+	int16 death_frame;
+	int16 anim_6_running;
 };
 
 static Scratch scratch;
diff --git a/engines/mads/madsv2/dragonsphere/rooms/room105.cpp b/engines/mads/madsv2/dragonsphere/rooms/room105.cpp
index 711eb723ec2..aef37c3279b 100644
--- a/engines/mads/madsv2/dragonsphere/rooms/room105.cpp
+++ b/engines/mads/madsv2/dragonsphere/rooms/room105.cpp
@@ -42,43 +42,25 @@ namespace MADSV2 {
 namespace Dragonsphere {
 namespace Rooms {
 
-// ---------------------------------------------------------------------------
-// Scratch layout (matches ROOM105.MAC)
-//
-//   game.scratch offsets:
-//     sprite[0..14]    = 0x00..0x1C
-//     sequence[0..14]  = 0x1E..0x3A
-//     animation[0..3]  = 0x3C..0x42
-//     temp             = 0x44
-//     maid_frame       = 0x46
-//     new_action       = 0x48
-//     last_action      = 0x4A
-//     maid_talking     = 0x4C
-//     situp            = 0x4E
-//     good_number      = 0x50
-//     maid_id[0]       = 0x52
-//     maid_id[1]       = 0x54
-//     bucket_id        = 0x56
-//     bone_id          = 0x58
-//     goblet_id        = 0x5A
-// ---------------------------------------------------------------------------
 struct Scratch {
-	int16 sprite[15];       // ss[]  — sprite series handles
-	int16 sequence[15];     // seq[] — sequence handles
-	int16 animation[4];     // aa[]  — animation handles
-	int16 temp;             // 0x44
-	int16 maid_frame;       // 0x46
-	int16 new_action;       // 0x48
-	int16 last_action;      // 0x4A
-	int16 maid_talking;     // 0x4C
-	int16 situp;            // 0x4E
-	int16 good_number;      // 0x50
-	int16 maid_id[2];       // 0x52
-	int16 bucket_id;        // 0x56
-	int16 bone_id;          // 0x58
-	int16 goblet_id;        // 0x5A
+	int16 sprite[15];
+	int16 sequence[15];
+	int16 animation[4];
+	int16 temp;
+	int16 maid_frame;
+	int16 new_action;
+	int16 last_action;
+	int16 maid_talking;
+	int16 situp;
+	int16 good_number;
+	int16 maid_id[2];
+	int16 bucket_id;
+	int16 bone_id;
+	int16 goblet_id;
 };
 
+static Scratch scratch;
+
 #define local (&scratch)
 #define ss    local->sprite
 #define seq   local->sequence
@@ -111,7 +93,7 @@ struct Scratch {
 #define WALK_TO_BONE_X       255
 #define WALK_TO_BONE_Y       145
 
-#define WALK_TO_GOBLET_X     63
+#define WALK_TO_GOBLET_X     65
 #define WALK_TO_GOBLET_Y     142
 
 /* cursor points */
@@ -166,14 +148,12 @@ struct Scratch {
 #define ROOM_105_TAKE_BONE2       84
 #define ROOM_105_TAKE_BONE3       85
 
-static Scratch scratch;
-
 
-void room_105_init() {
+static void room_105_init() {
 	ss[fx_fire_left]  = kernel_load_series(kernel_name('x', 0), false);
 	ss[fx_fire_right] = kernel_load_series(kernel_name('x', 1), false);
 	ss[fx_door]       = kernel_load_series(kernel_name('x', 2), false);
-	ss[fx_open_door]  = kernel_load_series("*KGRD_8", false);
+	ss[fx_open_door]  = kernel_load_series("*kgrd_8", false);
 
 	seq[fx_fire_left]  = kernel_seq_forward(ss[fx_fire_left],  false, 7, 0, 0, 0);
 	seq[fx_fire_right] = kernel_seq_forward(ss[fx_fire_right], false, 7, 3, 0, 0);
@@ -191,20 +171,20 @@ void room_105_init() {
 
 	if (object_is_here(goblet)) {
 		ss[fx_goblet]      = kernel_load_series(kernel_name('p', 1), false);
-		ss[fx_take_goblet] = kernel_load_series("*KGRM1_8", false);
+		ss[fx_take_goblet] = kernel_load_series("*kgrm_6", false);
 		seq[fx_goblet]     = kernel_seq_stamp(ss[fx_goblet], false, KERNEL_FIRST);
 		local->goblet_id   = kernel_add_dynamic(words_goblet, words_walk_to, SYNTAX_SINGULAR, seq[fx_goblet], 0, 0, 0, 0);
 		kernel_seq_depth(seq[fx_goblet], 6);
-		kernel_dynamic_walk(local->goblet_id, 63, 142, FACING_WEST);
+		kernel_dynamic_walk(local->goblet_id, WALK_TO_GOBLET_X, WALK_TO_GOBLET_Y, FACING_WEST);
 	}
 
 	if (object_is_here(bone)) {
 		ss[fx_bone]      = kernel_load_series(kernel_name('p', 0), false);
-		ss[fx_take_bone] = kernel_load_series("*KGRD_8", false);
+		ss[fx_take_bone] = kernel_load_series("*kgrl_6", false);
 		seq[fx_bone]     = kernel_seq_stamp(ss[fx_bone], false, KERNEL_FIRST);
 		local->bone_id   = kernel_add_dynamic(words_bone, words_walk_to, SYNTAX_SINGULAR, seq[fx_bone], 0, 0, 0, 0);
 		kernel_seq_depth(seq[fx_bone], 6);
-		kernel_dynamic_walk(local->bone_id, 255, 145, FACING_EAST);
+		kernel_dynamic_walk(local->bone_id, WALK_TO_BONE_X, WALK_TO_BONE_Y, FACING_EAST);
 	}
 
 	conv_get(2);
@@ -234,7 +214,7 @@ void room_105_init() {
 	section_1_music();
 }
 
-void room_105_get_random() {
+static void room_105_get_random() {
 	int random;
 
 	local->last_action = local->new_action;
@@ -254,7 +234,7 @@ void room_105_get_random() {
 	}
 }
 
-void room_105_random_wipebrow() {
+static void room_105_random_wipebrow() {
 	int random;
 
 	local->last_action = local->new_action;
@@ -270,7 +250,7 @@ void room_105_random_wipebrow() {
 	}
 }
 
-void room_105_daemon() {
+static void room_105_daemon() {
 	int reset_frame;
 
 	/* Control scullery maid animation */
@@ -446,7 +426,7 @@ void room_105_daemon() {
 	}
 }
 
-void room_105_conversation() {
+static void room_105_conversation() {
 	if (player_verb == conv002_counter_only) {
 		if (!local->situp) {
 			local->situp = true;
@@ -473,12 +453,12 @@ void room_105_conversation() {
 	}
 }
 
-void room_105_pre_parser() {
-	if (player_parse(words_talk_to, words_scullery_maid, 0))
+static void room_105_pre_parser() {
+	if (player_said_2(talk_to, scullery_maid))
 		local->situp = -1;
 }
 
-void room_105_parser() {
+static void room_105_parser() {
 	int temp;
 
 	if (player.look_around) {
@@ -585,7 +565,6 @@ void room_105_parser() {
 				break;
 
 			case 1:
-				/* sound_queue (N_PickUpObject006);*/
 				kernel_seq_delete(seq[fx_goblet]);
 				kernel_delete_dynamic(local->goblet_id);
 				sound_play(N_TakeObjectSnd);
@@ -613,14 +592,11 @@ void room_105_parser() {
 				seq[fx_take_bone] = kernel_seq_pingpong(ss[fx_take_bone],
 					false, 6, 0, 0, 2);
 				kernel_seq_player(seq[fx_take_bone], true);
-				kernel_seq_trigger(seq[fx_take_bone],
-					KERNEL_TRIGGER_SPRITE, 6, 1);
-				kernel_seq_trigger(seq[fx_take_bone],
-					KERNEL_TRIGGER_EXPIRE, 0, 2);
+				kernel_seq_trigger(seq[fx_take_bone], KERNEL_TRIGGER_SPRITE, 6, 1);
+				kernel_seq_trigger(seq[fx_take_bone], KERNEL_TRIGGER_EXPIRE, 0, 2);
 				break;
 
 			case 1:
-				/* sound_queue (N_PickUpObject006);*/
 				kernel_seq_delete(seq[fx_bone]);
 				sound_play(N_TakeObjectSnd);
 				kernel_delete_dynamic(local->bone_id);
@@ -642,14 +618,12 @@ void room_105_parser() {
 		}
 	}
 
-	if (player_said_2(take, bone) && player_has(bone) &&
-		player.main_object_source == STROKE_INTERFACE) {
+	if (player_said_2(take, bone) && player_has(bone) && player.main_object_source == STROKE_INTERFACE) {
 		text_show(40112);
 		goto handled;
 	}
 
 	if (player_said_1(look) || player_said_1(look_at)) {
-
 		if (player_said_1(floor)) {
 			text_show(10502);
 			goto handled;


Commit: b3022cdfdcc54bf4a2189333f8e163dd06e5c75c
    https://github.com/scummvm/scummvm/commit/b3022cdfdcc54bf4a2189333f8e163dd06e5c75c
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-05-25T21:03:26+10:00

Commit Message:
MADS: DRAGONSPHERE: Room 106 cleanups

Changed paths:
    engines/mads/madsv2/dragonsphere/rooms/room106.cpp
    engines/mads/madsv2/dragonsphere/rooms/room111.cpp
    engines/mads/madsv2/dragonsphere/sound_dragonsphere.cpp
    engines/mads/madsv2/dragonsphere/sound_dragonsphere.h


diff --git a/engines/mads/madsv2/dragonsphere/rooms/room106.cpp b/engines/mads/madsv2/dragonsphere/rooms/room106.cpp
index 8f15cef229d..ce9123da3ec 100644
--- a/engines/mads/madsv2/dragonsphere/rooms/room106.cpp
+++ b/engines/mads/madsv2/dragonsphere/rooms/room106.cpp
@@ -86,7 +86,6 @@ struct Scratch {
 
 static Scratch scratch;
 
-
 /* ========================= Sprites ========================= */
 
 #define fx_fire_sconce       1   /* rm106y */
@@ -157,11 +156,10 @@ static Scratch scratch;
 #define CONV_34_CUT_SCENE    34
 
 
-void room_106_init() {
+static void room_106_init() {
 	int count;
 
 	if (global[end_of_game]) {
-
 		local->prevent = true;
 		local->anim_0_running = false;
 		local->anim_2_running = false;
@@ -194,13 +192,11 @@ void room_106_init() {
 			} else {
 				aa[0] = kernel_run_animation(kernel_name('e', 2), ROOM_106_END_GAME_1);
 			}
-
 		} else {
 			aa[0] = kernel_run_animation(kernel_name('e', 1), ROOM_106_END_GAME_1);
 		}
 
 	} else {
-
 		conv_get(CONV_3_MACMORN);
 
 		/* Load sprite series */
@@ -267,7 +263,6 @@ void room_106_init() {
 			}
 
 		} else if (previous_room == 118) {      /* Player comes from Courtyard */
-
 			local->prevent = true;
 
 			if (player.been_here_before) {
@@ -288,7 +283,6 @@ void room_106_init() {
 			player.facing = FACING_NORTHWEST;
 
 		} else if (previous_room == 614) {      /* Cut scene */
-
 			conv_get(CONV_34_CUT_SCENE);
 
 			kernel_init_dialog();  /* clear interface */
@@ -363,9 +357,7 @@ void room_106_init() {
 			}
 
 		} else if (previous_room == KERNEL_RESTORING_GAME) {
-
 			if (local->anim_1_running) {
-
 				for (count = 0; count < room_num_spots; count++) {
 					if (room_spots[count].vocab == words_king_s_throne) {
 						room_spots[count].verb = words_look_at;
@@ -405,7 +397,6 @@ void room_106_init() {
 	section_1_music();
 }
 
-
 static void handle_animation_mac() {
 	int mac_reset_frame;
 
@@ -414,7 +405,6 @@ static void handle_animation_mac() {
 		mac_reset_frame = -1;
 
 		switch (local->mac_frame) {
-
 		case 1:
 		case 151:
 			if (player.y < 110) {
@@ -442,9 +432,7 @@ static void handle_animation_mac() {
 		case 12:   /* end of talk */
 		case 13:   /* end of talk */
 		case 159:  /* end of standing */
-
 			if (local->mac_action == MAC_TALK) {
-
 				mac_reset_frame = imath_random(10, 12);
 				++local->mac_talk_count;
 				if (local->mac_talk_count > 15) {
@@ -463,9 +451,7 @@ static void handle_animation_mac() {
 		case 160:  /* end of talk                   */
 		case 161:  /* end of talk                   */
 		case 162:  /* end of talk                   */
-
 			switch (local->mac_action) {
-
 			case MAC_TALK:
 				mac_reset_frame = imath_random(159, 161);
 				++local->mac_talk_count;
@@ -531,7 +517,6 @@ static void handle_animation_mac() {
 	}
 }
 
-
 static void handle_animation_sit() {
 	int sit_reset_frame;
 
@@ -540,7 +525,6 @@ static void handle_animation_sit() {
 		sit_reset_frame = -1;
 
 		switch (local->sit_frame) {
-
 		case 31:
 			player.commands_allowed = true;
 			break;
@@ -549,7 +533,6 @@ static void handle_animation_sit() {
 		case 33:  /* end of look around 2      */
 		case 34:  /* end of look around 3      */
 		case 35:  /* end of look around 4      */
-
 			if (local->sit_action == LOOK) {
 				if (local->sit_count >= imath_random(10, 20)) {
 					local->sit_count = 0;
@@ -565,12 +548,14 @@ static void handle_animation_sit() {
 					++local->sit_count;
 				}
 
-			} else switch (local->sit_frame) {
-			case 31:
-			case 32:
-			case 33: sit_reset_frame = 35; player.commands_allowed = false; break;
-			case 34: sit_reset_frame = 32; break;
-			case 35: sit_reset_frame = 33; break;
+			} else {
+				switch (local->sit_frame) {
+				case 31:
+				case 32:
+				case 33: sit_reset_frame = 35; player.commands_allowed = false; break;
+				case 34: sit_reset_frame = 32; break;
+				case 35: sit_reset_frame = 33; break;
+				}
 			}
 			break;
 
@@ -591,7 +576,6 @@ static void handle_animation_sit() {
 	}
 }
 
-
 static void handle_animation_a_macmorn() {
 	int a_mac_reset_frame;
 	int random;
@@ -602,16 +586,8 @@ static void handle_animation_a_macmorn() {
 
 		switch (local->a_mac_frame) {
 
-		case 114: /* just when macmorn and queen leave bottom of screen */
-
-			/* Test for existance of PDD_6.SS.  If not here, */
-			/* then this is demo version else continue game. */
-			/* if (!env_exist (filename)) {
-			  text_show (10625);
-			  game.going = false;
-			  win_status = 1;
-			}  */
-
+		case 114:
+			/* just when MacMorn and queen leave bottom of screen */
 			new_room = 614;
 			break;
 
@@ -637,9 +613,7 @@ static void handle_animation_a_macmorn() {
 		case 40:  /* end of talk 2 */
 		case 41:  /* end of talk 3 */
 		case 50:  /* end of come from talk */
-
 			switch (local->a_mac_action) {
-
 			case MAC_TALK:
 				if (local->a_mac_talk_count == 0) {
 					random = imath_random(1, 2);
@@ -674,9 +648,7 @@ static void handle_animation_a_macmorn() {
 		case 44:  /* end of talk 1 */
 		case 45:  /* end of talk 2 */
 		case 46:  /* end of talk 3 */
-
 			switch (local->a_mac_action) {
-
 			case MAC_TALK:
 				a_mac_reset_frame = imath_random(43, 45);
 				++local->a_mac_talk_count;
@@ -707,8 +679,6 @@ static void handle_animation_a_macmorn() {
 	}
 }
 
-
-
 static void handle_animation_a_queen() {
 	int a_q_reset_frame;
 	int random;
@@ -718,15 +688,12 @@ static void handle_animation_a_queen() {
 		a_q_reset_frame = -1;
 
 		switch (local->a_q_frame) {
-
 		case 1:  /* on throne          */
 		case 2:  /* on throne          */
 		case 3:  /* on throne          */
 		case 16: /* end talk           */
 		case 37: /* end talk with fist */
-
 			switch (local->a_q_action) {
-
 			case QUEEN_TALK:
 				a_q_reset_frame = 3;
 				local->a_q_action = QUEEN_SHUT_UP;
@@ -769,9 +736,7 @@ static void handle_animation_a_queen() {
 
 		case 81:  /* end of get up from throne and freeze standing */
 		case 93:  /* end of talk                                   */
-
 			switch (local->a_q_action) {
-
 			case QUEEN_TALK:
 				a_q_reset_frame = 81;
 				local->a_q_action = QUEEN_SHUT_UP;
@@ -799,7 +764,6 @@ static void handle_animation_a_queen() {
 	}
 }
 
-
 static void handle_animation_a_qmother() {
 	int a_qm_reset_frame;
 	int random;
@@ -809,13 +773,10 @@ static void handle_animation_a_qmother() {
 		a_qm_reset_frame = -1;
 
 		switch (local->a_qm_frame) {
-
 		case 9:   /* end of freeze */
 		case 10:  /* end of freeze */
 		case 23:  /* end of freeze */
-
 			switch (local->a_qm_action) {
-
 			case QUEEN_TALK:
 				a_qm_reset_frame = 23;
 				break;
@@ -845,9 +806,7 @@ static void handle_animation_a_qmother() {
 			break;
 
 		case 18:  /* end of freeze */
-
 			switch (local->a_qm_action) {
-
 			case QUEEN_TALK:
 			case QUEEN_FIST:
 				a_qm_reset_frame = 18;
@@ -871,9 +830,7 @@ static void handle_animation_a_qmother() {
 		case 32:  /* end of talk   */
 		case 44:  /* end of talk   */
 		case 54:  /* end of talk   */
-
 			switch (local->a_qm_action) {
-
 			case QUEEN_TALK:
 				random = imath_random(1, 3);
 				switch (random) {
@@ -914,8 +871,7 @@ static void handle_animation_a_qmother() {
 	}
 }
 
-
-void room_106_daemon() {
+static void room_106_daemon() {
 	int temp;
 
 	if (local->anim_0_running) {
@@ -951,7 +907,6 @@ void room_106_daemon() {
 	/* Close either door 104 or 105 when player enters */
 
 	switch (kernel.trigger) {
-
 	case ROOM_106_DOOR_CLOSES: /* left door closes */
 		kernel_seq_delete(seq[fx_door_104]);
 		sound_play(N_DoorCloses);
@@ -1129,7 +1084,7 @@ static void process_conv_abduction() {
 	local->a_qm_talk_count = 0;
 }
 
-void room_106_pre_parser() {
+static void room_106_pre_parser() {
 	int count;
 
 	if (player_said_2(walk_through, door_to_courtyard) || player_said_2(open, door_to_courtyard) ||
@@ -1137,20 +1092,16 @@ void room_106_pre_parser() {
 		player.walk_off_edge_to_room = 118;
 	}
 
-	if ((player_said_1(look_at) || player_said_1(look)) &&
-		player_said_1(Dragonsphere)) {
-
+	if ((player_said_1(look_at) || player_said_1(look)) && player_said_1(Dragonsphere)) {
 		if (!(global[player_score_flags] & SCORE_LOOK_SPHERE_106)) {
 			global[player_score_flags] = global[player_score_flags] | SCORE_LOOK_SPHERE_106;
 			global[player_score] += 1;
 		}
 
 		player.need_to_walk = true;
-		/* player_walk(START_X_ROOM_111, START_Y_ROOM_111, FACING_NORTHEAST); */
 	}
 
 	if (local->anim_1_running) {
-
 		if ((player_said_1(look_at) || player_said_1(look)) &&
 			player_said_1(king_s_throne)) {
 			player.need_to_walk = false;
@@ -1172,7 +1123,7 @@ void room_106_pre_parser() {
 	}
 }
 
-void room_106_parser() {
+static void room_106_parser() {
 	int temp;
 	int count;
 
diff --git a/engines/mads/madsv2/dragonsphere/rooms/room111.cpp b/engines/mads/madsv2/dragonsphere/rooms/room111.cpp
index 59688a9b2c9..b5d436097eb 100644
--- a/engines/mads/madsv2/dragonsphere/rooms/room111.cpp
+++ b/engines/mads/madsv2/dragonsphere/rooms/room111.cpp
@@ -50,13 +50,13 @@ struct Scratch {
 	int16 prev_room;
 };
 
+static Scratch scratch;
+
 #define local (&scratch)
 #define ss    local->sprite
 #define seq   local->sequence
 #define aa    local->animation
 
-static Scratch scratch;
-
 
 static void room_111_init() {
 	local->done_with_conv = false;
@@ -105,8 +105,6 @@ static void room_111_daemon() {
 					reset_frame = 29;
 				} else {
 					if (local->done_with_conv) {
-						/* reset_frame = 29; */
-						/* global[pre_room] = 110; */
 						new_room = 120;
 					} else {
 						switch (global[dragon_my_scene]) {
diff --git a/engines/mads/madsv2/dragonsphere/sound_dragonsphere.cpp b/engines/mads/madsv2/dragonsphere/sound_dragonsphere.cpp
index c6e9a011c2d..674f228a044 100644
--- a/engines/mads/madsv2/dragonsphere/sound_dragonsphere.cpp
+++ b/engines/mads/madsv2/dragonsphere/sound_dragonsphere.cpp
@@ -1029,26 +1029,24 @@ int ASound2::command72() {
  *-----------------------------------------------------------------------*/
 
 const ASound3::CommandPtr ASound3::_commandList[77] = {
-	// commands 0-8  (asound_commands1)
+	// commands 0-8  (off_11A14)
 	&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,
+	// commands 16-19  (off_11A26; slot 19 = no-op)
+	&ASound3::command16, &ASound3::command17, &ASound3::command18, nullptr,
+	// 20-23 absent
 	nullptr,             nullptr,             nullptr,             nullptr,
-	// commands 24-27  (asound_commands3)
+	// commands 24-31  (off_11A2E; slot at 32 = no-op/unreachable)
 	&ASound3::command24, &ASound3::command25, &ASound3::command26, &ASound3::command27,
-	// 28-31 absent
+	&ASound3::command28, &ASound3::command29, &ASound3::command30, &ASound3::command31,
+	// commands 32-33  (funcs_11C61; slot 34 = no-op)
+	&ASound3::command32, &ASound3::command33,
+	// 34-63 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,
@@ -1056,12 +1054,11 @@ const ASound3::CommandPtr ASound3::_commandList[77] = {
 	nullptr,             nullptr,             nullptr,             nullptr,
 	nullptr,             nullptr,             nullptr,             nullptr,
 	nullptr,             nullptr,
-	// commands 64-75  (asound_commands5)
+	// commands 64-73  (off_11A46); slots 74-76 = no-ops
 	&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::command72, &ASound3::command73,
+	nullptr,             nullptr,             nullptr
 };
 
 ASound3::ASound3(Audio::Mixer *mixer, OPL::OPL *opl)
@@ -1075,7 +1072,8 @@ ASound3::ASound3(Audio::Mixer *mixer, OPL::OPL *opl)
 int ASound3::command(int commandId, int param) {
 	if (commandId > 76 || !_commandList[commandId])
 		return 0;
-	
+	if (commandId >= 32 && commandId < 64)
+		setMusicIndex(commandId);
 	return (this->*_commandList[commandId])();
 }
 
@@ -1091,219 +1089,210 @@ 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.)
+// command16 (Pattern B deferred): timer=0xA8, musicIndex=0x10, ch0-6
 // ---------------------------------------------------------------------------
-void ASound3::sub11CC6() {
-	byte *pData = loadData(0x0C36);
+void ASound3::loadCommand16() {
+	resetCallbackTimer(0xA8);
+	setMusicIndex(0x10);
+	ASound::command1();
+	_channels[0]->load(loadData(0x1192));
+	_channels[1]->load(loadData(0x1279));
+	_channels[2]->load(loadData(0x1307));
+	_channels[3]->load(loadData(0x149E));
+	_channels[4]->load(loadData(0x153C));
+	_channels[5]->load(loadData(0x1624));
+	_channels[6]->load(loadData(0x1755));
+}
+
+int ASound3::command16() {
+	byte *pData = loadData(0x1192);
 	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));
+		if (isMusicChannelsActive())
+			scheduleCallback(MAKE_CALLBACK(ASound3, loadCommand16));
+		else
+			loadCommand16();
 	}
+	return 0;
 }
 
-// ---------------------------------------------------------------------------
-// command16 - isSoundActive guard, command1, load ch0-5
-// ---------------------------------------------------------------------------
-int ASound3::command16() {
-	byte *pData = loadData(0x24F2);
+// command17: isSoundActive guard, timer=0x60, command1, ch0-6
+int ASound3::command17() {
+	byte *pData = loadData(0x213A);
 	if (!isSoundActive(pData)) {
+		resetCallbackTimer(0x60);
 		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));
+		_channels[1]->load(loadData(0x216F));
+		_channels[2]->load(loadData(0x21A2));
+		_channels[3]->load(loadData(0x21BB));
+		_channels[4]->load(loadData(0x21EE));
+		_channels[5]->load(loadData(0x21FC));
+		_channels[6]->load(loadData(0x2214));
 	}
 	return 0;
 }
 
+// command18: re-launch last music piece (command1 + re-dispatch via musicIndex)
+int ASound3::command18() {
+	ASound::command1();
+	if (getMusicIndex() <= 0x12)
+		return command16();
+	return (this->*_commandList[getMusicIndex()])();
+}
+
 // ---------------------------------------------------------------------------
-// commands 24-27 (asound_commands3) - upper channel pool
+// commands 24-31 (off_11A2E)
 // ---------------------------------------------------------------------------
 
 int ASound3::command24() {
-	playSound(0x2A7C);
-	playSound(0x2AAF);
+	playSound(0x224D);
+	playSound(0x2282);
 	return 0;
 }
 
 int ASound3::command25() {
-	playSound(0x2ADD);
-	playSound(0x2B09);
+	playSound(0x22B2);
+	playSound(0x22E0);
 	return 0;
 }
 
 int ASound3::command26() {
-	playSound(0x2B37);
+	playSound(0x2310);
 	return 0;
 }
 
 int ASound3::command27() {
-	playSound(0x2B43);
+	playSound(0x231C);
 	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));
-	}
+int ASound3::command28() {
+	playSound(0x243B);
 	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));
-	}
+int ASound3::command29() {
+	playSound(0x2350);
 	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));
+int ASound3::command30() {
+	playSound(0x2388);
 	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));
-	}
+// command31: patch pitch byte then play (0x23EC = 0x23E9+3)
+int ASound3::command31() {
+	*loadData(0x23EC) = 0x67;
+	playSound(0x23E9);
 	return 0;
 }
 
-// command36 - isSoundActive guard, command1, load ch0-5
-int ASound3::command36() {
-	byte *pData = loadData(0x2072);
+// ---------------------------------------------------------------------------
+// commands 32-33 (funcs_11C61, Pattern B deferred)
+// ---------------------------------------------------------------------------
+void ASound3::loadCommand32() {
+	resetCallbackTimer(0xA8);
+	ASound::command1();
+	_channels[0]->load(loadData(0x17BA));
+	_channels[1]->load(loadData(0x1884));
+	_channels[2]->load(loadData(0x1954));
+	_channels[3]->load(loadData(0x1A03));
+	_channels[4]->load(loadData(0x1A40));
+	_channels[5]->load(loadData(0x1B17));
+	_channels[6]->load(loadData(0x1B99));
+}
+
+int ASound3::command32() {
+	byte *pData = loadData(0x17BA);
 	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));
+		if (isMusicChannelsActive())
+			scheduleCallback(MAKE_CALLBACK(ASound3, loadCommand32));
+		else
+			loadCommand32();
 	}
 	return 0;
 }
 
-// command37 - single upper-pool voice
-int ASound3::command37() {
-	playSound(0x298E);
+void ASound3::loadCommand33() {
+	resetCallbackTimer(0xA8);
+	ASound::command1();
+	_channels[0]->load(loadData(0x1D68));
+	_channels[1]->load(loadData(0x1E5D));
+	_channels[2]->load(loadData(0x1ECE));
+	_channels[3]->load(loadData(0x1F05));
+	_channels[4]->load(loadData(0x2006));
+	_channels[5]->load(loadData(0x203C));
+	_channels[6]->load(loadData(0x209B));
+}
+
+int ASound3::command33() {
+	byte *pData = loadData(0x1D68);
+	if (!isSoundActive(pData)) {
+		if (isMusicChannelsActive())
+			scheduleCallback(MAKE_CALLBACK(ASound3, loadCommand33));
+		else
+			loadCommand33();
+	}
 	return 0;
 }
 
 // ---------------------------------------------------------------------------
-// commands 64-75 (asound_commands5)
+// commands 64-73 (off_11A46)
 // ---------------------------------------------------------------------------
 
+// command64: patch pitch byte (0x78) then play — same block as command31 (0x78 vs 0x67)
 int ASound3::command64() {
-	_channels[6]->load(loadData(0x28CA));
-	_channels[8]->load(loadData(0x28FC));
+	*loadData(0x23EC) = 0x78;
+	playSound(0x23E9);
 	return 0;
 }
 
 int ASound3::command65() {
-	_channels[6]->load(loadData(0x2919));
-	_channels[8]->load(loadData(0x292A));
+	playSound(0x1C5E);
 	return 0;
 }
 
 int ASound3::command66() {
-	_channels[6]->load(loadData(0x2937));
-	_channels[7]->load(loadData(0x2956));
-	_channels[8]->load(loadData(0x2965));
+	playSound(0x1C74);
+	playSound(0x1C7C);
 	return 0;
 }
 
 int ASound3::command67() {
-	playSound(0x2984);
+	_channels[8]->load(loadData(0x1C8E));
 	return 0;
 }
 
 int ASound3::command68() {
-	playSound(0x2998);
-	playSound(0x29AE);
-	playSound(0x29C2);
+	_channels[7]->load(loadData(0x1CA2));
+	_channels[8]->load(loadData(0x1CAF));
 	return 0;
 }
 
 int ASound3::command69() {
-	playSound(0x29D8);
+	playSound(0x1CE9);
 	return 0;
 }
 
 int ASound3::command70() {
-	playSound(0x2B4F);
+	playSound(0x1CFB);
 	return 0;
 }
 
 int ASound3::command71() {
-	playSound(0x2B5E);
+	playSound(0x1D13);
 	return 0;
 }
 
 int ASound3::command72() {
-	_channels[7]->load(loadData(0x29EA));
-	_channels[8]->load(loadData(0x2A18));
+	_channels[7]->load(loadData(0x1D20));
+	_channels[8]->load(loadData(0x1D2B));
 	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));
+	_channels[7]->load(loadData(0x1D57));
 	return 0;
 }
 
@@ -1313,204 +1302,415 @@ int ASound3::command75() {
 /* ASound4  (asound.dr4)                                                  *
  *-----------------------------------------------------------------------*/
 
-const ASound4::CommandPtr ASound4::_commandList[71] = {
-	// commands 0-8  (asound_commands1)
+const ASound4::CommandPtr ASound4::_commandList[82] = {
+	// commands 0-8 (off_11A14; slot 5 = no-op)
 	&ASound4::command0,  &ASound4::command1,  &ASound4::command2,  &ASound4::command3,
-	&ASound4::command4,  &ASound4::command5,  &ASound4::command6,  &ASound4::command7,
+	&ASound4::command4,  nullptr,             &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,
+	// commands 16-19 (off_11A26; slot 19 = no-op)
+	&ASound4::command16, &ASound4::command17, &ASound4::command18, nullptr,
+	// 20-23 absent
 	nullptr,             nullptr,             nullptr,             nullptr,
-	// commands 24-27  (asound_commands3)
+	// commands 24-31 (off_11A2E; slot 32 unreachable via off_11A2E)
 	&ASound4::command24, &ASound4::command25, &ASound4::command26, &ASound4::command27,
-	// 28-63 absent (the 0x20-range table has max=0, unreachable)
+	&ASound4::command28, &ASound4::command29, &ASound4::command30, &ASound4::command31,
+	// commands 32-41 (funcs_11E51; slots 34 and 41 = no-ops)
+	&ASound4::command32, &ASound4::command33, nullptr,             &ASound4::command35,
+	&ASound4::command36, &ASound4::command37, &ASound4::command38, &ASound4::command39,
+	&ASound4::command40, nullptr,
+	// 42-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,
-	nullptr,             nullptr,             nullptr,             nullptr,
-	nullptr,             nullptr,             nullptr,             nullptr,
-	// commands 64-70  (asound_commands4)
+	nullptr,             nullptr,
+	// commands 64-81 (off_11A54; slot 79 = no-op; slots 80-81 = stubs)
 	&ASound4::command64, &ASound4::command65, &ASound4::command66, &ASound4::command67,
-	&ASound4::command68, &ASound4::command69, &ASound4::command70
+	&ASound4::command68, &ASound4::command69, &ASound4::command70, &ASound4::command71,
+	&ASound4::command72, &ASound4::command73, &ASound4::command74, &ASound4::command75,
+	&ASound4::command76, &ASound4::command77, &ASound4::command78, nullptr,
+	&ASound4::command80, &ASound4::command81
 };
 
 ASound4::ASound4(Audio::Mixer *mixer, OPL::OPL *opl)
 		: ASound(mixer, opl, "asound.dr4", 0x2120, 0x31d0) {
-	// Load sound samples
 	auto samplesStream = getDataStream(0x1dc);
 	for (int i = 0; i < 182; ++i)
 		_samples.push_back(AdlibSample(samplesStream));
 }
 
 int ASound4::command(int commandId, int param) {
-	if (commandId > 70 || !_commandList[commandId])
+	if (commandId > 81 || !_commandList[commandId])
 		return 0;
-	
+	if (commandId >= 32 && commandId < 64)
+		setMusicIndex(commandId);
 	return (this->*_commandList[commandId])();
 }
 
-// commands 0-8: delegate to base ASound
+// commands 0-8: delegate to base ASound (command5 slot = nullptr, not dispatched)
 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
+// command16 - Pattern B deferred music, timer=0xC0, ASound::command3, ch0-6
 // ---------------------------------------------------------------------------
+void ASound4::loadCommand16() {
+	resetCallbackTimer(0xC0);
+	setMusicIndex(0x10);
+	ASound::command3();
+	_channels[0]->load(loadData(0x1F1A));
+	_channels[1]->load(loadData(0x1F77));
+	_channels[2]->load(loadData(0x1FBA));
+	_channels[3]->load(loadData(0x2010));
+	_channels[4]->load(loadData(0x20F5));
+	_channels[5]->load(loadData(0x2117));
+	_channels[6]->load(loadData(0x213D));
+}
+
 int ASound4::command16() {
-	byte *pData = loadData(0x0C36);
+	byte *pData = loadData(0x1F1A);
+	if (!isSoundActive(pData)) {
+		if (isMusicChannelsActive())
+			scheduleCallback(MAKE_CALLBACK(ASound4, loadCommand16));
+		else
+			loadCommand16();
+	}
+	return 0;
+}
+
+// ---------------------------------------------------------------------------
+// command17 - Pattern A with timer reset, ASound::command1, ch0-6
+// ---------------------------------------------------------------------------
+int ASound4::command17() {
+	byte *pData = loadData(0x2BC0);
 	if (!isSoundActive(pData)) {
+		resetCallbackTimer(0x60);
 		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));
+		_channels[1]->load(loadData(0x2BF5));
+		_channels[2]->load(loadData(0x2C28));
+		_channels[3]->load(loadData(0x2C41));
+		_channels[4]->load(loadData(0x2C74));
+		_channels[5]->load(loadData(0x2C82));
+		_channels[6]->load(loadData(0x2C9A));
 	}
 	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.
+// command18 - re-dispatch to last music command
 // ---------------------------------------------------------------------------
+int ASound4::command18() {
+	ASound::command1();
+	if (getMusicIndex() <= 0x12)
+		return command16();
+	return (this->*_commandList[getMusicIndex()])();
+}
 
-int ASound4::command24() {
-	playSound(0x0FFA);
-	playSound(0x100C);
+// ---------------------------------------------------------------------------
+// commands 24-31 (off_11A2E) - SFX
+// ---------------------------------------------------------------------------
+int ASound4::command24() { playSound(0x2CD3); playSound(0x2D08); return 0; }
+int ASound4::command25() { playSound(0x2D38); playSound(0x2D66); return 0; }
+int ASound4::command26() { playSound(0x2D96); return 0; }
+int ASound4::command27() { playSound(0x2DA2); return 0; }
+int ASound4::command28() { playSound(0x2EC1); return 0; }
+int ASound4::command29() { playSound(0x2DD6); return 0; }
+int ASound4::command30() { playSound(0x2E0E); return 0; }
+int ASound4::command31() {
+	*loadData(0x2E72) = 0x67;
+	playSound(0x2E6F);
 	return 0;
 }
 
-int ASound4::command25() {
-	return command24();
+// ---------------------------------------------------------------------------
+// command32 - Pattern B deferred music, timer=0x60, ASound::command3, ch0-6
+// ---------------------------------------------------------------------------
+void ASound4::loadCommand32() {
+	resetCallbackTimer(0x60);
+	ASound::command3();
+	_channels[0]->load(loadData(0x1192));
+	_channels[1]->load(loadData(0x128E));
+	_channels[2]->load(loadData(0x14A8));
+	_channels[3]->load(loadData(0x1575));
+	_channels[4]->load(loadData(0x15B5));
+	_channels[5]->load(loadData(0x1638));
+	_channels[6]->load(loadData(0x16C8));
 }
 
-int ASound4::command26() {
-	playSound(0x119D);
+int ASound4::command32() {
+	byte *pData = loadData(0x1192);
+	if (!isSoundActive(pData)) {
+		if (isMusicChannelsActive())
+			scheduleCallback(MAKE_CALLBACK(ASound4, loadCommand32));
+		else
+			loadCommand32();
+	}
 	return 0;
 }
 
-int ASound4::command27() {
-	playSound(0x11A9);
+// ---------------------------------------------------------------------------
+// command33 - Pattern B deferred music, timer=0xC0, ASound::command3, ch0-6
+// ---------------------------------------------------------------------------
+void ASound4::loadCommand33() {
+	resetCallbackTimer(0xC0);
+	ASound::command3();
+	_channels[0]->load(loadData(0x16DE));
+	_channels[1]->load(loadData(0x1701));
+	_channels[2]->load(loadData(0x172B));
+	_channels[3]->load(loadData(0x176F));
+	_channels[4]->load(loadData(0x18E8));
+	_channels[5]->load(loadData(0x18F8));
+	_channels[6]->load(loadData(0x183F));
+}
+
+int ASound4::command33() {
+	byte *pData = loadData(0x16DE);
+	if (!isSoundActive(pData)) {
+		if (isMusicChannelsActive())
+			scheduleCallback(MAKE_CALLBACK(ASound4, loadCommand33));
+		else
+			loadCommand33();
+	}
 	return 0;
 }
 
 // ---------------------------------------------------------------------------
-// commands 64-70 (asound_commands4, base 0x40)
-// All entries use the upper pool
+// command35 - Pattern B deferred music, timer=0x54, ASound::command1, ch0-2
 // ---------------------------------------------------------------------------
+void ASound4::loadCommand35() {
+	resetCallbackTimer(0x54);
+	ASound::command1();
+	_channels[0]->load(loadData(0x1912));
+	_channels[1]->load(loadData(0x1965));
+	_channels[2]->load(loadData(0x1975));
+}
 
-int ASound4::command64() {
-	playSound(0x1017);
-	playSound(0x1031);
+int ASound4::command35() {
+	byte *pData = loadData(0x1912);
+	if (!isSoundActive(pData)) {
+		if (isMusicChannelsActive())
+			scheduleCallback(MAKE_CALLBACK(ASound4, loadCommand35));
+		else
+			loadCommand35();
+	}
 	return 0;
 }
 
-int ASound4::command65() {
-	playSound(0x1042);
-	playSound(0x104B);
-	return 0;
+// ---------------------------------------------------------------------------
+// command36 - Pattern B deferred music, timer=84, ASound::command1, ch0-6
+// ---------------------------------------------------------------------------
+void ASound4::loadCommand36() {
+	resetCallbackTimer(84);
+	ASound::command1();
+	_channels[0]->load(loadData(0x26CE));
+	_channels[1]->load(loadData(0x2935));
+	_channels[2]->load(loadData(0x296E));
+	_channels[3]->load(loadData(0x2992));
+	_channels[4]->load(loadData(0x2B8D));
+	_channels[5]->load(loadData(0x2B99));
+	_channels[6]->load(loadData(0x2BB2));
 }
 
-int ASound4::command66() {
-	playSound(0x105F);
-	playSound(0x1068);
+int ASound4::command36() {
+	byte *pData = loadData(0x26CE);
+	if (!isSoundActive(pData)) {
+		if (isMusicChannelsActive())
+			scheduleCallback(MAKE_CALLBACK(ASound4, loadCommand36));
+		else
+			loadCommand36();
+	}
 	return 0;
 }
 
-int ASound4::command67() {
-	playSound(0x1078);
-	playSound(0x1081);
+// ---------------------------------------------------------------------------
+// command37 - Pattern B deferred music, timer=0x40, ASound::command1, ch0-6
+// ---------------------------------------------------------------------------
+void ASound4::loadCommand37() {
+	resetCallbackTimer(0x40);
+	ASound::command1();
+	_channels[0]->load(loadData(0x1986));
+	_channels[1]->load(loadData(0x19CB));
+	_channels[2]->load(loadData(0x19FA));
+	_channels[3]->load(loadData(0x1A33));
+	_channels[4]->load(loadData(0x1A77));
+	_channels[5]->load(loadData(0x1AAA));
+	_channels[6]->load(loadData(0x1ABA));
+}
+
+int ASound4::command37() {
+	byte *pData = loadData(0x1986);
+	if (!isSoundActive(pData)) {
+		if (isMusicChannelsActive())
+			scheduleCallback(MAKE_CALLBACK(ASound4, loadCommand37));
+		else
+			loadCommand37();
+	}
 	return 0;
 }
 
-int ASound4::command68() {
-	playSound(0x108F);
+// ---------------------------------------------------------------------------
+// command38 - Pattern B deferred music, timer=0x40, ASound::command1, ch0-6
+// ---------------------------------------------------------------------------
+void ASound4::loadCommand38() {
+	resetCallbackTimer(0x40);
+	ASound::command1();
+	_channels[0]->load(loadData(0x1AC8));
+	_channels[1]->load(loadData(0x1B28));
+	_channels[2]->load(loadData(0x1B76));
+	_channels[3]->load(loadData(0x1BBC));
+	_channels[4]->load(loadData(0x1EC3));
+	_channels[5]->load(loadData(0x1ED8));
+	_channels[6]->load(loadData(0x1C16));
+}
+
+int ASound4::command38() {
+	byte *pData = loadData(0x1AC8);
+	if (!isSoundActive(pData)) {
+		if (isMusicChannelsActive())
+			scheduleCallback(MAKE_CALLBACK(ASound4, loadCommand38));
+		else
+			loadCommand38();
+	}
 	return 0;
 }
 
-int ASound4::command69() {
-	playSound(0x109B);
+// ---------------------------------------------------------------------------
+// command39 - Pattern B deferred music, timer=0x48, ASound::command1, ch0-5
+// (isSoundActive check uses offset 0x1D29; channels loaded from 0x2176+)
+// ---------------------------------------------------------------------------
+void ASound4::loadCommand39() {
+	resetCallbackTimer(0x48);
+	ASound::command1();
+	_channels[0]->load(loadData(0x2176));
+	_channels[1]->load(loadData(0x21F3));
+	_channels[2]->load(loadData(0x2269));
+	_channels[3]->load(loadData(0x232B));
+	_channels[4]->load(loadData(0x23CF));
+	_channels[5]->load(loadData(0x24A1));
+}
+
+int ASound4::command39() {
+	byte *pData = loadData(0x1D29);
+	if (!isSoundActive(pData)) {
+		if (isMusicChannelsActive())
+			scheduleCallback(MAKE_CALLBACK(ASound4, loadCommand39));
+		else
+			loadCommand39();
+	}
 	return 0;
 }
 
-int ASound4::command70() {
-	playSound(0x10A5);
-	playSound(0x10A8);
+// ---------------------------------------------------------------------------
+// command40 - Pattern B deferred music, timer=0xC0, ASound::command1, ch0-6
+// ---------------------------------------------------------------------------
+void ASound4::loadCommand40() {
+	resetCallbackTimer(0xC0);
+	ASound::command1();
+	_channels[0]->load(loadData(0x1F06));
+	_channels[1]->load(loadData(0x1F68));
+	_channels[2]->load(loadData(0x1FAB));
+	_channels[3]->load(loadData(0x2010));
+	_channels[4]->load(loadData(0x2106));
+	_channels[5]->load(loadData(0x212A));
+	_channels[6]->load(loadData(0x2159));
+}
+
+int ASound4::command40() {
+	byte *pData = loadData(0x1F06);
+	if (!isSoundActive(pData)) {
+		if (isMusicChannelsActive())
+			scheduleCallback(MAKE_CALLBACK(ASound4, loadCommand40));
+		else
+			loadCommand40();
+	}
 	return 0;
 }
 
+// ---------------------------------------------------------------------------
+// commands 64-81 (off_11A54) - SFX (command73 = empty, 80-81 = stubs)
+// ---------------------------------------------------------------------------
+int ASound4::command64() { playSound(0x25B4); return 0; }
+int ASound4::command65() { playSound(0x25F7); return 0; }
+int ASound4::command66() { playSound(0x2601); return 0; }
+int ASound4::command67() { playSound(0x260B); return 0; }
+int ASound4::command68() { playSound(0x2629); return 0; }
+int ASound4::command69() { playSound(0x25C0); return 0; }
+int ASound4::command70() { playSound(0x2643); playSound(0x264F); return 0; }
+int ASound4::command71() { playSound(0x265D); return 0; }
+int ASound4::command72() { playSound(0x2667); return 0; }
+int ASound4::command73() { return 0; }
+int ASound4::command74() { playSound(0x2643); playSound(0x2643); return 0; }
+int ASound4::command75() { ASound::command5(); playSound(0x2676); playSound(0x2683); return 0; }
+int ASound4::command76() { playSound(0x2E47); playSound(0x2E5B); return 0; }
+int ASound4::command77() { playSound(0x26AD); return 0; }
+int ASound4::command78() { playSound(0x26BC); return 0; }
+int ASound4::command80() { return 0; }
+int ASound4::command81() { return 0; }
+
 /*-----------------------------------------------------------------------*/
 
 /*-----------------------------------------------------------------------*/
 /* ASound5  (asound.dr5)                                                  *
  *-----------------------------------------------------------------------*/
 
-const ASound5::CommandPtr ASound5::_commandList[79] = {
-	// commands 0-8  (asound_commands1)
+const ASound5::CommandPtr ASound5::_commandList[82] = {
+	// commands 0-8 (off_11A14)
 	&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,
+	// commands 16-19 (off_11A26; slot 19 = no-op)
+	&ASound5::command16, &ASound5::command17, &ASound5::command18, nullptr,
+	// 20-23 absent
 	nullptr,             nullptr,             nullptr,             nullptr,
-	// commands 24-27  (asound_commands3)
+	// commands 24-31 (off_11A2E; slot 32 handled by funcs_11E05)
 	&ASound5::command24, &ASound5::command25, &ASound5::command26, &ASound5::command27,
-	// 28-31 absent
-	nullptr,             nullptr,             nullptr,             nullptr,
-	// commands 32-39  (asound_commands4)
+	&ASound5::command28, &ASound5::command29, &ASound5::command30, &ASound5::command31,
+	// commands 32-39 (funcs_11E05; slot 39 = no-op)
 	&ASound5::command32, &ASound5::command33, &ASound5::command34, &ASound5::command35,
-	&ASound5::command36, &ASound5::command37, &ASound5::command38, &ASound5::command39,
+	&ASound5::command36, &ASound5::command37, &ASound5::command38, nullptr,
 	// 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)
+	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-81 (off_11A50; slot 79 = no-op; 80-81 = stubs)
 	&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::command76, &ASound5::command77, &ASound5::command78, nullptr,
+	&ASound5::command80, &ASound5::command81
 };
 
 ASound5::ASound5(Audio::Mixer *mixer, OPL::OPL *opl)
 		: ASound(mixer, opl, "asound.dr5", 0x20d0, 0x2ee0) {
-	// Load sound samples
 	auto samplesStream = getDataStream(0x1dc);
 	for (int i = 0; i < 182; ++i)
 		_samples.push_back(AdlibSample(samplesStream));
+	_lastParam = 0;
 }
 
 int ASound5::command(int commandId, int param) {
-	if (commandId > 78 || !_commandList[commandId])
+	_lastParam = param;
+	if (commandId > 81 || !_commandList[commandId])
 		return 0;
-	
+	if (commandId >= 32 && commandId < 64)
+		setMusicIndex(commandId);
 	return (this->*_commandList[commandId])();
 }
 
@@ -1526,267 +1726,274 @@ int ASound5::command7() { return ASound::command7(); }
 int ASound5::command8() { return ASound::command8(); }
 
 // ---------------------------------------------------------------------------
-// command16 - isSoundActive guard, command1, load ch0-5
+// command16 - Pattern B deferred music, timer=0xC0, ch0-6
+// isSoundActive check uses 0x168A (not ch0's load offset 0x167C)
 // ---------------------------------------------------------------------------
+void ASound5::loadCommand16() {
+	resetCallbackTimer(0xC0);
+	setMusicIndex(0x10);
+	ASound::command1();
+	_channels[0]->load(loadData(0x167C));
+	_channels[1]->load(loadData(0x17ED));
+	_channels[2]->load(loadData(0x18A8));
+	_channels[3]->load(loadData(0x1995));
+	_channels[4]->load(loadData(0x1A4B));
+	_channels[5]->load(loadData(0x1C77));
+	_channels[6]->load(loadData(0x1CA0));
+}
+
 int ASound5::command16() {
-	byte *pData = loadData(0x4142);
+	byte *pData = loadData(0x168A);
 	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));
+		if (isMusicChannelsActive())
+			scheduleCallback(MAKE_CALLBACK(ASound5, loadCommand16));
+		else
+			loadCommand16();
 	}
 	return 0;
 }
 
 // ---------------------------------------------------------------------------
-// commands 24-27 (asound_commands3) - upper pool
+// command17 - isSoundActive guard, inline resetCallbackTimer(0x60), ch0-6
+// (no deferred path; timer is reset and channels loaded directly)
 // ---------------------------------------------------------------------------
-
-int ASound5::command24() {
-	playSound(0x51FA);
-	playSound(0x522D);
-	return 0;
-}
-
-int ASound5::command25() {
-	playSound(0x525B);
-	playSound(0x5287);
-	return 0;
-}
-
-int ASound5::command26() {
-	playSound(0x52B5);
+int ASound5::command17() {
+	byte *pData = loadData(0x28CC);
+	if (!isSoundActive(pData)) {
+		resetCallbackTimer(0x60);
+		ASound::command1();
+		_channels[0]->load(pData);
+		_channels[1]->load(loadData(0x2901));
+		_channels[2]->load(loadData(0x2934));
+		_channels[3]->load(loadData(0x294D));
+		_channels[4]->load(loadData(0x2980));
+		_channels[5]->load(loadData(0x298E));
+		_channels[6]->load(loadData(0x29A6));
+	}
 	return 0;
 }
 
-// three upper-pool voices
-int ASound5::command27() {
-	playSound(0x4040);
-	playSound(0x404A);
-	playSound(0x4061);
+// ---------------------------------------------------------------------------
+// command18 - re-entry dispatcher: fade + re-launch last music piece
+// ---------------------------------------------------------------------------
+int ASound5::command18() {
+	ASound::command1();
+	int musicIndex = getMusicIndex();
+	if (musicIndex <= 0x12)
+		return command16();
+	if (_commandList[musicIndex])
+		return (this->*_commandList[musicIndex])();
 	return 0;
 }
 
 // ---------------------------------------------------------------------------
-// commands 32-39 (asound_commands4)
+// commands 24-31 (off_11A2E) - SFX
 // ---------------------------------------------------------------------------
+int ASound5::command24() { playSound(0x29DF); playSound(0x2A14); return 0; }
+int ASound5::command25() { playSound(0x2A44); playSound(0x2A72); return 0; }
+int ASound5::command26() { playSound(0x2AA2); return 0; }
+int ASound5::command27() { playSound(0x2AAE); return 0; }
+int ASound5::command28() { playSound(0x2BCD); return 0; }
+int ASound5::command29() { playSound(0x2AE2); return 0; }
+int ASound5::command30() { playSound(0x2B1A); return 0; }
+int ASound5::command31() { *loadData(0x2B7E) = 0x67; playSound(0x2B7B); return 0; }
 
-// command1, eight loadAny (lower pool, AdlibChannel_loadAny)
-int ASound5::command32() {
+// ---------------------------------------------------------------------------
+// command32 - Pattern B deferred music, timer=0x48, ch0-5
+// ---------------------------------------------------------------------------
+void ASound5::loadCommand32() {
+	resetCallbackTimer(0x48);
+	setMusicIndex(0x10);
 	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;
+	_channels[0]->load(loadData(0x26C0));
+	_channels[1]->load(loadData(0x2705));
+	_channels[2]->load(loadData(0x2735));
+	_channels[3]->load(loadData(0x276D));
+	_channels[4]->load(loadData(0x27A1));
+	_channels[5]->load(loadData(0x282E));
 }
 
-// isSoundActive guard, command1, load ch0-6
-int ASound5::command33() {
-	byte *pData = loadData(0x21C6);
+int ASound5::command32() {
+	byte *pData = loadData(0x26C0);
 	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));
+		if (isMusicChannelsActive())
+			scheduleCallback(MAKE_CALLBACK(ASound5, loadCommand32));
+		else
+			loadCommand32();
 	}
 	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;
+// ---------------------------------------------------------------------------
+// command33 - Pattern B deferred music, timer=0x60, ch0-5
+// ---------------------------------------------------------------------------
+void ASound5::loadCommand33() {
+	resetCallbackTimer(0x60);
+	setMusicIndex(0x10);
+	ASound::command1();
+	_channels[0]->load(loadData(0x1192));
+	_channels[1]->load(loadData(0x1258));
+	_channels[2]->load(loadData(0x1309));
+	_channels[3]->load(loadData(0x1602));
+	_channels[4]->load(loadData(0x1518));
+	_channels[5]->load(loadData(0x161B));
 }
 
-// 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);
+int ASound5::command33() {
+	byte *pData = loadData(0x1192);
 	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));
+		if (isMusicChannelsActive())
+			scheduleCallback(MAKE_CALLBACK(ASound5, loadCommand33));
+		else
+			loadCommand33();
 	}
 	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;
+// ---------------------------------------------------------------------------
+// command34 - Pattern B deferred music, timer=0xC0, ch0-5
+// ---------------------------------------------------------------------------
+void ASound5::loadCommand34() {
+	resetCallbackTimer(0xC0);
+	ASound::command1();
+	_channels[0]->load(loadData(0x1E44));
+	_channels[1]->load(loadData(0x1EFA));
+	_channels[2]->load(loadData(0x1FEE));
+	_channels[3]->load(loadData(0x210E));
+	_channels[4]->load(loadData(0x21CF));
+	_channels[5]->load(loadData(0x2378));
 }
 
-// isSoundActive guard, command1, load ch0-8
-int ASound5::command37() {
-	byte *pData = loadData(0x1190);
+int ASound5::command34() {
+	byte *pData = loadData(0x1E44);
 	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));
+		if (isMusicChannelsActive())
+			scheduleCallback(MAKE_CALLBACK(ASound5, loadCommand34));
+		else
+			loadCommand34();
 	}
 	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;
+// ---------------------------------------------------------------------------
+// command35 - Pattern B deferred music, timer=0xC0, ch0-5
+// ---------------------------------------------------------------------------
+void ASound5::loadCommand35() {
+	resetCallbackTimer(0xC0);
+	ASound::command1();
+	_channels[0]->load(loadData(0x2402));
+	_channels[1]->load(loadData(0x2414));
+	_channels[2]->load(loadData(0x2446));
+	_channels[3]->load(loadData(0x2494));
+	_channels[4]->load(loadData(0x24B6));
+	_channels[5]->load(loadData(0x24CE));
 }
 
-// isSoundActive guard, command3 (lower-bank fade only), load ch0-5
-int ASound5::command39() {
-	byte *pData = loadData(0x5312);
+int ASound5::command35() {
+	byte *pData = loadData(0x2402);
 	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));
+		if (isMusicChannelsActive())
+			scheduleCallback(MAKE_CALLBACK(ASound5, loadCommand35));
+		else
+			loadCommand35();
 	}
 	return 0;
 }
 
 // ---------------------------------------------------------------------------
-// commands 64-78 (asound_commands5) - upper pool unless noted
+// command36 - direct: setMusicIndex(0x29), playSound (no channel loads)
 // ---------------------------------------------------------------------------
-
-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);
+int ASound5::command36() {
+	setMusicIndex(0x29);
+	playSound(0x24F9);
 	return 0;
 }
 
-int ASound5::command73() {
-	playSound(0x40DC);
-	playSound(0x40E7);
+// ---------------------------------------------------------------------------
+// command37 - direct: command1 + findFreeChannel (lower pool) ×6
+// ---------------------------------------------------------------------------
+int ASound5::command37() {
+	ASound::command1();
+	findFreeChannel(loadData(0x1D68));
+	findFreeChannel(loadData(0x1DA5));
+	findFreeChannel(loadData(0x1DDD));
+	findFreeChannel(loadData(0x1E16));
+	findFreeChannel(loadData(0x1E2D));
+	findFreeChannel(loadData(0x1E38));
 	return 0;
 }
 
-int ASound5::command74() {
-	playSound(0x410B);
-	return 0;
+// ---------------------------------------------------------------------------
+// command38 - Pattern B deferred music, timer=0xC0, ch0-6
+// ---------------------------------------------------------------------------
+void ASound5::loadCommand38() {
+	resetCallbackTimer(0xC0);
+	setMusicIndex(0x26);
+	ASound::command1();
+	_channels[0]->load(loadData(0x1EA9));
+	_channels[1]->load(loadData(0x1FB0));
+	_channels[2]->load(loadData(0x204C));
+	_channels[3]->load(loadData(0x21B7));
+	_channels[4]->load(loadData(0x2262));
+	_channels[5]->load(loadData(0x23CD));
+	_channels[6]->load(loadData(0x23F6));
 }
 
-int ASound5::command75() {
-	playSound(0x4129);
-	playSound(0x4134);
+int ASound5::command38() {
+	byte *pData = loadData(0x1EA9);
+	if (!isSoundActive(pData)) {
+		if (isMusicChannelsActive())
+			scheduleCallback(MAKE_CALLBACK(ASound5, loadCommand38));
+		else
+			loadCommand38();
+	}
 	return 0;
 }
 
-// same block as command70
-int ASound5::command76() {
-	return command70();
-}
+// ---------------------------------------------------------------------------
+// commands 64-78 (off_11A50) - SFX
+// ---------------------------------------------------------------------------
+int ASound5::command64() { playSound(0x252C); return 0; }
+int ASound5::command65() { playSound(0x253B); playSound(0x254C); return 0; }
+int ASound5::command66() { playSound(0x255E); return 0; }
+int ASound5::command67() { playSound(0x2585); playSound(0x2572); return 0; }
+int ASound5::command68() { playSound(0x25AD); playSound(0x25AB); return 0; }
+int ASound5::command69() { playSound(0x25D4); return 0; }
+int ASound5::command70() { playSound(0x25FF); playSound(0x25FF); return 0; }
+int ASound5::command71() { playSound(0x260F); playSound(0x262A); return 0; }
+int ASound5::command72() { playSound(0x2645); return 0; }
+int ASound5::command73() { playSound(0x2656); return 0; }
+int ASound5::command74() { playSound(0x266A); playSound(0x267E); return 0; }
+int ASound5::command75() { playSound(0x2692); return 0; }
+int ASound5::command76() { playSound(0x26A3); playSound(0x26AF); return 0; }
 
-// same block as command70
+// ---------------------------------------------------------------------------
+// command77 - param-based: param=0 writes loop counters at DS:0x20/0x22;
+// param≠0 sets velocity byte and conditionally plays sound 0x2B40.
+// _lastParam is stored by command() dispatcher before the near call.
+// ---------------------------------------------------------------------------
 int ASound5::command77() {
-	return command70();
-}
-
-int ASound5::command78() {
-	playSound(0x411F);
+	if (_lastParam == 0) {
+		if (!isSoundActive(loadData(0x2B40))) {
+			*(uint16 *)loadData(0x22) = 1;
+			*(uint16 *)loadData(0x20) = 1;
+		}
+	} else {
+		*loadData(0x2B4B) = _lastParam & 0x7F;
+		if (!isSoundActive(loadData(0x2B40)))
+			playSound(0x2B40);
+	}
 	return 0;
 }
 
+int ASound5::command78() { *loadData(0x2B7E) = 0x7F; playSound(0x2B7B); return 0; }
+int ASound5::command80() { return 0; }
+int ASound5::command81() { return 0; }
+
 /*-----------------------------------------------------------------------*/
 
 /*-----------------------------------------------------------------------*/
-/* ASound5  (asound.dr6)                                                  *
+/* ASound6  (asound.dr6)                                                  *
  *-----------------------------------------------------------------------*/
 
 const ASound6::CommandPtr ASound6::_commandList[98] = {
diff --git a/engines/mads/madsv2/dragonsphere/sound_dragonsphere.h b/engines/mads/madsv2/dragonsphere/sound_dragonsphere.h
index 57fba442974..d016394d0ef 100644
--- a/engines/mads/madsv2/dragonsphere/sound_dragonsphere.h
+++ b/engines/mads/madsv2/dragonsphere/sound_dragonsphere.h
@@ -221,24 +221,30 @@ public:
 };
 
 /**
- * ASound3  (asound.ph3, _dataOffset = 0x20c0)
+ * ASound3  (asound.dr3, _dataOffset = 0x1F30, _dataSize = 0x2750)
  *
- * 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)
+ * Dispatch table layout (five tables collapsed to flat [77]):
+ *   off_11A14:   commands  0–8   (base=0,    max=8)
+ *   off_11A26:   commands 16–19  (base=0x10, max=0x13; slot 19 = no-op)
+ *   off_11A2E:   commands 24–32  (base=0x18, max=0x20; slot 32 = no-op/unreachable)
+ *   funcs_11C61: commands 32–34  (base=0x20, max=0x22; slot 34 = no-op)
+ *   off_11A46:   commands 64–76  (base=0x40, max=0x4C; slots 74–76 = no-ops)
+ *
+ * command16 sets _musicIndex = 0x10 for command18 re-entry.
+ * commands 32–33: _musicIndex saved by dispatcher for command18 re-entry.
+ *
+ * command31 and command64 both target the same sound block (0x23E9) but
+ * patch byte 0x23EC to 0x67 vs 0x78 for different pitch variants.
  */
 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();
+	// Deferred loader callbacks (void, Pattern B)
+	void loadCommand16();
+	void loadCommand32();
+	void loadCommand33();
 
 	int command0();
 	int command1();
@@ -251,18 +257,20 @@ private:
 	int command8();
 
 	int command16();
+	int command17();
+	int command18();
 
 	int command24();
 	int command25();
 	int command26();
 	int command27();
+	int command28();
+	int command29();
+	int command30();
+	int command31();
 
 	int command32();
 	int command33();
-	int command34();
-	int command35();
-	int command36();
-	int command37();
 
 	int command64();
 	int command65();
@@ -274,8 +282,6 @@ private:
 	int command71();
 	int command72();
 	int command73();
-	int command74();
-	int command75();
 
 public:
 	ASound3(Audio::Mixer *mixer, OPL::OPL *opl);
@@ -284,46 +290,54 @@ public:
 };
 
 /**
- * ASound4  (asound.ph4, _dataOffset = 0x1f90)
+ * ASound4  (asound.dr4, _dataOffset = 0x2120, _dataSize = 0x31D0)
+ *
+ * Dispatch table layout (five tables collapsed to flat [82]):
+ *   off_11A14:   commands  0–8   (base=0,    max=8;    slot 5 = no-op)
+ *   off_11A26:   commands 16–19  (base=0x10, max=0x13; slot 19 = no-op)
+ *   off_11A2E:   commands 24–32  (base=0x18, max=0x20; slot 32 = no-op/unreachable)
+ *   funcs_11E51: commands 32–41  (base=0x20, max=0x29; slots 34,41 = no-ops)
+ *   off_11A54:   commands 64–81  (base=0x40, max=0x51; slot 79 = no-op; slots 80,81 = stubs)
  *
- * 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)
+ * command16 sets _musicIndex = 0x10 for command18 re-entry.
+ * commands 32–33 and 35–40: _musicIndex saved by dispatcher for command18 re-entry.
  *
- * commands 24 and 25 share the same handler (sub_11D0A).
+ * command31 patches _soundData[0x2E72] to 0x67 before playSound.
+ * commands 32–33 use ASound::command3() (partial fade) rather than command1().
+ * command39 loads only channels 0–5 (no channel 6).
  */
 class ASound4 : public ASound {
 private:
 	typedef int (ASound4::*CommandPtr)();
-	static const CommandPtr _commandList[71];
+	static const CommandPtr _commandList[82];
 
-	int command0();
-	int command1();
-	int command2();
-	int command3();
-	int command4();
-	int command5();
-	int command6();
-	int command7();
-	int command8();
+	// Deferred loader callbacks (void, Pattern B)
+	void loadCommand16();
+	void loadCommand32();
+	void loadCommand33();
+	void loadCommand35();
+	void loadCommand36();
+	void loadCommand37();
+	void loadCommand38();
+	void loadCommand39();
+	void loadCommand40();
 
-	int command16();
+	int command0(); int command1(); int command2(); int command3();
+	int command4(); int command6(); int command7(); int command8();
 
-	int command24();
-	int command25();
-	int command26();
-	int command27();
+	int command16(); int command17(); int command18();
 
-	int command64();
-	int command65();
-	int command66();
-	int command67();
-	int command68();
-	int command69();
-	int command70();
+	int command24(); int command25(); int command26(); int command27();
+	int command28(); int command29(); int command30(); int command31();
+
+	int command32(); int command33(); int command35(); int command36();
+	int command37(); int command38(); int command39(); int command40();
+
+	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();
+	int command80(); int command81();
 
 public:
 	ASound4(Audio::Mixer *mixer, OPL::OPL *opl);
@@ -332,65 +346,57 @@ public:
 };
 
 /**
- * ASound5  (asound.ph5, _dataOffset = 0x2140)
+ * ASound5  (asound.dr5, _dataOffset = 0x20D0, _dataSize = 0x2EE0)
+ *
+ * Dispatch table layout (five tables collapsed to flat [82]):
+ *   off_11A14:   commands  0–8   (base=0,    max=8)
+ *   off_11A26:   commands 16–19  (base=0x10, max=0x13; slot 19 = no-op)
+ *   off_11A2E:   commands 24–32  (base=0x18, max=0x20; slot 32 = no-op/unreachable)
+ *   funcs_11E05: commands 32–39  (base=0x20, max=0x27; slot 39 = no-op)
+ *   off_11A50:   commands 64–81  (base=0x40, max=0x51; slot 79 = no-op; slots 80–81 = stubs)
  *
- * 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)
+ * command16 and command32/33 set _musicIndex = 0x10 for command18 re-entry.
+ * command38 sets _musicIndex = 0x26; command36 sets it to 0x29 (beyond table).
+ * command17 uses a direct (non-deferred) load with inline resetCallbackTimer(0x60).
+ * command36 calls setMusicIndex(0x29) then playSound (no channel loads).
+ * command37 calls ASound::command1() then findFreeChannel (lower pool) ×6.
+ * command77 accesses _lastParam (stored by dispatcher) to branch on param value.
  *
- * commands 36/35/34 load channels in non-sequential data order.
- * commands 70, 77, and 78 all play the same 0x40BA sound block.
+ * _soundData[0x2B7E] — pitch-bend byte (command31 = 0x67, command78 = 0x7F)
+ * _soundData[0x2B4B] — velocity byte set by command77 (param≠0 path)
  */
 class ASound5 : public ASound {
 private:
 	typedef int (ASound5::*CommandPtr)();
-	static const CommandPtr _commandList[79];
+	static const CommandPtr _commandList[82];
 
-	int command0();
-	int command1();
-	int command2();
-	int command3();
-	int command4();
-	int command5();
-	int command6();
-	int command7();
+	// Deferred loader callbacks (void, Pattern B)
+	void loadCommand16();
+	void loadCommand32();
+	void loadCommand33();
+	void loadCommand34();
+	void loadCommand35();
+	void loadCommand38();
+
+	int _lastParam;    // param from command() stored for use by command77
+
+	int command0(); int command1(); int command2(); int command3();
+	int command4(); int command5(); int command6(); int command7();
 	int command8();
 
-	int command16();
+	int command16(); int command17(); int command18();
 
-	int command24();
-	int command25();
-	int command26();
-	int command27();
+	int command24(); int command25(); int command26(); int command27();
+	int command28(); int command29(); int command30(); int command31();
 
-	int command32();
-	int command33();
-	int command34();
-	int command35();
-	int command36();
-	int command37();
-	int command38();
-	int command39();
+	int command32(); int command33(); int command34(); int command35();
+	int command36(); int command37(); int command38();
 
-	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();
+	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();
+	int command80(); int command81();
 
 public:
 	ASound5(Audio::Mixer *mixer, OPL::OPL *opl);


Commit: 26ae7b4418f9a94f40e7c754d9612b08c3a9cc35
    https://github.com/scummvm/scummvm/commit/26ae7b4418f9a94f40e7c754d9612b08c3a9cc35
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-05-25T21:03:26+10:00

Commit Message:
MADS: DRAGONSPHERE: Room 107 cleanup

Changed paths:
    engines/mads/madsv2/dragonsphere/rooms/room106.cpp
    engines/mads/madsv2/dragonsphere/rooms/room107.cpp


diff --git a/engines/mads/madsv2/dragonsphere/rooms/room106.cpp b/engines/mads/madsv2/dragonsphere/rooms/room106.cpp
index ce9123da3ec..aad02665cb0 100644
--- a/engines/mads/madsv2/dragonsphere/rooms/room106.cpp
+++ b/engines/mads/madsv2/dragonsphere/rooms/room106.cpp
@@ -40,11 +40,6 @@ namespace MADSV2 {
 namespace Dragonsphere {
 namespace Rooms {
 
-#define local (&scratch)
-#define ss    local->sprite
-#define seq   local->sequence
-#define aa    local->animation
-
 /**
  * Room local variables
  */
@@ -86,6 +81,11 @@ struct Scratch {
 
 static Scratch scratch;
 
+#define local (&scratch)
+#define ss    local->sprite
+#define seq   local->sequence
+#define aa    local->animation
+
 /* ========================= Sprites ========================= */
 
 #define fx_fire_sconce       1   /* rm106y */
diff --git a/engines/mads/madsv2/dragonsphere/rooms/room107.cpp b/engines/mads/madsv2/dragonsphere/rooms/room107.cpp
index 1a217f09fe2..024df3eba86 100644
--- a/engines/mads/madsv2/dragonsphere/rooms/room107.cpp
+++ b/engines/mads/madsv2/dragonsphere/rooms/room107.cpp
@@ -44,7 +44,6 @@ struct Scratch {
 	int16 sequence[15];     /* Sequence handles      */
 	int16 animation[4];     /* Animation handles     */
 
-
 	int16 temp;             /* for synching sprites */
 
 	int16 qm_frame;         /* animation frame being held for Queen mom stuff */
@@ -59,13 +58,13 @@ struct Scratch {
 	int16 prevent;
 };
 
+static Scratch scratch;
+
 #define local (&scratch)
 #define ss    local->sprite
 #define seq   local->sequence
 #define aa    local->animation
 
-static Scratch scratch;
-
 /* ========================= Sprites ========================= */
 
 #define fx_shieldstone        1  /* rm107p0 */
@@ -124,7 +123,6 @@ static void room_107_init() {
 
 	conv_get(CONV_4_QUEENS);
 
-
 	/* Load sprite series */
 
 	ss[fx_fire] = kernel_load_series(kernel_name('y', 0), false);
@@ -198,9 +196,7 @@ static void room_107_init() {
 
 			player.commands_allowed = false;
 		}
-
 	} else {
-
 		seq[fx_door] = kernel_seq_stamp(ss[fx_door], false, KERNEL_FIRST);
 		kernel_seq_depth(seq[fx_door], 15);
 	}
@@ -246,7 +242,6 @@ static void handle_animation_qm() {
 		case 68:
 			if (local->anim_1_running) {
 				qm_reset_frame = 67;
-
 			} else {
 				kernel_abort_animation(aa[0]);
 				local->anim_0_running = false;
@@ -269,7 +264,6 @@ static void handle_animation_q() {
 		q_reset_frame = -1;
 
 		switch (local->q_frame) {
-
 		case 1:   /* end of freeze                       */
 		case 10:  /* end of talk                         */
 		case 27:  /* end of talk to QM (from other node) */
@@ -328,7 +322,7 @@ static void handle_animation_q() {
 	}
 }
 
-void room_107_daemon() {
+static void room_107_daemon() {
 	if (local->anim_0_running) {
 		handle_animation_qm();
 	}


Commit: dd7f87c3bd872fa7c12610b48fb09be09c87c786
    https://github.com/scummvm/scummvm/commit/dd7f87c3bd872fa7c12610b48fb09be09c87c786
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-05-25T21:03:26+10:00

Commit Message:
MADS: DRAGONSPHERE: Implemented remaining sound drivers

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


diff --git a/engines/mads/madsv2/dragonsphere/sound_dragonsphere.cpp b/engines/mads/madsv2/dragonsphere/sound_dragonsphere.cpp
index 674f228a044..1b8c68e42b5 100644
--- a/engines/mads/madsv2/dragonsphere/sound_dragonsphere.cpp
+++ b/engines/mads/madsv2/dragonsphere/sound_dragonsphere.cpp
@@ -75,7 +75,8 @@ void DragonSoundManager::loadDriver(int sectionNumber) {
 		_driver = new ASound5(_mixer, _opl);
 		break;
 	case 6:
-		// TODO
+		_driver = new ASound6(_mixer, _opl);
+		break;
 	case 9:
 		_driver = new ASound9(_mixer, _opl);
 		break;
@@ -1996,57 +1997,472 @@ int ASound5::command81() { return 0; }
 /* ASound6  (asound.dr6)                                                  *
  *-----------------------------------------------------------------------*/
 
-const ASound6::CommandPtr ASound6::_commandList[98] = {
-	// commands 0-8  (asound_commands1)
+const ASound6::CommandPtr ASound6::_commandList[102] = {
+	// commands 0-8  (off_11A14)
 	&ASound6::command0,  &ASound6::command1,  &ASound6::command2,  &ASound6::command3,
 	&ASound6::command4,  &ASound6::command5,  &ASound6::command6,  &ASound6::command7,
-	&ASound6::command8
+	&ASound6::command8,
+	// 9-15 absent
+	nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+	// commands 16-19 (off_11A26; slot 19 = no-op)
+	&ASound6::command16, &ASound6::command17, &ASound6::command18, nullptr,
+	// 20-23 absent
+	nullptr, nullptr, nullptr, nullptr,
+	// commands 24-31 (off_11A2E)
+	&ASound6::command24, &ASound6::command25, &ASound6::command26, &ASound6::command27,
+	&ASound6::command28, &ASound6::command29, &ASound6::command30, &ASound6::command31,
+	// commands 32-47 (funcs_1204D; slots 41-43 and 46-47 = no-op)
+	&ASound6::command32, &ASound6::command33, &ASound6::command34, &ASound6::command35,
+	&ASound6::command36, &ASound6::command37, &ASound6::command38, &ASound6::command39,
+	&ASound6::command40, nullptr, nullptr, nullptr,
+	&ASound6::command44, &ASound6::command45, nullptr, nullptr,
+	// 48-63 absent
+	nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+	nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+	// commands 64-101 (off_11A60; slot 99 = no-op)
+	&ASound6::command64, &ASound6::command65, &ASound6::command66, &ASound6::command67,
+	&ASound6::command68, &ASound6::command69, &ASound6::command70, &ASound6::command71,
+	&ASound6::command72, &ASound6::command73, &ASound6::command74, &ASound6::command75,
+	&ASound6::command76, &ASound6::command77, &ASound6::command78, &ASound6::command79,
+	&ASound6::command80, &ASound6::command81, &ASound6::command82, &ASound6::command83,
+	&ASound6::command84, &ASound6::command85, &ASound6::command86, &ASound6::command87,
+	&ASound6::command88, &ASound6::command89, &ASound6::command90, &ASound6::command91,
+	&ASound6::command92, &ASound6::command93, &ASound6::command94, &ASound6::command95,
+	&ASound6::command96, &ASound6::command97, &ASound6::command98, nullptr,
+	&ASound6::command100, &ASound6::command101
 };
 
 ASound6::ASound6(Audio::Mixer *mixer, OPL::OPL *opl)
-	: ASound(mixer, opl, "asound.dr6", 0x2370, 0x3870) {
-	// Load sound samples
+		: ASound(mixer, opl, "asound.dr6", 0x2370, 0x3870) {
 	auto samplesStream = getDataStream(0x1dc);
 	for (int i = 0; i < 182; ++i)
 		_samples.push_back(AdlibSample(samplesStream));
+	_cmd33Flag = 0;
+	_lastParam = 0;
 }
 
 int ASound6::command(int commandId, int param) {
-	if (commandId > 71 || !_commandList[commandId])
+	_lastParam = param;
+	if (commandId > 101 || !_commandList[commandId])
 		return 0;
-
+	if (commandId >= 32 && commandId < 64)
+		setMusicIndex(commandId);
 	return (this->*_commandList[commandId])();
 }
 
-// commands 0-8: delegate to base ASound
-int ASound6::command0() {
-	return ASound::command0();
+// commands 0-8: delegate to base
+int ASound6::command0() { return ASound::command0(); }
+int ASound6::command1() { return ASound::command1(); }
+int ASound6::command2() { return ASound::command2(); }
+int ASound6::command3() { return ASound::command3(); }
+int ASound6::command4() { return ASound::command4(); }
+int ASound6::command5() { return ASound::command5(); }
+int ASound6::command6() { return ASound::command6(); }
+int ASound6::command7() { return ASound::command7(); }
+int ASound6::command8() { return ASound::command8(); }
+
+// command16 — Pattern B with 5 isSoundActive guards; setMusicIndex(0x10)
+void ASound6::loadCommand16() {
+	resetCallbackTimer(0xC8);
+	setMusicIndex(0x10);
+	ASound::command1();
+	_channels[0]->load(loadData(0x2AA0));
+	_channels[1]->load(loadData(0x2B2B));
+	_channels[2]->load(loadData(0x2B70));
+	_channels[3]->load(loadData(0x2BC9));
+	_channels[4]->load(loadData(0x2BDA));
+	_channels[5]->load(loadData(0x2BED));
+}
+int ASound6::command16() {
+	if (isSoundActive(loadData(0x1542))) return 0;
+	if (isSoundActive(loadData(0x16F4))) return 0;
+	if (isSoundActive(loadData(0x1A10))) return 0;
+	if (isSoundActive(loadData(0x1E44))) return 0;
+	if (isSoundActive(loadData(0x2AA0))) return 0;
+	if (!isMusicChannelsActive())
+		loadCommand16();
+	else
+		scheduleCallback(MAKE_CALLBACK(ASound6, loadCommand16));
+	return 0;
+}
+
+// command17 — inline (non-deferred): resetCallbackTimer(0x60), ch0-ch6
+int ASound6::command17() {
+	byte *pData = loadData(0x3166);
+	if (!isSoundActive(pData)) {
+		resetCallbackTimer(0x60);
+		ASound::command1();
+		_channels[0]->load(pData);
+		_channels[1]->load(loadData(0x319B));
+		_channels[2]->load(loadData(0x31CE));
+		_channels[3]->load(loadData(0x31E7));
+		_channels[4]->load(loadData(0x321A));
+		_channels[5]->load(loadData(0x3228));
+		_channels[6]->load(loadData(0x3240));
+	}
+	return 0;
+}
+
+// command18 — re-entry dispatcher: command1() + musicIndex dispatch
+int ASound6::command18() {
+	ASound::command1();
+	int musicIndex = getMusicIndex();
+	if (musicIndex <= 0x12)
+		return command16();
+	if (_commandList[musicIndex])
+		return (this->*_commandList[musicIndex])();
+	return 0;
+}
+
+// commands 24-31 — SFX via playSound (loc_103DC = findFreeChannelFull)
+int ASound6::command24() { playSound(0x3279); playSound(0x32AE); return 0; }
+int ASound6::command25() { playSound(0x32DE); playSound(0x330C); return 0; }
+int ASound6::command26() { playSound(0x333C); return 0; }
+int ASound6::command27() { playSound(0x3348); return 0; }
+int ASound6::command28() { playSound(0x3354); return 0; }
+int ASound6::command29() { playSound(0x337C); return 0; }
+int ASound6::command30() { playSound(0x33B4); return 0; }
+int ASound6::command31() { *loadData(0x3418) = 0x67; playSound(0x3415); return 0; }
+
+// command32 — complex: optionally modifies active channel; Pattern B for ch0-ch5
+// Shared deferred loader with command33 (loc_11B29)
+void ASound6::loadCommand32() {
+	resetCallbackTimer(0x3C);
+	ASound::command1();
+	_channels[0]->load(loadData(0x1192));
+	_channels[1]->load(loadData(0x11D8));
+	_channels[2]->load(loadData(0x122C));
+	_channels[3]->load(loadData(0x1255));
+	_channels[4]->load(loadData(0x1317));
+	_channels[5]->load(loadData(0x134D));
+	if (_cmd33Flag == 0xFF) {
+		_cmd33Flag = 0;
+		_channels[6]->load(loadData(0x12F4));
+	}
+}
+int ASound6::command32() {
+	// If sound 0x12F4 is already active, set pending-stop and redirect its data
+	byte *p12F4 = loadData(0x12F4);
+	for (int ch = 0; ch < 9; ++ch) {
+		if (_channels[ch]->_activeCount && _channels[ch]->_soundData == p12F4) {
+			_channels[ch]->_pendingStop = 0xFF;
+			_channels[ch]->_soundData = loadData(0x3252);
+			break;
+		}
+	}
+	if (!isSoundActive(loadData(0x1192))) {
+		if (!isMusicChannelsActive())
+			loadCommand32();
+		else
+			scheduleCallback(MAKE_CALLBACK(ASound6, loadCommand32));
+	}
+	return 0;
+}
+
+// command33 — sets _cmd33Flag=0xFF then shares loadCommand32 loader
+int ASound6::command33() {
+	if (!isSoundActive(loadData(0x12F4))) {
+		_cmd33Flag = 0xFF;
+		if (!isMusicChannelsActive()) {
+			loadCommand32();
+		} else if (isSoundActive(loadData(0x1192))) {
+			// loc_11B69: sound 0x1192 already running — only load ch6
+			_cmd33Flag = 0;
+			_channels[6]->load(loadData(0x12F4));
+		} else {
+			scheduleCallback(MAKE_CALLBACK(ASound6, loadCommand32));
+		}
+	}
+	return 0;
+}
+
+// command34 — Pattern B with shortcut: if ch0 already playing 0x1362, load extra only
+void ASound6::loadCommand34() {
+	resetCallbackTimer(0x1E);
+	ASound::command1();
+	_channels[0]->load(loadData(0x1362));
+	_channels[4]->load(loadData(0x14F1));
+	_channels[1]->load(loadData(0x13C5));
+	_channels[5]->load(loadData(0x1510));
+	_channels[3]->load(loadData(0x14A7));
+	_channels[6]->load(loadData(0x152A));
+	_channels[2]->load(loadData(0x1418));
+}
+int ASound6::command34() {
+	if (!isSoundActive(loadData(0x13C5))) {
+		if (_channels[0]->_loopStartPtr == loadData(0x1362) && _channels[0]->_activeCount != 0) {
+			// Shortcut: ch0 already running 0x1362 — only load extra channels (loc_11C15)
+			_channels[1]->load(loadData(0x13C5));
+			_channels[5]->load(loadData(0x1510));
+			_channels[3]->load(loadData(0x14A7));
+			_channels[6]->load(loadData(0x152A));
+			_channels[2]->load(loadData(0x1418));
+		} else if (!isMusicChannelsActive()) {
+			loadCommand34();
+		} else {
+			scheduleCallback(MAKE_CALLBACK(ASound6, loadCommand34));
+		}
+	}
+	return 0;
+}
+
+// command35 — Pattern B, timer=0x1E, ch0+ch4 only
+void ASound6::loadCommand35() {
+	resetCallbackTimer(0x1E);
+	ASound::command1();
+	_channels[0]->load(loadData(0x1362));
+	_channels[4]->load(loadData(0x14F1));
+}
+int ASound6::command35() {
+	if (!isSoundActive(loadData(0x1362))) {
+		if (!isMusicChannelsActive())
+			loadCommand35();
+		else
+			scheduleCallback(MAKE_CALLBACK(ASound6, loadCommand35));
+	}
+	return 0;
+}
+
+// command36 — triple guard (0x16F4, 0x1A10, 0x1E44); Pattern B; ch0-ch5
+void ASound6::loadCommand36() {
+	resetCallbackTimer(0xC8);
+	ASound::command1();
+	_channels[0]->load(loadData(0x1542));
+	_channels[1]->load(loadData(0x1594));
+	_channels[2]->load(loadData(0x162A));
+	_channels[3]->load(loadData(0x16A5));
+	_channels[4]->load(loadData(0x16BF));
+	_channels[5]->load(loadData(0x16D9));
+}
+int ASound6::command36() {
+	if (isSoundActive(loadData(0x16F4))) return 0;
+	if (isSoundActive(loadData(0x1A10))) return 0;
+	if (isSoundActive(loadData(0x1E44))) return 0;
+	if (!isMusicChannelsActive())
+		loadCommand36();
+	else
+		scheduleCallback(MAKE_CALLBACK(ASound6, loadCommand36));
+	return 0;
+}
+
+// command37 — triple guard (0x1A10, 0x1E44, 0x16F4); Pattern B; ch0-ch5
+void ASound6::loadCommand37() {
+	resetCallbackTimer(0xC8);
+	ASound::command1();
+	_channels[0]->load(loadData(0x16F4));
+	_channels[1]->load(loadData(0x1757));
+	_channels[2]->load(loadData(0x17BF));
+	_channels[3]->load(loadData(0x18C0));
+	_channels[4]->load(loadData(0x19C7));
+	_channels[5]->load(loadData(0x19F7));
+}
+int ASound6::command37() {
+	if (isSoundActive(loadData(0x1A10))) return 0;
+	if (isSoundActive(loadData(0x1E44))) return 0;
+	if (isSoundActive(loadData(0x16F4))) return 0;
+	if (!isMusicChannelsActive())
+		loadCommand37();
+	else
+		scheduleCallback(MAKE_CALLBACK(ASound6, loadCommand37));
+	return 0;
+}
+
+// command38 — single guard (0x1A10); Pattern B; ch0-ch6
+void ASound6::loadCommand38() {
+	resetCallbackTimer(0xC8);
+	ASound::command1();
+	_channels[0]->load(loadData(0x1A10));
+	_channels[1]->load(loadData(0x1A76));
+	_channels[2]->load(loadData(0x1ADC));
+	_channels[3]->load(loadData(0x1B6C));
+	_channels[4]->load(loadData(0x1C29));
+	_channels[5]->load(loadData(0x1E14));
+	_channels[6]->load(loadData(0x1E2C));
+}
+int ASound6::command38() {
+	if (!isSoundActive(loadData(0x1A10))) {
+		if (!isMusicChannelsActive())
+			loadCommand38();
+		else
+			scheduleCallback(MAKE_CALLBACK(ASound6, loadCommand38));
+	}
+	return 0;
 }
-int ASound6::command1() {
-	return ASound::command1();
+
+// command39 — single guard (0x1E44); Pattern B; ch0-ch6
+void ASound6::loadCommand39() {
+	resetCallbackTimer(0xC8);
+	ASound::command1();
+	_channels[0]->load(loadData(0x1E44));
+	_channels[1]->load(loadData(0x1FA2));
+	_channels[2]->load(loadData(0x21AD));
+	_channels[3]->load(loadData(0x2249));
+	_channels[4]->load(loadData(0x2298));
+	_channels[5]->load(loadData(0x23D0));
+	_channels[6]->load(loadData(0x2461));
+}
+int ASound6::command39() {
+	if (!isSoundActive(loadData(0x1E44))) {
+		if (!isMusicChannelsActive())
+			loadCommand39();
+		else
+			scheduleCallback(MAKE_CALLBACK(ASound6, loadCommand39));
+	}
+	return 0;
 }
-int ASound6::command2() {
-	return ASound::command2();
+
+// command40 — single guard (0x2476); Pattern B; ch0-ch6
+void ASound6::loadCommand40() {
+	resetCallbackTimer(0xC8);
+	ASound::command1();
+	_channels[0]->load(loadData(0x2476));
+	_channels[1]->load(loadData(0x259C));
+	_channels[2]->load(loadData(0x2691));
+	_channels[3]->load(loadData(0x2786));
+	_channels[4]->load(loadData(0x28C1));
+	_channels[5]->load(loadData(0x29CB));
+	_channels[6]->load(loadData(0x2A7A));
+}
+int ASound6::command40() {
+	if (!isSoundActive(loadData(0x2476))) {
+		if (!isMusicChannelsActive())
+			loadCommand40();
+		else
+			scheduleCallback(MAKE_CALLBACK(ASound6, loadCommand40));
+	}
+	return 0;
 }
-int ASound6::command3() {
-	return ASound::command3();
+
+// command44 — Pattern B; setMusicIndex(0x25); all 9 channels; timer=0x30
+void ASound6::loadCommand44() {
+	resetCallbackTimer(0x30);
+	setMusicIndex(0x25);
+	ASound::command1();
+	_channels[0]->load(loadData(0x2C06));
+	_channels[1]->load(loadData(0x2C4D));
+	_channels[2]->load(loadData(0x2C71));
+	_channels[3]->load(loadData(0x2CA0));
+	_channels[4]->load(loadData(0x2CD1));
+	_channels[5]->load(loadData(0x2D7D));
+	_channels[6]->load(loadData(0x2D88));
+	_channels[7]->load(loadData(0x2D95));
+	_channels[8]->load(loadData(0x2D2E));
+}
+int ASound6::command44() {
+	if (!isSoundActive(loadData(0x2C06))) {
+		if (!isMusicChannelsActive())
+			loadCommand44();
+		else
+			scheduleCallback(MAKE_CALLBACK(ASound6, loadCommand44));
+	}
+	return 0;
 }
-int ASound6::command4() {
-	return ASound::command4();
+
+// command45 — Pattern B; timer=0x1E; 3×findFreeChannel (lower pool, sub_10388)
+void ASound6::loadCommand45() {
+	resetCallbackTimer(0x1E);
+	ASound::command1();
+	findFreeChannel(loadData(0x2DB0));
+	findFreeChannel(loadData(0x2DE7));
+	findFreeChannel(loadData(0x2DF2));
 }
-int ASound6::command5() {
-	return ASound::command5();
+int ASound6::command45() {
+	if (!isSoundActive(loadData(0x2DB0))) {
+		if (!isMusicChannelsActive())
+			loadCommand45();
+		else
+			scheduleCallback(MAKE_CALLBACK(ASound6, loadCommand45));
+	}
+	return 0;
 }
-int ASound6::command6() {
-	return ASound::command6();
+
+// command64 — param-based: param=0 sets global flags; param!=0 sets pitch byte and plays sfx
+int ASound6::command64() {
+	if (_lastParam == 0) {
+		if (!isSoundActive(loadData(0x33DA))) {
+			*(uint16 *)loadData(0x22) = 1;
+			*(uint16 *)loadData(0x20) = 1;
+		}
+	} else {
+		*loadData(0x33E5) = _lastParam & 0x7F;
+		if (!isSoundActive(loadData(0x33DA)))
+			playSound(0x33DA);
+	}
+	return 0;
 }
-int ASound6::command7() {
-	return ASound::command7();
+
+// commands 65-98 — SFX
+int ASound6::command65() { playSound(0x30F6); return 0; }
+int ASound6::command66() { playSound(0x2DFE); return 0; }
+int ASound6::command67() { playSound(0x3104); playSound(0x3128); return 0; }
+int ASound6::command68() { playSound(0x2E10); return 0; }
+int ASound6::command69() { findFreeChannel(loadData(0x2E13)); return 0; }
+int ASound6::command70() { playSound(0x2E29); return 0; }
+int ASound6::command71() { playSound(0x2E41); return 0; }
+int ASound6::command72() { playSound(0x2E51); playSound(0x2E76); return 0; }
+int ASound6::command73() { playSound(0x2ED9); return 0; }
+int ASound6::command74() { playSound(0x2EFF); return 0; }
+int ASound6::command75() { playSound(0x2F0B); playSound(0x2F17); return 0; }
+int ASound6::command76() { playSound(0x2F26); return 0; }
+int ASound6::command77() { playSound(0x2F3E); return 0; }
+int ASound6::command78() { playSound(0x2F63); return 0; }
+int ASound6::command79() { playSound(0x2F75); return 0; }
+
+// command80 — if sound 0x2F75 is active, set its _outerLoopCount to 1
+int ASound6::command80() {
+	byte *pData = loadData(0x2F75);
+	for (int ch = 0; ch < 9; ++ch) {
+		if (_channels[ch]->_activeCount && _channels[ch]->_soundData == pData) {
+			_channels[ch]->_outerLoopCount = 1;
+			break;
+		}
+	}
+	return 0;
 }
-int ASound6::command8() {
-	return ASound::command8();
+
+int ASound6::command81() { playSound(0x2F85); playSound(0x2F90); return 0; }
+int ASound6::command82() { playSound(0x2FAE); return 0; }
+int ASound6::command83() { playSound(0x2E9D); playSound(0x2EBA); return 0; }
+int ASound6::command84() { playSound(0x2FB8); return 0; }
+int ASound6::command85() { playSound(0x2FC5); return 0; }
+int ASound6::command86() { playSound(0x2FCF); playSound(0x2FDA); return 0; }
+int ASound6::command87() { playSound(0x2FF8); return 0; }
+int ASound6::command88() { playSound(0x300C); return 0; }
+int ASound6::command89() { playSound(0x3027); return 0; }
+int ASound6::command90() { playSound(0x3041); playSound(0x3053); return 0; }
+int ASound6::command91() { playSound(0x3062); return 0; }
+int ASound6::command92() { _channels[8]->load(loadData(0x3074)); return 0; }
+int ASound6::command93() { findFreeChannel(loadData(0x3088)); return 0; }
+int ASound6::command94() { findFreeChannel(loadData(0x3094)); return 0; }
+int ASound6::command95() { findFreeChannel(loadData(0x30A3)); return 0; }
+
+// command96 — Pattern B; timer=0x5A; ch0-ch6
+void ASound6::loadCommand96() {
+	resetCallbackTimer(0x5A);
+	ASound::command1();
+	_channels[0]->load(loadData(0x3482));
+	_channels[1]->load(loadData(0x34C8));
+	_channels[2]->load(loadData(0x350E));
+	_channels[3]->load(loadData(0x3554));
+	_channels[4]->load(loadData(0x34B3));
+	_channels[5]->load(loadData(0x34F9));
+	_channels[6]->load(loadData(0x353F));
+}
+int ASound6::command96() {
+	if (!isSoundActive(loadData(0x3482))) {
+		if (!isMusicChannelsActive())
+			loadCommand96();
+		else
+			scheduleCallback(MAKE_CALLBACK(ASound6, loadCommand96));
+	}
+	return 0;
 }
 
+int ASound6::command97() { playSound(0x30CA); playSound(0x30E0); return 0; }
+int ASound6::command98() { playSound(0x314C); playSound(0x314E); return 0; }
+int ASound6::command100() { return 0; }
+int ASound6::command101() { return 0; }
+
 /*-----------------------------------------------------------------------*/
 
 const ASound9::CommandPtr ASound9::_commandList[65] = {
diff --git a/engines/mads/madsv2/dragonsphere/sound_dragonsphere.h b/engines/mads/madsv2/dragonsphere/sound_dragonsphere.h
index d016394d0ef..0d2bcc0ad2e 100644
--- a/engines/mads/madsv2/dragonsphere/sound_dragonsphere.h
+++ b/engines/mads/madsv2/dragonsphere/sound_dragonsphere.h
@@ -405,25 +405,63 @@ public:
 };
 
 
+/**
+ * ASound6  (asound.dr6, _dataOffset = 0x2370, _dataSize = 0x3870)
+ * Dispatch table layout (five tables collapsed to flat [102]):
+ *   off_11A14:   commands  0– 8  (base=0,    max=8)
+ *   off_11A26:   commands 16–19  (base=0x10, max=0x13; slot 19 = no-op)
+ *   off_11A2E:   commands 24–31  (base=0x18, max=0x1F)
+ *   funcs_1204D: commands 32–47  (base=0x20, max=0x2F; slots 41–43, 46–47 = no-op)
+ *   off_11A60:   commands 64–101 (base=0x40, max=0x65; slot 99 = no-op)
+ */
 class ASound6 : public ASound {
 private:
-	typedef int (ASound6:: *CommandPtr)();
-	int command0();
-	int command1();
-	int command2();
-	int command3();
-	int command4();
-	int command5();
-	int command6();
-	int command7();
+	typedef int (ASound6::*CommandPtr)();
+	static const CommandPtr _commandList[102];
+
+	void loadCommand16();
+	void loadCommand32();   // shared deferred loader for commands 32 & 33
+	void loadCommand34();
+	void loadCommand35();
+	void loadCommand36();
+	void loadCommand37();
+	void loadCommand38();
+	void loadCommand39();
+	void loadCommand40();
+	void loadCommand44();
+	void loadCommand45();
+	void loadCommand96();
+
+	uint8 _cmd33Flag;   // byte_134D1: set by command33 to extend loadCommand32
+	int   _lastParam;   // param stored by command() for use by command64
+
+	int command0();  int command1();  int command2();  int command3();
+	int command4();  int command5();  int command6();  int command7();
 	int command8();
 
-	static const CommandPtr _commandList[98];
+	int command16(); int command17(); int command18();
+
+	int command24(); int command25(); int command26(); int command27();
+	int command28(); int command29(); int command30(); int command31();
+
+	int command32(); int command33(); int command34(); int command35();
+	int command36(); int command37(); int command38(); int command39();
+	int command40(); int command44(); int command45();
+
+	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(); int command79();
+	int command80(); int command81(); int command82(); int command83();
+	int command84(); int command85(); int command86(); int command87();
+	int command88(); int command89(); int command90(); int command91();
+	int command92(); int command93(); int command94(); int command95();
+	int command96(); int command97(); int command98();
+	int command100(); int command101();
 
 public:
 	ASound6(Audio::Mixer *mixer, OPL::OPL *opl);
-	~ASound6() override {
-	}
+	~ASound6() override {}
 	int command(int commandId, int param) override;
 };
 




More information about the Scummvm-git-logs mailing list