diff --git a/applications/PoP/docs/loose_floors_plan.md b/applications/PoP/docs/loose_floors_plan.md index 799080c..5ab72fa 100644 --- a/applications/PoP/docs/loose_floors_plan.md +++ b/applications/PoP/docs/loose_floors_plan.md @@ -89,6 +89,53 @@ - L4: mob (падающий кусок → debris снизу). - L5: урон Киду от падающего куска. +## Конкретика из SDLPoP (сверено 2026-07-18, готово к реализации) + +Таблицы (seg008.c), индекс = `get_loose_frame(modif)`: +- `loose_fram_left[] = {41,69,41,70,70,41,41,41,70,70,70,0}` +- `loose_fram_right[] = {42,71,42,72,72,42,42,42,72,72,72,0}` +- `loose_fram_bottom[]= {43,73,43,74,74,43,43,43,74,74,74,0}` +- `get_loose_frame(m)`: если `(m&0x80)` (или delay>11) → `m&=0x7F; if(m>10) return 1;` → `return m;` +- `y_loose_land[] = {2,65,128,191,254}` (mob), `loose_floor_delay = 11`. + +Триггеры (call-sites): +- **make_loose_fall(modifier=1)** — из `check_press()` (seg006): когда Kid + СТОИТ на тайле (FRAME_NEEDS_FLOOR, action < hang_climb / turn / bumped) и + `get_tile_at_char()==11`; ИЛИ `frame==79` (прыжок вверх) и + `get_tile_above_char()==11` (пробой сверху). `tile_is_floor(11)==1` — + Kid стоит на loose (start_fall НЕ зовётся). Тело: + `if(!(tile&0x20) && (sbyte)modif<=0){ modif=modifier; add_trob(type0); }` +- **do_knock(row)** — на ЖЁСТКОМ приземлении (SEQ_KNOCK_DOWN→check_knock, + seg003): по всем колонкам ряда `if(tile==11) loose_make_shake()` + (`if(modif==0){ modif=0x80; add_trob(type1); }`). +- **animate_loose** (каждый кадр, seg007:816): `++modif`; если `&0x80` + (тряска): `if(modif>=0x84){modif=0; trob=-1;}`; иначе (отсчёт): + `if(modif>=11){ remove_loose(tile→0); trob=-1; add_mob(); } else shake`. + +## Интеграция в наш движок (roomtest) — подход + +Наш движок ПЕКЁТ комнату один раз (двойной буфер: своя ОЗУ-копия на +страницу). Loose требует динамики + общего состояния pop_map↔pop_bg: +1. **Общая МУТАБЕЛЬНАЯ копия комнаты**: roomtest.c держит `uint8_t + room_fg[30]` (копия room1_fg) и передаёт ОДИН указатель и в + `pop_room_draw`, и в `pop_map_set` → мутации loose видны обоим. + (Сейчас g_fg — `const`; сделать неконстантным.) +2. **Состояние**: `uint8_t pop_loose_modif[30]` (0 / 0x80.. / 1..11). +3. **Модель** (pop_map): `check_press()` в `pop_phys_tick` (make_loose_fall + при стоянии на 11), `animate` каждый кадр. +4. **Перерисовка** (pop_bg, на back-странице каждый кадр): + - тряска/отсчёт (код всё ещё 11): `gfx_heal(tile rect)` (вернуть + печёный фон) + нарисовать loose-кадр (left/right/bottom по + get_loose_frame) банком SPRITE; + - падение (11→0): mutate `g_fg[pos]=0` + «запечь пустоту» на ОБЕИХ + страницах (bake-счётчик 2: чёрный bar + draw_tile empty банком NORMAL + на текущей странице 2 кадра подряд) → дальше heal показывает пусто. +5. **L4 mob**: падающий кусок → debris(14) снизу (y_loose_land); пока + отложено — упавший loose = пусто. **L5** урон — позже. + +Риск: перерисовка динамического тайла в двойном буфере (per-page heal + +bake) — единственное тонкое место; остальное — прямой порт логики выше. + ## Связанные Триггеры завязаны на физику Kid ([[pop_hang_state]] check_press/check_grab,