Ctrl+S — вкл/выкл звук; чит «выдать меч» убран
Порт Ctrl+S из SDLPoP (seg000:657). Выключение реально закрывает CBL, а не глушит сэмпл: иначе насос продолжал бы отдавать блоки тишины и платить те же 3,26 % процессорного времени. Флаг намерения pop_snd_want отдельно от pop_snd_ok: последний гасит служебная пауза на время загрузки уровня, и правь Ctrl+S только его — первая же смена уровня вернула бы выключенный звук. Индикация: пурпурная палочка в борте, когда звука НЕТ (включённый слышно и так, а молчание неотличимо от «нечему звучать»). Чит S «выдать меч» был отладочным и больше не нужен — снят, клавиша ушла под звук. Замер цены звука — sound_plan.md §9: 8 001 такт на прерывание при периоде 245 759 (3,26 % времени), +2,2 % к работе кадра в сцене 11/15, период кадра не сдвинулся ни разу. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -383,3 +383,73 @@ IBM PC 1989 года: один квадратный голос. Он у нас
|
|||||||
DOS-версией; у нас последовательности разведены по доменам
|
DOS-версией; у нас последовательности разведены по доменам
|
||||||
(`impl_diff.md`), поэтому у тряски свой сид, а холостой бросок не делаем —
|
(`impl_diff.md`), поэтому у тряски свой сид, а холостой бросок не делаем —
|
||||||
на розыгрыши физики и кладки это не влияет.
|
на розыгрыши физики и кладки это не влияет.
|
||||||
|
|
||||||
|
## 9. Цена звука в тактах (замер 2026-08-20, MAME)
|
||||||
|
|
||||||
|
Вопрос был поставлен так: звук идёт по прерываниям, значит размазан по всем
|
||||||
|
фазам кадра — и если фазы укладываются, всё хорошо? Да, но проверять это
|
||||||
|
надо не по фазам, а по двум числам, потому что **нагрузка от звука
|
||||||
|
постоянная и от сцены не зависит вовсе**.
|
||||||
|
|
||||||
|
### 9.1 Одно прерывание CBL
|
||||||
|
|
||||||
|
Зонды: `bpset` на входе трамплина (`_irq_tramp`) и на `reti` ветки CBL,
|
||||||
|
разница `totalcycles`. 398 замеров в сцене 11/15.
|
||||||
|
|
||||||
|
| величина | значение |
|
||||||
|
|---|---:|
|
||||||
|
| цена одного прерывания | **7 825 тактов ровно**, с разбросом до 8 299 (среднее 8 001) |
|
||||||
|
| период между прерываниями | 245 759 тактов (= 128 сэмплов на 10 937,5 Гц) |
|
||||||
|
| **доля процессорного времени** | **8 001 / 245 759 = 3,26 %** |
|
||||||
|
|
||||||
|
Цена постоянная, потому что работа фиксированная: OTIR ровно 128 байт плюс
|
||||||
|
скобка сохранения контекста. Ветвлений по данным в насосе нет.
|
||||||
|
|
||||||
|
### 9.2 Дрожание обслуживания — риск для ЗВУКА, не для кадра
|
||||||
|
|
||||||
|
Период плавает 228 804 … 262 734, то есть прерывание опаздывает максимум на
|
||||||
|
**~17 000 тактов = 0,8 мс**. Это самая длинная DI-скобка в коде
|
||||||
|
(акселератор режется по 16 строк, memory `sprinter_wait_states_2x`).
|
||||||
|
Буфер CBL — 128 сэмплов = **11,7 мс**, запас **14×**. Недолива быть не
|
||||||
|
может; счётчик `cbl_underruns()` это подтверждает косвенно (наш `fill`
|
||||||
|
всегда возвращает 1, поэтому он ловит только отсутствие данных, не
|
||||||
|
опоздание).
|
||||||
|
|
||||||
|
### 9.3 A/B в одном прогоне (Ctrl+S), сцена 11/15
|
||||||
|
|
||||||
|
Один и тот же кадр, звук выключается на ходу — сравнение чистое.
|
||||||
|
|
||||||
|
| | работа min | работа max | работа avg | прерываний CBL на кадр |
|
||||||
|
|---|---:|---:|---:|---:|
|
||||||
|
| звук ВКЛ | 453 132 | 572 532 | **498 064** | 1,40 |
|
||||||
|
| звук ВЫКЛ | 444 348 | 559 434 | **487 372** | 0,00 |
|
||||||
|
| разница | +8 784 | +13 098 | **+10 692 (+2,2 %)** | |
|
||||||
|
|
||||||
|
Разница на лёгком кадре (+8 784) — ровно одно прерывание, сходится с §9.1.
|
||||||
|
`CBL/кадр = 0` при выключенном звуке подтверждает, что Ctrl+S реально
|
||||||
|
ЗАКРЫВАЕТ CBL, а не глушит сэмпл: иначе насос продолжал бы отдавать блоки
|
||||||
|
тишины и платить те же 3,26 %.
|
||||||
|
|
||||||
|
### 9.4 Укладываемся ли
|
||||||
|
|
||||||
|
Логический кадр (`pop_pace.h`): NORMAL = 4 растра вне боя = **1 720 000
|
||||||
|
тактов**, FASTEST = 3 растра = **1 290 000**.
|
||||||
|
|
||||||
|
| | работа | доля NORMAL | доля FASTEST |
|
||||||
|
|---|---:|---:|---:|
|
||||||
|
| 11/15, обычная позиция | 498 064 | 29 % | 39 % |
|
||||||
|
| 11/15, тяжёлая позиция (Кид на 7 px правее) | 750 066 макс | 44 % | 58 % |
|
||||||
|
|
||||||
|
Период кадра за все прогоны: 1 719 936 … 1 720 752 — ровно 4 растра, ни
|
||||||
|
одного проскока. **Звук занимает 1,1 % бюджета NORMAL и 1,5 % FASTEST.**
|
||||||
|
|
||||||
|
### 9.5 Где 3,26 % МОГЛИ БЫ стоить дорого
|
||||||
|
|
||||||
|
Ответ «всё размазано, если фазы влезли — ок» верен с одной оговоркой.
|
||||||
|
Пейсинг квантован растром: работа 1,00 растра и 1,02 растра дают РАЗНЫЙ
|
||||||
|
период кадра (3 против 4 интервалов), то есть скачок сразу на 20 мс.
|
||||||
|
Значит звук опасен ровно в одной ситуации — когда сцена стоит в пределах
|
||||||
|
~8 000 тактов НИЖЕ кратного растру порога. Сейчас ближайший запас — 540 000
|
||||||
|
тактов до порога FASTEST, то есть в 60 раз больше цены звука. Проверять
|
||||||
|
эту оговорку заново стоит только если работа кадра подберётся к 430 000 или
|
||||||
|
860 000 вплотную.
|
||||||
|
|||||||
@@ -60,8 +60,9 @@ Kid — `kid_data.h` (генерится `pop_extract_kid_data.py`).
|
|||||||
дабл-буфер (в однобуфере видно баги рисования без мерцания-через-кадр);
|
дабл-буфер (в однобуфере видно баги рисования без мерцания-через-кадр);
|
||||||
**1** — заморозить кадр, **2** — продолжить (разбор позы/окклюзии);
|
**1** — заморозить кадр, **2** — продолжить (разбор позы/окклюзии);
|
||||||
**ESC** — выход. Читы (`pop_cheat.h`): **K** — убить стража, **I** —
|
**ESC** — выход. Читы (`pop_cheat.h`): **K** — убить стража, **I** —
|
||||||
бессмертие, **S** — выдать меч, **Shift+L** — следующий уровень,
|
бессмертие, **Shift+L** — следующий уровень,
|
||||||
**+/−** — обход комнат (`ROOMNAV`). Уровень грузится по номеру
|
**+/−** — обход комнат (`ROOMNAV`). Не чит, а штатная клавиша оригинала:
|
||||||
|
**Ctrl+S** — вкл/выкл звук (пурпурная палочка в борте = звука нет). Уровень грузится по номеру
|
||||||
(`pop_level_load_num`), на диске лежат все 15.
|
(`pop_level_load_num`), на диске лежат все 15.
|
||||||
|
|
||||||
## Модули
|
## Модули
|
||||||
|
|||||||
@@ -22,7 +22,9 @@ extern uint8_t pop_cheats; /* 0 = выключены, иначе включ
|
|||||||
#define KBD_CHEAT_IMMO 0x43 /* I (PS/2 set 2) — бессмертие Кида по кругу
|
#define KBD_CHEAT_IMMO 0x43 /* I (PS/2 set 2) — бессмертие Кида по кругу
|
||||||
* 0 -> 1 (только бой) -> 2 (и мелкий урон) -> 0;
|
* 0 -> 1 (только бой) -> 2 (и мелкий урон) -> 0;
|
||||||
* уровни расписаны в pop_state.h */
|
* уровни расписаны в pop_state.h */
|
||||||
#define KBD_CHEAT_SWORD 0x1B /* S (PS/2 set 2) — выдать Киду меч */
|
/* Ctrl+S (PS/2 set 2: S = 0x1B) — вкл/выкл звук; порт Ctrl+S из SDLPoP
|
||||||
|
* (seg000:657). С Ctrl, а не голая S: у оригинала клавиша именно такая. */
|
||||||
|
#define KBD_SOUND_TOGGLE 0x1B
|
||||||
#define KBD_CHEAT_NEXTLVL 0x4B /* Shift+L (PS/2 set 2) — следующий уровень */
|
#define KBD_CHEAT_NEXTLVL 0x4B /* Shift+L (PS/2 set 2) — следующий уровень */
|
||||||
#define KBD_CHEAT_XDEC 0x54 /* [ (PS/2 set 2) — сдвинуть Кида на 1 px влево */
|
#define KBD_CHEAT_XDEC 0x54 /* [ (PS/2 set 2) — сдвинуть Кида на 1 px влево */
|
||||||
#define KBD_CHEAT_XINC 0x5B /* ] (PS/2 set 2) — сдвинуть Кида на 1 px вправо */
|
#define KBD_CHEAT_XINC 0x5B /* ] (PS/2 set 2) — сдвинуть Кида на 1 px вправо */
|
||||||
|
|||||||
@@ -28,6 +28,18 @@
|
|||||||
uint8_t pop_snd_page[POP_SND_PAGES];
|
uint8_t pop_snd_page[POP_SND_PAGES];
|
||||||
uint8_t pop_snd_ok;
|
uint8_t pop_snd_ok;
|
||||||
|
|
||||||
|
/* ХОЧЕТ ЛИ ЗВУКА ПОЛЬЗОВАТЕЛЬ (Ctrl+S) — отдельно от pop_snd_ok.
|
||||||
|
*
|
||||||
|
* Разделять обязательно: pop_snd_ok значит «CBL сейчас открыт», и его
|
||||||
|
* гасит служебная пауза на время загрузки уровня. Если бы Ctrl+S правил
|
||||||
|
* только его, то первая же смена уровня позвала бы pop_sfx_start() и
|
||||||
|
* вернула звук, который пользователь выключил. Поэтому start уважает
|
||||||
|
* этот флаг, а pause его не трогает.
|
||||||
|
*
|
||||||
|
* Живёт в резиденте, а не в банке: метку в борте рисует отладочный ярлык
|
||||||
|
* каждый кадр, и тащить ради одного байта трамплин незачем. */
|
||||||
|
uint8_t pop_snd_want;
|
||||||
|
|
||||||
/* Курсор проигрывания. volatile: пишет главный цикл, читает прерывание.
|
/* Курсор проигрывания. volatile: пишет главный цикл, читает прерывание.
|
||||||
* Всё в 8/16 бит — 32-битной арифметики на Z80 избегаем (см. memory
|
* Всё в 8/16 бит — 32-битной арифметики на Z80 избегаем (см. memory
|
||||||
* avoid_32bit_arith_z80); поэтому и в таблице смещение уже разобрано на
|
* avoid_32bit_arith_z80); поэтому и в таблице смещение уже разобрано на
|
||||||
|
|||||||
@@ -38,6 +38,17 @@ void pop_sfx_pause(void) __banked;
|
|||||||
/* Закрыть CBL и отпустить страницы; звать на выходе. */
|
/* Закрыть CBL и отпустить страницы; звать на выходе. */
|
||||||
void pop_sfx_close(void) __banked;
|
void pop_sfx_close(void) __banked;
|
||||||
|
|
||||||
|
/* Вкл/выкл звук по воле пользователя (Ctrl+S, порт SDLPoP seg000:657).
|
||||||
|
* Правит pop_snd_want и приводит вывод в соответствие. */
|
||||||
|
void pop_sfx_toggle(void) __banked;
|
||||||
|
|
||||||
|
/* ХОЧЕТ ЛИ ЗВУКА ПОЛЬЗОВАТЕЛЬ. Не то же самое, что «CBL открыт»: вывод
|
||||||
|
* ещё гасит служебная пауза на время загрузки уровня. Читать для
|
||||||
|
* индикации; писать — только через pop_sfx_toggle. 0 и в случае, когда
|
||||||
|
* набор вообще не поднялся (нет файлов, нет страниц) — то есть флаг
|
||||||
|
* честно means «звука не будет». */
|
||||||
|
extern uint8_t pop_snd_want;
|
||||||
|
|
||||||
/* Начать эффект с номером id (0..56 — нумерация оригинала, см.
|
/* Начать эффект с номером id (0..56 — нумерация оригинала, см.
|
||||||
* sound_plan.md). Перебивает играющий. У звуков без оцифровки (это
|
* sound_plan.md). Перебивает играющий. У звуков без оцифровки (это
|
||||||
* музыка) длина 0 — вызов просто глушит текущий.
|
* музыка) длина 0 — вызов просто глушит текущий.
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ int pop_sfx_init(void) __banked
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
snd_blk = blk;
|
snd_blk = blk;
|
||||||
|
pop_snd_want = 1; /* набор есть — звук по умолчанию включён */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,8 +53,9 @@ int pop_sfx_init(void) __banked
|
|||||||
* резиденте W2 тесная, и её отказ ронял бы весь звук. */
|
* резиденте W2 тесная, и её отказ ронял бы весь звук. */
|
||||||
int pop_sfx_start(void) __banked
|
int pop_sfx_start(void) __banked
|
||||||
{
|
{
|
||||||
if (pop_snd_ok) return 0;
|
if (pop_snd_ok) return 0;
|
||||||
if (!snd_blk) return -1; /* набор не загружен */
|
if (!pop_snd_want) return 0; /* выключено пользователем (Ctrl+S) */
|
||||||
|
if (!snd_blk) return -1; /* набор не загружен */
|
||||||
if (cbl_open(CBL_FREQ_10K9, CBL_FMT_MONO8, CBL_PUMP_OTIR,
|
if (cbl_open(CBL_FREQ_10K9, CBL_FMT_MONO8, CBL_PUMP_OTIR,
|
||||||
CBL_UNDERRUN_APP, pop_sfx_fill) != 0)
|
CBL_UNDERRUN_APP, pop_sfx_fill) != 0)
|
||||||
return -1;
|
return -1;
|
||||||
@@ -74,3 +76,22 @@ void pop_sfx_close(void) __banked
|
|||||||
pop_sfx_pause();
|
pop_sfx_pause();
|
||||||
if (snd_blk) { mem_free_block(snd_blk); snd_blk = 0; }
|
if (snd_blk) { mem_free_block(snd_blk); snd_blk = 0; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Ctrl+S — порт `turn_sound_on_off((!is_sound_on) * 15)` из SDLPoP
|
||||||
|
* (seg000:657). Выключение реально ЗАКРЫВАЕТ CBL, а не глушит сэмпл:
|
||||||
|
* иначе насос продолжал бы отдавать блоки тишины 85 раз в секунду, а это
|
||||||
|
* 3,3 % процессорного времени ни за что (замер: 8 001 такт на прерывание
|
||||||
|
* при периоде 245 759). Открытие обратно дешёвое — cbl_open только
|
||||||
|
* настраивает железо, страницы набора никуда не девались. */
|
||||||
|
void pop_sfx_toggle(void) __banked
|
||||||
|
{
|
||||||
|
if (pop_snd_want) {
|
||||||
|
pop_sfx_pause(); /* pause сам не трогает want... */
|
||||||
|
pop_snd_want = 0; /* ...поэтому гасим его следом */
|
||||||
|
} else {
|
||||||
|
pop_snd_want = 1;
|
||||||
|
/* Набора может не быть вовсе (файлы не прочитались, страницы не
|
||||||
|
* дались) — тогда откатываем флаг, чтобы индикация не врала. */
|
||||||
|
if (pop_sfx_start() != 0) pop_snd_want = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -318,7 +318,7 @@ uint8_t pop_dbg_roomnav(uint8_t dir) __banked
|
|||||||
* Флаги «фронта» стали статиками модуля — раньше они были локалями main.
|
* Флаги «фронта» стали статиками модуля — раньше они были локалями main.
|
||||||
* Смысл прежний: одно нажатие = одно срабатывание.
|
* Смысл прежний: одно нажатие = одно срабатывание.
|
||||||
*/
|
*/
|
||||||
static uint8_t cheat_prev, immo_prev, sword_prev, nlvl_prev;
|
static uint8_t cheat_prev, immo_prev, sound_prev, nlvl_prev;
|
||||||
static uint8_t upsd_prev, xdec_prev, xinc_prev;
|
static uint8_t upsd_prev, xdec_prev, xinc_prev;
|
||||||
|
|
||||||
void pop_cheat_tick(void) __banked
|
void pop_cheat_tick(void) __banked
|
||||||
@@ -328,8 +328,10 @@ void pop_cheat_tick(void) __banked
|
|||||||
* K — убить стража;
|
* K — убить стража;
|
||||||
* I — бессмертие Кида (наш отладочный, в оригинале его нет:
|
* I — бессмертие Кида (наш отладочный, в оригинале его нет:
|
||||||
* иначе боёвку проверять получается ровно три раза);
|
* иначе боёвку проверять получается ровно три раза);
|
||||||
* S — выдать меч, не бегая за ним в комнату 15. Штатно меч
|
* Ctrl+S — вкл/выкл звук (порт Ctrl+S из SDLPoP, seg000:657).
|
||||||
* берётся с пола (pop_have_sword ставит подбор);
|
* НЕ чит: работает и без pop_cheats, как в оригинале.
|
||||||
|
* Ctrl обязателен — голая S у нас свободна, но менять
|
||||||
|
* пользовательскую раскладку оригинала незачем;
|
||||||
* Shift+L — следующий уровень (seg000:698, ветка next_level =
|
* Shift+L — следующий уровень (seg000:698, ветка next_level =
|
||||||
* current_level + 1). Единственный вменяемый способ
|
* current_level + 1). Единственный вменяемый способ
|
||||||
* тестировать уровни 2..15. NB: L без Shift — отладочный
|
* тестировать уровни 2..15. NB: L без Shift — отладочный
|
||||||
@@ -346,7 +348,8 @@ void pop_cheat_tick(void) __banked
|
|||||||
* следующего кадра. */
|
* следующего кадра. */
|
||||||
uint8_t k = kbd_raw_down(KBD_CHEAT_KILL);
|
uint8_t k = kbd_raw_down(KBD_CHEAT_KILL);
|
||||||
uint8_t i = kbd_raw_down(KBD_CHEAT_IMMO);
|
uint8_t i = kbd_raw_down(KBD_CHEAT_IMMO);
|
||||||
uint8_t s = kbd_raw_down(KBD_CHEAT_SWORD);
|
uint8_t s = (uint8_t)(kbd_raw_down(KBD_SOUND_TOGGLE) &&
|
||||||
|
(kbd_raw_down(KBD_LCTRL) || kbd_raw_down(KBD_RCTRL)));
|
||||||
uint8_t nl = (uint8_t)(kbd_raw_down(KBD_CHEAT_NEXTLVL) &&
|
uint8_t nl = (uint8_t)(kbd_raw_down(KBD_CHEAT_NEXTLVL) &&
|
||||||
(kbd_raw_down(KBD_LSHIFT) || kbd_raw_down(KBD_RSHIFT)));
|
(kbd_raw_down(KBD_LSHIFT) || kbd_raw_down(KBD_RSHIFT)));
|
||||||
uint8_t up = kbd_raw_down(KBD_CHEAT_UPSIDE);
|
uint8_t up = kbd_raw_down(KBD_CHEAT_UPSIDE);
|
||||||
@@ -357,7 +360,7 @@ void pop_cheat_tick(void) __banked
|
|||||||
* мелкий урон» -> 0. Что означают уровни — pop_state.h. */
|
* мелкий урон» -> 0. Что означают уровни — pop_state.h. */
|
||||||
if (pop_cheats && i && !immo_prev)
|
if (pop_cheats && i && !immo_prev)
|
||||||
pop_immortal = (uint8_t)(pop_immortal >= 2 ? 0 : pop_immortal + 1);
|
pop_immortal = (uint8_t)(pop_immortal >= 2 ? 0 : pop_immortal + 1);
|
||||||
if (pop_cheats && s && !sword_prev) pop_have_sword = 1;
|
if (s && !sound_prev) pop_sfx_toggle(); /* не под pop_cheats */
|
||||||
if (pop_cheats && nl && !nlvl_prev && pop_current_level < POP_LAST_LEVEL)
|
if (pop_cheats && nl && !nlvl_prev && pop_current_level < POP_LAST_LEVEL)
|
||||||
pop_next_level = (uint8_t)(pop_current_level + 1);
|
pop_next_level = (uint8_t)(pop_current_level + 1);
|
||||||
/* U — переворот экрана (seg000:0793 — чит и в оригинале).
|
/* U — переворот экрана (seg000:0793 — чит и в оригинале).
|
||||||
@@ -370,7 +373,7 @@ void pop_cheat_tick(void) __banked
|
|||||||
if (pop_cheats && xi && !xinc_prev) Kid.x = (uint8_t)(Kid.x + 1);
|
if (pop_cheats && xi && !xinc_prev) Kid.x = (uint8_t)(Kid.x + 1);
|
||||||
cheat_prev = k;
|
cheat_prev = k;
|
||||||
immo_prev = i;
|
immo_prev = i;
|
||||||
sword_prev = s;
|
sound_prev = s;
|
||||||
nlvl_prev = nl;
|
nlvl_prev = nl;
|
||||||
upsd_prev = up;
|
upsd_prev = up;
|
||||||
xdec_prev = xd;
|
xdec_prev = xd;
|
||||||
@@ -388,6 +391,11 @@ void pop_cheat_tick(void) __banked
|
|||||||
* белый x 100..175 комната (1..24)
|
* белый x 100..175 комната (1..24)
|
||||||
* голубой x 190..205 скорость (1 палочка NORMAL, 2 FAST, 3 FASTEST)
|
* голубой x 190..205 скорость (1 палочка NORMAL, 2 FAST, 3 FASTEST)
|
||||||
* красный x 220..230 бессмертие (1 палочка = только бой, 2 = и мелкий урон)
|
* красный x 220..230 бессмертие (1 палочка = только бой, 2 = и мелкий урон)
|
||||||
|
* пурпурный x 245 звук ВЫКЛЮЧЕН (Ctrl+S) либо не поднялся вовсе
|
||||||
|
|
||||||
|
* Звук показан «от противного» — палочка есть, когда звука НЕТ. Иначе
|
||||||
|
* индикатор ничего не сообщает: включённый звук слышно и так, а вот
|
||||||
|
* молчание неотличимо от «в этот момент нечему звучать».
|
||||||
*
|
*
|
||||||
* ЦВЕТА — индексы ИГРОВОЙ палитры, и выбраны они не по вкусу, а по двум
|
* ЦВЕТА — индексы ИГРОВОЙ палитры, и выбраны они не по вкусу, а по двум
|
||||||
* ограничениям.
|
* ограничениям.
|
||||||
@@ -413,6 +421,7 @@ static uint8_t room_label_sig = 0xFF; /* последняя показанна
|
|||||||
static uint8_t lvl_label_sig = 0xFF; /* ...уровень */
|
static uint8_t lvl_label_sig = 0xFF; /* ...уровень */
|
||||||
static uint8_t spd_label_sig = 0xFF; /* ...режим скорости */
|
static uint8_t spd_label_sig = 0xFF; /* ...режим скорости */
|
||||||
static uint8_t imm_label_sig = 0xFF; /* ...бессмертие */
|
static uint8_t imm_label_sig = 0xFF; /* ...бессмертие */
|
||||||
|
static uint8_t snd_label_sig = 0xFF; /* ...звук (pop_snd_want) */
|
||||||
static uint8_t room_label_redraw; /* остаток кадров (2 = обе страницы) */
|
static uint8_t room_label_redraw; /* остаток кадров (2 = обе страницы) */
|
||||||
|
|
||||||
/* Группа палочек: n штук от x вправо, шаг 5, ширина 2. */
|
/* Группа палочек: n штук от x вправо, шаг 5, ширина 2. */
|
||||||
@@ -428,17 +437,21 @@ void pop_dbg_room_label(uint8_t room) __banked
|
|||||||
* (`if (n != g) g = n;` пишет разность вместо значения). */
|
* (`if (n != g) g = n;` пишет разность вместо значения). */
|
||||||
uint8_t prev_room = room_label_sig, prev_lvl = lvl_label_sig;
|
uint8_t prev_room = room_label_sig, prev_lvl = lvl_label_sig;
|
||||||
uint8_t prev_spd = spd_label_sig, prev_imm = imm_label_sig;
|
uint8_t prev_spd = spd_label_sig, prev_imm = imm_label_sig;
|
||||||
|
uint8_t prev_snd = snd_label_sig;
|
||||||
uint8_t lvl = pop_current_level, spd = pop_speed_mode, imm = pop_immortal;
|
uint8_t lvl = pop_current_level, spd = pop_speed_mode, imm = pop_immortal;
|
||||||
|
uint8_t snd = pop_snd_want;
|
||||||
room_label_sig = room;
|
room_label_sig = room;
|
||||||
lvl_label_sig = lvl;
|
lvl_label_sig = lvl;
|
||||||
spd_label_sig = spd;
|
spd_label_sig = spd;
|
||||||
imm_label_sig = imm;
|
imm_label_sig = imm;
|
||||||
if (room != prev_room || lvl != prev_lvl || spd != prev_spd || imm != prev_imm)
|
snd_label_sig = snd;
|
||||||
|
if (room != prev_room || lvl != prev_lvl || spd != prev_spd ||
|
||||||
|
imm != prev_imm || snd != prev_snd)
|
||||||
room_label_redraw = 2;
|
room_label_redraw = 2;
|
||||||
if (!room_label_redraw) return;
|
if (!room_label_redraw) return;
|
||||||
|
|
||||||
setfillstyle(SOLID_FILL, BLACK);
|
setfillstyle(SOLID_FILL, BLACK);
|
||||||
bar(10, 0, 230, 5);
|
bar(10, 0, 250, 5);
|
||||||
|
|
||||||
setfillstyle(SOLID_FILL, 0x3E); /* уровень — жёлтый */
|
setfillstyle(SOLID_FILL, 0x3E); /* уровень — жёлтый */
|
||||||
label_bars(10, (uint8_t)(lvl / 10));
|
label_bars(10, (uint8_t)(lvl / 10));
|
||||||
@@ -457,6 +470,10 @@ void pop_dbg_room_label(uint8_t room) __banked
|
|||||||
setfillstyle(SOLID_FILL, 0x3C);
|
setfillstyle(SOLID_FILL, 0x3C);
|
||||||
label_bars(220, imm); /* палочек = уровень (1 или 2) */
|
label_bars(220, imm); /* палочек = уровень (1 или 2) */
|
||||||
}
|
}
|
||||||
|
if (!snd) { /* звука НЕТ — пурпурный */
|
||||||
|
setfillstyle(SOLID_FILL, 0x3D);
|
||||||
|
label_bars(245, 1);
|
||||||
|
}
|
||||||
room_label_redraw--;
|
room_label_redraw--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user