Музыка на прыжке и на плите: SUB затирал A в звуке тряски

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 <noreply@anthropic.com>
This commit is contained in:
2026-08-26 11:04:55 +03:00
parent e5179af9d8
commit f66fd0e1b6
2 changed files with 28 additions and 6 deletions
+6 -1
View File
@@ -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])