Files
Sprinter-SDCC/applications/PoP/docs/loose_floors_plan.md
T
snark13 fce3e58830 applications/PoP/docs: план порта loose floors (проваливающиеся полы)
Разбор SDLPoP (seg007 loose/trob/mob, seg008 draw_loose): хранение
состояния (tile 11 + curr_room_modif: 0 покой / 0x80.. тряска / 1..11
отсчёт падения), триггеры тряски (do_knock на приземлении → shake ряда)
и падения (make_loose_fall при стойке/зацепе на loose), падающий кусок
(mob → debris снизу, empty сверху), отрисовка по статусу (loose_fram_*
через get_loose_frame).  Порядок реализации L1..L5 + что нужно в нашем
движке (динамический тайловый слой: room_modif[], trob-очередь, mob).

ПЛАН — не реализация.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-18 12:31:23 +03:00

97 lines
6.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Loose floors (проваливающиеся полы) — план порта
Разбор SDLPoP (seg007 loose/trob/mob, seg008 draw_loose). ПЛАН, ещё не
реализовано. Тайл в комнате 1: `[2,6] = 0x0B = tiles_11_loose`.
## 1. Хранение состояния
- **Тип тайла**: `curr_room_tiles[tilepos] & 0x1F == 11` (tiles_11_loose).
Бит `0x20` = «solid» loose (авто-падающий вариант, ур.13 — от шага НЕ
падает). После падения тайл → `0` (tiles_0_empty).
- **Модификатор** `curr_room_modif[tilepos]` = состояние анимации:
- `0` — покой (обычный loose-пол);
- `0x80..0x83`**трясётся** (бит7); за ~4 кадра затухает обратно в 0;
- `1..11`**обратный отсчёт до падения** (на нём что-то стоит);
достигает `loose_floor_delay = 11` → падает.
## 2. Анимация тряски (shake) — когда включается
- **Триггер = do_knock** (seg007:0FE0): на ЖЁСТКОМ приземлении в кадрах
посадки играет `SEQ_KNOCK_DOWN` → взводит `knock``check_knock()`
`do_knock(room, curr_row (knock>0))`.
- `do_knock(room, row)`: по всем колонкам ряда — если тайл loose →
`loose_make_shake()`.
- `loose_make_shake()` (seg007:0FB4): если `modif==0` (и не ур.13) →
`modif = 0x80`, `add_trob(type 1)`.
- **Отсюда кейс пользователя**: Kid падает/приземляется на `[2,4]`
do_knock трясёт ВСЕ loose-тайлы ряда 2 → `[2,6]` трясётся. (Через
knock-смещение ряда может задеть и соседний ряд.)
- `animate_loose` (кадрово): `++modif`; при бите7 трясёт до `>=0x84`
сброс в 0, `trob.type=-1`. `loose_shake()` играет звук
(sound 20/21/22) по таблице `loose_sound[]`.
## 3. Анимация падения (fall) — когда включается
- **Триггер = make_loose_fall(1)** (seg007:0EF6), вызывается когда:
- Kid СТОИТ на loose-тайле — `check_press()` (seg006): кадр с
FRAME_NEEDS_FLOOR над loose → make_loose_fall(1);
- зацеп/подтягивание на loose (`check_grab`, `check_jump_up`);
- пробой сверху: кадр 79 (jumphang) над loose → make_loose_fall(1);
- авто-падающие (ур.13) — `make_loose_fall(-(prandom&0x0F))`.
- `make_loose_fall(modifier)`: если НЕ solid (`tiles & 0x20 == 0`) и
`(sbyte)modif <= 0``modif = modifier`, `add_trob(type 0)`.
- `animate_loose`: `++modif`; когда `modif >= 11` (loose_floor_delay) →
`remove_loose()` (тайл → empty) + `add_mob()` (спавн падающего куска).
## 4. Падающий кусок (mob)
- `add_mob()` кладёт `curmob` в `mobs[]` (до 14). `do_mobs()` каждый
кадр: `move_mob()` (гравитация, y растёт) + `check_loose_fall_on_kid()`
(урон Киду/страже, если попал).
- Приземление куска → тайл под ним `curr_room_tiles[...] = tiles_14_debris`
(seg007 move_mob:1053). Т.е. **loose(11) упал → сверху empty(0), снизу
debris(14)**.
## 5. Отрисовка по статусу
- Куски тайла: `loose_fram_left[]={41,69,41,70,70,41,41,41,70,70,70,0}`,
`loose_fram_right[]={42,71,...}`, `loose_fram_bottom[]={43,73,...}`
(env-спрайты, seg008:518/596/608).
- Индекс кадра = `get_loose_frame(modifier)` (seg008): `0` = ровный
(41/42/43); `1..10` = дрожащие варианты (69–74); при бите7/большой
задержке — низкие индексы.
- **До падения**: рисуем loose с `get_loose_frame(modif)` (0 = ровно,
иначе колеблется). **После**: сверху empty, снизу debris(14) — обычная
статическая отрисовка (у нас уже есть tile 0x0E/14 debris в tile_table).
## 6. Что нужно в нашем движке (сейчас НЕТ)
Наш `pop_bg` рисует комнату СТАТИЧЕСКИ один раз. Loose-полы требуют
**динамического тайлового слоя**:
1. **Массив модификаторов** `room_modif[30]` (у нас есть `bg[30]` — можно
переиспользовать/рядом) — состояние каждого тайла.
2. **Очередь trob** (список анимируемых тайлов) + `animate_loose` пер-кадр
→ перерисовка ТОЛЬКО изменившихся тайлов (как heal-прямоугольник Kid).
3. **make_loose_fall / do_knock / loose_make_shake** — триггеры (из
физики Kid: приземление→knock, стойка на loose→fall).
4. **mob-система** (падающий кусок): минимум 1–2 mob'а, гравитация,
приземление → debris. Урон Киду (`check_loose_fall_on_kid`) — можно
Фазой 2.
5. **Перерисовка тайла**: `draw_tile(row,col)` у нас уже умеет loose
(`code==11`, `loose_fram_*` в env) — нужно вызывать его выборочно с
текущим модификатором (сейчас draw_tile берёт статический bg).
**Порядок реализации (предложение):**
- L1: room_modif[] + выборочная перерисовка тайла по модификатору
(draw_loose с get_loose_frame) — статика→динамика одного тайла.
- L2: trob-очередь + animate_loose (тряска по do_knock на приземлении).
- L3: make_loose_fall (стойка на loose) + отсчёт + remove → empty.
- L4: mob (падающий кусок → debris снизу).
- L5: урон Киду от падающего куска.
## Связанные
Триггеры завязаны на физику Kid ([[pop_hang_state]] check_press/check_grab,
приземление land/SEQ_KNOCK_DOWN). Отрисовка — [[pop_fore_layer]] /
[[pop_background_strategy]] (draw_tile уже знает loose_fram_*).