Страж возвращался в комнату не туда: колонку несёт 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:
@@ -111,13 +111,25 @@ void pop_guard_enter(uint8_t room)
|
||||
* записанный в его комнате. */
|
||||
pop_guard_set_palette(pop_level_guard_type(pop_current_level) == 0
|
||||
? color : 0);
|
||||
/* enter_guard (seg002:0112) + pos_guards (seg003): X считается из
|
||||
* колонки тайла, а не берётся из файла. */
|
||||
/* enter_guard (seg002:0112). Из ТАЙЛА берётся только РЯД — колонки в нём
|
||||
* нет: leave_guard кладёт туда get_tilepos(0, row), то есть обнуляет её
|
||||
* намеренно. Носитель колонки — guards_x, её пишет тот же leave_guard, а
|
||||
* при загрузке уровня заполняет pos_guards (см. pop_gstate_init).
|
||||
*
|
||||
* Считать X из `tile % 10`, как мы делали, значит после ПЕРВОГО же выхода
|
||||
* из комнаты телепортировать живого стража в КОЛОНКУ 0 — потому что там
|
||||
* с этого момента ноль. Уровень 8, комната 24: страж стоит в (0,6), ряд 0
|
||||
* в колонках 1..3 ПУСТОЙ, и после возврата Кида страж оказывался над
|
||||
* дырой (x = 72 — это колонка 1 по таблице деления), падал с ряда 0 на
|
||||
* ряд 2 и разбивался. Наблюдения пользователя — «страж был на 0,0»,
|
||||
* «страж падает на 2,1 и разбивается» — это ровно оно.
|
||||
*
|
||||
* Y всегда по ряду: enter_guard ставит стража НА ПОЛ (y_land[row+1]), а не
|
||||
* туда, где он был по вертикали. Поэтому «дорисовать падение» при
|
||||
* возврате в комнату оригинал не умеет — и не должен. */
|
||||
Guard.room = room;
|
||||
Guard.curr_row = (int8_t)(tile / 10);
|
||||
Guard.y = (uint8_t)pop_y_land[Guard.curr_row + 1];
|
||||
Guard.x = (uint8_t)(pop_x_bump[(tile % 10) + FIRST_ONSCREEN_COLUMN] + TILE_SIZEX);
|
||||
Guard.curr_col = (int8_t)(tile % 10);
|
||||
Guard.direction = dir;
|
||||
/* seg002:196: на уровне со скелетами слот поднимает СКЕЛЕТА, и он
|
||||
* встаёт сразу активным — с вынутым мечом (seq_63), а не в стойке
|
||||
@@ -142,22 +154,21 @@ void pop_guard_enter(uint8_t room)
|
||||
* ровно там, где лёг (порт ветки guards_seq_hi != 0). */
|
||||
{
|
||||
uint16_t saved_seq = pop_guard_state_seq(room);
|
||||
/* У ЗАПОМНЕННОГО трупа X берём сохранённую: pos_guards (seg003:620)
|
||||
* пересчитывает её из колонки только при загрузке уровня, а дальше
|
||||
* ею владеет leave_guard. Иначе тело при возврате прыгает в центр
|
||||
* тайла. */
|
||||
if (saved_seq) Guard.x = pop_guard_state_x(room);
|
||||
/* ...и КОЛОНКУ пересчитываем из X (enter_guard, seg002:180:
|
||||
* `Char.curr_col = get_tile_div_mod_m7(Char.x)`). Брать её из
|
||||
* тайла нельзя: leave_guard сохраняет get_tilepos(0, row), то
|
||||
* есть колонку 0 всегда. У живого стража это незаметно (X там
|
||||
* сам считается из колонки), а у ЗАПОМНЕННОГО ТРУПА X
|
||||
* настоящая, и curr_col оставался нулём при теле, лежащем в
|
||||
* колонке 2. Тайл трупа шёл в обходе раньше тайла Кида, и Кид
|
||||
* рисовался ПОВЕРХ тела вместо того, чтобы пройти за ним
|
||||
* (BUG-DRAWORDER-1). Колонка нужна не только отрисовке — на
|
||||
* неё смотрят коллизия и check_can_guard_see_kid. */
|
||||
Guard.curr_col = guard_col_from_x(Guard.x);
|
||||
/* X — ВСЕГДА из запомненной (enter_guard, seg002:179:
|
||||
* `Char.x = level.guards_x[room_minus_1]`), и живого стража это
|
||||
* касается ровно так же, как трупа: страж, с которым Кид не стал
|
||||
* драться, обязан остаться СТОЯТЬ ТАМ ЖЕ. Иначе он не просто
|
||||
* «дёргается» — он может встретить Кида прямо на входе в комнату,
|
||||
* не дав тому достать меч. */
|
||||
Guard.x = pop_guard_state_x(room);
|
||||
/* КОЛОНКА — из X (enter_guard, seg002:180:
|
||||
* `Char.curr_col = get_tile_div_mod_m7(Char.x)`). Из тайла её брать
|
||||
* нельзя, там всегда 0 (см. выше). Колонка нужна не только
|
||||
* отрисовке: на неё смотрят коллизия и check_can_guard_see_kid, а у
|
||||
* ЗАПОМНЕННОГО ТРУПА ещё и порядок обхода тайлов — иначе Кид
|
||||
* рисовался поверх тела вместо того, чтобы пройти за ним
|
||||
* (BUG-DRAWORDER-1). */
|
||||
Guard.curr_col = guard_col_from_x(Guard.x);
|
||||
pop_loadshad();
|
||||
if (saved_seq) Char.curr_seq = saved_seq;
|
||||
else pop_char_set_seq(SEQ_77_GUARD_STAND_INACTIVE);
|
||||
|
||||
Reference in New Issue
Block a user