L5-SHADOW: тень уровня 5 крадёт зелье (спецсобытие комнаты 24)
Порт seg002: check_shadow (0064), do_init_shad (0000), do_auto_moves (1089),
autocontrol_shadow_level5 (1157) + таблица shad_drink_move (data.h:866).
Механика. При входе в комнату 24 уровня 5, если зелье (кол 3, ряд 0) ещё
на месте, слот соперника занимает ТЕНЬ — и занимает его ВМЕСТО стража:
enter_guard в этой комнате оригинал не зовёт НИКОГДА (в данных страж есть,
guards_tile[23] = 8, но check_shadow уходит в return до него — в том числе
когда зелье уже выпито). Поэтому pop_check_shadow вернула 1 = «событие
обработано, стража не поднимать», и вызов стоит ПЕРЕД pop_guard_enter.
Тень стоит, пока не откроются ворота комнаты (openness >= 80), затем
проигрывает ЗАПИСЬ ходов: подойти, взять, выпить, развернуться, уйти за
левый край. do_auto_moves — тот же движок, что у демо-режима заставки;
тонкость выбора записи (при достигнутом времени индекс сдвигается, а ход
берётся из ещё не сдвинутой записи) портирована дословно.
Три вещи, найденные по дороге:
1. ГЕЙТ ВЫКЛЮЧЕННОГО ПЕРСОНАЖА. play_guard_frame (seg000:1248) начинается
с `if (Guard.direction != dir_56_none)`, и clear_char выключает
персонажа именно так — он не трогает charid. У нас гейт был только по
charid, поэтому ушедшая за край тень продолжала тикать: do_auto_moves за
концом таблицы отдаёт последнюю запись {0x31,1} = «вперёд», тень
разворачивалась, вбегала обратно, пробегала верхний ряд и падала в проём
(наблюдение пользователя в MAME). Гейт добавлен и в pop_guard_tick, и в
pop_guard_phys_tick.
2. ЭФФЕКТ ЗЕЛЬЯ — ТОЛЬКО КИДУ. proc_get_object (seg006:16CB) начинается с
`if (Char.charid != charid_0_kid || ...) return`: предмет забирает любой
персонаж, а эффект достаётся только Киду. На этом стоит всё спецсобытие
— тень пьёт, зелье исчезает и не достаётся никому. Без проверки
hitp_delta уходил бы Киду, то есть тень его ЛЕЧИЛА бы.
3. ВЕТКА ТЕНИ в check_guard_fallout (seg002:0241): исчезает, только если
реально падает (action == 4). Была помечена в коде как «появится с
L3-SKEL» — на самом деле она про тень.
Чит ROOMNAV: телепорт ставил Кида в первый попавшийся пол, то есть почти
всегда (0,0). Теперь ищет пол С МАКСИМАЛЬНЫМ Y (ряд 2 -> 1 -> 0, по
просьбе пользователя): в комнате 24 старая посадка была вплотную к тени, и
вместо сцены кражи начиналась схватка, которой там быть не должно.
Отладочный тумблер POP_DBG_SHADOW_NOWAIT (pop_tune.h, по умолчанию 0) —
посмотреть сцену, не проходя уровень до кнопки.
Проверено в MAME (уровень 5, комната 24): при закрытых воротах тень стоит
за левым краем и не видна; с тумблером — подошла, выпила (зелье исчезло),
развернулась, ушла за край, выключилась и НЕ вернулась. tests-host 5/5,
make size-check OK. Цена: резидент +102 Б (24637 -> 24739), банк 1
+368 Б, банк 3 +11 Б.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1147,9 +1147,17 @@ static void do_pickup(int8_t obj_type, uint8_t tilepos)
|
||||
}
|
||||
|
||||
/* proc_get_object (seg006:16CB): эффект поднятого предмета. Зовётся из
|
||||
* play_seq по опкоду SEQ_GET_ITEM с аргументом 1 (pop_kid). */
|
||||
* play_seq по опкоду SEQ_GET_ITEM с аргументом 1 (pop_kid).
|
||||
*
|
||||
* ПЕРВАЯ СТРОКА ОРИГИНАЛА — `if (Char.charid != charid_0_kid || ...) return`:
|
||||
* предмет ЗАБИРАЕТ любой персонаж (тайл стирает do_pickup), а ЭФФЕКТ
|
||||
* достаётся только Киду. На этом стоит всё спецсобытие уровня 5: тень
|
||||
* выпивает зелье, оно исчезает — и не достаётся никому. Без проверки
|
||||
* hitp_delta уходил бы Киду, то есть тень его лечила бы (найдено при
|
||||
* портировании L5-SHADOW 2026-08-11, до живого прогона). */
|
||||
void pop_proc_get_object(void) __banked
|
||||
{
|
||||
if (Char.charid != CHARID_0_KID) return;
|
||||
if (pickup_obj_type == -1) {
|
||||
pop_have_sword = 1; /* в оригинале have_sword = -1 */
|
||||
/* Вспышка фона: flash_color = color_14_brightyellow, flash_time = 8
|
||||
@@ -2546,7 +2554,10 @@ void pop_phys_tick(void) __banked
|
||||
* Char стоит копию 16 байт. */
|
||||
void pop_guard_phys_tick(void) __banked
|
||||
{
|
||||
if (Guard.charid == 0 || Guard.room != g_room) return;
|
||||
/* Тот же гейт, что в pop_guard_tick: dir_56_none = персонаж выключен
|
||||
* (clear_char), физику ему тоже не крутим. */
|
||||
if (Guard.charid == 0 || Guard.direction == DIR_56_NONE ||
|
||||
Guard.room != g_room) return;
|
||||
pop_loadshad_and_opp();
|
||||
/* seg000:1254 — физика работает, ТОЛЬКО пока страж внутри комнаты: за
|
||||
* пределами полосы персонаж просто перестаёт двигаться, а
|
||||
|
||||
Reference in New Issue
Block a user