Страж возвращался в комнату не туда: колонку несёт guards_x, а не тайл

Уровень 8 комната 24: после первого же выхода Кида страж телепортировался
в колонку 0, а ряд 0 там пустой в колонках 1..3 — страж падал с ряда 0 на
ряд 2 и разбивался.

leave_guard (seg002:02F5) кладёт в guards_tile get_tilepos(0, row), то есть
обнуляет колонку НАМЕРЕННО: позицию по горизонтали несёт guards_x, туда же
она и пишется.  enter_guard берёт x оттуда всегда.  Мы же считали x из
tile % 10 (то есть из нуля), а запомненную брали только у трупа.

Заодно портирован pos_guards (seg003:0913): при загрузке уровня guards_x
пересчитывается из колонки тайла, а файловое значение выбрасывается — в
комнате 24 уровня 8 там 255.

Проверено в MAME: три входа подряд дают одну и ту же позицию (x 156, ряд 0),
страж стоит на полу.  Host-тесты 5106 проверок без расхождений.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-18 16:20:40 +03:00
parent 0077ef3850
commit c40ae3f8f5
3 changed files with 108 additions and 20 deletions
@@ -16,6 +16,7 @@
#include <sprite.h> /* gfx_w0_map / gfx_w0_unmap */
#include "pop_level.h"
#include "_pop_level.h"
#include "pop_geom.h" /* pop_x_bump / FIRST_ONSCREEN_COLUMN — pos_guards */
/* ISR-стаб W0-страницы (тот же приём, что atlas_load): при прерывании с
* замапленной в W0 страницей CPU прыгает на 0x0038 → там обязан быть JP на
@@ -247,6 +248,15 @@ void pop_gstate_init(void) __banked
g[GS_DIR] = p[BP_GDIR + r];
g[GS_X] = p[BP_GX + r];
g[GS_SKILL] = p[BP_GSKILL + r];
/* pos_guards (seg003:0913), сразу после load_level: X стража
* ПЕРЕСЧИТЫВАЕТСЯ из колонки тайла, а то, что лежит в файле, оригинал
* выбрасывает (в комнате 24 уровня 8 там, например, 255). Дальше X
* владеет leave_guard, и именно она — единственный носитель КОЛОНКИ:
* в guards_tile leave_guard кладёт get_tilepos(0, row), то есть
* колонку обнуляет намеренно. */
if (g[GS_TILE] < 30)
g[GS_X] = (uint8_t)(pop_x_bump[(g[GS_TILE] % 10) + FIRST_ONSCREEN_COLUMN]
+ TILE_SIZEX);
/* guards_seq_lo/hi в ФАЙЛЕ не используются — там 0xFF во всех
* комнатах (оригинал чистит их в reset_level_unused_fields).
* Осмысленное значение туда кладёт только leave_guard, поэтому