70c1668e9f
Вход в комнату: одна отрисовка в скрытую страницу, показ флипом, вторая страница — gfx_copy_page(DIRECT) вместо повторной отрисовки. Процесс рисования тайлов больше не виден, обе страницы синхронны (два снимка подряд идентичны). Видимую страницу главный цикл теперь перечитывает у железа в начале кадра: её меняют и вход в комнату, и переворот — оба из банка. MEM-COLD2 п.2: guard_over_kid с хелперами (objtile_at_char/char_x_left_of/ tile_div_mod) — в банк 8. Куча 1005 -> 1574 Б, цена — один трамплин на кадр. tests-host 6/6, size-check OK, в MAME проверены старт уровня 9, переходы между комнатами и отрисовка стража. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
388 lines
23 KiB
C
388 lines
23 KiB
C
/*
|
||
* roomtest_cold.c — ХОЛОДНАЯ половина главного цикла, собирается в БАНК
|
||
* (--bank 8=roomtest_cold.c, окно W3). Здесь всё, что отрабатывает раз на
|
||
* уровень или только по отладочной клавише; кадровый путь остался в
|
||
* roomtest.c. Зачем разделили и что осталось снаружи — см. roomtest_cold.h.
|
||
*
|
||
* Правила банка те же, что у guards.c: состояние — в W1/W2 (данные этого
|
||
* модуля тоже, --bank-data не включён), звать можно резидент W1/W2 и другие
|
||
* __banked-модули через трамплины.
|
||
*/
|
||
#include <graphics.h>
|
||
#include <gfx.h>
|
||
#include "roomtest_cold.h"
|
||
#include "pop_bg.h" /* pop_loose_mob_reset — банк 7, зовём через трамплин */
|
||
#include "pop_kid.h"
|
||
#include "pop_map.h"
|
||
#include "pop_level.h"
|
||
#include "pop_trob.h"
|
||
#include "pop_guard.h"
|
||
#include "pop_state.h"
|
||
#include "pop_geom.h"
|
||
#include "pop_cdraw.h" /* pop_cd — инвалидация слотов после переворота */
|
||
#include <sprite.h> /* gfx_copy_page */
|
||
#include "pop_tune.h"
|
||
|
||
#define SEQ_STAND 2
|
||
#define SEQ_TURN 5
|
||
#define SEQ_FALL 7
|
||
#define SEQ_RUN 84
|
||
#define ENTRY_POSE_FALL 1 /* tbl_entry_pose[1] */
|
||
#define ENTRY_POSE_RUN 2 /* tbl_entry_pose[13] */
|
||
#define TILE_LEVELDOOR_LEFT 16 /* tiles_16_level_door_left */
|
||
#define TILE_EMPTY 0
|
||
#define LINK_DOWN 3 /* сторона links: 0=L,1=R,2=U,3=D */
|
||
|
||
/* find_start_level_door (seg003:02E6): дверь уровня В СТАРТОВОЙ КОМНАТЕ —
|
||
* это дверь, через которую Кид ВОШЁЛ, поэтому она открыта полностью
|
||
* (modif = 43) и заводится trob'ом типа 3 (start_level_door, seg007:0D72).
|
||
* Без этого на уровне 2 Кид материализуется внутри глухой закрытой створки:
|
||
* его стартовый тайл (комната 5, ряд 1, колонка 3) — правая половина
|
||
* той самой двери. */
|
||
static void find_start_level_door(uint8_t room)
|
||
{
|
||
uint8_t *m = pop_trob_modif(room);
|
||
uint8_t tp;
|
||
if (!m) return;
|
||
/* Батч-доступ к странице уровня тут не нужен: функция отрабатывает раз
|
||
* за уровень, а pop_add_trob сам лезет в W0. */
|
||
for (tp = 0; tp < 30; tp++) {
|
||
if (pop_level_tile(room, tp) != TILE_LEVELDOOR_LEFT) continue;
|
||
m[tp] = 43; /* створка поднята полностью */
|
||
pop_add_trob(room, tp, 3); /* ...и тут же поедет ВНИЗ (type>=3) */
|
||
}
|
||
}
|
||
|
||
/* start_level (seg003:0055) + do_startpos (seg003:01A3) + set_start_pos
|
||
* (seg003:028A).
|
||
*
|
||
* Позиция берётся ИЗ ДАННЫХ уровня (pop_level_start_*), а не из #define:
|
||
* start_pos — тайл 0..29 (row*10+col), start_dir — направление, в котором
|
||
* персонаж должен ОКАЗАТЬСЯ.
|
||
*
|
||
* Направление ИНВЕРТИРУЕТСЯ (`Char.direction = ~level.start_dir`): персонаж
|
||
* ставится спиной и доворачивается кадрами позы входа. Сама поза — из
|
||
* tbl_entry_pose (data.h:848 = {0,1,0,…,2,…}):
|
||
* 1 (уровень 1) — падение внутрь (seq_7_fall) + нажатие кнопки room5(0,2);
|
||
* это оно захлопывает решётку за спиной в первой комнате;
|
||
* 2 (уровень 13) — вбегание (seq_84_run);
|
||
* иначе — разворот на месте (seq_5_turn).
|
||
* Таблица индексируется НОМЕРОМ УРОВНЯ — pop_level_entry_pose(). */
|
||
void pop_start_level(void) __banked
|
||
{
|
||
uint8_t entry_pose, start_room, pos, seq = SEQ_TURN, chkp;
|
||
int8_t dir;
|
||
|
||
pop_leveldoor_open = 0; /* seg003:97 — дверь прошлого уровня не в счёт */
|
||
pop_feather = 0; /* seg003:189 — перо не переживает старт уровня */
|
||
/* upside_down тоже сбрасывается стартом уровня (seg003:38/188). Если
|
||
* картинка была перевёрнута, отрисовка комнаты ниже уже пойдёт обычной
|
||
* стороной, поэтому переворачивать ничего не надо — только снять флаги. */
|
||
pop_upside = 0;
|
||
pop_upside_dirty = 0;
|
||
entry_pose = pop_level_entry_pose(pop_current_level);
|
||
start_room = pop_level_start_room();
|
||
pos = pop_level_start_pos();
|
||
dir = (int8_t)~pop_level_start_dir();
|
||
/* Особое событие: старт с чекпойнта (do_startpos, seg003:0141).
|
||
* Числа — в pop_tune.h. Плиту снимаем ПОСЛЕ pop_level_reset_tiles()
|
||
* ниже, иначе рестарт её вернёт. */
|
||
chkp = (uint8_t)(pop_current_level == POP_CHKP_LEVEL && pop_checkpoint);
|
||
if (chkp) {
|
||
start_room = POP_CHKP_RESPAWN_ROOM;
|
||
pos = POP_CHKP_RESPAWN_TILEPOS;
|
||
dir = (int8_t)~POP_CHKP_RESPAWN_DIR; /* стартует в ПРОТИВОположную
|
||
* и разворачивается seq_5 */
|
||
}
|
||
|
||
/* Рестарт уровня = load_level() заново (play_level, seg003:57): в
|
||
* исходное возвращаются И модификаторы (пики/ворота), И сами тайлы —
|
||
* разбитые плиты целы, выпитые зелья на месте (BUG-RESPAWN-1), и
|
||
* убитые стражи снова живы на своих тайлах (BUG-RESPAWN-2). */
|
||
pop_trob_reset();
|
||
pop_level_reset_tiles();
|
||
pop_level_reset_guards();
|
||
pop_guard_reset(); /* start_level: Guard.direction = none */
|
||
pop_loose_mob_reset(); /* start_level: mobs_count = 0 (seg003:88) */
|
||
/* «Особое событие: убрать loose-плиту» (do_startpos): без этого путь в
|
||
* комнату-чекпойнт после респавна остался бы непройденным. */
|
||
if (chkp)
|
||
pop_level_set_tile(POP_CHKP_CLEAR_ROOM,
|
||
(uint8_t)(POP_CHKP_CLEAR_ROW * 10 + POP_CHKP_CLEAR_COL),
|
||
TILE_EMPTY);
|
||
|
||
/* Кнопку жмём ДО отрисовки комнаты — как в оригинале (do_startpos
|
||
* отрабатывает раньше первого draw_room), иначе шов кадр показывал бы
|
||
* ещё не тронутое состояние решётки. */
|
||
if (entry_pose == ENTRY_POSE_FALL) {
|
||
/* get_tile(5,2,0) + trigger_button(0,0,-1) — «нажать» кнопку room5,
|
||
* col2, row0 её же типом и модификатором (в оригинале и то и другое
|
||
* берётся из curr_* после get_tile). */
|
||
uint8_t tp = 2; /* row0*10 + col2 */
|
||
pop_trigger_button(5, tp, pop_level_tile(5, tp), pop_trob_modif(5)[tp]);
|
||
seq = SEQ_FALL;
|
||
} else if (entry_pose == ENTRY_POSE_RUN) {
|
||
seq = SEQ_RUN;
|
||
}
|
||
|
||
/* Тоже ДО отрисовки комнаты: дверь, через которую вошли, обязана быть
|
||
* открыта уже в первом кадре (в оригинале find_start_level_door стоит
|
||
* между do_startpos и draw_level_first). */
|
||
find_start_level_door(start_room);
|
||
|
||
enter_room(start_room);
|
||
kid_init(seq, (int8_t)(pos % 10), (int8_t)(pos / 10), dir);
|
||
/* Спецсобытие «вход падением» (set_start_pos, seg003:0196): на 7-м
|
||
* уровне Кид ставится в комнату 17, а экран тут же переводится на
|
||
* комнату ПОД ней (`goto_other_room(3)`: y −= 189, ряд пересчитать) —
|
||
* он влетает в неё сверху, продолжая падение с шестого уровня. */
|
||
if (pop_current_level == FALLING_ENTRY_LEVEL &&
|
||
start_room == FALLING_ENTRY_ROOM) {
|
||
uint8_t below = pop_room_link(start_room, LINK_DOWN);
|
||
if (below) {
|
||
Kid.y = (uint8_t)(Kid.y - 189);
|
||
Kid.curr_row = pop_y_to_row((int16_t)Kid.y);
|
||
enter_room(below);
|
||
}
|
||
}
|
||
Kid.sword = 0; /* set_start_pos: sword_0_sheathed */
|
||
/* play_level (seg003:106): have_sword = level >= have_sword_from_level
|
||
* (=2) — начиная со второго уровня меч у Кида уже есть. */
|
||
pop_have_sword = (uint8_t)(pop_current_level >= 2);
|
||
pop_kid_hp_reset();
|
||
}
|
||
|
||
/* ---- ОТЛАДКА: обход комнат по номеру -------------------------------- *
|
||
*
|
||
* Нужен, чтобы пройти все комнаты уровня и собрать список багов отрисовки,
|
||
* включая недостижимые обычным путём.
|
||
*
|
||
* Здесь БЫЛ pop_trob_reset() перед enter_room — «чтобы каждая комната
|
||
* смотрелась в исходном состоянии». Убран: reset обнуляет room_seen, и
|
||
* модификаторы перечитываются из уровня заново, то есть чит ОТМАТЫВАЕТ МИР
|
||
* — открытые/закрытые ворота, выдвинутые пики, нажатые кнопки. Навигация
|
||
* обязана только телепортировать; исходное состояние даёт перезапуск. */
|
||
uint8_t pop_dbg_roomnav(uint8_t dir) __banked
|
||
{
|
||
uint8_t r, i, c, pos = 20, any = 0xFF;
|
||
|
||
/* Кид МЁРТВ: сначала честный рестарт уровня, потом телепорт. Навигация
|
||
* только переставляет Кида (kid_init + сброс HP), то есть «оживляет» его
|
||
* мимо start_level — а тот обязан вернуть тайлы, модификаторы и ОЧИСТИТЬ
|
||
* слот соперника (seg003:100: Guard.direction = dir_56_none). Без этого
|
||
* после смерти оставался живой скелет рядом с вернувшейся кучей костей. */
|
||
if (pop_kid_dead) pop_start_level();
|
||
|
||
r = cur_room;
|
||
r = (dir == 1) ? (uint8_t)(r == 24 ? 1 : r + 1)
|
||
: (uint8_t)(r == 1 ? 24 : r - 1);
|
||
enter_room(r);
|
||
|
||
/* Куда поставить Кида в новой комнате: пол С МАКСИМАЛЬНЫМ Y — сначала
|
||
* НИЖНИЙ ряд (2), потом 1, и только потом 0 (пользователь 2026-08-11).
|
||
* Раньше брался первый пол подряд, то есть почти всегда (0,0) — верхний
|
||
* левый угол: это и «прилёт» в проём/ворота, и, на уровне 5, посадка
|
||
* вплотную к тени спецсобытия, которая ждёт в колонке −1 ряда 0. Вместо
|
||
* сцены кражи зелья начиналась схватка, которой в этой комнате быть не
|
||
* должно. Снизу вверх нужно и самой навигации: в верхнем ряду пола чаще
|
||
* нет, и Кид проваливается из комнаты сразу после телепорта.
|
||
*
|
||
* ИСКЛЮЧЕНИЕ — комната 14 уровня 7 (пользователь 2026-08-12): её проходят
|
||
* СВЕРХУ ВНИЗ (с ряда 0 на ряд 2 через зацеп за кромки), и с нижнего ряда
|
||
* этот спуск не проверить вовсе. Пол в ряду 0 там есть, так что Кид не
|
||
* проваливается.
|
||
*
|
||
* В каждом ряду сначала ищем ОБЫЧНЫЙ пол, и только если его там нет —
|
||
* любой проходимый tile_is_floor (seg001: всё, кроме пустоты, верха
|
||
* колонны, верха двери, стены и «половинок» 26..29). */
|
||
{
|
||
int8_t row, step = -1, first = 2;
|
||
if (pop_current_level == GRAB_DOWN_LEVEL &&
|
||
r == GRAB_DOWN_ROOM) { first = 0; step = 1; }
|
||
for (row = first; row >= 0 && row <= 2 && any == 0xFF;
|
||
row = (int8_t)(row + step)) {
|
||
uint8_t fallback = 0xFF;
|
||
for (i = (uint8_t)(row * 10); i < (uint8_t)(row * 10 + 10); i++) {
|
||
c = (uint8_t)(room_fg[i] & 0x1F);
|
||
if (c == 1) { any = i; break; }
|
||
if (fallback == 0xFF && c && c != 9 && c != 12 &&
|
||
c != 20 && !(c >= 26 && c <= 29)) fallback = i;
|
||
}
|
||
if (any == 0xFF) any = fallback;
|
||
}
|
||
}
|
||
if (any != 0xFF) pos = any;
|
||
kid_init(SEQ_STAND, (int8_t)(pos % 10), (int8_t)(pos / 10), 0);
|
||
pop_kid_hp_reset();
|
||
|
||
/* ВЫХОД ИЗ БОЯ (BUG-CHEAT-FIGHT-1). Телепорт с вынутым мечом заклинивал
|
||
* управление намертво: pop_control при Kid.sword == SWORD_2_DRAWN уходит
|
||
* в control_with_sword, а там единственный выход — ветка «убрать меч» на
|
||
* кадре FRAME_171_STAND_WITH_SWORD. После kid_init(SEQ_STAND) кадр
|
||
* обычный, стража в новой комнате нет, swordfight не запускается — и
|
||
* диспетчер каждый кадр не делает НИЧЕГО. Это болезнь ЧИТА: в оригинале
|
||
* телепорта между комнатами нет, попасть в режим боя без соперника
|
||
* нечем. Меч в инвентаре (pop_have_sword) НЕ теряем — только состояние
|
||
* схватки. */
|
||
Kid.sword = SWORD_0_SHEATHED;
|
||
holding_sword = 0;
|
||
offguard = 0;
|
||
guard_refrac = 0;
|
||
return 1;
|
||
}
|
||
|
||
/* ---- ОТЛАДКА: номер отрисованной комнаты в верхнем борте ------------- */
|
||
|
||
static uint8_t room_label_sig = 0xFF; /* последняя показанная комната */
|
||
static uint8_t room_label_redraw; /* остаток кадров (2 = обе страницы) */
|
||
|
||
void pop_dbg_room_label(uint8_t room) __banked
|
||
{
|
||
uint8_t prev = room_label_sig, i;
|
||
room_label_sig = room; /* СНАЧАЛА сохранить (sdcc_z80_cmp_store_a_bug) */
|
||
if (room != prev) room_label_redraw = 2;
|
||
if (!room_label_redraw) return;
|
||
/* Номер ПАЛОЧКАМИ, а не outtextxy: текст тянет системный знакогенератор
|
||
* (_gfx_font_buf, 2 КБ статики в W2) и сажает кучу. Слева десятки,
|
||
* справа единицы: || |||| = 24. */
|
||
setfillstyle(SOLID_FILL, BLACK);
|
||
bar(100, 0, 175, 5);
|
||
/* 0x57, а НЕ WHITE: палитра игровая, запись 15 в ней чёрная
|
||
* (kid.pal: 0x0F = 0,0,0; чистый белый = 0x57). */
|
||
setfillstyle(SOLID_FILL, 0x57);
|
||
for (i = 0; i < (uint8_t)(room / 10); i++) bar(100 + i * 5, 0, 101 + i * 5, 5);
|
||
for (i = 0; i < (uint8_t)(room % 10); i++) bar(130 + i * 5, 0, 131 + i * 5, 5);
|
||
room_label_redraw--;
|
||
}
|
||
|
||
/* ---- Порядок «Kid vs страж» (BUG-DRAWORDER-1) -----------------------
|
||
*
|
||
* В оригинале никто не «поверх» по определению: и Кид, и страж попадают в
|
||
* midtable при обработке СВОЕГО тайла (set_objtile_at_char, seg006:13F3), а
|
||
* тайлы обходятся в фиксированном порядке — redraw_needed_tiles (seg008:1B06)
|
||
* идёт рядами 2,1,0 и внутри ряда колонками 0..9. Кто нарисован ПОЗЖЕ — тот
|
||
* поверх. Отсюда «Кид проходит ЗА телом стража»: тело лежит правее и/или
|
||
* выше, его тайл в обходе позже. Совпали тайлы — решает sort_curr_objs
|
||
* (seg008:203C): у обычных объектов (не тень, не плита) ниже по obj_y = позже.
|
||
*
|
||
* Мы рисовали страж→Кид всегда, то есть Кид был поверх безусловно.
|
||
*
|
||
* Ключ обхода: чем больше, тем позже. Ряды идут 2,1,0 → (2 - row). */
|
||
#define OBJ_ORDER_KEY(row, col) ((int)(2 - (row)) * 10 + (int)(col))
|
||
|
||
/* get_tile_div_mod (seg006:750): колонка комнаты по X (БЕЗ поправки −7). */
|
||
static int8_t tile_div_mod(int x)
|
||
{
|
||
int v = x - 58; /* pop_x_bump[FIRST_ONSCREEN_COLUMN] */
|
||
int c = v / TILE_SIZEX;
|
||
if (v % TILE_SIZEX < 0) --c;
|
||
return (int8_t)c;
|
||
}
|
||
|
||
/* char_x_left из set_char_collision (seg006:0723) — левая граница габарита.
|
||
* ВАЖНО: величина НЕ утоньшённая; поправку THIN оригинал применяет только к
|
||
* *_coll, а колонки char_col_left/right считает по этой. */
|
||
static int char_x_left_of(uint8_t x, int8_t dir, int8_t dx,
|
||
uint8_t flags, uint16_t w)
|
||
{
|
||
int e = (int)x + ((dir < 0) ? -dx : dx); /* char_dx_forward */
|
||
uint8_t fl = flags;
|
||
if (dir < 0) fl ^= 0x80;
|
||
/* odd-pixel + усечение деления к нулю — та же поправка, что в pop_map */
|
||
if (!(fl & 0x80) && e <= 57) e++;
|
||
if (dir >= 0) e -= (int)((w + 1) >> 1); /* char_width_half */
|
||
return e;
|
||
}
|
||
|
||
/* set_objtile_at_char (seg006:13F3) — ТАЙЛ ОБЪЕКТА персонажа.
|
||
*
|
||
* Ветка actions_1_run_jump обязательна, а не «упрощаемая» (как я решил
|
||
* сначала): в беге оригинал берёт НЕ curr_row/curr_col, а нижний ряд и ЛЕВУЮ
|
||
* колонку ГАБАРИТА. При беге вправо левая колонка меньше curr_col, поэтому
|
||
* бегущий Кид уходит ЗА объекты справа от себя. Без этой ветки часть кадров
|
||
* бега рисовала Кида поверх лежащего стража. Считаем одинаково для обоих:
|
||
* enter_guard (seg002) тоже ставит стражу action = 1, и односторонний учёт
|
||
* дал бы перекос в другую сторону. */
|
||
static void objtile_at_char(int8_t *row, int8_t *col,
|
||
const pop_char_t *ch, int8_t dx, int8_t dy,
|
||
uint8_t flags, uint16_t w)
|
||
{
|
||
int8_t r = ch->curr_row, c = ch->curr_col;
|
||
if (ch->action == 1) { /* actions_1_run_jump */
|
||
int8_t br = pop_y_to_row((int16_t)((int)ch->y + dy));
|
||
if (br == -1) br = 3; /* char_bottom_row */
|
||
r = br;
|
||
c = tile_div_mod(char_x_left_of(ch->x, ch->direction, dx, flags, w));
|
||
if (c < 0) c = 0; /* MAX(char_col_left, 0) */
|
||
}
|
||
if ((ch->frame >= 135 && ch->frame < 149) ||
|
||
ch->action == 2 || ch->action == 3 ||
|
||
ch->action == 4 || ch->action == 6) c--;
|
||
*row = r; *col = c;
|
||
}
|
||
|
||
/* 1 = страж рисуется ПОСЛЕ Кида (поверх). __banked: зовётся раз в кадр,
|
||
* то есть один трамплин — а 500 Б кода в резиденте дороже. */
|
||
uint8_t guard_over_kid(void) __banked
|
||
{
|
||
int8_t kr, kc, gr, gc;
|
||
int kk, gk;
|
||
if (Guard.charid == 0 || Guard.room != cur_room) return 0;
|
||
objtile_at_char(&kr, &kc, &Kid, kid_cur_dx(), kid_cur_dy(),
|
||
kid_cur_flags(), pop_cd[POP_CH_KID].fpw);
|
||
objtile_at_char(&gr, &gc, &Guard, pop_gframe.dx, pop_gframe.dy,
|
||
pop_gframe.flags, pop_cd[POP_CH_OPP].fpw);
|
||
kk = OBJ_ORDER_KEY(kr, kc);
|
||
gk = OBJ_ORDER_KEY(gr, gc);
|
||
if (gk != kk) return (uint8_t)(gk > kk);
|
||
/* один тайл — ниже по obj_y рисуется позже (sort_curr_objs) */
|
||
return (uint8_t)((int)Guard.y + pop_gframe.dy > pop_cd[POP_CH_KID].fpy);
|
||
}
|
||
|
||
|
||
/* ---- Переворот уже нарисованного (зелье инверсии, уровень 9) --------- *
|
||
*
|
||
* Порт need_redraw_because_flipped (seg000:15E9 + 939/946). Оригинал
|
||
* держит готовый offscreen и переворачивает его на выводе; у нас страниц
|
||
* ровно две, рабочей третьей нет, поэтому переворачиваем то, что уже
|
||
* нарисовано, — построчной копией акселератора (gfx_copy_page).
|
||
*
|
||
* Почему это законно и почему heal после не ломается: accel ЧИТАЕТ
|
||
* ОЗУ-копию, значит копируется ЧИСТЫЙ ФОН без персонажей, а пишет банком
|
||
* 0x50 — и в видео, и в копию приёмника. После двух проходов обе страницы
|
||
* дабл-буфера содержат перевёрнутый фон в обеих плоскостях, и heal
|
||
* восстанавливает уже его (memory accel_port_y_between_triggers,
|
||
* регресс — tests/pageflip).
|
||
*
|
||
* Порядок: перевернуть в СКРЫТУЮ, показать её, скопировать оттуда во
|
||
* вторую (теперь скрытую) — прямой копией. Так игрок видит результат
|
||
* сразу, а не после второго прохода.
|
||
*
|
||
* Переворачиваем ТОЛЬКО игровое поле (POP_PLAYFIELD_H): полоса HP лежит
|
||
* ниже него и в оригинале тоже не переворачивается. */
|
||
void pop_flip_screen(void) __banked
|
||
{
|
||
gfx_rect_t area;
|
||
uint8_t back = (uint8_t)(gfx_get_visible_page() ^ 1);
|
||
|
||
area.x = 0; area.y = POP_YOFF;
|
||
area.w = 320; area.h = POP_PLAYFIELD_H;
|
||
|
||
gfx_set_draw_page(back);
|
||
gfx_copy_page(&area, GFX_COPY_VFLIP); /* источник — видимая страница */
|
||
gfx_set_visible_page(back);
|
||
|
||
gfx_set_draw_page((uint8_t)(back ^ 1));
|
||
gfx_copy_page(&area, GFX_COPY_DIRECT); /* вторую страницу — прямой копией */
|
||
|
||
/* Всё, что рисуется поверх фона, надо положить заново: прошлые
|
||
* прямоугольники персонажей относятся к СТАРОЙ (неперевёрнутой)
|
||
* картинке, и heal по ним стёр бы не то место. */
|
||
pop_cd[POP_CH_KID].valid[0] = pop_cd[POP_CH_KID].valid[1] = 0;
|
||
pop_cd[POP_CH_KID].ovalid[0] = pop_cd[POP_CH_KID].ovalid[1] = 0;
|
||
pop_cd[POP_CH_OPP].valid[0] = pop_cd[POP_CH_OPP].valid[1] = 0;
|
||
pop_cd[POP_CH_OPP].ovalid[0] = pop_cd[POP_CH_OPP].ovalid[1] = 0;
|
||
POP_CD_TOUCH_ALL(); /* фон трогали целиком */
|
||
pop_hp_invalidate(); /* полосу HP перерисовать */
|
||
}
|