PoP: roomtest — объекты/обломки/переходы комнат + арт
Порт Prince of Persia (applications/PoP/roomtest): развитие уровня, объекты (loose-полы/обломки), переходы между комнатами, фон-упаковка; планы (room_model/size_optimization), bug_list, pop_trob. Арт third_party/16x16-RPG-characters. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,333 @@
|
||||
# roomtest — список известных багов (Фаза B и смежное)
|
||||
|
||||
Найдено при тестировании Фазы B (кнопки/ворота) в MAME. **НЕ решаем сейчас**
|
||||
— задача следующего этапа. Правило проекта: механику сверять с
|
||||
`applications/PoP/SDLPoP/src/` ДО кодинга.
|
||||
|
||||
Статус на момент записи: 2026-07-21. Тестовый старт — комната 6 (`START_ROOM`
|
||||
в `roomtest.c`). Кнопка room6(0,2, opener) → ворота room8(0,9), видны в левом
|
||||
шве room6.
|
||||
|
||||
---
|
||||
|
||||
## BUG-1. Боковой переход через ворота: Kid проваливается на row 1 — **Critical**
|
||||
|
||||
**Симптом:** при проходе через ОТКРЫТЫЕ ворота в соседнюю комнату (через шов)
|
||||
Kid оказывается на ряду **row 1** вместо row 0 — «проваливается» на этаж ниже
|
||||
(стоит в дверном проёме на неправильной высоте).
|
||||
|
||||
**Где:** `pop_map.c` `check_leave()` (порт seg002 leave_room) — боковой уход
|
||||
`pop_leave_dir`; репроекция координат `Kid.x ∓= 140` есть, но Y/`curr_row`
|
||||
при боковом переходе НЕ репроецируются (в отличие от `check_leave_below`,
|
||||
где `Kid.y -= 189; curr_row = y_to_row`). При входе в соседнюю комнату у
|
||||
шва Kid, видимо, попадает в позицию, где `determine_col`/физика следующего
|
||||
кадра сбрасывают его на row 1 (нет пола на row 0 у входа, либо неверный y).
|
||||
|
||||
**Сверить с SDLPoP:** `goto_other_room` (seg002) — как именно
|
||||
пересчитываются `Char.curr_row`/`Char.y` при side-переходе (left/right).
|
||||
Для вертикального перехода мы это сделали, для бокового — нет.
|
||||
|
||||
## BUG-2. Возврат из комнаты назад: Kid отбрасывается обратно (ping-pong) — **Critical**
|
||||
|
||||
**Симптом:** после перехода в соседнюю комнату попытка сразу вернуться
|
||||
обратно приводит к тому, что Kid снова закидывается в ту же комнату —
|
||||
переход «пинг-понгует», выйти нельзя.
|
||||
|
||||
**Где:** `pop_map.c` `check_leave()`. После перехода Kid репроецирован к
|
||||
ПРОТИВОПОЛОЖНОЙ кромке новой комнаты (`x ∓ 140`). На СЛЕДУЮЩЕМ же кадре
|
||||
передний край снова за порогом ухода в обратную сторону → `pop_leave_dir`
|
||||
взводится опять → мгновенный обратный переход. Нужен guard «только что
|
||||
перешёл» (подавить повторный leave на N кадров / пока Kid не отойдёт от
|
||||
кромки), как в оригинале (`next_room`/leave обрабатываются раз за кадр +
|
||||
Kid входит достаточно внутрь).
|
||||
|
||||
**Сверить с SDLPoP:** порядок `leave_room`/`goto_other_room` + на какой
|
||||
X ставится персонаж при входе (должен быть НЕ на самой кромке, иначе
|
||||
мгновенный обратный триггер).
|
||||
|
||||
## BUG-3. Climb-up на тайл-кнопку: неправильная окклюзия (Kid поверх кнопки) — **Critical**
|
||||
|
||||
**Симптом:** когда Kid подтягивается (climb-up) на тайл, верх которого —
|
||||
КНОПКА (opener/closer), а не обычный пол, отрисовка неверная: Kid рисуется
|
||||
ПОВЕРХ кнопки, хотя передняя грань пола/кнопки должна перекрывать нижнюю
|
||||
часть Kid во время подъёма.
|
||||
|
||||
**Где:** `pop_bg.c` `climb_overlay_tile()` — floor-overlay при подъёме
|
||||
рисуется только для floor-подобных тайлов `code ∈ {1,3,5,19}`. Кнопка
|
||||
(opener 0x0F / closer 0x06) в этот набор НЕ входит → пол-оверлей кнопки не
|
||||
рисуется поверх Kid. Нужно: для нажатой кнопки (draw как floor/stuck)
|
||||
трактовать её как floor-тайл в climb-overlay (учесть подстановку из
|
||||
`get_tile_to_draw`), и/или добавить opener/closer в набор.
|
||||
|
||||
**Сверить с SDLPoP:** `draw_floor_overlay` (seg008) + `get_tile_to_draw`
|
||||
(нажатая кнопка → tiles_1_floor / tiles_5_stuck) — оверлей должен идти по
|
||||
ПОДСТАВЛЕННОМУ типу тайла.
|
||||
|
||||
---
|
||||
|
||||
## Оптимизации (отложено)
|
||||
|
||||
### OPT-1. Хирургический редрой левого шва (ворота соседа) — 2026-07-22
|
||||
|
||||
**Возможность:** `pop_room_redraw_seam_left()` (pop_bg.c) на каждое изменение
|
||||
openness рисует `bar(BLACK)` по всему col0 + **полный `draw_tile(0,0)`**
|
||||
(стены, `topright`, `wall_pattern` с `prandom()` — десятки блитов). Реально
|
||||
анимируются только бары решётки — `draw_gate_back` (~9 `env_b`).
|
||||
|
||||
**Стоимость:** seam-блок (синий io_border) занимает ~30-50% кадрового периода,
|
||||
**но только пока openness меняется** — т.е. во время открытия и медленного
|
||||
авто-закрытия (~5 сек после схода с кнопки). В покое (ворота открыты-держим
|
||||
кнопку / закрыты / FF) — 0%. Замерено в MAME: брейк на
|
||||
`_pop_room_redraw_seam_left` (0x5A54) срабатывает ⟺ сегмент дорогой.
|
||||
|
||||
**Приём** (как у пик, но сложнее — heal НЕ годится: печёные бары устаревшие,
|
||||
поэтому и стоит `bar(BLACK)`+redraw): `bar(BLACK)` только по полосе баров
|
||||
(x=0, gate_top..gate_bot) + `draw_gate_back(lmod,...)` + дорисовать статику
|
||||
тайла (0,0), задетую полосой. Ожидаемо срезает бóльшую часть 30-50%.
|
||||
**Пиксель-чувствительно** — полоса баров пересекается со статикой col0,
|
||||
обязательна выверка в MAME по кромкам.
|
||||
|
||||
**Решение (2026-07-22):** оставляем как есть — стоимость транзиентная, в бюджет
|
||||
помещаемся. Делать, если упрёмся в кадровый бюджет на сценах с воротами.
|
||||
|
||||
---
|
||||
|
||||
## Исправлено
|
||||
|
||||
- **Шов ворот жёг 50% кадра в покое (закрытая решётка)** — ИСПРАВЛЕНО
|
||||
2026-07-22. Причина — **баг кодогенератора SDCC z80** (memory
|
||||
`sdcc_z80_cmp_store_a_bug`): `if (m[9] != seam_sig) seam_sig = m[9];`
|
||||
компилировался в `sub (seam_sig)` (A ← разность) + `ld (seam_sig),a` —
|
||||
сохранял РАЗНОСТЬ `m[9]-seam_sig`, не `m[9]`. `seam_sig` осциллировала
|
||||
(напр. 25↔231), `m[9]!=seam_sig` истинно каждый кадр → `draw_tile(0,0)`
|
||||
каждый кадр даже у неподвижной решётки. Фикс: store-до-сравнения
|
||||
(`seam_sig = g;` из чистого `g` ДО `sub`), подтверждён в .asm. Прочёс всех
|
||||
модулей PoP: других случайных compare-then-store нет.
|
||||
|
||||
- **Пики: 2×полный `draw_tile` на кадр анимации** → хирургический редрой,
|
||||
2026-07-22. `pop_spike_redraw`: `heal_off` уже возвращает всю печёную
|
||||
статику (база 127, пол, грани); поверх анимируются только два острия
|
||||
(`SPIKES_FRAM_LEFT` в своей ячейке + `SPIKES_FRAM_RIGHT` в соседней).
|
||||
Заменили 2×`draw_tile` на 2×`env_b` — пиксель-в-пиксель тот же результат,
|
||||
в разы дешевле (шахта из нескольких пик больше не съедает полный кадр).
|
||||
|
||||
- **Отрисовка нажатой кнопки (0,2)/(0,3)** — ИСПРАВЛЕНО. Причина: `fore_tile`
|
||||
(pop_bg.c, fore-слой поверх Kid) рисовал переднюю грань КНОПКИ (bottom_id
|
||||
149) поверх уже нарисованной грани пола (43) — «остаток нажатой кнопки».
|
||||
Фикс: `fore_tile` применяет ту же подстановку нажатой кнопки, что и
|
||||
`draw_tile` (opener→floor / closer→stuck при таймере связи >1). Плюс
|
||||
`pop_button_redraw` — wipe своей ячейки + правой грани (дальний угол в
|
||||
0,3), низ строго yb+64 (не залезать в стену ряда 1).
|
||||
|
||||
## Заметки
|
||||
|
||||
- Тестовые клавиши осторожного шага: **J** = шаг влево, **L** = шаг вправо
|
||||
(эмуляция Shift+стрелка), см. `pop_ctrl.c` `KBD_DBG_STEP*`. Первый шаг в
|
||||
сторону = разворот (как в оригинале safe_step), движение со второго.
|
||||
- Респавн после смерти — по **↑** (или авто через `RESPAWN_DELAY`).
|
||||
- `START_ROOM=6` — временный тестовый старт; вернуть на
|
||||
`pop_level_start_room()` после отладки объектов.
|
||||
|
||||
---
|
||||
|
||||
## BUG-CEIL-1. Прыжок вверх: руки Kid рисуются ПОВЕРХ потолка — **Medium**
|
||||
|
||||
**Симптом (2026-07-22):** при прыжке вверх (SEQ up, кадры 67..79) руки/голова
|
||||
Kid заходят в полосу кладки у потолка (row -1) и рисуются ПОВЕРХ неё — потолок
|
||||
должен окклюдить руки (как передняя грань).
|
||||
|
||||
**Где:** `pop_bg.c` — полоса потолка (`draw_tile(-1)`) сейчас только фон
|
||||
(запечена в pop_room_draw), не окклюдер поверх Kid. Нужен ceiling-overlay в
|
||||
`pop_fore_over_kid` (перерисовать срез полосы над Kid поверх спрайта), по
|
||||
аналогии с fore-тайлами. Инфраструктура `g_clip_top`/`gfx_blit_part` уже есть.
|
||||
|
||||
## BUG-CEIL-2. Тряска/разбитие loose-плиты в потолке (row -1) не работает — **Medium**
|
||||
|
||||
**Симптом (2026-07-22):** loose-плита в ряду 2 верхнего соседа (room5 (2,5) →
|
||||
потолок room6 над (0,5)) при прыжках Kid на (0,5) НЕ трясётся и не разбивается.
|
||||
|
||||
**Где:** верхний сосед не «живой» — `above_fg` берётся из статики уровня,
|
||||
loose-состояние соседней комнаты не тянем (per-room loose/modif не персистятся,
|
||||
P0). check_press/knock работают только по текущей комнате. Нужно: (а) пробой
|
||||
loose сверху через границу комнаты, (б) персистентное loose-состояние соседа +
|
||||
его отрисовка в полосе. Пока полоса рисует loose статически (кадр покоя).
|
||||
|
||||
## BUG-OCCL-1. Тень дальней колонны перекрывает Kid в (0,4)-(0,5) — **Medium**
|
||||
|
||||
**Симптом (2026-07-22):** Kid, стоя/прыгая у (0,4)-(0,5), частично перекрыт
|
||||
тёмной штриховкой — это ТЕНЬ/боковая грань ДАЛЬНЕЙ колонны (сзади по глубине),
|
||||
которая НЕ должна окклюдить персонажа. Over-occlusion fore-слоя.
|
||||
|
||||
**Где:** `pop_bg.c` `pop_fore_over_kid`/`fore_tile` — рисует fore футпринт-тайлов
|
||||
без учёта глубины (какая грань РЕАЛЬНО перед Kid). Порт seg003 redraw_at_char
|
||||
окклюдит только передние грани; дальняя колонна (за Kid) не должна. Сверить с
|
||||
SDLPoP redraw_at_char (какие тайлы/грани идут в fore vs back по y-сортировке).
|
||||
|
||||
## BUG-CEIL-3. Анимация ворот стирает потолок над ними — **Medium**
|
||||
|
||||
**Симптом (2026-07-22):** при опускании/поднятии решётки шва (анимация openness)
|
||||
полоса кладки у потолка НАД воротами пропадает (см. потолок над левым швом).
|
||||
|
||||
**Где:** `pop_bg.c` `pop_room_redraw_seam_left` (и `pop_button_redraw`/
|
||||
`pop_spike_redraw` — общий класс): чёрный `bar` по col0 row0 стирает потолочную
|
||||
полосу (row-1), а redraw рисует только сам гейт, не восстанавливая полосу.
|
||||
Нужно: при перерисовке шва/тайла у потолка перерисовать и срез потолочной полосы
|
||||
(draw_tile(-1,col) с g_clip_top) над затронутыми колонками.
|
||||
|
||||
---
|
||||
|
||||
# BUG-SEAM-PINGPONG (#4). Пинг-понг drawn_room у шва с закрытыми воротами — **РЕШЁН 2026-07-22**
|
||||
|
||||
Статус: 2026-07-22, вечер. НАСТОЯЩИЙ корень найден потиковой трассой ЖИВОГО
|
||||
SDLPoP 1.23 (lldb-брейкпоинты на leave_room/bumped/safe_step с логом Char +
|
||||
char_x_left/right; fixes выключены = vanilla). Все прежние гипотезы ниже
|
||||
оставлены для истории — они НЕ были причиной.
|
||||
|
||||
## КОРЕНЬ (подтверждён трассой + исходником)
|
||||
|
||||
`set_char_collision` (seg006:0723): `char_x_right = obj_x/2 + 58`, где
|
||||
`load_frame_to_obj` (seg008:1728) считает `obj_x = 2*char_dx_forward(dx) - 116`
|
||||
и **добавляет +1** для кадров «чётного пикселя»:
|
||||
`if ((sbyte)(cur_frame.flags ^ obj_direction) >= 0) ++obj_x;`
|
||||
(бит 0x80 флагов кадра XOR направление; вправо: +1 если бит НЕ стоит).
|
||||
Деление `obj_x/2` — C-усечение К НУЛЮ, поэтому при `e = x+dx <= 57`
|
||||
(obj_x < 0, зона левого шва) поправка +1 даёт `char_x_right = e+1`, а при
|
||||
e >= 58 формула сокращается к чистому `e`.
|
||||
|
||||
Итог: Kid, осевший после отскока от ворот шва на x=57 (frame15, флаги 0x43 —
|
||||
бит 0x80 не стоит), имеет **char_x_right = 58** и порога leave-left (<=57)
|
||||
НЕ достигает. Наш движок считал передний край как `Kid.x + dx` без поправки
|
||||
→ 57 → ложный leave → пинг-понг.
|
||||
|
||||
Эталонный цикл SDLPoP (сн normalized по трассе): стойка x=61 → тап вправо →
|
||||
safe_step(d=0) → step, на первом dx(1) x=62 → bump (edge-триггер) → align 61 →
|
||||
seq47 dx(-4) → **x=57** (скрыт за кромкой) → кадры 50/51/52 (cxr 61/60/58, у
|
||||
всех бит 0x80 снят, e>57 — без сдвига) → стойка cxr=58 → leave НЕ срабатывает;
|
||||
тап → safe_step d=3 → x=60 (1/3 видно); тап → step1 → x=61 (2/3 видно); тап →
|
||||
bump → 57 … по кругу. Char.room и drawn_room НЕ меняются вообще.
|
||||
|
||||
## Фикс (pop_map.c)
|
||||
|
||||
`char_x_forward_edge()`: `e = char_dx_forward(dx); if (((flags ^ (dir<0 ?
|
||||
0x80 : 0)) & 0x80) == 0 && e <= 57) e++;` — используется в `char_front_coll`
|
||||
(коллизия/bump/edge_distance) и в `check_leave` (порог ухода). Плюс порт
|
||||
doortop-гарда leave-right из leave_room (тайл (9,row) = doortop → правого
|
||||
выхода нет). `pop_leave_timer` (exit_room_timer) оставлен — он реален в
|
||||
seg002/seg003.
|
||||
|
||||
## Гипотезы, ОТПАВШИЕ после трассы (история диагноза)
|
||||
|
||||
## Симптом (подтверждён пользователем + инструментально)
|
||||
|
||||
Kid стоит за решёткой закрытых ворот шва (левый сосед room8 виден в кромке
|
||||
room6). При удержании/нажатии ВПРАВО экран пинг-понгует между двумя
|
||||
состояниями:
|
||||
- **A**: показывается room6, Kid у левой кромки за решёткой (спрайт виден на 2/3);
|
||||
- **B**: показывается room8, Kid у его правой кромки.
|
||||
|
||||
Эталон SDLPoP (описан пользователем): drawn_room **всегда остаётся room6**,
|
||||
Kid осциллирует у кромки (1/3→2/3→отступил→по кругу), в room8 экран НЕ
|
||||
переключается. То есть у нас лишний свитч A→B.
|
||||
|
||||
## Тестовый контекст
|
||||
|
||||
START_ROOM=6. Ворота room8(0,9) закрыты, видны в col0 room6. Kid-структура
|
||||
kframe: см. pop_kid.h (frame,x,y,direction,curr_col,curr_row,action,...).
|
||||
Адрес _Kid и статиков — в .sprinter-cc-roomtest/roomtest.map (сдвигается от
|
||||
сборки к сборке). MAME: memory `mame_mcp_bridge`/`mame_hdd_test_disk`.
|
||||
Отладочные: J/L — короткий шаг влево/вправо (эмуляция Shift+стрелка).
|
||||
|
||||
## Инструментальный диагноз (watchpoint на pop_leave_dir)
|
||||
|
||||
В момент лишнего свитча A→B: `pop_leave_dir=1 (LEFT)`, Kid **frame=15 (СТОЯ,
|
||||
не transient!), Kid.x=57** (до репроекции +140). То есть:
|
||||
- `char_x_right = char_dx_forward(kid_cur_dx()) = Kid.x + frame15.dx = 57+0 = 57`.
|
||||
- Порог leave-left (взгляд вправо): `char_x_right <= 57` → срабатывает РОВНО на 57.
|
||||
- Грань ворот (где их держит коллизия) = **61** (`wall_dist_from_left[1]=10 +
|
||||
coll_tile_left_xpos=51`). Между 57 и 61 — **зазор 4px**: Kid НЕ удержан
|
||||
воротами (d=61−57=4≥0 → check_bumped не бампит), но уже на пороге ухода.
|
||||
- Kid оседает на 57 из-за recoil отскока: seq_47 = `act(bumped), dx(-4),
|
||||
frame_50, 51, 52`; SEQ_DX(−4) двигает Char.x на −4 суммарно; frame_50.dx=4
|
||||
компенсирует ТОЛЬКО точку коллизии НА кадре 50, но при возврате в стойку
|
||||
(frame15, dx=0) `char_x_right = Char.x = aligned−4 = 57`.
|
||||
|
||||
## Что ИСКЛЮЧЕНО (сверено с исходниками SDLPoP, НЕ причина)
|
||||
|
||||
- Формула char_x: `char_x_right = obj_x/2+58 = Char.x+frame.dx` (seg006
|
||||
set_char_collision) — совпадает с нашим char_dx_forward.
|
||||
- Позиция грани ворот: `get_left_wall_xpos = wall_dist_from_left[1](10) +
|
||||
xpos_in_drawn_room(x_bump[9+5])+7 = 10+(184−140)+7 = 61` — совпадает с нашим
|
||||
(`x_bump[−1+5]=44`, +7, +10 = 61).
|
||||
- Порог leave: SDLPoP leave_room looking-right `char_x_right<=57` — совпадает.
|
||||
- Данные кадров: frame_50 (image=49,dx=4,flags=0x67) и frame_15
|
||||
(image=14,dx=0,flags=0x43,sword=9) — БАЙТ-В-БАЙТ как в SDLPoP frame_table_kid.
|
||||
- seq_47 (act bumped, dx(-4), frame 50/51/52) — совпадает.
|
||||
|
||||
## Почему точечные фиксы НЕ работают
|
||||
|
||||
- Гард в check_leave (подавить leave на закрытых воротах) — это ОТСЕБЯТИНА,
|
||||
не SDLPoP (в leave_room такого нет); откачено.
|
||||
- `exit_room_timer=2` (порт seg002 exit_room — РЕАЛЬНЫЙ механизм, оставлен как
|
||||
pop_leave_timer): блокирует leave 2 кадра после входа в комнату. НЕ спасает:
|
||||
положение Char.x=57 **устойчивое** (Kid стоит), а не transient — после
|
||||
истечения таймера leave срабатывает.
|
||||
- По коду SDLPoP raw-рассуждением раз за разом выходит, что leave-left ДОЛЖЕН
|
||||
сработать и там (Char.x=57), но эталон показывает, что нет. Значит различие
|
||||
не в этих кусках, а в ДИНАМИКЕ: где именно оседает Char.x у шва И как
|
||||
вычисляется drawn_room.
|
||||
|
||||
## КОРЕНЬ (гипотеза)
|
||||
|
||||
Наш движок держит `drawn_room == комната_Kid` ВСЕГДА, а шов подделан:
|
||||
- коллизия — самодельные снапшоты кромок соседа (g_lcol/g_rcol, 1 колонка) +
|
||||
`x_bump[tcol=-1]`, а НЕ порт `curr_row_coll_room[]`/`get_all_coll_row`/
|
||||
`xpos_in_drawn_room` из seg004;
|
||||
- уход — мгновенный `enter_room(сосед)` при пороге char_x, а НЕ отложенный
|
||||
drawn_room через `next_room`/`check_the_end`.
|
||||
|
||||
Из-за упрощённой коллизии Char.x у шва оседает иначе, чем в SDLPoP (у нас ровно
|
||||
57 = порог), и/или drawn_room переключается там, где в оригинале нет.
|
||||
|
||||
## План S2/S3 (порт coll_room + отложенный drawn_room) — НЕ потребовался для
|
||||
## этого бага (трасса показала: в эталоне Char.room/drawn_room вообще не
|
||||
## меняются). Остаётся как задел под стражей/двух персонажей в кадре.
|
||||
|
||||
Правило проекта: SDLPoP — источник истины, переводить 1:1, НЕ рассуждать «как
|
||||
должно быть». Нужно портировать связку целиком:
|
||||
|
||||
1. **Раздельные комнаты.** `Char.room` (реальная комната персонажа) ≠
|
||||
`drawn_room` (отрисованная). У нас уже есть `kid_room` (S1) + рендер-смещение
|
||||
`pop_kid_set_render_dx(∓140)` (порт xpos_in_drawn_room для СПРАЙТА).
|
||||
|
||||
2. **Коллизия по Char.room через coll_room (seg004, S2).** Портировать
|
||||
`check_collisions` → `get_row_collision_data` (строки curr/below/above) →
|
||||
`get_left_wall_xpos`/`get_right_wall_xpos` (по `xpos_in_drawn_room(x_bump[
|
||||
col+FIRST_ONSCREEN_COLUMN])`, ±140 когда колонка принадлежит соседу) →
|
||||
массивы `curr_row_coll_room[]`/`_flags[]`, `bump_col_left_of_wall`/
|
||||
`bump_col_right_of_wall` → `check_bumped_look_left/right` → `bumped()`.
|
||||
Тайлы берутся из РЕАЛЬНОЙ комнаты колонки (get_tile(room,col,row) для любой
|
||||
комнаты), НЕ из снапшота. Именно это определяет, где Char.x оседает у шва.
|
||||
|
||||
3. **Отрисовка по drawn_room, персонаж со сдвигом.** Рисуем drawn_room; Kid
|
||||
(и будущие стражи) — со смещением ±140, если их комната ≠ drawn_room.
|
||||
|
||||
4. **Отложенная смена drawn_room (seg002/seg000, S3).** Уход =
|
||||
`leave_room` (seg002:0504, ПОРТ ЦЕЛИКОМ, включая up/down/side, guard'ы
|
||||
climb/standup/turn, doortop-check для right) → `goto_other_room`
|
||||
(seg002:0486: Char.room=сосед, x±140/y±189). `exit_room` (seg002:03C7):
|
||||
`exit_room_timer` + `next_room = Char.room`. `check_the_end` (seg000:0FBD):
|
||||
`if (next_room != 0 && next_room != drawn_room) drawn_room = next_room;
|
||||
redraw`. drawn_room меняется ТОЛЬКО так, а не по нашему прямому enter_room.
|
||||
|
||||
Ключевой момент, который надо переводить БУКВАЛЬНО (а не выводить): порядок
|
||||
вызовов в play_frame (seg000:863 `play_frame`: … play_kid_frame → exit_room →
|
||||
check_the_end) + set_char_collision перед leave_room в exit_room.
|
||||
|
||||
Карта сегментов: seg002 (leave/goto/exit_room), seg004 (коллизия/coll_room/
|
||||
bumped), seg006 (set_char_collision/play_seq/frame_table_kid), seg000
|
||||
(play_frame/check_the_end/draw). Наши файлы: pop_map.c (коллизия/физика/leave),
|
||||
roomtest.c (enter_room/drawn_room/главный цикл), pop_kid.c (кадры/рендер-сдвиг).
|
||||
|
||||
Реализовано на 2026-07-22: S1 (kid_room + render_dx) + pop_leave_timer.
|
||||
S2/S3 отложены — баг закрыт odd-pixel поправкой (см. КОРЕНЬ выше).
|
||||
Память: [[pop_seam_room_model]], [[sdlpop_odd_pixel_char_x]].
|
||||
Reference in New Issue
Block a user