Музыка на прыжке и на плите: 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:
@@ -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): сотрясение от
|
||||
|
||||
@@ -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])
|
||||
|
||||
Reference in New Issue
Block a user