From cb995bf0fc3a49a583490f441a098ea807bc4eb3 Mon Sep 17 00:00:00 2001 From: Alexander Petrov Date: Wed, 2 Sep 2026 17:40:45 +0300 Subject: [PATCH] =?UTF-8?q?SprPoP:=20=D0=BD=D0=B5=D0=BF=D1=80=D0=B5=D1=80?= =?UTF-8?q?=D1=8B=D0=B2=D0=BD=D1=8B=D0=B9=20=D0=B2=D0=B7=D0=BC=D0=B0=D1=85?= =?UTF-8?q?=20=D0=BA=D0=BB=D0=B8=D0=BD=D0=BA=D0=B0=20=D1=83=20=D0=B1=D0=B5?= =?UTF-8?q?=D0=B7=D0=BE=D1=80=D1=83=D0=B6=D0=BD=D0=BE=D0=B3=D0=BE=20=D0=9A?= =?UTF-8?q?=D0=B8=D0=B4=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Симптом (пользователь, 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 Claude-Session: https://claude.ai/code/session_018T2k4VZrSyERwk6H97Sfi1 --- applications/SprPoP/src/guards.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/applications/SprPoP/src/guards.c b/applications/SprPoP/src/guards.c index f7579d6..59e4ef1 100644 --- a/applications/SprPoP/src/guards.c +++ b/applications/SprPoP/src/guards.c @@ -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): прогнать проверку с ОБЕИХ сторон. */