Атлас Тени: запечённый набор вместо спрайтов стража
Оригинал кладёт спрайт дважды — прозрачным блитом в x и XOR-блиттером в x+1; пакетный блит так не умеет, поэтому результат запечён упаковщиком. Две половины, как и у оригинала: sk* — кадры вне боя (спрайты Кида), sf* — кадры 150..189 (SHADOW.DAT, тоже графика Кида). 251 спрайт, 32 EMM-страницы, палитра 16 цветов в 0xA0..0xAF. Закрывает BUG-SHADOW-SET: раньше тип 4 уходил в guard_names, и Тень в бою дралась серым стражем. Грабля: kid.pal заливает все 256 записей и затирает слоты Тени — палитра вынесена в pop_shadow_pal_apply рядом с pop_bg_pal_apply. Проверено в MAME на 6-м уровне: силуэт с контуром, как в оригинале.
This commit is contained in:
@@ -24,6 +24,7 @@
|
||||
| [GRAB-KBD-TIMING](#grab-kbd-timing) | зацеп в падении срабатывает менее стабильно, чем в оригинале | **после всех уровней** | открыт: подозрение на клавиатурный модуль, не на физику |
|
||||
| [GUARD-ENTRY-DEATH](#guard-entry-death) | вход в комнату вплотную к стражу = мгновенная смерть (не портирован `bump_into_opponent`) | порт | **фикс есть, ждёт проверки в MAME** |
|
||||
| [BUG-SHADOW-SET](#bug-shadow-set) | Тень на 12-м уровне дерётся спрайтами СТРАЖА: SHADOW.DAT у нас нет вовсе | порт | открыт, разбор готов |
|
||||
| [BUG-CORPSE-AIR](#bug-corpse-air) | труп Кида висит в воздухе, когда убившая его плита улетела вниз | физика | открыт |
|
||||
| [LOOSE-ROOM-CHANGE](#loose-room-change) | расшатанная плита не доваливается, если Кид ушёл в соседнюю комнату | порт | закрыт 2026-08-13, кроме [LOOSE-SEAM-ANIM](#loose-seam-anim) |
|
||||
| [JUMP-FLOOR-LEGS](#jump-floor-legs) | в прыжке с пола ноги Кида рисуются ПОВЕРХ кромки пола, а должны за ней | окклюзия | **корень найден и починен, ждёт проверки в MAME** |
|
||||
| [MOB-CLIP-RIGHT](#mob-clip-right) | окна и узор кладки рисуются ПОВЕРХ падающих плит | окклюзия | открыт: корень найден 2026-08-13 |
|
||||
@@ -870,3 +871,25 @@ Makefile правила нет.
|
||||
**Оговорка.** `pop_guard_set_palette` для типа 4 звать НЕЛЬЗЯ — она
|
||||
затрёт палитру Тени палитрой стража (`curr_guard_color` у не-стражей = 0,
|
||||
`seg002:183`).
|
||||
|
||||
### <a id="bug-corpse-air"></a>BUG-CORPSE-AIR. Труп висит в воздухе после падения плиты
|
||||
|
||||
**Симптом** (найдено пользователем 2026-08-20, ур. 12 к. 15, старт с
|
||||
`POS=15`): Кид встал на проваливающийся пол (0,6), плита обрушилась и
|
||||
убила его, но ТЕЛО осталось лежать на уровне исчезнувшего пола, а плита
|
||||
улетела дальше вниз. Труп висит в пустоте.
|
||||
|
||||
**Где смотреть.** Кадр смерти — `actions_5_bumped` (см. seq в
|
||||
`kid_data`), а гравитация в `check_action` (seg006:05CD) для действия 5
|
||||
включается только на кадрах приседа: у оригинала есть отдельные фиксы
|
||||
`FIX_DEAD_FLOATING_IN_AIR` (кадры 177..185) именно про этот случай —
|
||||
значит **в оригинале 1989 года труп в воздухе тоже висит**, и SDLPoP
|
||||
чинит это опциональным фиксом, по умолчанию выключенным.
|
||||
|
||||
**Отсюда вопрос к решению**, а не сразу правка: чинить ли вообще. Если
|
||||
чинить — портировать `fix_dead_floating_in_air` и записать как
|
||||
осознанное расхождение в `../docs/impl_diff.md` (мы уже отказались от
|
||||
двух других опциональных фиксов SDLPoP в `bump_into_opponent`).
|
||||
|
||||
**Приоритет низкий:** ситуация возникает только когда труп остаётся на
|
||||
проваливающемся полу, играбельности не мешает.
|
||||
|
||||
@@ -35,7 +35,7 @@ MEMORY ?= huge # small-раскладка + банки кода в W
|
||||
# ВАЖНО: любое сравнение занятости банков имеет смысл только при ОДНОМ и том
|
||||
# же ALLOCS — иначе сравниваются не правки, а уровни оптимизации.
|
||||
ALLOCS ?= 3000
|
||||
EXTRA_FLAGS ?= --gfx 256 -I $(CURDIR)/../poc/res/bg --max-allocs $(ALLOCS) --bank 2=pop_bg.c --bank 7=pop_room.c --bank 4=pop_cdraw.c --bank 4=pop_kdraw.c --bank 3=pop_map.c --bank 1=guards.c --bank 5=pop_ctrl.c --bank 6=pop_trob.c --bank 7=pop_redraw.c --bank 8=roomtest_cold.c --bank 8=pop_level_cold.c --bank 8=pop_kboot.c --bank 8=pop_guard_cold.c $(PROF_FLAGS)
|
||||
EXTRA_FLAGS ?= --gfx 256 -I $(CURDIR)/../poc/res/bg --max-allocs $(ALLOCS) --bank 2=pop_bg.c --bank 7=pop_room.c --bank 4=pop_cdraw.c --bank 4=pop_kdraw.c --bank 3=pop_map.c --bank 1=guards.c --bank 5=pop_ctrl.c --bank 6=pop_trob.c --bank 7=pop_redraw.c --bank 8=roomtest_cold.c --bank 8=pop_level_cold.c --bank 8=pop_kboot.c --bank 8=pop_guard_cold.c --bank 8=pop_shadow.c $(PROF_FLAGS)
|
||||
# Профилирование полосами бордюра (см. PROF() в roomtest.c) — ВКЛЮЧЕНО по
|
||||
# умолчанию, пока идёт работа с производительностью; make PROF=0 выключает.
|
||||
# Каждая фаза кадра красит бордюр в свой цвет, высота полосы на скриншоте
|
||||
@@ -112,8 +112,16 @@ VIZIER_DIR := $(CURDIR)/../poc/res/vizier
|
||||
VIZIER_DATA := $(VIZIER_DIR)/g0.atl $(VIZIER_DIR)/g1.atl $(VIZIER_DIR)/g2.atl \
|
||||
$(VIZIER_DIR)/g3.atl $(VIZIER_DIR)/g4.atl
|
||||
|
||||
# ТЕНЬ — свой набор, запечённый упаковщиком (наложение спрайта на себя со
|
||||
# сдвигом; наш блит так не умеет, см. ../docs/shadow_atlas_plan.md). Две
|
||||
# половины в одном наборе: sk* — кадры вне боя (спрайты Кида), sf* — кадры
|
||||
# 150..189 (SHADOW.DAT, это тоже графика Кида, а не стража).
|
||||
SHADOW_DIR := $(CURDIR)/../poc/res/shadow
|
||||
SHADOW_DATA := $(foreach n,0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27,$(SHADOW_DIR)/sk$(n).atl) \
|
||||
$(foreach n,0 1 2 3,$(SHADOW_DIR)/sf$(n).atl)
|
||||
|
||||
EXTRA_DATA := $(BG_DATA) $(KID_DATA) $(KID_BIN) $(GUARD_DATA) $(SKEL_DATA) \
|
||||
$(VIZIER_DATA) $(LVL_DATA)
|
||||
$(VIZIER_DATA) $(SHADOW_DATA) $(LVL_DATA)
|
||||
include $(PROJ_ROOT)/app.mk
|
||||
|
||||
# Образ HDD для MAME: ресурсы раскладываются ПО КАТАЛОГАМ (8.3, как в DSS),
|
||||
@@ -130,6 +138,7 @@ hdd: $(EXAMPLE).exe
|
||||
$(foreach f,$(GUARD_DATA),GUARD:$(f)) \
|
||||
$(foreach f,$(SKEL_DATA),SKEL:$(f)) \
|
||||
$(foreach f,$(VIZIER_DATA),VIZIER:$(f)) \
|
||||
$(foreach f,$(SHADOW_DATA),SHADOW:$(f)) \
|
||||
$(foreach f,$(LVL_DATA),LEVELS:$(f))
|
||||
|
||||
TC := $(PROJ_ROOT)/applications/PoP/toolchain
|
||||
@@ -144,6 +153,9 @@ $(SKEL_DATA): $(TC)/pop_pack_guard.py
|
||||
$(VIZIER_DATA): $(TC)/pop_pack_guard.py
|
||||
cd $(TC) && python3 pop_pack_guard.py VIZIER
|
||||
|
||||
$(SHADOW_DATA) pop_shadow_atlas.h: $(TC)/pop_pack_shadow.py $(TC)/pop_pack_bg.py $(TC)/pop_pack_kid.py
|
||||
cd $(TC) && python3 pop_pack_shadow.py
|
||||
|
||||
$(KID_DATA): $(TC)/pop_pack_kid.py $(TC)/pop_pack_bg.py
|
||||
cd $(TC) && python3 pop_pack_kid.py
|
||||
kid_data.h $(KID_BIN): $(TC)/pop_extract_kid_data.py
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "_pop_kdraw.h"
|
||||
#include "pop_vflip.h" /* зеркальные страницы атласов (зелье инверсии) */ /* меч + блит по id — сосед по банку 4 */ /* атласы/кадр Кида, pop_sword_draw, окна Char */
|
||||
#include "pop_cdraw.h"
|
||||
#include "pop_shadow.h" /* запечённый набор Тени */
|
||||
#include "pop_pace.h" /* pop_beam_sample — счёт кадров по лучу */
|
||||
#include "pop_state.h" /* ВРЕМЕННО: зонды pop_dbg_b* */
|
||||
#include "pop_bg.h" /* POP_YOFF, pop_fore_over_char, pop_fore_set_clip */
|
||||
@@ -527,6 +528,10 @@ void pop_char_draw(uint8_t who) __banked
|
||||
const pop_char_t *ch;
|
||||
const kframe *fr;
|
||||
const atlas_t *pages;
|
||||
/* Атлас БРЫЗГ отдельно от кадра: у оригинала они всегда из «своего»
|
||||
* chtab (Кид — chtab_2 image 218, прочие — chtab_5 image 1,
|
||||
* seg006:2019), а у Тени кадр может прийти из другой половины набора. */
|
||||
const atlas_t *spl;
|
||||
const uint8_t *img;
|
||||
uint8_t npages, page, idx, dp, flip, hurt, lskip;
|
||||
uint8_t w, h, vis_w;
|
||||
@@ -549,19 +554,31 @@ void pop_char_draw(uint8_t who) __banked
|
||||
if (who == POP_CH_KID) {
|
||||
pop_loadkid();
|
||||
ch = &Kid; fr = &kid_frame; pages = kidp; npages = kid_npages;
|
||||
spl = kidp;
|
||||
hurt = pop_kid_hurt;
|
||||
} else {
|
||||
pop_loadshad();
|
||||
ch = &Guard; fr = &pop_gframe; pages = gp;
|
||||
npages = g_ok ? GUARD_PAGES : 0;
|
||||
spl = gp;
|
||||
hurt = pop_guard_hurt;
|
||||
if (Guard.charid == 0) return; /* соперника на сцене нет */
|
||||
/* ТЕНЬ (ур. 4) — это зеркальный Кид: вне боевых кадров 150..189 она
|
||||
* ходит по таблице КИДА (seg006:0532), а `image` из неё индексирует
|
||||
* спрайты Кида, а не стража. Набор атласов обязан идти за таблицей —
|
||||
* условие берём из того же места, что load_frame, чтобы они не
|
||||
* разъехались. */
|
||||
if (!pop_frame_tbl_is_guard(Guard.charid, Guard.frame)) {
|
||||
/* Набор атласов обязан идти за ТАБЛИЦЕЙ КАДРОВ — условие берём из
|
||||
* того же места, что load_frame (seg006:0532), чтобы они не
|
||||
* разъехались: вне боевых кадров 150..189 Тень ходит по таблице
|
||||
* КИДА, и `image` из неё индексирует спрайты Кида. */
|
||||
if (Guard.charid == CHARID_1_SHADOW && pop_shadow_kid_n) {
|
||||
/* У Тени СВОЙ запечённый набор (pop_shadow.h): её вид даёт
|
||||
* наложение спрайта на себя со сдвигом, а пакетный блит так не
|
||||
* умеет. Обе половины лежат в нём же, поэтому подмены на kidp
|
||||
* здесь уже не нужно. */
|
||||
if (pop_frame_tbl_is_guard(Guard.charid, Guard.frame)) {
|
||||
pages = pop_shadow_fgt; npages = pop_shadow_fgt_n;
|
||||
} else {
|
||||
pages = pop_shadow_kid; npages = pop_shadow_kid_n;
|
||||
}
|
||||
spl = pop_shadow_fgt; /* брызги — из половины chtab_5 */
|
||||
} else if (!pop_frame_tbl_is_guard(Guard.charid, Guard.frame)) {
|
||||
pages = kidp; npages = kid_npages;
|
||||
}
|
||||
}
|
||||
@@ -741,7 +758,7 @@ void pop_char_draw(uint8_t who) __banked
|
||||
/* по нему считается футпринт */
|
||||
}
|
||||
pop_dbg_m15(); /* ЗАМЕР: снимок прямоугольника сделан */
|
||||
if (hurt) cd_splash(s, who, pages, fp_x, obj_y);
|
||||
if (hurt) cd_splash(s, who, spl, fp_x, obj_y);
|
||||
/* add_sword_to_objtable (seg006:1798): клинок отдельным спрайтом поверх
|
||||
* персонажа — со своим прямоугольником heal. */
|
||||
{
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* pop_shadow.c — загрузка запечённого набора спрайтов Тени. Зачем набор
|
||||
* отдельный и почему половин две — в шапке pop_shadow.h.
|
||||
*
|
||||
* Код ХОЛОДНЫЙ (раз на уровень), поэтому живёт в банке 8 вместе с прочей
|
||||
* загрузкой. Сами atlas_t — в W2: их читает отрисовка из банка 4, а
|
||||
* данные видны из любого банка.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <gfx.h>
|
||||
#include <sprite.h>
|
||||
#include "pop_shadow.h"
|
||||
#include "pop_shadow_atlas.h"
|
||||
|
||||
atlas_t pop_shadow_kid[POP_SHADOW_KID_PAGES];
|
||||
atlas_t pop_shadow_fgt[POP_SHADOW_FGT_PAGES];
|
||||
uint8_t pop_shadow_kid_n, pop_shadow_fgt_n;
|
||||
|
||||
/* ГРУЗИМ ОДИН РАЗ НА ЗАПУСК, а не по уровням.
|
||||
*
|
||||
* Тень бывает на ЧЕТЫРЁХ уровнях: 4 — рождается прыжком сквозь зеркало
|
||||
* (jump_through_mirror, seg003:0811, ставит Char.charid = charid_1_shadow
|
||||
* прямо из Кида), 5 — крадёт зелье, 6 — прыгает через пропасть, 12 —
|
||||
* дерётся. Читается как три, потому что таблиц init_shad_N всего три
|
||||
* (5/6/12): четвёртой нет — на 4-м Тень копируется с Кида, а не поднимается
|
||||
* из таблицы. Так вот, напрашивается
|
||||
* грузить набор только там, как это сделано с перевёрнутыми наборами
|
||||
* (pop_vflip_load_all зовётся лишь на POP_UPSIDE_LEVEL). Решение
|
||||
* пользователя — грузить сразу, и оно правильное по двум причинам:
|
||||
* страниц EMM с запасом (32 из ~215 свободных), а вот забыть перезагрузку
|
||||
* на границе уровня легко — ровно так и появился BUG-SHADOW-SET. Разовая
|
||||
* загрузка убирает целый класс ошибок и заодно не тормозит переход между
|
||||
* уровнями на 32 файла. */
|
||||
int pop_shadow_load(void) __banked
|
||||
{
|
||||
uint8_t i;
|
||||
if (pop_shadow_kid_n || pop_shadow_fgt_n) return 0; /* уже загружен */
|
||||
|
||||
for (i = 0; i < POP_SHADOW_KID_PAGES; i++) {
|
||||
if (atlas_load(&pop_shadow_kid[i], pop_shadow_kid_atl[i]) != 0) {
|
||||
pop_shadow_free();
|
||||
return -1;
|
||||
}
|
||||
pop_shadow_kid_n = (uint8_t)(i + 1);
|
||||
}
|
||||
for (i = 0; i < POP_SHADOW_FGT_PAGES; i++) {
|
||||
if (atlas_load(&pop_shadow_fgt[i], pop_shadow_fgt_atl[i]) != 0) {
|
||||
pop_shadow_free();
|
||||
return -1;
|
||||
}
|
||||
pop_shadow_fgt_n = (uint8_t)(i + 1);
|
||||
}
|
||||
|
||||
pop_shadow_pal_apply();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ПАЛИТРА ОТДЕЛЬНО ОТ ЗАГРУЗКИ, и это не косметика.
|
||||
*
|
||||
* `gfx_pal_fload("KID\\kid.pal")` заливает ВСЕ 256 записей — это единая
|
||||
* игровая палитра, — и затирает любые слоты, выставленные до него. Ровно
|
||||
* та же беда уже была с тайлсетом: сразу за ним стоит pop_bg_pal_apply,
|
||||
* который возвращает цвета env/wall. Наши 0xA0..0xAF из той же оперы, и
|
||||
* в первом заходе я на это наступил: набор грузился, силуэт рисовался
|
||||
* правильной формы, но ЦЕЛИКОМ ЧЁРНЫЙ (поймано пользователем на 6-м
|
||||
* уровне). Поэтому вызов живёт рядом с pop_bg_pal_apply, а не внутри
|
||||
* загрузки атласов.
|
||||
*
|
||||
* Обе страницы дабл-буфера: у них свои палитры. Через буфер в W2 —
|
||||
* gfx_pal_load отдаёт указатель BIOS ($A4), а тот читает только
|
||||
* #4000-#BFFF и банковую rodata не увидит. */
|
||||
void pop_shadow_pal_apply(void) __banked
|
||||
{
|
||||
uint8_t buf[64], k;
|
||||
if (!pop_shadow_kid_n) return; /* набора нет — нечего красить */
|
||||
for (k = 0; k < 64; k++) buf[k] = pop_shadow_pal[k];
|
||||
gfx_pal_load(0, POP_SHADOW_PAL_BASE, 16, buf);
|
||||
gfx_pal_load(1, POP_SHADOW_PAL_BASE, 16, buf);
|
||||
}
|
||||
|
||||
void pop_shadow_free(void) __banked
|
||||
{
|
||||
uint8_t i;
|
||||
for (i = 0; i < pop_shadow_kid_n; i++) atlas_free(&pop_shadow_kid[i]);
|
||||
for (i = 0; i < pop_shadow_fgt_n; i++) atlas_free(&pop_shadow_fgt[i]);
|
||||
pop_shadow_kid_n = pop_shadow_fgt_n = 0;
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* pop_shadow.h — запечённый набор спрайтов ТЕНИ.
|
||||
*
|
||||
* Оригинал спрайтов Тени не хранит: он кладёт обычный спрайт дважды — в x
|
||||
* прозрачным блитом и в x+1 «блиттером XOR» (draw_objtable_item,
|
||||
* seg008.c:1600). Пакетный блит так не умеет, поэтому результат запечён
|
||||
* заранее (toolchain/pop_pack_shadow.py); разбор и замеры —
|
||||
* ../docs/shadow_atlas_plan.md.
|
||||
*
|
||||
* ПОЛОВИН ДВЕ, и это не наша выдумка. Набор спрайтов у оригинала выбирает
|
||||
* не персонаж, а поле `sword` САМОГО КАДРА (load_frame_to_obj,
|
||||
* seg008.c:1752: chtab_base жёстко = chtab_2, плюс `sword >> 6`). У всех
|
||||
* кадров таблицы Кида эти биты нулевые, у всех кадров таблицы стража —
|
||||
* 0xC0. Тень берёт таблицу стража для кадров 150..189 (seg006.c:533),
|
||||
* значит идёт через chtab_5 — а chtab_5 на 12-м уровне грузится из
|
||||
* SHADOW.DAT (tbl_guard_type[12] == 4), и это графика КИДА в боевых позах.
|
||||
* Отсюда:
|
||||
*
|
||||
* pop_shadow_kid[] — кадры вне боя (запечены из спрайтов Кида);
|
||||
* pop_shadow_fgt[] — кадры 150..189 (запечены из SHADOW.DAT).
|
||||
*
|
||||
* Какая половина нужна, отрисовка уже знает — тем же условием, что
|
||||
* выбирает таблицу кадров (pop_frame_tbl_is_guard).
|
||||
*
|
||||
* СПРАЙТ ТЕНИ НА ПИКСЕЛЬ ШИРЕ исходного: второй проход оригинала кладётся
|
||||
* в x+1, суммарный след занимает [x, x+w]. Рисовать по тем же
|
||||
* координатам, что и Кида — сдвиг уже внутри спрайта.
|
||||
*/
|
||||
#ifndef POP_SHADOW_H
|
||||
#define POP_SHADOW_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sprite.h>
|
||||
|
||||
extern atlas_t pop_shadow_kid[]; /* половина «вне боя» */
|
||||
extern atlas_t pop_shadow_fgt[]; /* половина «в бою» (SHADOW.DAT) */
|
||||
/* Сколько страниц реально загружено; 0 = набора нет (уровень без Тени
|
||||
* или загрузка не удалась) — отрисовка тогда идёт прежним путём. */
|
||||
extern uint8_t pop_shadow_kid_n, pop_shadow_fgt_n;
|
||||
|
||||
/* Загрузить набор. Звать ОДИН РАЗ при старте: набор не зависит от
|
||||
* уровня, а перезагрузка на границе — лишний повод её забыть (почему
|
||||
* именно так — в шапке pop_shadow.c). Повторный вызов — no-op.
|
||||
* Возврат: 0 — OK, -1 — ошибка загрузки. */
|
||||
int pop_shadow_load(void) __banked;
|
||||
|
||||
/* Залить 16 слотов палитры Тени. ЗВАТЬ ПОСЛЕ ЛЮБОЙ заливки общей
|
||||
* палитры (gfx_pal_fload kid.pal): та кладёт все 256 записей и затирает
|
||||
* наши — см. развёрнуто в pop_shadow.c. Рядом с pop_bg_pal_apply. */
|
||||
void pop_shadow_pal_apply(void) __banked;
|
||||
|
||||
/* Освободить страницы; звать на выходе из программы. */
|
||||
void pop_shadow_free(void) __banked;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,71 @@
|
||||
/* pop_shadow_atlas.h — раскладка атласа ТЕНИ.
|
||||
* СГЕНЕРЕНО toolchain/pop_pack_shadow.py — НЕ править вручную.
|
||||
*
|
||||
* Две половины, потому что и у оригинала их две (см. шапку
|
||||
* упаковщика): кадры вне боя адресуют chtab_2 (спрайты Кида),
|
||||
* кадры 150..189 — chtab_5, а он на 12-м уровне это SHADOW.DAT.
|
||||
* Какая половина нужна, приложение уже знает — тем же условием,
|
||||
* что выбирает таблицу кадров (pop_frame_tbl_is_guard).
|
||||
*
|
||||
* Спрайт Тени НА ОДИН ПИКСЕЛЬ ШИРЕ исходного: второй проход
|
||||
* оригинала кладётся в x+1, и суммарный след занимает [x, x+w].
|
||||
* Рисовать по тем же координатам, что и Кида — сдвиг уже внутри.
|
||||
*/
|
||||
#ifndef POP_SHADOW_ATLAS_H
|
||||
#define POP_SHADOW_ATLAS_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define POP_SHADOW_SHIFT 3
|
||||
#define POP_SHADOW_MASK 7
|
||||
#define POP_SHADOW_PAL_BASE 0xA0 /* слоты Sprinter под Тень */
|
||||
|
||||
/* Половина «вне боя» — кадры Кида (chtab_2). */
|
||||
#define POP_SHADOW_KID_PAGES 28
|
||||
/* Половина «в бою» — SHADOW.DAT (chtab_5, кадры 150..189). */
|
||||
#define POP_SHADOW_FGT_PAGES 4
|
||||
|
||||
static const char *const pop_shadow_kid_atl[POP_SHADOW_KID_PAGES] = {
|
||||
"SHADOW\\sk0.atl",
|
||||
"SHADOW\\sk1.atl",
|
||||
"SHADOW\\sk2.atl",
|
||||
"SHADOW\\sk3.atl",
|
||||
"SHADOW\\sk4.atl",
|
||||
"SHADOW\\sk5.atl",
|
||||
"SHADOW\\sk6.atl",
|
||||
"SHADOW\\sk7.atl",
|
||||
"SHADOW\\sk8.atl",
|
||||
"SHADOW\\sk9.atl",
|
||||
"SHADOW\\sk10.atl",
|
||||
"SHADOW\\sk11.atl",
|
||||
"SHADOW\\sk12.atl",
|
||||
"SHADOW\\sk13.atl",
|
||||
"SHADOW\\sk14.atl",
|
||||
"SHADOW\\sk15.atl",
|
||||
"SHADOW\\sk16.atl",
|
||||
"SHADOW\\sk17.atl",
|
||||
"SHADOW\\sk18.atl",
|
||||
"SHADOW\\sk19.atl",
|
||||
"SHADOW\\sk20.atl",
|
||||
"SHADOW\\sk21.atl",
|
||||
"SHADOW\\sk22.atl",
|
||||
"SHADOW\\sk23.atl",
|
||||
"SHADOW\\sk24.atl",
|
||||
"SHADOW\\sk25.atl",
|
||||
"SHADOW\\sk26.atl",
|
||||
"SHADOW\\sk27.atl",
|
||||
};
|
||||
|
||||
static const char *const pop_shadow_fgt_atl[POP_SHADOW_FGT_PAGES] = {
|
||||
"SHADOW\\sf0.atl",
|
||||
"SHADOW\\sf1.atl",
|
||||
"SHADOW\\sf2.atl",
|
||||
"SHADOW\\sf3.atl",
|
||||
};
|
||||
|
||||
/* 16 цветов, запись 4 байта (B, G, R, 0) — формат gfx_pal_load. */
|
||||
static const uint8_t pop_shadow_pal[64] = {
|
||||
0x00,0x00,0x00,0x00,0xD8,0xFC,0xFC,0x00,0x6C,0x80,0xDC,0x00,0x78,0x44,0x24,0x00,0xA0,0xB8,0xD8,0x00,0xB5,0x7C,0x21,0x00,0x00,0x90,0xB8,0x00,0x5D,0x6D,0xAB,0x00,0x0C,0xF0,0x6C,0x00,0xCC,0x38,0x05,0x00,0x38,0xCC,0xC0,0x00,0x58,0xDB,0xA7,0x00,0xBB,0x9F,0x54,0x00,0x5D,0x18,0x60,0x00,0x37,0xD7,0x37,0x00,0x2F,0x17,0xD2,0x00,
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <sprite.h> /* gfx_copy_page */
|
||||
#include "pop_tune.h"
|
||||
#include "pop_ctrl.h" /* pop_ctrl_init/close — ввод поднимает и закрывает boot */
|
||||
#include "pop_shadow.h" /* запечённый набор Тени */
|
||||
#include "pop_vflip.h" /* сброс зеркальных страниц на смене уровня */
|
||||
#include "pop_cheat.h" /* pop_cheats — режим разработки включает pop_boot */
|
||||
#include "pop_pace.h" /* pop_speed_mode — режим скорости в отладочной метке */
|
||||
@@ -749,6 +750,7 @@ int pop_boot(void) __banked
|
||||
}
|
||||
pop_sword_load(); /* меч в руке (без него кадры 229+ без клинка) */
|
||||
pop_guard_load(); /* атласы стража (GUARD\\g0..g4) */
|
||||
pop_shadow_load(); /* запечённый набор Тени — один раз на запуск */
|
||||
if (pop_kid_load(28) != 0) { /* ВСЕ страницы: бег+стоп+разворот+присед+прыжок */
|
||||
puts("kid atlas load failed");
|
||||
return -1;
|
||||
@@ -771,6 +773,8 @@ int pop_boot(void) __banked
|
||||
* дворцовых уровнях без этого рисуется дворцовая геометрия подземельными
|
||||
* красками (сине-серое вместо песочного). */
|
||||
pop_bg_pal_apply();
|
||||
/* ...и палитру Тени: kid.pal затёр и её 16 слотов (pop_shadow.c). */
|
||||
pop_shadow_pal_apply();
|
||||
|
||||
/* Фон комнаты рисуется в ОБЕ графические страницы: у каждой своя
|
||||
* ОЗУ-копия/видео-ОЗУ, а heal берёт чистый фон из ОЗУ-копии ТОЙ
|
||||
@@ -853,6 +857,7 @@ void pop_shutdown(void) __banked
|
||||
closegraph();
|
||||
pop_bg_free();
|
||||
pop_kid_free();
|
||||
pop_shadow_free();
|
||||
pop_guard_free();
|
||||
pop_kid_data_free();
|
||||
pop_level_free();
|
||||
|
||||
Reference in New Issue
Block a user