Compare commits
2 Commits
eef6eebd8c
...
4cffbc9aa4
| Author | SHA1 | Date | |
|---|---|---|---|
| 4cffbc9aa4 | |||
| 24bb724c22 |
@@ -12,7 +12,7 @@ MEMORY ?= small
|
|||||||
# __banked-модулей (стражи): из банка резидентная страница W3 не видна —
|
# __banked-модулей (стражи): из банка резидентная страница W3 не видна —
|
||||||
# ни напрямую, ни транзитивно. См. docs/layout_plan_v2.md §2 (R2), §4.
|
# ни напрямую, ни транзитивно. См. docs/layout_plan_v2.md §2 (R2), §4.
|
||||||
EXTRA_FLAGS ?= --gfx 256 --w3 pop_bg.c
|
EXTRA_FLAGS ?= --gfx 256 --w3 pop_bg.c
|
||||||
EXTRA_SRCS := pop_kid.c pop_ctrl.c pop_level.c pop_map.c pop_trob.c
|
EXTRA_SRCS := pop_kid.c pop_ctrl.c pop_level.c pop_map.c pop_trob.c pop_redraw.c
|
||||||
|
|
||||||
BG_DIR := $(CURDIR)/../poc/res/bg
|
BG_DIR := $(CURDIR)/../poc/res/bg
|
||||||
KID_DIR := $(CURDIR)/../poc/res/kid
|
KID_DIR := $(CURDIR)/../poc/res/kid
|
||||||
@@ -42,4 +42,4 @@ $(KID_DATA): $(TC)/pop_pack_kid.py $(TC)/pop_pack_bg.py
|
|||||||
kid_data.h $(KID_BIN): $(TC)/pop_extract_kid_data.py
|
kid_data.h $(KID_BIN): $(TC)/pop_extract_kid_data.py
|
||||||
cd $(TC) && python3 pop_extract_kid_data.py
|
cd $(TC) && python3 pop_extract_kid_data.py
|
||||||
|
|
||||||
$(EXAMPLE).exe: pop_bg.c pop_bg.h pop_kid.c pop_kid.h pop_ctrl.c pop_ctrl.h pop_map.c pop_map.h pop_level.c pop_level.h pop_trob.c pop_trob.h kid_data.h $(BG_DATA) $(KID_DATA) $(KID_BIN) $(LVL_DATA)
|
$(EXAMPLE).exe: pop_bg.c pop_bg.h pop_redraw.c pop_redraw.h pop_kid.c pop_kid.h pop_ctrl.c pop_ctrl.h pop_map.c pop_map.h pop_level.c pop_level.h pop_trob.c pop_trob.h kid_data.h $(BG_DATA) $(KID_DATA) $(KID_BIN) $(LVL_DATA)
|
||||||
|
|||||||
@@ -19,7 +19,14 @@
|
|||||||
#include "pop_kid.h"
|
#include "pop_kid.h"
|
||||||
#include "pop_map.h"
|
#include "pop_map.h"
|
||||||
#include "pop_ctrl.h" /* pop_ctrl_shift_held() — для check_grab */
|
#include "pop_ctrl.h" /* pop_ctrl_shift_held() — для check_grab */
|
||||||
#include "pop_bg.h" /* pop_loose_shake_draw/bake_empty — перерисовка */
|
#include "pop_redraw.h" /* пометки перерисовки (порт set_redraw_*) */
|
||||||
|
/* pop_bg нужен ТОЛЬКО падающему куску (mob): spawn/tick/pos — это движущийся
|
||||||
|
* ОБЪЕКТ, а не перерисовка тайла (в оригинале он и живёт отдельно: mobs +
|
||||||
|
* draw_moving). Из-за него pop_loose_tick — единственная функция модуля,
|
||||||
|
* которую нельзя звать из __banked-кода; вся коллизия/физика/предметы, то
|
||||||
|
* есть то, что понадобится стражам, чиста от графики. Разделение mob на
|
||||||
|
* логику и отрисовку — задел следующей фазы. */
|
||||||
|
#include "pop_bg.h"
|
||||||
#include "pop_trob.h" /* room_modif + trob-список (пики/ворота) */
|
#include "pop_trob.h" /* room_modif + trob-список (пики/ворота) */
|
||||||
|
|
||||||
/* ---- Тайлы / действия / seq id (подмножество PoP) ------------------ */
|
/* ---- Тайлы / действия / seq id (подмножество PoP) ------------------ */
|
||||||
@@ -142,11 +149,9 @@ static uint8_t g_lcol[6], g_rcol[6];
|
|||||||
* отдельное — pop_ceil_modif[col] с той же семантикой (0 покой, 0x80.. —
|
* отдельное — pop_ceil_modif[col] с той же семантикой (0 покой, 0x80.. —
|
||||||
* тряска, 1..11 — отсчёт до падения). */
|
* тряска, 1..11 — отсчёт до падения). */
|
||||||
uint8_t pop_ceil_modif[10]; /* публично: читает pop_bg при отрисовке */
|
uint8_t pop_ceil_modif[10]; /* публично: читает pop_bg при отрисовке */
|
||||||
static uint8_t ceil_rest[10]; /* «перерисовать ПОКОЙ» (2 = обе страницы) */
|
|
||||||
static uint8_t ceil_bake[10]; /* «запечь колодец» на второй странице */
|
|
||||||
static uint8_t land_bake, land_bake_pos; /* щебень от приземления — вторая страница */
|
|
||||||
static uint8_t *g_above; /* ряд 2 комнаты сверху (fg), мутабельный */
|
static uint8_t *g_above; /* ряд 2 комнаты сверху (fg), мутабельный */
|
||||||
uint8_t pop_ceil_fell; /* 0 = нет; иначе col+1 провалившейся плиты-потолка */
|
uint8_t pop_ceil_fell; /* 0 = нет; иначе col+1 провалившейся плиты-потолка */
|
||||||
|
|
||||||
uint8_t pop_debris_at; /* 0 = нет; иначе tilepos+1 нового щебня в ЭТОЙ комнате */
|
uint8_t pop_debris_at; /* 0 = нет; иначе tilepos+1 нового щебня в ЭТОЙ комнате */
|
||||||
|
|
||||||
void pop_map_set_above(uint8_t *above_row2_fg) { g_above = above_row2_fg; }
|
void pop_map_set_above(uint8_t *above_row2_fg) { g_above = above_row2_fg; }
|
||||||
@@ -1027,8 +1032,6 @@ static void check_bumped(void)
|
|||||||
* отсчёт до падения (на тайле стоят/пробили). Порт animate_loose/
|
* отсчёт до падения (на тайле стоят/пробили). Порт animate_loose/
|
||||||
* make_loose_fall/check_press. Перерисовка — в pop_bg (shake/bake). */
|
* make_loose_fall/check_press. Перерисовка — в pop_bg (shake/bake). */
|
||||||
uint8_t pop_loose_modif[30]; /* публично: читает pop_bg при отрисовке */
|
uint8_t pop_loose_modif[30]; /* публично: читает pop_bg при отрисовке */
|
||||||
static uint8_t loose_bake[30]; /* счётчик «запечь пусто» (2 = обе страницы) */
|
|
||||||
static uint8_t loose_rest[30]; /* счётчик «перерисовать ПОКОЙ» после тряски (2 = обе стр.) */
|
|
||||||
|
|
||||||
/* Плита-ПОТОЛОК: состояние/сигналы — см. объявления перед get_tile. */
|
/* Плита-ПОТОЛОК: состояние/сигналы — см. объявления перед get_tile. */
|
||||||
|
|
||||||
@@ -1131,18 +1134,13 @@ void pop_loose_reset(void)
|
|||||||
int i;
|
int i;
|
||||||
for (i = 0; i < 30; i++) {
|
for (i = 0; i < 30; i++) {
|
||||||
pop_loose_modif[i] = 0;
|
pop_loose_modif[i] = 0;
|
||||||
loose_bake[i] = 0;
|
|
||||||
loose_rest[i] = 0;
|
|
||||||
}
|
}
|
||||||
for (i = 0; i < 10; i++) {
|
for (i = 0; i < 10; i++) {
|
||||||
pop_ceil_modif[i] = 0;
|
pop_ceil_modif[i] = 0;
|
||||||
ceil_rest[i] = 0;
|
|
||||||
ceil_bake[i] = 0;
|
|
||||||
}
|
}
|
||||||
pop_ceil_fell = 0;
|
pop_ceil_fell = 0;
|
||||||
pop_debris_at = 0;
|
pop_debris_at = 0;
|
||||||
pop_loose_landed = 0;
|
pop_loose_landed = 0;
|
||||||
land_bake = 0;
|
|
||||||
pop_loose_mob_reset();
|
pop_loose_mob_reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1201,24 +1199,17 @@ void pop_loose_tick(void)
|
|||||||
* Инкремент+сравнение считают row/col без деления. */
|
* Инкремент+сравнение считают row/col без деления. */
|
||||||
uint8_t row = 0, col = 0;
|
uint8_t row = 0, col = 0;
|
||||||
for (pos = 0; pos < 30; pos++) {
|
for (pos = 0; pos < 30; pos++) {
|
||||||
if (loose_bake[pos]) { /* упал: запечь пусто (2 кадра=2 стр.) */
|
if (pop_loose_modif[pos] != 0) {
|
||||||
pop_loose_bake_empty(row, col);
|
|
||||||
loose_bake[pos]--;
|
|
||||||
} else if (loose_rest[pos]) { /* тряска кончилась: перерисовать ПОКОЙ */
|
|
||||||
/* modif уже 0 → shake_draw рисует базовый кадр (покой) обоих тайлов
|
|
||||||
* (col и col+1: правая грань loose живёт в 2,7). 2 кадра = обе
|
|
||||||
* страницы дабл-буфера — иначе на одной остаётся застывший
|
|
||||||
* дрожащий кадр правой грани → мерцание («бесконечная тряска»). */
|
|
||||||
pop_loose_shake_draw(row, col);
|
|
||||||
loose_rest[pos]--;
|
|
||||||
} else if (pop_loose_modif[pos] != 0) {
|
|
||||||
uint8_t m = ++pop_loose_modif[pos];
|
uint8_t m = ++pop_loose_modif[pos];
|
||||||
if (m & 0x80) { /* тряска (do_knock) */
|
if (m & 0x80) { /* тряска (do_knock) */
|
||||||
if (m >= 0x84) { /* конец тряски: сброс + перерисовать покой */
|
if (m >= 0x84) { /* конец тряски: сброс + покой */
|
||||||
pop_loose_modif[pos] = 0;
|
pop_loose_modif[pos] = 0;
|
||||||
loose_rest[pos] = 2; /* покой на ОБЕИХ страницах */
|
/* modif уже 0 → кадр покоя обоих тайлов (col и col+1:
|
||||||
|
* правая грань loose живёт в соседе). ОБЕ страницы —
|
||||||
|
* иначе на одной застывает дрожащий кадр → мерцание. */
|
||||||
|
pop_set_redraw(pos, POP_RD_LOOSE, 2);
|
||||||
} else {
|
} else {
|
||||||
pop_loose_shake_draw(row, col); /* дрожащий кадр */
|
pop_set_redraw(pos, POP_RD_LOOSE, 1); /* дрожащий кадр */
|
||||||
}
|
}
|
||||||
} else if (m >= 11) { /* loose_floor_delay — падение */
|
} else if (m >= 11) { /* loose_floor_delay — падение */
|
||||||
/* remove_loose (seg007:0EB8): тайл → EMPTY (не debris!).
|
/* remove_loose (seg007:0EB8): тайл → EMPTY (не debris!).
|
||||||
@@ -1228,12 +1219,11 @@ void pop_loose_tick(void)
|
|||||||
* (стена-вниз от тайла снизу + чёрный фон). */
|
* (стена-вниз от тайла снизу + чёрный фон). */
|
||||||
g_fg[pos] = TILE_EMPTY;
|
g_fg[pos] = TILE_EMPTY;
|
||||||
pop_loose_modif[pos] = 0;
|
pop_loose_modif[pos] = 0;
|
||||||
pop_loose_bake_empty(row, col); /* запечь пусто на ТЕКУЩЕЙ странице сразу */
|
pop_set_redraw(pos, POP_RD_LOOSE_GONE, 2); /* запечь пусто, обе стр. */
|
||||||
loose_bake[pos] = 1; /* + вторая страница следующим кадром */
|
pop_loose_mob_spawn(row, col); /* отрыв падающего куска */
|
||||||
pop_loose_mob_spawn(row, col); /* отрыв падающего куска (L4) */
|
pop_loose_fell = (uint8_t)(pos + 1); /* сигнал приложению */
|
||||||
pop_loose_fell = (uint8_t)(pos + 1); /* сигнал приложению: кусок улетел */
|
|
||||||
} else { /* отсчёт 1..10 — дрожащий кадр */
|
} else { /* отсчёт 1..10 — дрожащий кадр */
|
||||||
pop_loose_shake_draw(row, col);
|
pop_set_redraw(pos, POP_RD_LOOSE, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (++col == 10) { col = 0; row++; } /* row/col без деления */
|
if (++col == 10) { col = 0; row++; } /* row/col без деления */
|
||||||
@@ -1242,27 +1232,21 @@ void pop_loose_tick(void)
|
|||||||
* рисуются в полосе у потолка, а провалившаяся плита становится EMPTY в
|
* рисуются в полосе у потолка, а провалившаяся плита становится EMPTY в
|
||||||
* НАШЕЙ копии ряда (g_above) — сверху открывается колодец. */
|
* НАШЕЙ копии ряда (g_above) — сверху открывается колодец. */
|
||||||
for (col = 0; col < 10; col++) {
|
for (col = 0; col < 10; col++) {
|
||||||
if (ceil_rest[col]) {
|
if (pop_ceil_modif[col] != 0) {
|
||||||
pop_ceil_shake_draw(col); /* modif уже 0 → кадр покоя */
|
|
||||||
ceil_rest[col]--;
|
|
||||||
} else if (pop_ceil_modif[col] != 0) {
|
|
||||||
uint8_t m = ++pop_ceil_modif[col];
|
uint8_t m = ++pop_ceil_modif[col];
|
||||||
if (m & 0x80) { /* тряска от сотрясения (do_knock) */
|
if (m & 0x80) { /* тряска от сотрясения (do_knock) */
|
||||||
if (m >= 0x84) { pop_ceil_modif[col] = 0; ceil_rest[col] = 2; }
|
if (m >= 0x84) { pop_ceil_modif[col] = 0;
|
||||||
else pop_ceil_shake_draw(col);
|
pop_set_redraw_above(col, POP_RDA_CEIL, 2); }
|
||||||
|
else pop_set_redraw_above(col, POP_RDA_CEIL, 1);
|
||||||
} else if (m >= 11) { /* loose_floor_delay — плита рушится */
|
} else if (m >= 11) { /* loose_floor_delay — плита рушится */
|
||||||
pop_ceil_modif[col] = 0;
|
pop_ceil_modif[col] = 0;
|
||||||
if (g_above) g_above[col] = TILE_EMPTY; /* remove_loose */
|
if (g_above) g_above[col] = TILE_EMPTY; /* remove_loose */
|
||||||
pop_ceil_bake_empty(col); /* колодец наверх на ТЕКУЩЕЙ странице */
|
pop_set_redraw_above(col, POP_RDA_CEIL_GONE, 2); /* колодец, обе стр. */
|
||||||
ceil_bake[col] = 1; /* + вторая страница следующим кадром */
|
|
||||||
pop_loose_mob_spawn(-1, col); /* кусок отрывается от потолка */
|
pop_loose_mob_spawn(-1, col); /* кусок отрывается от потолка */
|
||||||
pop_ceil_fell = (uint8_t)(col + 1); /* сигнал приложению */
|
pop_ceil_fell = (uint8_t)(col + 1); /* сигнал приложению */
|
||||||
} else {
|
} else {
|
||||||
pop_ceil_shake_draw(col); /* отсчёт 1..10 — дрожащий кадр */
|
pop_set_redraw_above(col, POP_RDA_CEIL, 1); /* отсчёт 1..10 */
|
||||||
}
|
}
|
||||||
} else if (ceil_bake[col]) {
|
|
||||||
pop_ceil_bake_empty(col);
|
|
||||||
ceil_bake[col]--;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pop_loose_mob_tick(); /* продвинуть+нарисовать падающий кусок (после тайлов) */
|
pop_loose_mob_tick(); /* продвинуть+нарисовать падающий кусок (после тайлов) */
|
||||||
@@ -1270,29 +1254,18 @@ void pop_loose_tick(void)
|
|||||||
/* Отложенная допечка ПРОШЛОГО приземления на вторую страницу — ПЕРЕД
|
/* Отложенная допечка ПРОШЛОГО приземления на вторую страницу — ПЕРЕД
|
||||||
* разбором нового: иначе при двух плитах, севших подряд, land_bake
|
* разбором нового: иначе при двух плитах, севших подряд, land_bake
|
||||||
* затирался новым и на одной странице оставался старый пол. */
|
* затирался новым и на одной странице оставался старый пол. */
|
||||||
if (land_bake && pop_loose_landed) {
|
|
||||||
uint8_t r = 0, c = land_bake_pos;
|
|
||||||
while (c >= 10) { c -= 10; r++; }
|
|
||||||
pop_floor_bake(r, c);
|
|
||||||
land_bake = 0;
|
|
||||||
}
|
|
||||||
if (pop_loose_landed) { /* loose_land (seg007:11E8): на месте куска — щебень */
|
if (pop_loose_landed) { /* loose_land (seg007:11E8): на месте куска — щебень */
|
||||||
uint8_t pos = (uint8_t)(pop_loose_landed - 1);
|
uint8_t pos = (uint8_t)(pop_loose_landed - 1);
|
||||||
uint8_t r = 0, c = pos;
|
uint8_t r = 0, c = pos;
|
||||||
pop_loose_landed = 0;
|
pop_loose_landed = 0;
|
||||||
while (c >= 10) { c -= 10; r++; }
|
while (c >= 10) { c -= 10; r++; }
|
||||||
g_fg[pos] = TILE_DEBRIS;
|
g_fg[pos] = TILE_DEBRIS;
|
||||||
/* Перерисовка ПО ПЛОЩАДИ ПОЛА (не bake_empty: та стирает и верх стены
|
/* Перерисовка ПО ПЛОЩАДИ ПОЛА (не LOOSE_GONE: та стирает и верх стены
|
||||||
* ряда ниже — оставался чёрный прямоугольник под тайлом). */
|
* ряда ниже — оставался чёрный прямоугольник под тайлом). Обе
|
||||||
pop_floor_bake(r, c);
|
* страницы дабл-буфера. */
|
||||||
land_bake_pos = pos; land_bake = 1; /* вторая страница дабл-буфера */
|
pop_set_redraw(pos, POP_RD_FLOOR, 2);
|
||||||
do_knock(r); /* удар плиты трясёт loose этого ряда */
|
do_knock(r); /* удар плиты трясёт loose этого ряда */
|
||||||
pop_debris_at = (uint8_t)(pos + 1); /* сигнал приложению (персистентность) */
|
pop_debris_at = (uint8_t)(pos + 1); /* сигнал приложению (персистентность) */
|
||||||
} else if (land_bake) {
|
|
||||||
uint8_t r = 0, c = land_bake_pos;
|
|
||||||
while (c >= 10) { c -= 10; r++; }
|
|
||||||
pop_floor_bake(r, c);
|
|
||||||
land_bake = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
* pop_redraw.c — пометки перерисовки тайлов и их разбор. См. pop_redraw.h.
|
||||||
|
*
|
||||||
|
* Живёт в W1/W2 (НЕ в резиденте W3): пометки ставит логика, которая должна
|
||||||
|
* оставаться достижимой из будущих __banked-модулей. Сам разбор зовёт
|
||||||
|
* pop_bg (резидент W3) — это законно, потому что разбор дёргает только
|
||||||
|
* главный цикл.
|
||||||
|
*/
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "pop_redraw.h"
|
||||||
|
#include "pop_bg.h"
|
||||||
|
|
||||||
|
#define NTILES 30
|
||||||
|
#define NCOLS 10
|
||||||
|
|
||||||
|
static uint8_t rd_kind[NTILES], rd_cnt[NTILES];
|
||||||
|
static uint8_t rda_kind[NCOLS], rda_cnt[NCOLS];
|
||||||
|
/* Сколько всего непустых пометок: без него проход по 40 ячейкам крутился бы
|
||||||
|
* КАЖДЫЙ кадр впустую (замер 2026-07-27 на прежнем rest-цикле: ~12 % кадра). */
|
||||||
|
static uint8_t rd_pending;
|
||||||
|
|
||||||
|
void pop_redraw_reset(void)
|
||||||
|
{
|
||||||
|
uint8_t i;
|
||||||
|
for (i = 0; i < NTILES; i++) { rd_kind[i] = 0; rd_cnt[i] = 0; }
|
||||||
|
for (i = 0; i < NCOLS; i++) { rda_kind[i] = 0; rda_cnt[i] = 0; }
|
||||||
|
rd_pending = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pop_set_redraw(uint8_t tilepos, uint8_t kind, uint8_t pages)
|
||||||
|
{
|
||||||
|
if (tilepos >= NTILES) return;
|
||||||
|
if (!rd_cnt[tilepos]) rd_pending++;
|
||||||
|
rd_kind[tilepos] = kind;
|
||||||
|
if (pages > rd_cnt[tilepos]) rd_cnt[tilepos] = pages;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pop_set_redraw_above(uint8_t col, uint8_t kind, uint8_t pages)
|
||||||
|
{
|
||||||
|
if (col >= NCOLS) return;
|
||||||
|
if (!rda_cnt[col]) rd_pending++;
|
||||||
|
rda_kind[col] = kind;
|
||||||
|
if (pages > rda_cnt[col]) rda_cnt[col] = pages;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* redraw_needed (seg008:0178): пройти пометки и нарисовать. row/col ведём
|
||||||
|
* бегущими счётчиками, а не через i/10 и i%10 — у Z80 нет деления, и SDCC
|
||||||
|
* выносит __divuchar/__moduchar в вершину цикла как общее подвыражение
|
||||||
|
* аргументов (30*2 делений за кадр даже когда рисовать нечего). */
|
||||||
|
void pop_redraw_needed(void)
|
||||||
|
{
|
||||||
|
uint8_t i, row = 0, col = 0, left = 0;
|
||||||
|
if (!rd_pending) return;
|
||||||
|
for (i = 0; i < NTILES; i++) {
|
||||||
|
if (rd_cnt[i]) {
|
||||||
|
switch (rd_kind[i]) {
|
||||||
|
case POP_RD_SPIKE: pop_spike_redraw(row, col); break;
|
||||||
|
case POP_RD_LOOSE: pop_loose_shake_draw(row, col); break;
|
||||||
|
case POP_RD_LOOSE_GONE: pop_loose_bake_empty(row, col); break;
|
||||||
|
case POP_RD_FLOOR: pop_floor_bake(row, col); break;
|
||||||
|
case POP_RD_LEVELDOOR: pop_leveldoor_redraw(row, col); break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
if (--rd_cnt[i]) left++;
|
||||||
|
else rd_kind[i] = 0;
|
||||||
|
}
|
||||||
|
if (++col == 10) { col = 0; row++; }
|
||||||
|
}
|
||||||
|
for (i = 0; i < NCOLS; i++) {
|
||||||
|
if (rda_cnt[i]) {
|
||||||
|
if (rda_kind[i] == POP_RDA_CEIL) pop_ceil_shake_draw(i);
|
||||||
|
else pop_ceil_bake_empty(i);
|
||||||
|
if (--rda_cnt[i]) left++;
|
||||||
|
else rda_kind[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rd_pending = left;
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* pop_redraw.h — пометки «перерисовать тайл» и их разбор.
|
||||||
|
*
|
||||||
|
* Порт архитектуры оригинала: логика анимации НИЧЕГО не рисует, она ставит
|
||||||
|
* флаг (`set_redraw_full`/`set_wipe`/`redraw_20h`/`redraw_21h`, seg007), а
|
||||||
|
* отрисовка идёт отдельным проходом (`redraw_needed`, seg008:0178). У нас
|
||||||
|
* так же: pop_map/pop_trob зовут pop_set_redraw*, а pop_redraw_needed()
|
||||||
|
* (главный цикл) разбирает пометки и дёргает pop_bg.
|
||||||
|
*
|
||||||
|
* ЗАЧЕМ (кроме сходства с SDLPoP): из __banked-кода резидентная страница W3
|
||||||
|
* недостижима — ни напрямую, ни транзитивно (docs/layout_plan_v2.md §2 R2).
|
||||||
|
* Пока pop_map звал pop_bg, его нельзя было использовать из банка стражей.
|
||||||
|
* Пометки живут в W1/W2 и зовутся откуда угодно.
|
||||||
|
*
|
||||||
|
* ОТЛИЧИЕ ОТ ОРИГИНАЛА: у нас не один экран с dirty-rect, а две страницы
|
||||||
|
* дабл-буфера со своей ОЗУ-копией фона, поэтому счётчик пометки — это ЧИСЛО
|
||||||
|
* СТРАНИЦ (обычно 2), а вид перерисовки хранится явно: heal+рисовать поверх
|
||||||
|
* (транзиент) или запечь новый фон. В оригинале вид кодируется тем, в какой
|
||||||
|
* из таблиц redraw_frames_* стоит флаг.
|
||||||
|
*/
|
||||||
|
#ifndef POP_REDRAW_H
|
||||||
|
#define POP_REDRAW_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/* Виды перерисовки тайла (row*10+col). */
|
||||||
|
#define POP_RD_SPIKE 1 /* пики: heal + оба тайла (redraw_21h) */
|
||||||
|
#define POP_RD_LOOSE 2 /* loose: дрожащий кадр / кадр покоя */
|
||||||
|
#define POP_RD_LOOSE_GONE 3 /* loose провалился: запечь пусто */
|
||||||
|
#define POP_RD_FLOOR 4 /* пол изменился: кнопка/щебень/поднятый меч */
|
||||||
|
#define POP_RD_LEVELDOOR 5 /* створка двери уровня (ПРАВАЯ половина) */
|
||||||
|
|
||||||
|
/* Виды перерисовки полосы у потолка (по колонке). */
|
||||||
|
#define POP_RDA_CEIL 1 /* плита-потолок: дрожащий кадр / покой */
|
||||||
|
#define POP_RDA_CEIL_GONE 2 /* плита-потолок провалилась: колодец */
|
||||||
|
|
||||||
|
/* Пометить тайл/колонку: kind — вид, pages — на скольких страницах
|
||||||
|
* дабл-буфера перерисовать (1 = только текущая, 2 = обе). Повторная
|
||||||
|
* пометка перекрывает вид и берёт максимум счётчика. */
|
||||||
|
void pop_set_redraw(uint8_t tilepos, uint8_t kind, uint8_t pages);
|
||||||
|
void pop_set_redraw_above(uint8_t col, uint8_t kind, uint8_t pages);
|
||||||
|
|
||||||
|
/* Разобрать пометки: нарисовать всё помеченное на ТЕКУЩЕЙ (back) странице и
|
||||||
|
* уменьшить счётчики. Звать из главного цикла в слое ФОНА — до kid_draw. */
|
||||||
|
void pop_redraw_needed(void);
|
||||||
|
|
||||||
|
/* Сбросить все пометки (смена комнаты/уровня). */
|
||||||
|
void pop_redraw_reset(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -5,7 +5,13 @@
|
|||||||
*/
|
*/
|
||||||
#include "pop_trob.h"
|
#include "pop_trob.h"
|
||||||
#include "pop_level.h"
|
#include "pop_level.h"
|
||||||
#include "pop_bg.h" /* pop_spike_redraw */
|
#include "pop_redraw.h" /* пометки перерисовки тайлов (вместо прямых вызовов) */
|
||||||
|
/* pop_bg нужен ТОЛЬКО для пламени факела и пузырька зелья: это не тайловая
|
||||||
|
* перерисовка, а покадровый оверлей поверх фона (в оригинале — свои
|
||||||
|
* add_backtable/add_foretable внутри draw_tile). Всё остальное идёт через
|
||||||
|
* пометки, поэтому pop_process_trobs — единственная функция модуля, которую
|
||||||
|
* нельзя звать из __banked-кода. */
|
||||||
|
#include "pop_bg.h"
|
||||||
|
|
||||||
/* Коды тайлов (fg & 0x1F), которые анимируются. */
|
/* Коды тайлов (fg & 0x1F), которые анимируются. */
|
||||||
#define TILE_SPIKE 0x02
|
#define TILE_SPIKE 0x02
|
||||||
@@ -30,11 +36,6 @@ static trob_t trobs[TROBS_MAX];
|
|||||||
static uint8_t trobs_count;
|
static uint8_t trobs_count;
|
||||||
static uint8_t trob_code[TROBS_MAX]; /* префетч кодов тайлов на кадр (1 map W0) */
|
static uint8_t trob_code[TROBS_MAX]; /* префетч кодов тайлов на кадр (1 map W0) */
|
||||||
|
|
||||||
/* Отложенная перерисовка «покоя» законченных пик/кнопок текущей комнаты
|
|
||||||
* (2 кадра = обе страницы дабл-буфера, как loose_rest). */
|
|
||||||
static uint8_t spike_rest[POP_ROOMTILES];
|
|
||||||
static uint8_t button_rest[POP_ROOMTILES];
|
|
||||||
|
|
||||||
/* Последняя НАРИСОВАННАЯ draw-сигнатура тайла (spike: modifier; button:
|
/* Последняя НАРИСОВАННАЯ draw-сигнатура тайла (spike: modifier; button:
|
||||||
* признак «нажата» = таймер связи >1). Редрой пики/кнопки — ТОЛЬКО при её
|
* признак «нажата» = таймер связи >1). Редрой пики/кнопки — ТОЛЬКО при её
|
||||||
* изменении (порт redraw_11h-on-change из SDLPoP). Без этого кнопка под
|
* изменении (порт redraw_11h-on-change из SDLPoP). Без этого кнопка под
|
||||||
@@ -43,18 +44,6 @@ static uint8_t button_rest[POP_ROOMTILES];
|
|||||||
* расхождение было именно в безусловном редрое). */
|
* расхождение было именно в безусловном редрое). */
|
||||||
static uint8_t trob_drawn[POP_ROOMTILES];
|
static uint8_t trob_drawn[POP_ROOMTILES];
|
||||||
|
|
||||||
/* Сколько тайлов ждут отложенного редроя (spike_rest/button_rest). Без
|
|
||||||
* него цикл по 30 тайлам крутился КАЖДЫЙ кадр впустую: замер в MAME
|
|
||||||
* (2026-07-27) — служебная часть pop_process_trobs ~50 000 тактов при
|
|
||||||
* кадре 430 080, то есть ~12 % кадра на пустой проход. */
|
|
||||||
static uint8_t rest_pending;
|
|
||||||
|
|
||||||
/* Дверь уровня: отложенный редрой ВТОРОЙ страницы дабл-буфера. Створка
|
|
||||||
* анимируется покадрово в back-страницу, поэтому последний кадр анимации
|
|
||||||
* попадает только на одну из двух страниц — вторая застревает на шаг раньше
|
|
||||||
* и дверь «дрожит» через кадр. ldoor_pos = tilepos ПРАВОЙ половины. */
|
|
||||||
static uint8_t ldoor_rest, ldoor_pos;
|
|
||||||
|
|
||||||
/* prandom (seg009.c:321, 32-бит LCG) — нужен для стартовой фазы факела и
|
/* prandom (seg009.c:321, 32-бит LCG) — нужен для стартовой фазы факела и
|
||||||
* выбора следующего кадра пламени. */
|
* выбора следующего кадра пламени. */
|
||||||
static unsigned long trob_seed;
|
static unsigned long trob_seed;
|
||||||
@@ -70,9 +59,8 @@ void pop_trob_reset(void)
|
|||||||
{
|
{
|
||||||
uint8_t i;
|
uint8_t i;
|
||||||
for (i = 0; i < POP_NROOMS; i++) room_seen[i] = 0;
|
for (i = 0; i < POP_NROOMS; i++) room_seen[i] = 0;
|
||||||
for (i = 0; i < POP_ROOMTILES; i++) { spike_rest[i] = 0; button_rest[i] = 0; trob_drawn[i] = 0; }
|
for (i = 0; i < POP_ROOMTILES; i++) trob_drawn[i] = 0;
|
||||||
rest_pending = 0;
|
pop_redraw_reset();
|
||||||
ldoor_rest = 0;
|
|
||||||
trobs_count = 0;
|
trobs_count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,9 +104,8 @@ void pop_add_trob(uint8_t room, uint8_t tilepos, int8_t type)
|
|||||||
void pop_trob_room_changed(void)
|
void pop_trob_room_changed(void)
|
||||||
{
|
{
|
||||||
uint8_t i;
|
uint8_t i;
|
||||||
for (i = 0; i < POP_ROOMTILES; i++) { spike_rest[i] = 0; button_rest[i] = 0; trob_drawn[i] = 0; }
|
for (i = 0; i < POP_ROOMTILES; i++) trob_drawn[i] = 0;
|
||||||
rest_pending = 0;
|
pop_redraw_reset();
|
||||||
ldoor_rest = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* anim_tile_modif (seg000:0B12) — при входе в комнату завести анимации её
|
/* anim_tile_modif (seg000:0B12) — при входе в комнату завести анимации её
|
||||||
@@ -373,26 +360,6 @@ void pop_process_trobs(uint8_t cur_room)
|
|||||||
* выносит оба деления (__divuchar/__moduchar) в вершину цикла как общее
|
* выносит оба деления (__divuchar/__moduchar) в вершину цикла как общее
|
||||||
* подвыражение аргументов redraw — 30*2=60 делений/кадр даже когда нет
|
* подвыражение аргументов redraw — 30*2=60 делений/кадр даже когда нет
|
||||||
* активных пик/кнопок (тот же случай, что был в pop_loose_tick). */
|
* активных пик/кнопок (тот же случай, что был в pop_loose_tick). */
|
||||||
if (rest_pending) {
|
|
||||||
uint8_t row = 0, col = 0, left = 0;
|
|
||||||
for (i = 0; i < POP_ROOMTILES; i++) {
|
|
||||||
if (spike_rest[i]) {
|
|
||||||
pop_spike_redraw(row, col);
|
|
||||||
if (--spike_rest[i]) left++;
|
|
||||||
}
|
|
||||||
if (button_rest[i]) {
|
|
||||||
pop_button_redraw(row, col);
|
|
||||||
if (--button_rest[i]) left++;
|
|
||||||
}
|
|
||||||
if (++col == 10) { col = 0; row++; }
|
|
||||||
}
|
|
||||||
rest_pending = left;
|
|
||||||
}
|
|
||||||
if (ldoor_rest) { /* доложить финальный кадр створки на 2-ю страницу */
|
|
||||||
pop_leveldoor_redraw(ldoor_pos / 10, ldoor_pos % 10);
|
|
||||||
ldoor_rest--;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (trobs_count == 0) return;
|
if (trobs_count == 0) return;
|
||||||
|
|
||||||
/* Префетч кодов тайлов всех trob'ов за ОДИН map/unmap окна 0, а не
|
/* Префетч кодов тайлов всех trob'ов за ОДИН map/unmap окна 0, а не
|
||||||
@@ -477,24 +444,20 @@ void pop_process_trobs(uint8_t cur_room)
|
|||||||
* неизменной сигнатурой, и стёртое уже не возвращается: рядом с
|
* неизменной сигнатурой, и стёртое уже не возвращается: рядом с
|
||||||
* Кидом остриё пропадало, а нижний кусок мерцал (стёрт на одной
|
* Кидом остриё пропадало, а нижний кусок мерцал (стёрт на одной
|
||||||
* странице дабл-буфера из двух). */
|
* странице дабл-буфера из двух). */
|
||||||
uint8_t trow = tp / 10, tcol = tp % 10;
|
/* Последний кадр (пика убралась, trob умирает) — пометить ОБЕ
|
||||||
pop_spike_redraw(trow, tcol);
|
* страницы: живой trob метит каждый кадр по одной. */
|
||||||
/* Последний кадр (пика убралась, trob умирает) — на ВТОРУЮ страницу
|
pop_set_redraw(tp, POP_RD_SPIKE, (uint8_t)(type < 0 ? 2 : 1));
|
||||||
* его уже никто не положит: ставим отложенный редрой. */
|
|
||||||
if (type < 0) { spike_rest[tp] = 1; rest_pending++; }
|
|
||||||
}
|
}
|
||||||
if (room == cur_room && code == TILE_LEVELDOOR) {
|
if (room == cur_room && code == TILE_LEVELDOOR) {
|
||||||
/* Створка едет каждый кадр — перерисовываем ПРАВУЮ половину (там
|
/* Створка едет каждый кадр — перерисовываем ПРАВУЮ половину (там
|
||||||
* её рисует draw_tile_anim_right) С ЗАПЕЧКОЙ в ОЗУ-копию: иначе
|
* её рисует draw_tile_anim_right) С ЗАПЕЧКОЙ в ОЗУ-копию: иначе
|
||||||
* kid_heal вернул бы из фона закрытую створку. Куски двери
|
* kid_heal вернул бы из фона закрытую створку. Куски двери
|
||||||
* непрозрачны, поэтому wipe не нужен. */
|
* непрозрачны, поэтому wipe не нужен. */
|
||||||
uint8_t trow = tp / 10, tcol = tp % 10;
|
/* Створку рисует ПРАВАЯ половина двери; последний кадр анимации
|
||||||
if (tcol + 1 < 10) {
|
* помечаем на обе страницы, иначе дверь дрожит через кадр. */
|
||||||
pop_leveldoor_redraw(trow, tcol + 1);
|
if (tp % 10 + 1 < 10)
|
||||||
/* Анимация кончилась — этот кадр лёг только на ОДНУ страницу;
|
pop_set_redraw((uint8_t)(tp + 1), POP_RD_LEVELDOOR,
|
||||||
* повторить его на второй, иначе дверь дрожит через кадр. */
|
(uint8_t)(type < 0 ? 2 : 1));
|
||||||
if (type < 0) { ldoor_pos = (uint8_t)(tp + 1); ldoor_rest = 1; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (room == cur_room && code == TILE_SWORD) {
|
if (room == cur_room && code == TILE_SWORD) {
|
||||||
/* МЕЧ — редрой только на смене видимого кадра (блеск = modif==1):
|
/* МЕЧ — редрой только на смене видимого кадра (блеск = modif==1):
|
||||||
@@ -503,9 +466,7 @@ void pop_process_trobs(uint8_t cur_room)
|
|||||||
* следующим кадром через rest-цикл. */
|
* следующим кадром через rest-цикл. */
|
||||||
uint8_t sig = (uint8_t)(mod[tp] == 1);
|
uint8_t sig = (uint8_t)(mod[tp] == 1);
|
||||||
if (sig != trob_drawn[tp]) {
|
if (sig != trob_drawn[tp]) {
|
||||||
uint8_t trow = tp / 10, tcol = tp % 10;
|
pop_set_redraw(tp, POP_RD_FLOOR, 2); /* обе страницы */
|
||||||
pop_button_redraw(trow, tcol);
|
|
||||||
button_rest[tp] = 1; rest_pending++;
|
|
||||||
trob_drawn[tp] = sig;
|
trob_drawn[tp] = sig;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -517,9 +478,7 @@ void pop_process_trobs(uint8_t cur_room)
|
|||||||
* считаем только в момент редроя (редко), а не каждый кадр. */
|
* считаем только в момент редроя (редко), а не каждый кадр. */
|
||||||
uint8_t sig = (uint8_t)(get_doorlink_timer(mod[tp]) > 1);
|
uint8_t sig = (uint8_t)(get_doorlink_timer(mod[tp]) > 1);
|
||||||
if (sig != trob_drawn[tp]) {
|
if (sig != trob_drawn[tp]) {
|
||||||
uint8_t trow = tp / 10, tcol = tp % 10;
|
pop_set_redraw(tp, POP_RD_FLOOR, 2); /* обе страницы */
|
||||||
pop_button_redraw(trow, tcol);
|
|
||||||
button_rest[tp] = 1; rest_pending++;
|
|
||||||
trob_drawn[tp] = sig;
|
trob_drawn[tp] = sig;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
#include "pop_map.h"
|
#include "pop_map.h"
|
||||||
#include "pop_level.h"
|
#include "pop_level.h"
|
||||||
#include "pop_trob.h"
|
#include "pop_trob.h"
|
||||||
|
#include "pop_redraw.h"
|
||||||
|
|
||||||
__sfr __at (0xFE) io_border;
|
__sfr __at (0xFE) io_border;
|
||||||
|
|
||||||
@@ -343,8 +344,10 @@ int main(void)
|
|||||||
pop_loose_tick(); /* loose-полы: анимация + перерисовка (СЛОЙ ФОНА */
|
pop_loose_tick(); /* loose-полы: анимация + перерисовка (СЛОЙ ФОНА */
|
||||||
/* — ДО Kid, чтобы Kid всегда был поверх плиты) */
|
/* — ДО Kid, чтобы Kid всегда был поверх плиты) */
|
||||||
io_border = 6; /* голубой */
|
io_border = 6; /* голубой */
|
||||||
pop_process_trobs(cur_room); /* пики/ворота: продвинуть + перерисовать (тоже */
|
pop_process_trobs(cur_room); /* пики/ворота/дверь: продвинуть СОСТОЯНИЕ (порт */
|
||||||
/* слой фона — ДО Kid) */
|
/* process_trobs — рисования внутри нет) */
|
||||||
|
pop_redraw_needed(); /* и разобрать пометки перерисовки тайлов (порт */
|
||||||
|
/* redraw_needed, seg008:0178) — СЛОЙ ФОНА, до Kid */
|
||||||
io_border = 4; /* синий */
|
io_border = 4; /* синий */
|
||||||
{ /* ворота соседа слева (room8) видны в col0 — */
|
{ /* ворота соседа слева (room8) видны в col0 — */
|
||||||
uint8_t lft = pop_room_link(cur_room, 0); /* редрой шва ТОЛЬКО при изменении openness */
|
uint8_t lft = pop_room_link(cur_room, 0); /* редрой шва ТОЛЬКО при изменении openness */
|
||||||
|
|||||||
Reference in New Issue
Block a user