ENTER-ROOM-FAST + вынос порядка отрисовки в банк 8
Вход в комнату: одна отрисовка в скрытую страницу, показ флипом, вторая страница — 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>
This commit is contained in:
@@ -297,7 +297,20 @@ void gfx_copy_rect(uint8_t src_page, int sx, int sy,
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# Часть III — побочная задача ENTER-ROOM-FAST
|
# Часть III — ENTER-ROOM-FAST — СДЕЛАНО 2026-08-12
|
||||||
|
|
||||||
|
Комната теперь рисуется ОДИН раз — в скрытую страницу, — тут же
|
||||||
|
показывается флипом, а вторая страница получает её `gfx_copy_page(DIRECT)`.
|
||||||
|
Процесс рисования тайлов больше не виден: игрок получает готовый кадр.
|
||||||
|
Проверено в MAME: старт уровня и чит-переход между комнатами, два
|
||||||
|
последовательных снимка идентичны (обе страницы синхронны, мерцания нет).
|
||||||
|
|
||||||
|
Побочно понадобилось: видимую страницу главный цикл больше не ведёт сам, а
|
||||||
|
перечитывает у железа в начале кадра (`front = gfx_get_visible_page()`) —
|
||||||
|
её меняют и вход в комнату, и переворот, причём оба из банка, где локальные
|
||||||
|
переменные `main` недоступны.
|
||||||
|
|
||||||
|
# Часть III (исходное описание)
|
||||||
|
|
||||||
Идея пользователя, самостоятельная ценность (сейчас при входе в комнату видно,
|
Идея пользователя, самостоятельная ценность (сейчас при входе в комнату видно,
|
||||||
как рисуются тайлы): рисовать комнату ОДИН раз в скрытую страницу, показать её
|
как рисуются тайлы): рисовать комнату ОДИН раз в скрытую страницу, показать её
|
||||||
|
|||||||
@@ -158,6 +158,11 @@ fore-слоя, и клип (`clip_char`), и брызги; полоса HP и л
|
|||||||
<a id="mem-cold2"></a>
|
<a id="mem-cold2"></a>
|
||||||
### MEM-COLD2. Второй шаг разгрузки резидента
|
### MEM-COLD2. Второй шаг разгрузки резидента
|
||||||
|
|
||||||
|
> **Пункт 2 сделан 2026-08-12**: `guard_over_kid` с хелперами
|
||||||
|
> (`objtile_at_char` / `char_x_left_of` / `tile_div_mod`) уехал в банк 8 —
|
||||||
|
> куча 1005 → **1574 Б**. Зовётся раз в кадр, то есть цена — один трамплин.
|
||||||
|
> Остались пункты 1 (`enter_room_side`) и 3 (блок редроя шва).
|
||||||
|
|
||||||
После [MEM-COLD1](TASKS_CLOSED.md#mem-cold1) куча 1707 Б. Когда упрётся
|
После [MEM-COLD1](TASKS_CLOSED.md#mem-cold1) куча 1707 Б. Когда упрётся
|
||||||
снова, в банк 8 переезжают следующие кандидаты (в порядке выгоды):
|
снова, в банк 8 переезжают следующие кандидаты (в порядке выгоды):
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include <conio.h>
|
#include <conio.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <kbd_raw.h>
|
#include <kbd_raw.h>
|
||||||
|
#include <sprite.h> /* gfx_copy_page — вход в комнату и переворот */
|
||||||
#include "pop_bg.h"
|
#include "pop_bg.h"
|
||||||
#include "pop_kid.h"
|
#include "pop_kid.h"
|
||||||
#include "pop_ctrl.h"
|
#include "pop_ctrl.h"
|
||||||
@@ -145,89 +146,6 @@ static void update_kid_render_dx(void)
|
|||||||
pop_char_set_render_dx(POP_CH_KID, dx);
|
pop_char_set_render_dx(POP_CH_KID, dx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---- Порядок «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 = страж рисуется ПОСЛЕ Кида (поверх). */
|
|
||||||
static uint8_t guard_over_kid(void)
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Change-driven редрой ЛЕВОГО шва (ворота соседа room8 видны в col0): тяжёлый
|
/* Change-driven редрой ЛЕВОГО шва (ворота соседа room8 видны в col0): тяжёлый
|
||||||
* draw_tile(0,0) в pop_room_redraw_seam_left зовём ТОЛЬКО когда openness гейта
|
* draw_tile(0,0) в pop_room_redraw_seam_left зовём ТОЛЬКО когда openness гейта
|
||||||
* реально изменился. Пока Кид держит кнопку и гейт открыт — modifier стабилен
|
* реально изменился. Пока Кид держит кнопку и гейт открыт — modifier стабилен
|
||||||
@@ -379,11 +297,31 @@ static void enter_room_side(uint8_t room, uint8_t side)
|
|||||||
rcol_bg[0] = m[0]; rcol_bg[1] = m[10]; rcol_bg[2] = m[20]; }
|
rcol_bg[0] = m[0]; rcol_bg[1] = m[10]; rcol_bg[2] = m[20]; }
|
||||||
}
|
}
|
||||||
seam_redraw = 0; seam_rows = 0; /* шов свежий на обеих страницах — редрой не нужен */
|
seam_redraw = 0; seam_rows = 0; /* шов свежий на обеих страницах — редрой не нужен */
|
||||||
for (pg = 0; pg < 2; pg++) {
|
/* ENTER-ROOM-FAST: комната рисуется ОДИН раз — в скрытую страницу, — и
|
||||||
|
* тут же показывается флипом; вторая страница дабл-буфера получает её
|
||||||
|
* КОПИЕЙ акселератора (gfx_copy_page, ~384 burst-строки против почти
|
||||||
|
* полумиллиона тактов на вторую отрисовку). Побочный эффект важнее
|
||||||
|
* тактов: игрок больше не видит, КАК рисуются тайлы — только готовый
|
||||||
|
* кадр.
|
||||||
|
*
|
||||||
|
* Копия идёт банком 0x50, то есть обновляет и VRAM, и ОЗУ-копию
|
||||||
|
* страницы-приёмника — иначе heal на ней восстанавливал бы фон прошлой
|
||||||
|
* комнаты (инвариант gfx_copy_page, регресс tests/pageflip).
|
||||||
|
*
|
||||||
|
* Видимая страница здесь МЕНЯЕТСЯ, поэтому главный цикл перечитывает её
|
||||||
|
* в начале каждого кадра (front = gfx_get_visible_page()), а не ведёт
|
||||||
|
* свой счёт. */
|
||||||
|
{
|
||||||
|
gfx_rect_t full;
|
||||||
|
pg = (uint8_t)(gfx_get_visible_page() ^ 1); /* скрытая */
|
||||||
gfx_set_draw_page(pg);
|
gfx_set_draw_page(pg);
|
||||||
setfillstyle(SOLID_FILL, BLACK);
|
setfillstyle(SOLID_FILL, BLACK);
|
||||||
bar(0, 0, 319, 255);
|
bar(0, 0, 319, 255);
|
||||||
pop_room_draw(room, room_fg, room_mod, lcol_fg, lcol_bg);
|
pop_room_draw(room, room_fg, room_mod, lcol_fg, lcol_bg);
|
||||||
|
gfx_set_visible_page(pg); /* показать готовое */
|
||||||
|
gfx_set_draw_page((uint8_t)(pg ^ 1));
|
||||||
|
full.x = 0; full.y = 0; full.w = 320; full.h = 256;
|
||||||
|
gfx_copy_page(&full, GFX_COPY_DIRECT); /* вторую — копией */
|
||||||
}
|
}
|
||||||
cur_room = room;
|
cur_room = room;
|
||||||
kid_room = room; /* S1: комната Kid синхронна отрисованной (S3 разведёт) */
|
kid_room = room; /* S1: комната Kid синхронна отрисованной (S3 разведёт) */
|
||||||
@@ -584,7 +522,11 @@ int main(void)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Рисуем в СКРЫТУЮ страницу (при dbuf); в однобуфере — в 0. */
|
/* Рисуем в СКРЫТУЮ страницу (при dbuf); в однобуфере — в 0.
|
||||||
|
* Видимую перечитываем У ЖЕЛЕЗА, а не ведём свой счёт: её меняют и
|
||||||
|
* вход в комнату (ENTER-ROOM-FAST), и переворот экрана
|
||||||
|
* (pop_flip_screen), причём оба — из банка, где front недоступен. */
|
||||||
|
front = gfx_get_visible_page();
|
||||||
back = dbuf ? (uint8_t)(front ^ 1) : 0;
|
back = dbuf ? (uint8_t)(front ^ 1) : 0;
|
||||||
gfx_set_draw_page(back);
|
gfx_set_draw_page(back);
|
||||||
|
|
||||||
@@ -595,8 +537,7 @@ int main(void)
|
|||||||
if (pop_upside_dirty) {
|
if (pop_upside_dirty) {
|
||||||
pop_upside_dirty = 0;
|
pop_upside_dirty = 0;
|
||||||
pop_flip_screen();
|
pop_flip_screen();
|
||||||
front = gfx_get_visible_page();
|
back = dbuf ? (uint8_t)(gfx_get_visible_page() ^ 1) : 0;
|
||||||
back = dbuf ? (uint8_t)(front ^ 1) : 0;
|
|
||||||
gfx_set_draw_page(back);
|
gfx_set_draw_page(back);
|
||||||
}
|
}
|
||||||
pop_check_skel(); /* спецсобытие ур.3: скелет встаёт */
|
pop_check_skel(); /* спецсобытие ур.3: скелет встаёт */
|
||||||
|
|||||||
@@ -255,6 +255,91 @@ void pop_dbg_room_label(uint8_t room) __banked
|
|||||||
room_label_redraw--;
|
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) --------- *
|
/* ---- Переворот уже нарисованного (зелье инверсии, уровень 9) --------- *
|
||||||
*
|
*
|
||||||
* Порт need_redraw_because_flipped (seg000:15E9 + 939/946). Оригинал
|
* Порт need_redraw_because_flipped (seg000:15E9 + 939/946). Оригинал
|
||||||
|
|||||||
@@ -50,6 +50,12 @@ uint8_t pop_dbg_roomnav(uint8_t dir) __banked;
|
|||||||
* звать можно каждый кадр. */
|
* звать можно каждый кадр. */
|
||||||
void pop_dbg_room_label(uint8_t room) __banked;
|
void pop_dbg_room_label(uint8_t room) __banked;
|
||||||
|
|
||||||
|
/* Кто рисуется ПОЗЖЕ — Кид или соперник (порядок обхода тайлов оригинала,
|
||||||
|
* set_objtile_at_char + sort_curr_objs). 1 = соперник поверх. Зовётся раз
|
||||||
|
* в кадр, поэтому живёт в банке: трамплин на кадр дешевле полукилобайта
|
||||||
|
* резидента. */
|
||||||
|
uint8_t guard_over_kid(void) __banked;
|
||||||
|
|
||||||
/* Перевернуть уже нарисованное (зелье инверсии, уровень 9): две копии
|
/* Перевернуть уже нарисованное (зелье инверсии, уровень 9): две копии
|
||||||
* акселератором + инвалидация слотов персонажей и полосы HP. Звать РАЗ на
|
* акселератором + инвалидация слотов персонажей и полосы HP. Звать РАЗ на
|
||||||
* переключение, по флагу pop_upside_dirty. */
|
* переключение, по флагу pop_upside_dirty. */
|
||||||
|
|||||||
Reference in New Issue
Block a user