Уровни 12 и 13: тень, Джафар, падающие плиты + разбор слоёв
Уровень 12 (тень) — порт seg002/seg006: - check_shadow: подъём тени в комнате 15 по условию «меч подобран», init_shad_12, вход падением (seq 7); - autocontrol_shadow_level12: ждать Кида, бой, сближение, СЛИЯНИЕ; - общий урон (ранил тень — ранил себя) и check_killed_shadow (убил тень — убил себя); - таймер вспышки слияния 42 -> -1, sword_disappears при уходе из комнаты 18, появление плит в комнатах 2/13 после слияния. Переход 12 -> 13 бесшовный: двери у уровня нет, он кончается фактом попадания в комнату 23 (tbl_seamless_exit); флаг pop_seamless не даёт сбросить HP. Чит навигации по комнатам этот триггер придерживает — иначе комнату 23 двенадцатого уровня не посмотреть в принципе. Уровень 13 (Джафар): guard_notice_timer (фора после встречи), on_guard_killed + Jaffar_exit, check_fall_flo (гряда плит сверху) и три исключения loose-механики. Плюс спрайты визиря VIZIER.DAT — без них он рисовался обычным стражем; заодно цвет из данных комнаты применяется только к обычному стражу, как в оригинале. Падающие плиты — семь дефектов, найденных прогонами: - MOB_MAX 4 -> 14: check_fall_flo роняет шесть плит разом, лишние терялись без щебня; - одиночные сигналы посадки/провала больше не затираются в кадре; - честный loose_fall: сбитая плита рождается в том же кадре, от места удара, с половинной скоростью; - при снятии плиты метится и сосед справа (висел передний торец); - heal и отрисовка кусков разнесены на два прохода; - куски рисуются ПОСЛЕ фона, порядок между собой — по убыванию y (compare_curr_objs для пары 0x80 сортирует наоборот); - wall_pattern убран из ceil_over_kid_tile: у оригинала узор из draw_tile_bottom идёт в фон, а не в передний слой. Хост-тесты: два новых набора, t_shadow (45 проверок) и t_jaffar (44). TK_ROOMS 8 -> 24 — спецсобытия адресуют комнаты по реальным номерам. Осознанные расхождения (docs/impl_diff.md): нет мигания Кида спрайтами тени при слиянии, чит навигации не запускает бесшовный переход, чит K убивает через штатный путь смерти. Открытым остаётся разбор слоёв: MOB-CLIP-RIGHT, MID-OVERLAY-LAYER, GUARD-FALLOUT-VICTORY, BG-ONCE (BUGS_OPEN.md / TASKS_OPEN.md). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -464,6 +464,29 @@ static void draw_gate_back(uint8_t modl, int xh, int dby, int dmy)
|
||||
pop_env_b(DOOR_FRAM_SLICE[gate_frame], x, yb);
|
||||
}
|
||||
|
||||
/* Та же решётка, но в ПЕРЕДНИЙ слой — поверх персонажа, стоящего в проёме
|
||||
* (draw_gate_fore, seg008:1153). От back-варианта отличается ровно тем, что
|
||||
* есть в оригинале: только ПРОЗРАЧНЫЕ куски (51 низ + 52 восьмипиксельные
|
||||
* ломти), без непрозрачного 50 и без хвостового DOOR_FRAM_SLICE — фон под
|
||||
* баррами уже нарисован, здесь возвращаются только сами прутья.
|
||||
* Клип по прямоугольнику персонажа делает pop_t_fclip (см. pop_tile.h). */
|
||||
static void draw_gate_fore(uint8_t modl, int xh, int dby, int dmy)
|
||||
{
|
||||
int x = xh * 8;
|
||||
int gate_top_y = dby - 62;
|
||||
int openness = (((modl > 188) ? 188 : modl) >> 2) + 1;
|
||||
int gate_bot_y = dmy - openness;
|
||||
int yb;
|
||||
|
||||
pop_env_b(51, x, gate_bot_y - 2);
|
||||
yb = gate_bot_y - 12;
|
||||
if (yb < 192)
|
||||
while (yb >= 0 && yb > 7 && (yb - 7) > gate_top_y) {
|
||||
pop_env_b(52, x, yb);
|
||||
yb -= 8;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -599,7 +622,17 @@ static void ceil_over_kid_tile(int col)
|
||||
if (code == 20) { /* draw_tile_bottom: стена */
|
||||
if (!pop_palace) /* seg008:576 */
|
||||
pop_wall_b(POP_WALL_FRAM_BOTTOM[pop_wall_modifier(-1, col)], x, dby);
|
||||
wall_pattern(-1, col, 0);
|
||||
/* wall_pattern ЗДЕСЬ НЕТ — и это не упущение. draw_tile_bottom
|
||||
* (seg008:588) кладёт в foretable ТОЛЬКО кадр грани `id`, под своим
|
||||
* `arg_0`; узор вызывается строкой ниже, вне этой ветки, и уходит в
|
||||
* текущую таблицу, то есть в ФОН. Мы же звали его прямо в переднем
|
||||
* проходе — узор задней стены штамповался поверх всего, что уже
|
||||
* нарисовано, включая падающие плиты (найдено прогоном 2026-08-13).
|
||||
* В фон он попадает там, где и положено, — при отрисовке тайла.
|
||||
*
|
||||
* Не путать с fore_only_tile: там узор в переднем слое ЗАКОННЫЙ,
|
||||
* это порт draw_tile_fore (seg008:715), где он стоит явно рядом с
|
||||
* главной гранью стены, обязанной перекрывать персонажа. */
|
||||
} else if (t->bottom_id) {
|
||||
pop_env_b(t->bottom_id, x, dby);
|
||||
}
|
||||
@@ -948,9 +981,27 @@ void pop_fore_over_char(const pop_char_t *ch, int obj_x, int obj_y,
|
||||
/* на 141 — до него Kid ещё */
|
||||
/* в ряду 1 ПОД полом [0,3]) */
|
||||
if (do_ov) {
|
||||
/* ВЕСЬ диапазон рядов, а не только два крайних. В оригинале
|
||||
* (redraw_at_char2, seg003:0645) стоит ровно два вызова —
|
||||
* char_bottom_row и char_top_row, — и этого хватает, потому что
|
||||
* там они ВСЕГДА соседние. У нас между ними бывает пропуск:
|
||||
* char_footprint форсит rT = rB−1 (голова торчит в ряд выше), а
|
||||
* потом окно fore-клипа расширяет rB ещё на ряд вниз — rT=0,
|
||||
* rB=2 давали обход рядов 0 и 2 МИМО ряда 1.
|
||||
*
|
||||
* Ровно так терялась передняя грань пола у Кида, спрыгнувшего с
|
||||
* кромки: кадр 103, action 3, ряд по y = 1, а обход шёл по 0 и 2
|
||||
* (трасса MAME 2026-08-13: rT=0 rB=2 cL=0 cR=1, ни одного вызова
|
||||
* overlay_mid_tile). Глубже в падении y_to_row давал уже 2, ряд
|
||||
* 1 попадал в пару крайних — и плита вдруг начинала рисоваться
|
||||
* правильно, что и было видно глазом (JUMP-FLOOR-LEGS). */
|
||||
for (c = cR; c >= cL; c--) {
|
||||
if (action != 2) other_overlay_tile(rB, c); /* опорный ряд */
|
||||
if (rT != rB) other_overlay_tile(rT, c); /* верхний ряд */
|
||||
int8_t r2;
|
||||
for (r2 = rB; r2 >= rT; r2--) {
|
||||
/* seg003:0645: при hang_climb опорный ряд НЕ трогаем. */
|
||||
if (r2 == rB && action == 2) continue;
|
||||
other_overlay_tile(r2, c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -961,6 +1012,23 @@ void pop_fore_over_char(const pop_char_t *ch, int obj_x, int obj_y,
|
||||
for (r = rT; r <= rB; r++)
|
||||
for (c = cL; c <= cR; c++)
|
||||
fore_tile(r, c);
|
||||
/* Первое условие draw_tile_fore (seg008:0D15): персонаж СТОИТ на тайле
|
||||
* ворот — их решётка возвращается поверх него. Решение приняла карта
|
||||
* (pop_gate_over_char, разбор там же); здесь остаётся отрисовка. Бары
|
||||
* рисуются в колонке curr_col+1: графика ворот принадлежит ПРАВОМУ краю
|
||||
* своего тайла и в оригинале кладётся в проходе следующей колонки.
|
||||
*
|
||||
* Один вызов через трамплин на персонажа за кадр — не в тайловом цикле:
|
||||
* тайл-кандидат всегда ровно один, а fore-проход и так самый горячий
|
||||
* кусок кадра (memory pop_fore_layer_cost). */
|
||||
if (pop_gate_over_char(ch)) {
|
||||
int8_t gr = ch->curr_row, gc = (int8_t)(ch->curr_col + 1);
|
||||
if (tile_in_fclip(gr, gc)) {
|
||||
int dby = 63 * gr + 65;
|
||||
draw_gate_fore(pop_t_bg ? pop_t_bg[gr * 10 + ch->curr_col] : 0,
|
||||
POP_COL_XH[gc], dby, dby - 3);
|
||||
}
|
||||
}
|
||||
/* redraw_needed_above (seg008:0221): полоса кладки У ПОТОЛКА (ряд −1 =
|
||||
* ряд 2 комнаты сверху). В оригинале она рисуется в самом конце обхода
|
||||
* тайлов — ПОСЛЕ объектов, т.е. поверх персонажа (redraw_frames_above,
|
||||
|
||||
Reference in New Issue
Block a user