SprPoP: непрерывный взмах клинка у безоружного Кида
Симптом (пользователь, 2026-09-02): на подъёме Кида шёл нескончаемый свист клинка, хотя меча у него нет. ОПОЗНАНИЕ. Звук снят с живой машины, а не угадан: snd_curr == 11 (sound_11_sword_moving). Заодно проверено, что тракт исправен — указатели насоса (pg 2, ptr 0x2B80, left 512) сошлись с записью 11 в SND/snd.idx (страница 2, off 0x2880, длина 1280, конец 0x2D80) байт в байт. То есть играл честно заявленный эффект из своих данных, и виновата была ЗАЯВКА, а не звук. ПРИЧИНА. Хвост check_hurting был портирован не до конца. В оригинале (seg002:1039..1044) звук 11 стоит В КОНЦЕ функции, после ОБЕИХ веток, и защищён тремя вещами: ранним выходом по dir_56_none, кадром 154 и условием Opp.action != actions_99_hurt. У нас он стоял ВНУТРИ ветки «не парировано», до присвоения Opp.action = 99_hurt, без проверки на попадание и — главное — без гарда по dir_56_none, который автор SDLPoP подписал прямым текстом: «Fix looping sword moving sound». Направление dir_56_none означает «персонаж выключен» (clear_char), махать ему нечем. Наш движок эту константу знает и применяет в pop_guard_tick — в check_hurting она просто не доехала. ТОНКОСТЬ ПОРТА: хвост оригинала ПЕРЕЧИТЫВАЕТ Char.frame и Opp.frame у персонажей, а не берёт снимки начала функции. Ветка парирования только что записала Opp.frame, а play_seq в ней — Char.frame; на кэшированных cf/of условие дало бы неверный ответ. Живая проверка в MAME пользователем: корректно. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018T2k4VZrSyERwk6H97Sfi1
This commit is contained in:
@@ -1102,8 +1102,6 @@ static void check_hurting(void)
|
||||
(of != FRAME_161_PARRY && of != FRAME_150_PARRY)) {
|
||||
/* Соперник НЕ парирует. */
|
||||
if (cf == FRAME_154_POKING) {
|
||||
/* seg002:0DAE — свист клинка мимо цели. */
|
||||
pop_sfx_play(11);
|
||||
min_range = (uint8_t)(Opp.sword < SWORD_2_DRAWN ? 8 : 12);
|
||||
distance = pop_char_opp_dist();
|
||||
if (distance >= (int16_t)min_range && distance < 29)
|
||||
@@ -1116,6 +1114,29 @@ static void check_hurting(void)
|
||||
pop_char_set_seq(SEQ_69_ATTACK_WAS_PARRIED);
|
||||
play_seq();
|
||||
}
|
||||
|
||||
/* СВИСТ КЛИНКА МИМО ЦЕЛИ (seg002:1039..1044) — в оригинале он стоит в
|
||||
* ХВОСТЕ функции, после ОБЕИХ веток, а не внутри ветки «не парировано».
|
||||
* Мы его туда и переносим; раньше он звучал раньше времени и без двух
|
||||
* условий оригинала, отчего на подъёме Кида шёл непрерывный взмах
|
||||
* клинка у безоружного (наблюдение пользователя 2026-09-02, звук
|
||||
* опознан по snd_curr == 11 в живой сессии).
|
||||
*
|
||||
* Три отличия от прежнего кода, все из оригинала:
|
||||
*
|
||||
* 1. Ранний выход по dir_56_none — это ИМЕННО анти-зацикливание, автор
|
||||
* SDLPoP так его и подписал («Fix looping sword moving sound»).
|
||||
* Направление dir_56_none означает «персонаж выключен» (clear_char),
|
||||
* и махать клинком ему нечем.
|
||||
* 2. Условие `Opp.action != ACTION_99_HURT`: попали — играет звук боли,
|
||||
* а не свист мимо. Поэтому звук обязан идти ПОСЛЕ присвоения выше.
|
||||
* 3. Кадры перечитываются у персонажей, а не берутся из cf/of: ветка
|
||||
* парирования только что записала Opp.frame, а play_seq в ней —
|
||||
* Char.frame, и снимки выше уже устарели. */
|
||||
if (Char.direction == DIR_56_NONE) return;
|
||||
if (Char.frame == FRAME_154_POKING && Opp.frame != FRAME_161_PARRY &&
|
||||
Opp.action != ACTION_99_HURT)
|
||||
pop_sfx_play(11);
|
||||
}
|
||||
|
||||
/* check_sword_hurting (seg002:0D1A): прогнать проверку с ОБЕИХ сторон. */
|
||||
|
||||
Reference in New Issue
Block a user