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

6.4 KiB
Raw Blame History

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 → взводит knockcheck_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 <= 0modif = 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_*).