From f66fd0e1b670ec9c34c1f0a5274cd35ab815d490 Mon Sep 17 00:00:00 2001 From: Alexander Petrov Date: Wed, 26 Aug 2026 11:04:55 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9C=D1=83=D0=B7=D1=8B=D0=BA=D0=B0=20=D0=BD?= =?UTF-8?q?=D0=B0=20=D0=BF=D1=80=D1=8B=D0=B6=D0=BA=D0=B5=20=D0=B8=20=D0=BD?= =?UTF-8?q?=D0=B0=20=D0=BF=D0=BB=D0=B8=D1=82=D0=B5:=20SUB=20=D0=B7=D0=B0?= =?UTF-8?q?=D1=82=D0=B8=D1=80=D0=B0=D0=BB=20A=20=D0=B2=20=D0=B7=D0=B2?= =?UTF-8?q?=D1=83=D0=BA=D0=B5=20=D1=82=D1=80=D1=8F=D1=81=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Watchpoint на pop_mus_req поймал виновника: заявку ставил pop_sfx_play с id 27, а звал его loose_shake — звук дрожащей плиты. Классический sdcc_z80_cmp_store_a_bug. Было: do { id = prandom(...) + 20; } while (id == last_loose_snd); last_loose_snd = id; pop_sfx_play(id); собиралось как ld a, e / add a, #0x14 ; A = 20..22 — номер сэмпла sub a, (hl) ; A = РАЗНОСТЬ, номер потерян ld (_last_loose_snd), a ; сохраняем разность jp _pop_sfx_play ; играем разность То есть в звук уходил не сэмпл тряски, а id минус предыдущий id. Пока такие «номера» попадали в пустые слоты набора, это молчало; с приходом музыки мусор вида 22-251 = 27 стал запускать ТРЕК — отсюда музыка на прыжке с уступа и на падающей плите. Обход тот же, что в pop_status и pop_cdraw: записать ДО сравнения и играть перечитанное из памяти. Проверено по сгенерированному asm. Вторая линия обороны: pop_sfx_play принимает музыкальную заявку только в диапазоне оригинала (24..43). Случайный мусорный id теперь молчит, а не играет минуту музыки. Проверено в MAME: тем же бегом, что раньше ловил заявку 27, watchpoint больше не срабатывает. Host-тесты: 15 наборов. Co-Authored-By: Claude Opus 5 --- applications/PoP/roomtest/pop_map.c | 27 ++++++++++++++++++++++----- applications/PoP/roomtest/pop_sfx.c | 7 ++++++- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/applications/PoP/roomtest/pop_map.c b/applications/PoP/roomtest/pop_map.c index 3541253..ccd7e58 100644 --- a/applications/PoP/roomtest/pop_map.c +++ b/applications/PoP/roomtest/pop_map.c @@ -2413,12 +2413,29 @@ static uint8_t last_loose_snd; static void loose_shake(uint8_t force, uint8_t modif) { - uint8_t id; + uint8_t id, prev; + if (!force && !loose_sound[modif & 0x7F]) return; - do { id = (uint8_t)(pop_prandom(&loose_seed, 2) + 20); } - while (id == last_loose_snd); - last_loose_snd = id; - pop_sfx_play(id); + /* ЗАПИСЬ ДО СРАВНЕНИЯ — обход sdcc_z80_cmp_store_a_bug. + * + * Прежняя запись (`do { id = ... } while (id == last_loose_snd); + * last_loose_snd = id; pop_sfx_play(id);`) собиралась так: + * ld a, e / add a, #0x14 ; A = 20..22, номер сэмпла + * ld hl, #_last_loose_snd + * sub a, (hl) ; A = РАЗНОСТЬ, номер потерян + * ld (_last_loose_snd), a ; сохраняем разность + * jp _pop_sfx_play ; играем разность + * то есть в звук уходил не сэмпл тряски, а id минус предыдущий id. + * Пока такие «номера» попадали в пустые слоты набора, это молчало; + * с приходом музыки мусор вида 22-251 = 27 стал запускать ТРЕК — + * пользователь слышал музыку на прыжке и на падающей плите. */ + prev = last_loose_snd; + for (;;) { + id = (uint8_t)(pop_prandom(&loose_seed, 2) + 20); + last_loose_snd = id; /* store раньше любого сравнения */ + if (id != prev) break; + } + pop_sfx_play(last_loose_snd); /* читаем из памяти, не из A */ } /* do_knock (seg007:0FE0) + loose_make_shake (seg007:0FB4): сотрясение от diff --git a/applications/PoP/roomtest/pop_sfx.c b/applications/PoP/roomtest/pop_sfx.c index 032e0f5..808a220 100644 --- a/applications/PoP/roomtest/pop_sfx.c +++ b/applications/PoP/roomtest/pop_sfx.c @@ -243,7 +243,12 @@ void pop_sfx_play(uint8_t id) * В конкурсе эффектов такой id не участвует: он не глушит живой звук * (порт проверки `if (NULL == sound_pointers[id]) return;`). */ if (pop_snd_tbl[id].len == 0) { - if (pop_mus_want) pop_mus_req = id; + /* Заявку принимаем ТОЛЬКО в музыкальном диапазоне оригинала + * (24..43 — Adlib-треки игры). Пустых слотов в наборе больше нет, + * но случайный мусорный id обязан молчать, а не запускать трек на + * минуту: ровно так проявился sdcc_z80_cmp_store_a_bug в звуке + * тряски — разность двух номеров попала в 27 и заиграла музыка. */ + if (pop_mus_want && id >= 24 && id <= 43) pop_mus_req = id; return; } if (!snd_next1 || snd_prio[id] <= snd_prio[snd_next1 - 1])