Музыка по ходу игры: смерть, зелья, меч, конец уровня, катсцены

Звуки 24..43 в наборе оцифровки пустые — в оригинале это Adlib-музыка, и
в digisnd её нет. На этом и построено подключение: pop_sfx_play для звука
с нулевой длиной кладёт номер в pop_mus_req, а разбирает заявку
pop_music_service() — один вызов на кадр из любого цикла (игра, интро,
катсцена). Всё чтение с диска живёт там.

Ждать полной загрузки джингла нельзя — это фриз посреди игры. Поэтому
pop_music_stream читает первую страницу (33 мс) и сразу пускает трек: она
звучит 1,5 с, а следующая читается те же 33 мс. Остальные доливаются по
одной за кадр.

Расставлено по местам оригинала: смерть (24/28/32), вступление первого
уровня и тень шестого (25), сцены перед уровнями (27/35/40), встреча с
Джафаром (29), зелья (30/33/39), время вышло (36), меч и смерть стража
(37), смерть Джафара (43), конец уровня (41/32), встреча с принцессой
(26). Темы «раз за уровень» сбрасывает pop_music_level_start.

Упакован 21 трек (2,4 МБ). Не озвучен только финал: won — 115 с и 78
страниц EMM, ему нужен кольцевой стриминг (задача MUS-WON на доске).

Проверено в MAME: вступительная тема первого уровня отыгрывается на
старте (курсор дошёл до конца, id 25). Host-тесты: 15 наборов.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-25 21:52:37 +03:00
parent 65797af44c
commit 7e6b38cca6
33 changed files with 300 additions and 35 deletions
+23
View File
@@ -22,6 +22,7 @@
#include "pop_kid.h"
#include "pop_sfx.h" /* звуковые эффекты (../docs/sound_plan.md) */
#include "pop_map.h"
#include "pop_level.h" /* pop_current_level — вступительная тема 1-го */
#include "pop_guard.h" /* charid, состояние меча, seq стража */
/* ---- CONTROL_* и seq/frame id (подмножество types.h) --------------- */
@@ -254,9 +255,24 @@ static void safe_step(void)
}
}
/* Вступительная тема уровня 1 играется один раз за заход на уровень;
* сбрасывает флаг pop_ctrl_level_start (её зовёт запуск уровня). */
static uint8_t lvl1_music;
void pop_ctrl_level_start(void) __banked { lvl1_music = 0; }
/* ---- control_* обработчики состояний ------------------------------ */
static void control_crouched(void)
{
/* «Presentation» (seg005:02EB): на первом уровне Кид начинает игру
* сидя, и пока он сидит, звучит вступительная тема. Оригинал ждёт
* тишины (`if (!check_sound_playing())`) — у нас достаточно одного
* запуска: заявку разберёт главный цикл, а насос сам придержит музыку,
* пока доигрывает эффект. */
if (pop_current_level == 1 && !lvl1_music) {
lvl1_music = 1;
pop_sfx_play(25);
}
/* Shift в приседе — поднять предмет (seg005 control_crouched). */
if (control_shift2 == CONTROL_HELD && get_item_action()) return;
if (control_y != CONTROL_HELD_DOWN) {
@@ -711,6 +727,13 @@ static void ctrl_kid_death(void)
if (Kid.alive < 0 && hitp_curr == 0) {
Kid.alive = 0;
pop_kid_dead = 1;
/* play_death_music (seg006:15B5): траурный трек зависит от того,
* КАК умер Кид — в бою, от руки тени или просто так. Оригинал ждёт
* шести тиков, чтобы доиграл звук удара; у нас ждать не нужно —
* насос держит курсор музыки, пока звучит эффект. */
if (Guard.charid == CHARID_1_SHADOW) pop_sfx_play(32);
else if (holding_sword) pop_sfx_play(28);
else pop_sfx_play(24);
}
}