Files
Sprinter-SDCC/applications/PoP/roomtest/pop_kdraw.c
T
snark13 147cb185b1 Резидент: pop_kid/pop_guard/main расколоты по частоте вызова (куча 6669 Б)
MEM-COLD3, шаги 3-5.  Кандидаты выбирались не по размеру, а по тому, КТО
зовёт: если единственный вызывающий уже в банке, код едет к нему и трамплин
не появляется вовсе.

* pop_kdraw.c -> БАНК 4 (к pop_cdraw.c): клинок в руке (pop_sword_draw) и
  блит спрайта chtab_2 по id (pop_kid_img_blit).  Оба звал ровно pop_cdraw,
  теперь вызовы прямые — контракт и условие корректности в _pop_kdraw.h.
* pop_kboot.c -> БАНК 8: загрузка атласов Кида и страницы kid_data.bin
  (раз за игру).  Дескриптор страницы — _pop_kid.h.
* pop_guard_cold.c -> БАНК 8: страж идёт за Кидом + вход стража в комнату.
  Оба зовёт roomtest_cold.c из того же банка — снова без трамплина.
* Из main в банк 8 уехали pop_boot (загрузка ресурсов, палитра, первый
  экран), pop_level_switch (смена уровня) и pop_shutdown.  FIRST_LEVEL
  переехал в pop_tune.h — константа нужна обеим половинам цикла.

_CODE 23005 -> 19861, куча 3525 -> 6669 Б.  Банк 8 — 6.5 из 16 КБ.
tests-host 6/6 (в наборы добавлены eng_pop_kboot и eng_pop_guard_cold).
2026-08-12 22:03:34 +03:00

122 lines
6.6 KiB
C
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.
/*
* pop_kdraw.c — отрисовка ИЗ АТЛАСОВ КИДА, которая нужна только слою
* персонажей: клинок в руке (add_sword_to_objtable, seg006:1798) и блит
* спрайта chtab_2 по его id (полоса HP). БАНК 4, вместе с pop_cdraw.c.
*
* Почему здесь. Оба вызова приходят РОВНО из pop_cdraw.c и больше ниоткуда
* (проверено грепом), а лежали они в pop_kid.c — то есть в резиденте W1,
* съедая ~1.2 КБ дефицитного окна ради кода, который зовёт сосед по банку.
* Раз модуль в том же банке 4 — вызовы прямые, без трамплина: объявления в
* _pop_kdraw.h НЕ помечены __banked (см. там же условие корректности).
*
* Загрузка атласа меча (pop_sword_load) осталась публичной и __banked: её
* зовёт инициализация, один раз за игру.
*/
#include <graphics.h>
#include <gfx.h>
#include <sprite.h>
#include "pop_kid.h"
#include "_pop_kdraw.h"
#include "pop_guard.h" /* CHARID_* — клинок есть и у стража */
#include "pop_bg.h" /* POP_YOFF — вертикальное центрирование */
#include "_pop_draw.h" /* pop_onscreen_cols */
#include "kid_data.h"
/* chtab_0 «меч в руке» (add_sword_to_objtable, seg006:1798): клинок —
* ОТДЕЛЬНЫЙ спрайт поверх персонажа, один и тот же атлас у Кида и у стража.
* Таблица sword_tbl (kid_data.h, генерится из seg006) индексируется
* sword_frame = кадр.sword & 0x3F; id 255 = клинка в этом кадре нет.
* Смещения — в ЭКРАННЫХ пикселях: оригинал применяет их ПОСЛЕ
* calc_screen_x_coord, x — «вперёд» по направлению персонажа. */
static const uint8_t SWORD_ID[KID_NSWORD] = KID_SWORD_ID_INIT;
static const int8_t SWORD_DX[KID_NSWORD] = KID_SWORD_DX_INIT;
static const int8_t SWORD_DY[KID_NSWORD] = KID_SWORD_DY_INIT;
static atlas_t swordp;
static uint8_t sword_ok;
int pop_sword_load(void) __banked
{
if (atlas_load(&swordp, "KID\\sword.atl") != 0) return -1;
sword_ok = 1;
return 0;
}
/* add_sword_to_objtable (seg006:1798). Клинок рисуется, если персонаж в
* кадрах подъёма/ножен, ИЛИ держит меч, ИЛИ это ЖИВОЙ страж (у стража меч
* в руке всегда, даже пока sword ещё sheathed). Страницу W0 оставляем
* замапленной — вызывающий делает gfx_w0_unmap сам. */
uint8_t pop_sword_draw(const pop_char_t *ch, const kframe *fr,
int obj_x, int obj_y,
int *rx, int *ry, uint16_t *rw, uint16_t *rh)
{
uint8_t sf, id, flip;
const uint8_t *simg;
uint16_t w, h;
int bx, top;
if (!sword_ok) return 0;
if (!((ch->frame >= 229 && ch->frame < 238) ||
ch->sword != 0 ||
((ch->charid == CHARID_2_GUARD || ch->charid == CHARID_4_SKELETON) &&
ch->alive < 0)))
return 0;
sf = (uint8_t)(fr->sword & 0x3F);
if (sf == 0 || sf >= KID_NSWORD) return 0;
id = SWORD_ID[sf];
if (id == 0xFF) return 0;
simg = (const uint8_t *)atlas_image(&swordp, id);
gfx_w0_map(swordp.page);
w = (uint16_t)(simg[0] | ((uint16_t)simg[1] << 8));
h = (uint16_t)(simg[2] | ((uint16_t)simg[3] << 8));
if (!w || !h) return 0;
flip = (uint8_t)(ch->direction >= 0);
bx = obj_x + ((ch->direction < 0) ? -(int)SWORD_DX[sf] : (int)SWORD_DX[sf]);
top = obj_y + (int)SWORD_DY[sf] - (int)h + 1;
if (flip) bx -= (int)w;
/* Поле комнаты — 192 строки (reset_obj_clip, seg006:0507): клинок
* обрезается по нему так же, как сам персонаж. Без этого у падающего
* в пропасть скелета меч оставался виден НИЖЕ поля, на полосе HP. */
{
int skip = 0, rows = (int)h;
if (top < 0) { skip = -top; rows -= skip; top = 0; }
if (top + rows > 192) rows = 192 - top;
if (rows <= 0) return 0;
gfx_set_bank(GFX_BANK_SPRITE);
/* Клинок почти всегда целиком на экране — noclip-путь (см. gfx.h:
* подготовка клипающего варианта стоит ~5.6 К тактов на вызов). */
if (pop_onscreen_cols(bx, top + POP_YOFF, w, (uint16_t)rows))
gfx_blit_cols_part_noclip(bx, top + POP_YOFF, simg, flip,
(uint8_t)skip, (uint8_t)rows);
else
gfx_blit_cols_part(bx, top + POP_YOFF, simg, flip, skip, rows);
gfx_set_bank(GFX_BANK_NORMAL);
*rx = bx; *ry = top; *rw = w; *rh = (uint16_t)rows;
}
return 1;
}
/* Блит спрайта chtab_2 (атласы Kid) по ЕГО id, левым верхним углом в (x,y).
* Нужен полосе HP: она рисует id 216/217 из тех же атласов, что и кадры
* Кида, а держать вторую копию раскладки в pop_cdraw ни к чему. */
void pop_kid_img_blit(uint8_t image, int x, int y)
{
uint8_t pg = (uint8_t)(image >> 3); /* раскладка атласов: 8 спрайтов/стр. */
uint8_t idx = (uint8_t)(image & 7);
const uint8_t *img;
uint16_t w, h;
if (pg >= kid_npages) return;
img = (const uint8_t *)atlas_image(&kidp[pg], idx);
gfx_w0_map(kidp[pg].page);
w = (uint16_t)(img[0] | ((uint16_t)img[1] << 8));
h = (uint16_t)(img[2] | ((uint16_t)img[3] << 8));
/* Атласы Кида хранятся COLUMN-MAJOR (transpose_cols в pop_pack_kid —
* ради бесплатного горизонтального флипа), поэтому блит обязан быть
* колоночным. Row-major gfx_blit_noclip выдал бы марку транспонированной.
* noclip БЕЗ проверки (CLIP-1): единственный вызывающий — полоса HP
* (pop_cdraw.c), у неё координаты фиксированные и заведомо на экране. */
if (w && h) gfx_blit_cols_part_noclip(x, y, img, 0, 0, 0);
gfx_w0_unmap();
}