Музыка по ходу игры: смерть, зелья, меч, конец уровня, катсцены
Звуки 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:
@@ -845,3 +845,46 @@ EMM: `pop_music_load*` всегда пишет в НЕ играющий, `pop_mu
|
|||||||
курсор `pop_mus_id` меняется ровно на своих кадрах, интро доходит до
|
курсор `pop_mus_id` меняется ровно на своих кадрах, интро доходит до
|
||||||
демо-режима. Слуховая проверка (нет ли хрипа от диска при играющей
|
демо-режима. Слуховая проверка (нет ли хрипа от диска при играющей
|
||||||
музыке) — за пользователем.
|
музыке) — за пользователем.
|
||||||
|
|
||||||
|
## 7. МУЗЫКА ПО ХОДУ ИГРЫ (2026-08-26)
|
||||||
|
|
||||||
|
Звуки 24..43 в наборе оцифровки ПУСТЫЕ — в оригинале это Adlib-музыка, и
|
||||||
|
в digisnd её нет вовсе. На этом и построено подключение: `pop_sfx_play`
|
||||||
|
для звука с нулевой длиной не пытается его играть, а кладёт НОМЕР в
|
||||||
|
`pop_mus_req` (один байт). Заявку разбирает `pop_music_service()` — один
|
||||||
|
вызов на кадр из любого цикла (игрового, интро, катсцены); всё чтение с
|
||||||
|
диска живёт там.
|
||||||
|
|
||||||
|
**Стриминг вместо загрузки.** Ждать полной загрузки джингла нельзя — это
|
||||||
|
фриз на треть секунды посреди игры. `pop_music_stream` читает ПЕРВУЮ
|
||||||
|
страницу (33 мс) и сразу пускает трек: она звучит 1,5 с, а следующая
|
||||||
|
читается те же 33 мс — запас сорокакратный. Остальные доливаются по
|
||||||
|
одной за кадр, пока `pop_music_loading()`. Номера страниц известны сразу
|
||||||
|
после `mem_alloc_pages`, поэтому таблица для насоса заполняется целиком —
|
||||||
|
данные появятся раньше, чем насос до них дойдёт.
|
||||||
|
|
||||||
|
**Что и где играет** (номера и места — из SDLPoP):
|
||||||
|
|
||||||
|
| трек | событие | место у нас |
|
||||||
|
|------|---------|-------------|
|
||||||
|
| 24 / 28 / 32 | смерть: обычная / в бою / от руки тени | `ctrl_kid_death` |
|
||||||
|
| 25 | вступление 1-го уровня (Кид сидит), тень 6-го | `control_crouched`, `guards.c` |
|
||||||
|
| 27 / 35 / 40 | сцены перед 2/4/6/12, 8/9, «времени мало» | `pop_pre_cutscene_show` |
|
||||||
|
| 29 | встреча с Джафаром | `pop_meet_jaffar` |
|
||||||
|
| 30 / 33 | большая склянка / малая | `pop_proc_get_object` |
|
||||||
|
| 36 | время вышло | `pop_time_expired_show` |
|
||||||
|
| 37 / 43 | меч найден, страж убит / смерть Джафара | `pop_proc_get_object`, `on_guard_killed` |
|
||||||
|
| 39 | перо (медленное падение) | `pop_proc_get_object` |
|
||||||
|
| 41 / 32 | конец уровня / конец 4-го (тень) | опкод SND_LEVEL в `play_seq` |
|
||||||
|
| 26 | встреча с принцессой | `cut_ending` |
|
||||||
|
|
||||||
|
Темы, которые звучат один раз за заход на уровень (вступление 1-го, тень
|
||||||
|
6-го), сбрасывает `pop_music_level_start()` из `pop_start_level`. Оригинал
|
||||||
|
для этого портит переменную двери (`leveldoor_open = 0x4D`) — у нас на это
|
||||||
|
есть свои два байта.
|
||||||
|
|
||||||
|
**Чего пока нет.** Финальный `won` (56): 115 с, 1,2 МБ, 78 страниц EMM —
|
||||||
|
в `POP_MUS_PAGES` (20) он не помещается даже теоретически. Ему нужен
|
||||||
|
КОЛЬЦЕВОЙ стриминг: держать в памяти несколько страниц и дочитывать в те,
|
||||||
|
что насос уже прошёл. Это отдельная задача — курсор насоса придётся
|
||||||
|
научить заворачиваться, а загрузчик — держать дистанцию от него.
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -207,12 +207,14 @@ SND_ARC := $(SND_DIR)/snd.arc
|
|||||||
SND_DATA := $(SND_ARC)
|
SND_DATA := $(SND_ARC)
|
||||||
|
|
||||||
# МУЗЫКА: записи DOS-версии, приведённые к формату CBL
|
# МУЗЫКА: записи DOS-версии, приведённые к формату CBL
|
||||||
# (toolchain/pop_pack_music.py). Сейчас озвучена вся заставка:
|
# (toolchain/pop_pack_music.py). Номера — оригинала, чтобы игровой код
|
||||||
# 54 — тема титров, 55 — «In the absence», 50/53/52 — три реплики сцены
|
# просил трек тем же числом, каким SDLPoP зовёт play_sound.
|
||||||
# с принцессой и Джафаром. Игровые джинглы (смерть, зелья) пойдут
|
# заставка 54 55 50 53 52
|
||||||
# отдельной задачей: там музыка спорит с эффектами за единственный CBL.
|
# катсцены 26 27 35 36 40
|
||||||
|
# игра 24 25 28 29 30 32 33 37 39 41 43
|
||||||
|
# Нет только 56 (won, 115 с / 1,2 МБ) — финалу нужен стриминг с диска.
|
||||||
MUS_DIR := $(CURDIR)/../poc/res/music
|
MUS_DIR := $(CURDIR)/../poc/res/music
|
||||||
MUS_IDS := 50 52 53 54 55
|
MUS_IDS := 24 25 26 27 28 29 30 32 33 35 36 37 39 40 41 43 50 52 53 54 55
|
||||||
MUS_DATA := $(foreach i,$(MUS_IDS),$(MUS_DIR)/m$(i).bin)
|
MUS_DATA := $(foreach i,$(MUS_IDS),$(MUS_DIR)/m$(i).bin)
|
||||||
|
|
||||||
# UI: два исходных шрифта SDLPoP в одном EMM-атласе. Файл короче страницы:
|
# UI: два исходных шрифта SDLPoP в одном EMM-атласе. Файл короче страницы:
|
||||||
|
|||||||
@@ -1206,6 +1206,22 @@ N навык M» — отдельная надобность, если пона
|
|||||||
|
|
||||||
Фазы З1..З5 и список «проверить артефактом до кодинга» — в доке.
|
Фазы З1..З5 и список «проверить артефактом до кодинга» — в доке.
|
||||||
|
|
||||||
|
### <a id="mus-won"></a>MUS-WON. Финальная тема — кольцевой стриминг с диска
|
||||||
|
|
||||||
|
Трек 56 (`won`, 115 с) — это 1,2 МБ, 78 страниц EMM. Ни в `POP_MUS_PAGES`
|
||||||
|
(20), ни в разумный бюджет памяти он не влезает, поэтому единственный
|
||||||
|
оставшийся неозвученным кусок игры — экран победы.
|
||||||
|
|
||||||
|
**Что нужно.** Кольцевой буфер: держать в EMM несколько страниц (8 = 128
|
||||||
|
КБ хватит с запасом — это 12 с звучания), а загрузчик дочитывает в те, что
|
||||||
|
насос уже прошёл. Курсор насоса (`pop_mus_pg`) при этом обязан
|
||||||
|
заворачиваться, а загрузчик — держать дистанцию от него и не обгонять на
|
||||||
|
круг. Чтение страницы 33 мс против 1,5 с её звучания — запаса вдоволь,
|
||||||
|
вся сложность в аккуратности индексов, а не в скорости.
|
||||||
|
|
||||||
|
**Заодно.** Тот же механизм снимает ограничение `POP_MUS_PAGES` со всех
|
||||||
|
треков: сейчас каждый должен помещаться в память целиком.
|
||||||
|
|
||||||
### <a id="arc-atlases"></a>ARC-ATLASES. Атласы — в архивы PBA1, как звук и музыка
|
### <a id="arc-atlases"></a>ARC-ATLASES. Атласы — в архивы PBA1, как звук и музыка
|
||||||
|
|
||||||
**Что сделано.** Формат PBA1 и читатель готовы и работают на звуке:
|
**Что сделано.** Формат PBA1 и читатель готовы и работают на звуке:
|
||||||
|
|||||||
@@ -46,6 +46,18 @@
|
|||||||
/* tile_is_floor (seg004): не-пол — пустота, ковёр, верх двери, стена и
|
/* tile_is_floor (seg004): не-пол — пустота, ковёр, верх двери, стена и
|
||||||
* «половинки» 26..29. Дубликат крошечного switch'а из pop_map: тянуть его
|
* «половинки» 26..29. Дубликат крошечного switch'а из pop_map: тянуть его
|
||||||
* через границу банка дороже, чем повторить. */
|
* через границу банка дороже, чем повторить. */
|
||||||
|
/* Темы, которые звучат ОДИН раз за заход на уровень: тень шестого уровня
|
||||||
|
* (seg002:0090) и вступление первого. Оригинал отмечает «уже играли»
|
||||||
|
* через leveldoor_open = 0x4D, то есть портит переменную двери; у нас на
|
||||||
|
* это есть свои байты, а сбрасывает их старт уровня. */
|
||||||
|
static uint8_t shadow6_music;
|
||||||
|
|
||||||
|
void pop_music_level_start(void) __banked
|
||||||
|
{
|
||||||
|
shadow6_music = 0;
|
||||||
|
pop_ctrl_level_start();
|
||||||
|
}
|
||||||
|
|
||||||
static uint8_t tile_is_floor(uint8_t t)
|
static uint8_t tile_is_floor(uint8_t t)
|
||||||
{
|
{
|
||||||
switch (t) {
|
switch (t) {
|
||||||
@@ -343,12 +355,16 @@ uint8_t pop_check_shadow(uint8_t room) __banked
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
/* Уровень 6 (seg002:0090): условий на содержимое комнаты нет вовсе —
|
/* Уровень 6 (seg002:0090): условий на содержимое комнаты нет вовсе —
|
||||||
* тень встаёт при КАЖДОМ входе в комнату 1. Оригинал здесь ещё играет
|
* тень встаёт при КАЖДОМ входе в комнату 1. Оригинал играет здесь
|
||||||
* sound_25_presentation один раз, отмечая это `leveldoor_open = 0x4D`
|
* sound_25_presentation, помечая «уже играли» через leveldoor_open =
|
||||||
* (переменная двери используется как флаг); звука у нас нет, а чужую
|
* 0x4D (переменную двери он использует как флаг). Чужую переменную не
|
||||||
* переменную портить незачем — TODO вместе со звуком. */
|
* трогаем: у нас для этого свой однобайтовый флаг. */
|
||||||
if (pop_current_level == SHADOW_STEP_LEVEL) {
|
if (pop_current_level == SHADOW_STEP_LEVEL) {
|
||||||
if (room != SHADOW_STEP_ROOM) return 0;
|
if (room != SHADOW_STEP_ROOM) return 0;
|
||||||
|
if (!shadow6_music) {
|
||||||
|
shadow6_music = 1;
|
||||||
|
pop_sfx_play(25);
|
||||||
|
}
|
||||||
do_init_shad(init_shad_6, room, SEQ_2_STAND);
|
do_init_shad(init_shad_6, room, SEQ_2_STAND);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -384,7 +400,6 @@ void pop_sword_disappears(void) __banked
|
|||||||
* комнаты 3 и попадает прямо к Джафару. Всё событие — фора: пока
|
* комнаты 3 и попадает прямо к Джафару. Всё событие — фора: пока
|
||||||
* pop_guard_notice_timer идёт, Джафар не встаёт в боевую стойку
|
* pop_guard_notice_timer идёт, Джафар не встаёт в боевую стойку
|
||||||
* (autocontrol_guard_inactive), то есть у Кида есть ~2 секунды достать меч.
|
* (autocontrol_guard_inactive), то есть у Кида есть ~2 секунды достать меч.
|
||||||
* В оригинале здесь же играет sound_29_meet_Jaffar — звука у нас нет.
|
|
||||||
*
|
*
|
||||||
* `pop_leveldoor_open == 0` в условии не косметика: вернувшись к Джафару
|
* `pop_leveldoor_open == 0` в условии не косметика: вернувшись к Джафару
|
||||||
* после его смерти (дверь уже открыта), форы быть не должно.
|
* после его смерти (дверь уже открыта), форы быть не должно.
|
||||||
@@ -396,6 +411,7 @@ void pop_meet_jaffar(void) __banked
|
|||||||
if (pop_current_level != JAFFAR_LEVEL) return;
|
if (pop_current_level != JAFFAR_LEVEL) return;
|
||||||
if (pop_leveldoor_open != 0) return;
|
if (pop_leveldoor_open != 0) return;
|
||||||
if (Kid.room != JAFFAR_MEET_ROOM) return;
|
if (Kid.room != JAFFAR_MEET_ROOM) return;
|
||||||
|
pop_sfx_play(29); /* тема встречи с Джафаром */
|
||||||
pop_guard_notice_timer = JAFFAR_NOTICE_TIME;
|
pop_guard_notice_timer = JAFFAR_NOTICE_TIME;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -426,7 +442,13 @@ void pop_jaffar_exit(void) __banked
|
|||||||
* Демо-уровень (0) сюда тоже не входит: его ветка — часть аттракта. */
|
* Демо-уровень (0) сюда тоже не входит: его ветка — часть аттракта. */
|
||||||
static void on_guard_killed(void)
|
static void on_guard_killed(void)
|
||||||
{
|
{
|
||||||
if (pop_current_level != JAFFAR_LEVEL) return;
|
if (pop_current_level != JAFFAR_LEVEL) {
|
||||||
|
/* seg006:1940 — победный трек за стража; за тень его нет: она не
|
||||||
|
* «убита», а слилась с Кидом. */
|
||||||
|
if (Char.charid != CHARID_1_SHADOW) pop_sfx_play(37);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pop_sfx_play(43); /* смерть Джафара — свой трек */
|
||||||
pop_flash_color = POP_FLASH_WHITE;
|
pop_flash_color = POP_FLASH_WHITE;
|
||||||
pop_flash_time = JAFFAR_FLASH_TIME;
|
pop_flash_time = JAFFAR_FLASH_TIME;
|
||||||
pop_leveldoor_open = 2;
|
pop_leveldoor_open = 2;
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
#include "pop_kid.h"
|
#include "pop_kid.h"
|
||||||
#include "pop_sfx.h" /* звуковые эффекты (../docs/sound_plan.md) */
|
#include "pop_sfx.h" /* звуковые эффекты (../docs/sound_plan.md) */
|
||||||
#include "pop_map.h"
|
#include "pop_map.h"
|
||||||
|
#include "pop_level.h" /* pop_current_level — вступительная тема 1-го */
|
||||||
#include "pop_guard.h" /* charid, состояние меча, seq стража */
|
#include "pop_guard.h" /* charid, состояние меча, seq стража */
|
||||||
|
|
||||||
/* ---- CONTROL_* и seq/frame id (подмножество types.h) --------------- */
|
/* ---- 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_* обработчики состояний ------------------------------ */
|
/* ---- control_* обработчики состояний ------------------------------ */
|
||||||
static void control_crouched(void)
|
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). */
|
/* Shift в приседе — поднять предмет (seg005 control_crouched). */
|
||||||
if (control_shift2 == CONTROL_HELD && get_item_action()) return;
|
if (control_shift2 == CONTROL_HELD && get_item_action()) return;
|
||||||
if (control_y != CONTROL_HELD_DOWN) {
|
if (control_y != CONTROL_HELD_DOWN) {
|
||||||
@@ -711,6 +727,13 @@ static void ctrl_kid_death(void)
|
|||||||
if (Kid.alive < 0 && hitp_curr == 0) {
|
if (Kid.alive < 0 && hitp_curr == 0) {
|
||||||
Kid.alive = 0;
|
Kid.alive = 0;
|
||||||
pop_kid_dead = 1;
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -71,4 +71,7 @@ extern int8_t control_forward, control_backward, control_up, control_down,
|
|||||||
* своего тика напрямую. */
|
* своего тика напрямую. */
|
||||||
void pop_control(void) __banked;
|
void pop_control(void) __banked;
|
||||||
|
|
||||||
|
/* Снять флаг «вступительная тема уровня 1 уже играла». */
|
||||||
|
void pop_ctrl_level_start(void) __banked;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -332,6 +332,10 @@ int pop_guard_load(void) __banked;
|
|||||||
* инверсии; зовётся из pop_vflip_load_all (pop_vflip.h). Живёт рядом с
|
* инверсии; зовётся из pop_vflip_load_all (pop_vflip.h). Живёт рядом с
|
||||||
* pop_guard_load: там же gp[] и выбор GUARD/SKEL. */
|
* pop_guard_load: там же gp[] и выбор GUARD/SKEL. */
|
||||||
int pop_guard_vflip_load(void) __banked;
|
int pop_guard_vflip_load(void) __banked;
|
||||||
|
|
||||||
|
/* Сброс «одноразовых» музыкальных тем уровня (вступление 1-го, тень 6-го).
|
||||||
|
* Зовёт pop_start_level. */
|
||||||
|
void pop_music_level_start(void) __banked;
|
||||||
void pop_guard_free(void) __banked;
|
void pop_guard_free(void) __banked;
|
||||||
|
|
||||||
/* Вход в комнату: поднять стража из данных уровня (порт enter_guard,
|
/* Вход в комнату: поднять стража из данных уровня (порт enter_guard,
|
||||||
|
|||||||
@@ -831,6 +831,7 @@ static int intro_pv_animated(void)
|
|||||||
torch_right, sand_frame, flash,
|
torch_right, sand_frame, flash,
|
||||||
render_tick);
|
render_tick);
|
||||||
pop_sfx_tick(); /* как в оригинале — в конце отрисовки кадра */
|
pop_sfx_tick(); /* как в оригинале — в конце отрисовки кадра */
|
||||||
|
pop_music_service(); /* заявки на музыку из сцены (эффект без оцифровки) */
|
||||||
/* Страницу следующей реплики читаем ЗДЕСЬ, до досыпания кадра:
|
/* Страницу следующей реплики читаем ЗДЕСЬ, до досыпания кадра:
|
||||||
* 33 мс диска укладываются в паузу логического кадра (133 мс) и
|
* 33 мс диска укладываются в паузу логического кадра (133 мс) и
|
||||||
* анимации не стоят. */
|
* анимации не стоят. */
|
||||||
@@ -1252,6 +1253,8 @@ static uint8_t cut_run(uint16_t frames, uint8_t kid_visible)
|
|||||||
gfx_set_visible_page(back);
|
gfx_set_visible_page(back);
|
||||||
for (hold = 1; hold < CUT_FRAME_VSYNC; hold++) gfx_wait_vsync();
|
for (hold = 1; hold < CUT_FRAME_VSYNC; hold++) gfx_wait_vsync();
|
||||||
|
|
||||||
|
pop_sfx_tick();
|
||||||
|
pop_music_service(); /* «встреча с принцессой» — трек, а не эффект */
|
||||||
cut_torch_l = (uint8_t)((cut_torch_l + 1) % 9);
|
cut_torch_l = (uint8_t)((cut_torch_l + 1) % 9);
|
||||||
cut_torch_r = (uint8_t)((cut_torch_r + 1) % 9);
|
cut_torch_r = (uint8_t)((cut_torch_r + 1) % 9);
|
||||||
cut_sand = (uint8_t)((cut_sand + 1) % 3);
|
cut_sand = (uint8_t)((cut_sand + 1) % 3);
|
||||||
@@ -1519,8 +1522,24 @@ void pop_pre_cutscene_show(pop_pre_cutscene_t scene) __banked
|
|||||||
const pop_cs_cmd_t *script = 0;
|
const pop_cs_cmd_t *script = 0;
|
||||||
|
|
||||||
pop_sfx_pause();
|
pop_sfx_pause();
|
||||||
|
/* Музыка сцены — как в оригинале: 27 для 2/4/6/12 (seg001:401),
|
||||||
|
* 35 для 8/9 (seg001:298), 40 для короткой «времени мало» (seg001:388).
|
||||||
|
* Экран в этот момент чёрный, поэтому читаем трек целиком: пауза на
|
||||||
|
* диск здесь никому не мешает. */
|
||||||
|
{
|
||||||
|
uint8_t track = 27;
|
||||||
|
|
||||||
|
if (scene == POP_PRE_8 || scene == POP_PRE_9) track = 35;
|
||||||
|
else if (scene == POP_PRE_12_SHORT) track = 40;
|
||||||
|
if (pop_music_load(track) == 0) {
|
||||||
|
(void)pop_sfx_start();
|
||||||
|
pop_music_play();
|
||||||
|
}
|
||||||
|
}
|
||||||
if (scene == POP_PRE_2_6 || scene == POP_PRE_4 || scene == POP_PRE_12) {
|
if (scene == POP_PRE_2_6 || scene == POP_PRE_4 || scene == POP_PRE_12) {
|
||||||
if (pre_princess_animated(scene) >= 0) {
|
if (pre_princess_animated(scene) >= 0) {
|
||||||
|
pop_music_free();
|
||||||
|
pop_sfx_pause();
|
||||||
intro_restore_game_palette();
|
intro_restore_game_palette();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1530,6 +1549,8 @@ void pop_pre_cutscene_show(pop_pre_cutscene_t scene) __banked
|
|||||||
if (scene == POP_PRE_8 || scene == POP_PRE_9) {
|
if (scene == POP_PRE_8 || scene == POP_PRE_9) {
|
||||||
int done = (scene == POP_PRE_8) ? cut_scene_8() : cut_scene_9();
|
int done = (scene == POP_PRE_8) ? cut_scene_8() : cut_scene_9();
|
||||||
if (done == 0) {
|
if (done == 0) {
|
||||||
|
pop_music_free();
|
||||||
|
pop_sfx_pause();
|
||||||
intro_restore_game_palette();
|
intro_restore_game_palette();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1539,16 +1560,29 @@ void pop_pre_cutscene_show(pop_pre_cutscene_t scene) __banked
|
|||||||
else if (scene == POP_PRE_8) script = pre_8;
|
else if (scene == POP_PRE_8) script = pre_8;
|
||||||
else if (scene == POP_PRE_9) script = pre_9;
|
else if (scene == POP_PRE_9) script = pre_9;
|
||||||
else if (scene == POP_PRE_12_SHORT) script = pre_12_short;
|
else if (scene == POP_PRE_12_SHORT) script = pre_12_short;
|
||||||
if (!script) return;
|
if (!script) {
|
||||||
|
pop_music_free();
|
||||||
|
pop_sfx_pause();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
intro_run(script);
|
intro_run(script);
|
||||||
|
pop_music_free();
|
||||||
|
pop_sfx_pause();
|
||||||
intro_restore_game_palette();
|
intro_restore_game_palette();
|
||||||
}
|
}
|
||||||
|
|
||||||
void pop_time_expired_show(void) __banked
|
void pop_time_expired_show(void) __banked
|
||||||
{
|
{
|
||||||
pop_sfx_pause();
|
pop_sfx_pause();
|
||||||
|
/* time_expired (seg001:365) начинается с play_sound(sound_36). */
|
||||||
|
if (pop_music_load(36) == 0) {
|
||||||
|
(void)pop_sfx_start();
|
||||||
|
pop_music_play();
|
||||||
|
}
|
||||||
intro_run(time_expired_script);
|
intro_run(time_expired_script);
|
||||||
|
pop_music_free();
|
||||||
|
pop_sfx_pause();
|
||||||
intro_restore_game_palette();
|
intro_restore_game_palette();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -345,8 +345,7 @@ void play_seq(void)
|
|||||||
* 2 BUMP — звук 8, и шум;
|
* 2 BUMP — звук 8, и шум;
|
||||||
* 3 DRINK — звук 18, не шум;
|
* 3 DRINK — звук 18, не шум;
|
||||||
* 4 LEVEL — МУЗЫКА конца уровня (32 на 4-м, иначе 41,
|
* 4 LEVEL — МУЗЫКА конца уровня (32 на 4-м, иначе 41,
|
||||||
* на 13/15 молчок). Оцифровки у неё нет,
|
* на 13/15 молчок).
|
||||||
* это путь A на AY — пока тишина.
|
|
||||||
* Второй смысл опкода («Кид нашумел») терять нельзя даже
|
* Второй смысл опкода («Кид нашумел») терять нельзя даже
|
||||||
* без звука, см. BUG-GUARD-DEAF-1. */
|
* без звука, см. BUG-GUARD-DEAF-1. */
|
||||||
{
|
{
|
||||||
@@ -356,6 +355,13 @@ void play_seq(void)
|
|||||||
if (ev == 1) pop_sfx_play(23);
|
if (ev == 1) pop_sfx_play(23);
|
||||||
else if (ev == 2) pop_sfx_play(8);
|
else if (ev == 2) pop_sfx_play(8);
|
||||||
else if (ev == 3) pop_sfx_play(18);
|
else if (ev == 3) pop_sfx_play(18);
|
||||||
|
else if (ev == 4) {
|
||||||
|
/* seg006:646. На четвёртом уровне уход за дверь — это
|
||||||
|
* встреча с тенью, и трек там свой; на 13-м (Джафар) и
|
||||||
|
* 15-м оригинал молчит. */
|
||||||
|
if (pop_current_level == 4) pop_sfx_play(32);
|
||||||
|
else if (pop_current_level != 13) pop_sfx_play(41);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0xF1: /* END_LEVEL: seq_70 доиграл — уровень пройден.
|
case 0xF1: /* END_LEVEL: seq_70 доиграл — уровень пройден.
|
||||||
|
|||||||
@@ -1330,6 +1330,7 @@ void pop_proc_get_object(void) __banked
|
|||||||
if (Char.charid != CHARID_0_KID) return;
|
if (Char.charid != CHARID_0_KID) return;
|
||||||
if (pickup_obj_type == -1) {
|
if (pickup_obj_type == -1) {
|
||||||
pop_have_sword = 1; /* в оригинале have_sword = -1 */
|
pop_have_sword = 1; /* в оригинале have_sword = -1 */
|
||||||
|
pop_sfx_play(37); /* победный трек «меч найден» */
|
||||||
/* Вспышка фона: flash_color = color_14_brightyellow, flash_time = 8
|
/* Вспышка фона: flash_color = color_14_brightyellow, flash_time = 8
|
||||||
* (seg006 proc_get_object). do_flash = set_bg_attr(0, color) —
|
* (seg006 proc_get_object). do_flash = set_bg_attr(0, color) —
|
||||||
* оригинал подменяет НУЛЕВУЮ запись палитры, т.е. вспыхивает всё
|
* оригинал подменяет НУЛЕВУЮ запись палитры, т.е. вспыхивает всё
|
||||||
@@ -1343,12 +1344,16 @@ void pop_proc_get_object(void) __banked
|
|||||||
switch (pickup_obj_type) {
|
switch (pickup_obj_type) {
|
||||||
case 1: /* здоровье: +1 HP, красная вспышка */
|
case 1: /* здоровье: +1 HP, красная вспышка */
|
||||||
if (hitp_curr != hitp_max) {
|
if (hitp_curr != hitp_max) {
|
||||||
|
pop_sfx_stop(); /* seg006:1871 — stop_sounds */
|
||||||
|
pop_sfx_play(33);
|
||||||
hitp_delta = 1;
|
hitp_delta = 1;
|
||||||
pop_flash_color = POP_FLASH_RED;
|
pop_flash_color = POP_FLASH_RED;
|
||||||
pop_flash_time = 2;
|
pop_flash_time = 2;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 2: /* большая склянка: +1 к ПОТОЛКУ HP */
|
case 2: /* большая склянка: +1 к ПОТОЛКУ HP */
|
||||||
|
pop_sfx_stop(); /* seg006:1878 — stop_sounds */
|
||||||
|
pop_sfx_play(30);
|
||||||
pop_kid_add_life();
|
pop_kid_add_life();
|
||||||
pop_flash_color = POP_FLASH_RED;
|
pop_flash_color = POP_FLASH_RED;
|
||||||
pop_flash_time = 4; /* seg006:1878 — вспышка длиннее */
|
pop_flash_time = 4; /* seg006:1878 — вспышка длиннее */
|
||||||
@@ -1359,6 +1364,8 @@ void pop_proc_get_object(void) __banked
|
|||||||
* и играет sound_39_low_weight — по нему же меряет срок; у нас
|
* и играет sound_39_low_weight — по нему же меряет срок; у нас
|
||||||
* срок задан кадрами (POP_FEATHER_FRAMES). */
|
* срок задан кадрами (POP_FEATHER_FRAMES). */
|
||||||
pop_feather = POP_FEATHER_FRAMES;
|
pop_feather = POP_FEATHER_FRAMES;
|
||||||
|
pop_sfx_stop();
|
||||||
|
pop_sfx_play(39); /* «низкий вес» — весь эффект */
|
||||||
pop_flash_color = POP_FLASH_GREEN;
|
pop_flash_color = POP_FLASH_GREEN;
|
||||||
pop_flash_time = 3;
|
pop_flash_time = 3;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -159,6 +159,38 @@ int8_t pop_music_load(uint8_t id) __banked
|
|||||||
return (r < 0) ? -1 : 0;
|
return (r < 0) ? -1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ЗАПУСК С ПОДКАЧКОЙ НА ХОДУ — для игровых джинглов (смерть, зелья, меч).
|
||||||
|
* Ждать полной загрузки нельзя: это фриз на треть секунды посреди игры.
|
||||||
|
* Зато можно начать сразу после ПЕРВОЙ страницы: она звучит 1,5 с, а
|
||||||
|
* следующая читается 33 мс — запас сорокакратный. Дальше вызывающий
|
||||||
|
* доливает по странице за кадр (pop_music_load_step, pop_music_loading).
|
||||||
|
*
|
||||||
|
* Номера страниц известны сразу после mem_alloc_pages, поэтому таблицу для
|
||||||
|
* насоса заполняем целиком: данные в этих страницах появятся раньше, чем
|
||||||
|
* он до них доберётся.
|
||||||
|
* 0 — играет, -1 — трека нет или память кончилась. */
|
||||||
|
int8_t pop_music_stream(uint8_t id) __banked
|
||||||
|
{
|
||||||
|
uint8_t i, n;
|
||||||
|
|
||||||
|
if (pop_music_load_begin(id) != 0) return -1;
|
||||||
|
if (pop_music_load_step() < 0) return -1; /* первая страница */
|
||||||
|
n = ld_slot;
|
||||||
|
pop_mus_left = 0; /* насос — на тишину */
|
||||||
|
for (i = 0; i < ld_pages; i++)
|
||||||
|
pop_mus_page[i] = mem_get_page(slot_blk[n], i);
|
||||||
|
if (n != mus_cur) slot_release(mus_cur);
|
||||||
|
mus_cur = n;
|
||||||
|
slot_pages[n] = ld_pages;
|
||||||
|
slot_blocks[n] = pop_mus_tbl[id].blocks;
|
||||||
|
slot_id[n] = id;
|
||||||
|
pop_mus_id = id;
|
||||||
|
pop_mus_pg = 0;
|
||||||
|
pop_mus_ptr = 0;
|
||||||
|
pop_mus_left = slot_blocks[n];
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void pop_music_play(void) __banked
|
void pop_music_play(void) __banked
|
||||||
{
|
{
|
||||||
uint8_t n, i;
|
uint8_t n, i;
|
||||||
@@ -182,6 +214,21 @@ void pop_music_play(void) __banked
|
|||||||
pop_mus_left = slot_blocks[n];
|
pop_mus_left = slot_blocks[n];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void pop_music_service(void) __banked
|
||||||
|
{
|
||||||
|
/* Один вызов на кадр из ЛЮБОГО цикла — игрового, интро, катсцены.
|
||||||
|
* Заявку кладёт pop_sfx_play (звук без оцифровки = музыка оригинала),
|
||||||
|
* а диск трогаем только здесь. */
|
||||||
|
if (pop_mus_req) {
|
||||||
|
uint8_t id = pop_mus_req;
|
||||||
|
|
||||||
|
pop_mus_req = 0;
|
||||||
|
(void)pop_music_stream(id);
|
||||||
|
} else if (ld_busy) {
|
||||||
|
(void)pop_music_load_step();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t pop_music_busy(void) __banked
|
uint8_t pop_music_busy(void) __banked
|
||||||
{
|
{
|
||||||
return (uint8_t)(pop_mus_left != 0);
|
return (uint8_t)(pop_mus_left != 0);
|
||||||
|
|||||||
@@ -72,11 +72,22 @@ uint8_t pop_music_loading(void) __banked;
|
|||||||
/* Отпустить ОБА слота. Останавливает проигрывание, если оно шло. */
|
/* Отпустить ОБА слота. Останавливает проигрывание, если оно шло. */
|
||||||
void pop_music_free(void) __banked;
|
void pop_music_free(void) __banked;
|
||||||
|
|
||||||
|
/* Пустить трек СРАЗУ, дочитывая его по ходу звучания: первая страница
|
||||||
|
* читается здесь (33 мс), остальные — вызывающим, по одной за кадр, пока
|
||||||
|
* pop_music_loading(). Для игровых джинглов, где паузы на диск быть не
|
||||||
|
* может. 0 — играет, -1 — трека нет либо не хватило памяти. */
|
||||||
|
int8_t pop_music_stream(uint8_t id) __banked;
|
||||||
|
|
||||||
/* Пустить последний загруженный трек с начала; слот предыдущего при этом
|
/* Пустить последний загруженный трек с начала; слот предыдущего при этом
|
||||||
* освобождается. Без парного load ничего не делает. */
|
* освобождается. Без парного load ничего не делает. */
|
||||||
void pop_music_play(void) __banked;
|
void pop_music_play(void) __banked;
|
||||||
void pop_music_stop(void) __banked;
|
void pop_music_stop(void) __banked;
|
||||||
|
|
||||||
|
/* ОБСЛУЖИВАНИЕ МУЗЫКИ — один вызов на кадр из любого цикла (игра, интро,
|
||||||
|
* катсцена): разбирает заявку pop_mus_req и доливает страницы начатого
|
||||||
|
* стрима. Всё чтение с диска живёт здесь. */
|
||||||
|
void pop_music_service(void) __banked;
|
||||||
|
|
||||||
/* Трек ещё звучит? 0 — доиграл или не запускался. */
|
/* Трек ещё звучит? 0 — доиграл или не запускался. */
|
||||||
uint8_t pop_music_busy(void) __banked;
|
uint8_t pop_music_busy(void) __banked;
|
||||||
|
|
||||||
|
|||||||
@@ -46,26 +46,26 @@ static const pop_mus_ent_t pop_mus_tbl[POP_MUS_COUNT] = {
|
|||||||
{ 0, 0 }, /* 21 */
|
{ 0, 0 }, /* 21 */
|
||||||
{ 0, 0 }, /* 22 */
|
{ 0, 0 }, /* 22 */
|
||||||
{ 0, 0 }, /* 23 */
|
{ 0, 0 }, /* 23 */
|
||||||
{ 0, 0 }, /* 24 */
|
{ 3, 305 }, /* 24 regular_death */
|
||||||
{ 0, 0 }, /* 25 */
|
{ 2, 196 }, /* 25 find_mirror_and_find_shadow */
|
||||||
{ 0, 0 }, /* 26 */
|
{ 9, 1132 }, /* 26 embrace */
|
||||||
{ 0, 0 }, /* 27 */
|
{ 8, 915 }, /* 27 cutscene_before_2_4_6_12 */
|
||||||
{ 0, 0 }, /* 28 */
|
{ 6, 656 }, /* 28 fight_death */
|
||||||
{ 0, 0 }, /* 29 */
|
{ 4, 428 }, /* 29 meet_Jaffar */
|
||||||
{ 0, 0 }, /* 30 */
|
{ 3, 299 }, /* 30 life_potion */
|
||||||
{ 0, 0 }, /* 31 */
|
{ 0, 0 }, /* 31 */
|
||||||
{ 0, 0 }, /* 32 */
|
{ 5, 624 }, /* 32 end_level_4_and_killed_by_shadow */
|
||||||
{ 0, 0 }, /* 33 */
|
{ 2, 205 }, /* 33 potion */
|
||||||
{ 0, 0 }, /* 34 */
|
{ 0, 0 }, /* 34 */
|
||||||
{ 0, 0 }, /* 35 */
|
{ 7, 888 }, /* 35 cutscene_before_8_9 */
|
||||||
{ 0, 0 }, /* 36 */
|
{ 10, 1256 }, /* 36 out_of_time */
|
||||||
{ 0, 0 }, /* 37 */
|
{ 3, 280 }, /* 37 guard_death_and_obtaining_the_sword */
|
||||||
{ 0, 0 }, /* 38 */
|
{ 0, 0 }, /* 38 */
|
||||||
{ 0, 0 }, /* 39 */
|
{ 13, 1591 }, /* 39 floating */
|
||||||
{ 0, 0 }, /* 40 */
|
{ 5, 596 }, /* 40 cutscene_not_much_time_left */
|
||||||
{ 0, 0 }, /* 41 */
|
{ 9, 1043 }, /* 41 story_5_level_end_and_merge_with_shadow */
|
||||||
{ 0, 0 }, /* 42 */
|
{ 0, 0 }, /* 42 */
|
||||||
{ 0, 0 }, /* 43 */
|
{ 3, 285 }, /* 43 killed_Jaffar */
|
||||||
{ 0, 0 }, /* 44 */
|
{ 0, 0 }, /* 44 */
|
||||||
{ 0, 0 }, /* 45 */
|
{ 0, 0 }, /* 45 */
|
||||||
{ 0, 0 }, /* 46 */
|
{ 0, 0 }, /* 46 */
|
||||||
|
|||||||
@@ -55,6 +55,10 @@ uint8_t pop_mus_id;
|
|||||||
/* Тик насоса: +1 на каждый отданный CBL блок, то есть 85,4 Гц. */
|
/* Тик насоса: +1 на каждый отданный CBL блок, то есть 85,4 Гц. */
|
||||||
volatile uint8_t pop_snd_tick;
|
volatile uint8_t pop_snd_tick;
|
||||||
|
|
||||||
|
/* Заявка на музыкальный трек: номер в нумерации оригинала, 0 — нет заявки
|
||||||
|
* (нулевого трека не бывает). Ставит pop_sfx_play, снимает главный цикл. */
|
||||||
|
uint8_t pop_mus_req;
|
||||||
|
|
||||||
static volatile uint8_t sfx_pg; /* индекс в pop_snd_page[] */
|
static volatile uint8_t sfx_pg; /* индекс в pop_snd_page[] */
|
||||||
static volatile uint16_t sfx_ptr; /* адрес в окне W0: 0x0000..0x3FFF */
|
static volatile uint16_t sfx_ptr; /* адрес в окне W0: 0x0000..0x3FFF */
|
||||||
static volatile uint16_t sfx_left; /* сколько байт осталось (кратно 128) */
|
static volatile uint16_t sfx_left; /* сколько байт осталось (кратно 128) */
|
||||||
@@ -225,10 +229,17 @@ static uint8_t snd_interruptible(uint8_t id)
|
|||||||
void pop_sfx_play(uint8_t id)
|
void pop_sfx_play(uint8_t id)
|
||||||
{
|
{
|
||||||
if (!pop_snd_ok || id >= POP_SND_COUNT) return;
|
if (!pop_snd_ok || id >= POP_SND_COUNT) return;
|
||||||
/* Нет оцифровки (музыка) — не номинируем вовсе: порт проверки
|
/* НЕТ ОЦИФРОВКИ — ЗНАЧИТ ЭТО МУЗЫКА. В оригинале звуки 24..43 играет
|
||||||
* `if (NULL == sound_pointers[id]) return;`. Иначе музыкальный id
|
* Adlib по MIDI, и в digisnd их нет вовсе; у нас на их месте записи
|
||||||
* выигрывал бы конкурс и глушил живой эффект. */
|
* DOS-версии, которые надо читать с диска. В прерывании и в горячем
|
||||||
if (pop_snd_tbl[id].len == 0) return;
|
* коде этого делать нельзя, поэтому здесь только ЗАЯВКА одним байтом —
|
||||||
|
* её разбирает главный цикл (pop_music_stream, банк 9).
|
||||||
|
* В конкурсе эффектов такой id не участвует: он не глушит живой звук
|
||||||
|
* (порт проверки `if (NULL == sound_pointers[id]) return;`). */
|
||||||
|
if (pop_snd_tbl[id].len == 0) {
|
||||||
|
pop_mus_req = id;
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!snd_next1 || snd_prio[id] <= snd_prio[snd_next1 - 1])
|
if (!snd_next1 || snd_prio[id] <= snd_prio[snd_next1 - 1])
|
||||||
snd_next1 = (uint8_t)(id + 1);
|
snd_next1 = (uint8_t)(id + 1);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,6 +59,12 @@ extern uint8_t pop_snd_want;
|
|||||||
* запасной путь по кадрам луча. */
|
* запасной путь по кадрам луча. */
|
||||||
extern volatile uint8_t pop_snd_tick;
|
extern volatile uint8_t pop_snd_tick;
|
||||||
|
|
||||||
|
/* ЗАЯВКА НА МУЗЫКУ. pop_sfx_play(id) для звука без оцифровки (24..43 —
|
||||||
|
* в оригинале это Adlib-музыка) кладёт сюда номер трека, а разбирает
|
||||||
|
* заявку главный цикл: чтение с диска ни в прерывании, ни в горячем коде
|
||||||
|
* недопустимо. 0 — заявки нет. Снимать обязан тот, кто обработал. */
|
||||||
|
extern uint8_t pop_mus_req;
|
||||||
|
|
||||||
/* Заявить эффект с номером id (0..56 — нумерация оригинала, см.
|
/* Заявить эффект с номером id (0..56 — нумерация оригинала, см.
|
||||||
* sound_plan.md). НЕ запускает его немедленно и НЕ перебивает играющий:
|
* sound_plan.md). НЕ запускает его немедленно и НЕ перебивает играющий:
|
||||||
* это порт play_sound (seg000:12C5), который лишь НОМИНИРУЕТ кандидата на
|
* это порт play_sound (seg000:12C5), который лишь НОМИНИРУЕТ кандидата на
|
||||||
|
|||||||
@@ -18,7 +18,8 @@
|
|||||||
#include "pop_trob.h"
|
#include "pop_trob.h"
|
||||||
#include "pop_redraw.h"
|
#include "pop_redraw.h"
|
||||||
#include "pop_geom.h" /* pop_y_to_row, TILE_SIZEX — тайл объекта */
|
#include "pop_geom.h" /* pop_y_to_row, TILE_SIZEX — тайл объекта */
|
||||||
#include "pop_sfx.h" /* pop_sfx_tick — решение о запуске звука за кадр */
|
#include "pop_sfx.h"
|
||||||
|
#include "pop_music.h" /* pop_sfx_tick — решение о запуске звука за кадр */
|
||||||
#include "pop_guard.h"
|
#include "pop_guard.h"
|
||||||
#include "pop_cdraw.h" /* общая отрисовка персонажей (слоты Кид/соперник) */
|
#include "pop_cdraw.h" /* общая отрисовка персонажей (слоты Кид/соперник) */
|
||||||
#include "pop_cheat.h"
|
#include "pop_cheat.h"
|
||||||
@@ -995,6 +996,11 @@ int main(void)
|
|||||||
* кадра, seg000:954: все заявки кадра уже поданы, и из них выбирается
|
* кадра, seg000:954: все заявки кадра уже поданы, и из них выбирается
|
||||||
* важнейшая. Раньше по кадру нельзя — потеряются поздние заявки. */
|
* важнейшая. Раньше по кадру нельзя — потеряются поздние заявки. */
|
||||||
pop_sfx_tick();
|
pop_sfx_tick();
|
||||||
|
/* МУЗЫКА ПО ХОДУ ИГРЫ. Заявку положил pop_sfx_play (звук без
|
||||||
|
* оцифровки — это Adlib-трек оригинала), а диск трогаем здесь:
|
||||||
|
* первая страница читается сразу и трек уже звучит, остальные
|
||||||
|
* доливаются по одной за кадр — 33 мс на кадр, пока догоняем. */
|
||||||
|
pop_music_service();
|
||||||
|
|
||||||
/* Обе служебные полосы — нижняя статус-строка (сообщения оригинала)
|
/* Обе служебные полосы — нижняя статус-строка (сообщения оригинала)
|
||||||
* и верхняя отладочная. Всё change-driven и целиком в банке 9,
|
* и верхняя отладочная. Всё change-driven и целиком в банке 9,
|
||||||
|
|||||||
@@ -94,6 +94,7 @@ void pop_start_level(void) __banked
|
|||||||
int8_t dir;
|
int8_t dir;
|
||||||
|
|
||||||
pop_leveldoor_open = 0; /* seg003:97 — дверь прошлого уровня не в счёт */
|
pop_leveldoor_open = 0; /* seg003:97 — дверь прошлого уровня не в счёт */
|
||||||
|
pop_music_level_start(); /* одноразовые темы уровня — заново */
|
||||||
pop_feather = 0; /* seg003:189 — перо не переживает старт уровня */
|
pop_feather = 0; /* seg003:189 — перо не переживает старт уровня */
|
||||||
/* upside_down тоже сбрасывается стартом уровня (seg003:38/188). Если
|
/* upside_down тоже сбрасывается стартом уровня (seg003:38/188). Если
|
||||||
* картинка была перевёрнута, отрисовка комнаты ниже уже пойдёт обычной
|
* картинка была перевёрнута, отрисовка комнаты ниже уже пойдёт обычной
|
||||||
|
|||||||
Reference in New Issue
Block a user