applications/PoP: порт Prince of Persia — PoC (roomtest) + пайплайн

Порт PoP на Sprinter.  Текущий PoC — applications/PoP/roomtest/:
комната 1 (фон-композиция тайлов) + Kid с управлением на raw-клавиатуре
и коллизией с картой.

- roomtest — pop_bg (фон), pop_kid (спрайты Kid, column-major флип,
  seqtbl-анимация), pop_ctrl (порт control() PoP на held-state
  kbd_raw), pop_map (коллизия seg004/005: бег/стоп у стены,
  падение/приземление, отскок seq_47, вертикальный прыжок K4.1).
  MEMORY=small (DATA сразу за CODE, ~23КБ кода не лезет в huge).
- toolchain (PoP) — pop_pack_kid/pop_pack_bg/render_room/extract —
  распаковка res-графики MSDOS в атласы + композиция комнат.
- toolchain/ (корень) — make_hdd.sh (быстрый HDD-тест вместо FDD),
  png_strip.py / room_compose.py (ассет-пайплайн).
- docs — PORT_PLAN, KID_PLAN, форматы ресурсов (Apple II / MSDOS / DAT).
- bgtest/coltest/poc — ранние PoC (фон, коллизия, первый прототип).

.gitignore: build-артефакты applications/*/*/*; исключены внешние
референс-репозитории (SDLPoP/mininim/PR/Apple-II — свои git-клоны) и
оригинальные game-данные MSDOS/ (копирайт, только для реверса форматов).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-17 17:51:08 +03:00
parent 484b18d10c
commit cd8d566d82
196 changed files with 6630 additions and 0 deletions
+53
View File
@@ -0,0 +1,53 @@
# PoC порта Prince of Persia (applications/PoP/docs/PORT_PLAN.md §5).
# --memory huge, БЕЗ --bank.
#
# ПОЧЕМУ huge, а НЕ small (исправлено 2026-07-16): poc использует
# raw-клавиатуру (kbd_raw_open → IM2-таблица). Буферы IM2 (_irq_vec_buf,
# BSS) ОБЯЗАНЫ жить в W2 (0x8000-0xBFFF) — во время прерывания W1/W3
# могут быть перемаплены DSS (см. libc/irq/_irq_table.c, memory/
# fps_divider: «verified tiny/big/huge, small=EINVAL»). --memory small
# пулит W1+W2 в плоские ~32КБ и чейнит DATA за CODE — при небольшом CODE
# BSS уезжает в W1 (<0x8000), и _irq_table_ref отдаёт EINVAL →
# kbd_raw_open молча возвращал -1, poc печатал ошибку УЖЕ в графическом
# режиме (невидимо) и выходил в prompt. huge кладёт CODE в W1, а
# DATA/BSS/STACK/HEAP жёстко в W2 → IM2 работает. Цена: раздел 16КБ
# CODE / 16КБ DATA вместо общего 32КБ-пула small — сейчас влезает с
# запасом; при росте настоящего PoP CODE>16КБ понадобится банк под код.
#
# --bank НЕ нужен: gfx_blit_part()/atlas_load() сами временно трогают W3
# (видеобанк / чтение атласа) — банк room.c в W3 давал вероятностный
# «снег»; банк в W1 несовместим с CODE=W1 (трамплин переключения W1 сам
# бы уехал). sprintf() заменён на ручное hex-форматирование пути в
# tile_atlas_load() (единственный потребитель printf, ~2.9КБ).
PROJ_ROOT := $(abspath $(CURDIR)/../../..)
EXAMPLE := poc
MEMORY ?= huge
EXTRA_FLAGS ?= --gfx 256
EXTRA_SRCS := room.c
TILE_ATLASES := res/tiles/tile01.atl res/tiles/tile14.atl res/tiles/tile03.atl \
res/tiles/tile13.atl res/tiles/tile0e.atl res/tiles/tile0b.atl
EXTRA_DATA := tools/kid.atl tools/room.pal res/room1.dat $(TILE_ATLASES)
include $(PROJ_ROOT)/app.mk
LEVEL1_BIN := $(PROJ_ROOT)/applications/PoP/SDLPoP/data/LEVELS/res2001.bin
tools/kid.raw tools/kid.pal: tools/gen_kid_placeholder.py
cd tools && python3 gen_kid_placeholder.py
tools/kid.atl: tools/kid.raw
python3 $(PROJ_ROOT)/toolchain/mkatlas.py $@ tools/kid.raw:16x16:1x12
res/room1.dat: tools/extract_room.py $(LEVEL1_BIN)
python3 tools/extract_room.py $(LEVEL1_BIN) 1 res/room1.dat
res/tiles/1F-0.png: tools/gen_tile_placeholders.py
cd tools && python3 gen_tile_placeholders.py
tools/room.pal $(TILE_ATLASES): tools/kid.pal res/tiles/1F-0.png tools/build_room_palette.py
cd tools && python3 build_room_palette.py
# make_disk.py упаковывает EXTRA_DATA на диск ПОД БАЗОВЫМ ИМЕНЕМ
# (плоская ФС) — tileNN.atl/room1.dat оказываются в корне рядом с
# kid.atl/room.pal, room.c/poc.c грузят их без пути.
$(EXAMPLE).exe: room.c tools/kid.atl tools/room.pal res/room1.dat $(TILE_ATLASES)
+153
View File
@@ -0,0 +1,153 @@
/*
* level.h — структуры уровня PoP под наш движок.
*
* Формат — POP-DAT-FormatSpecifications.pdf §3.4 (DAT 1.0): комната =
* 30 тайлов (10 колонок x 3 ряда), foretable даёт тип тайла,
* backtable — модификатор/состояние (семантика зависит от типа).
* Адресация тайла: tile = (room-1)*30 + tileOffset, tileOffset 0-9 =
* верхний ряд, 10-19 = средний, 20-29 = нижний, слева направо.
*
* Фаза 1 (applications/PoP/docs/PORT_PLAN.md §5, сузили объём):
* только геометрия (пол/стены/провалы) для коллизий — двери, факелы,
* ловушки, гарды НЕ используются (структуры под них здесь тоже
* упрощены/оставлены как заготовка на потом, см. §7 плана Фаза 2).
*/
#ifndef LEVEL_H
#define LEVEL_H
#include <stdint.h>
/* 1 (не 24) — PoC грузит и рисует только комнату 1; расширить, когда
* появится настоящий level_load() на несколько комнат. */
#define LEVEL_ROOMS 1 /* комнаты нумеруются 1..24 в файле,
* здесь индекс 0..23 = комната N+1 */
#define ROOM_COLS 10
#define ROOM_ROWS 3
#define ROOM_TILES (ROOM_COLS * ROOM_ROWS) /* 30 */
/* --- Типы тайлов (Table 7 спецификации) --- */
#define TILE_TYPE(byte) ((uint8_t)((byte) & 0x1F))
#define TILE_MODIFIER(byte) ((uint8_t)(((byte) >> 5) & 1))
enum {
TILE_EMPTY = 0x00,
TILE_FLOOR = 0x01,
TILE_SPIKES = 0x02,
TILE_PILLAR = 0x03,
TILE_GATE = 0x04,
TILE_STUCK_BUTTON = 0x05,
TILE_DROP_BUTTON = 0x06,
TILE_TAPESTRY = 0x07,
TILE_PILLAR_BOTTOM = 0x08,
TILE_PILLAR_TOP = 0x09,
TILE_POTION = 0x0A,
TILE_LOOSE = 0x0B,
TILE_TAPESTRY_TOP = 0x0C,
TILE_MIRROR = 0x0D,
TILE_DEBRIS = 0x0E,
TILE_RAISE_BUTTON = 0x0F,
TILE_EXIT_LEFT = 0x10,
TILE_EXIT_RIGHT = 0x11,
TILE_CHOPPER = 0x12,
TILE_TORCH = 0x13,
TILE_WALL = 0x14,
TILE_SKELETON = 0x15,
TILE_SWORD = 0x16,
TILE_BALCONY_LEFT = 0x17,
TILE_BALCONY_RIGHT = 0x18,
TILE_LATTICE_PILLAR = 0x19,
TILE_LATTICE_SUPPORT= 0x1A,
TILE_LATTICE_SMALL = 0x1B,
TILE_LATTICE_LEFT = 0x1C,
TILE_LATTICE_RIGHT = 0x1D,
TILE_TORCH_DEBRIS = 0x1E,
TILE_NULL = 0x1F
};
/* Твёрдые тайлы — Фаза 1 (только геометрия); классификация наша, для
* коллизий движка, не часть исходного формата. Двери/шипы/дробилки и
* т.п. сознательно исключены из объёма Фазы 1 (см. §5 плана) — при
* встрече в реальных данных трактовать как проходимые до Фазы 2.
*
* tile_is_solid() — "есть опора сверху" (вертикальный смысл: можно
* стоять НА этом тайле) — Floor ТОЖЕ solid в этом смысле! Для
* горизонтальной коллизии (можно ли ВОЙТИ в эту клетку сбоку) нужен
* ОТДЕЛЬНЫЙ предикат — см. tile_blocks_side ниже. Баг 2026-07-16:
* col_blocked() в poc.c ошибочно звал tile_is_solid() для бокового
* упора — Floor блокировал сам себя, Кид не мог сдвинуться с места
* стоя на полу. */
static inline uint8_t tile_is_solid(uint8_t byte)
{
switch (TILE_TYPE(byte)) {
case TILE_FLOOR:
case TILE_PILLAR:
case TILE_PILLAR_BOTTOM:
case TILE_PILLAR_TOP:
case TILE_WALL:
case TILE_BALCONY_LEFT:
case TILE_BALCONY_RIGHT:
return 1;
default:
return 0;
}
}
/* tile_blocks_side() — настоящая преграда СБОКУ (нельзя войти в
* клетку по горизонтали): Wall/Pillar-семейство. Floor/Balcony НЕ
* блокируют — по ним идёшь (тайл под ногами, не впереди). Lattice-
* колонны (0x19-0x1D) — узкие, Кид физически проходит мимо (см.
* gen_tile_placeholders.py draw_lattice_like) — тоже НЕ блокируют. */
static inline uint8_t tile_blocks_side(uint8_t byte)
{
switch (TILE_TYPE(byte)) {
case TILE_PILLAR:
case TILE_PILLAR_BOTTOM:
case TILE_PILLAR_TOP:
case TILE_WALL:
return 1;
default:
return 0;
}
}
/* --- Тайл и комната --- */
typedef struct {
uint8_t type; /* foretable byte (rrmccccc — см. TILE_TYPE/MODIFIER) */
uint8_t state; /* backtable byte — модификатор/состояние */
} tile_t;
typedef struct {
tile_t tiles[ROOM_TILES]; /* индекс = tileOffset 0..29 */
uint8_t link_left, link_right; /* links-блок: 0 = нет соседа */
uint8_t link_up, link_down;
uint8_t guard_location; /* 0..29; 30 (и выше) = нет гарда */
int8_t guard_direction; /* 0 = вправо, -1 = влево */
uint8_t guard_skill; /* 0..9 */
uint8_t guard_colour; /* индекс палитры, Table 11 */
/* door I/II (событийные цепочки) — Фаза 2, не здесь */
} room_t;
typedef struct {
room_t rooms[LEVEL_ROOMS]; /* индекс 0 = комната 1 (файл 1-based) */
uint8_t start_room; /* 1..24 */
uint8_t start_location; /* 0..29 */
int8_t start_direction; /* 0 = вправо, -1 = влево */
} level_t;
/* Тайл по (room 1-based, col 0-9, row 0-2). */
static inline tile_t *level_tile(level_t *lv, uint8_t room, uint8_t col, uint8_t row)
{
return &lv->rooms[room - 1].tiles[row * ROOM_COLS + col];
}
/* Загружает ОДНУ комнату + стартовую позицию уровня из файла в формате
* tools/extract_room.py (63 Б: foretable[30]+backtable[30] той комнаты
* + start_room+start_pos+start_dir, вырезанные из res20NN.bin — layout
* подтверждён декодом байт 2026-07-15/16: файл начинается СРАЗУ с
* foretable[720], потом backtable[720], без заголовка; start_position
* — смещение 2112, сверено со структурой level_type в SDLPoP/src/
* types.h). Заполняет lv->start_room/start_location/start_direction.
* 0 — OK, -1 — файл не найден/короче 63 Б. */
int level_load_room(level_t *lv, uint8_t room, const char *path);
#endif
+264
View File
@@ -0,0 +1,264 @@
/*
* poc.c — PoC порта Prince of Persia (applications/PoP/docs/PORT_PLAN.md
* §5): проверяем управление (raw-клавиатура, held-state) + коллизию
* по краям экрана + анимацию ходьбы + прыжок/присед поверх готового
* спрайтового движка (sprite.h).
*
* ВАЖНО: персонаж — ВРЕМЕННАЯ ЗАГЛУШКА (лицензированный спрайт-пак
* third_party/16x16-RPG-characters через tools/gen_kid_placeholder.py,
* тот же источник, что уже использует examples/rpgwalk), НЕ графика
* оригинальной Prince of Persia — см. §5 и §8.5 плана. У заглушки нет
* отдельных поз прыжка/приседа — механика (тайминг дуги, состояние,
* коллизия с полом) проверяется на том же спрайте без смены позы;
* визуально это упрощение, не финальный вид.
*
* Дуга прыжка (jump_height[]) — СВОЯ, приблизительная (не таблица
* смещений оригинала — см. §6 плана: авторские таблицы кадров решено
* не переносить, только код/структуры).
*
* Нет ещё (следующие итерации): реальный уровень/фон по BLUETYPE,
* рывок вбок при прыжке с разбега, зацепление за уступ.
*/
#include <graphics.h>
#include <gfx.h>
#include <sprite.h>
#include <kbd_raw.h>
#include <conio.h>
#include <stdio.h>
#include "level.h"
#include "room.h"
/* Комната 1 уровня 1 — РЕАЛЬНАЯ геометрия (foretable/backtable),
* вырезана tools/extract_room.py из applications/PoP/SDLPoP/data/
* LEVELS/res2001.bin (level_load_room(), см. level.h/room.c) — не
* плейсхолдер. Верхний ряд (row0) — floor-уступ на cols 3-7 (там
* реально стоит персонаж в оригинале), стены по cols 8-9; ряды 1-2 —
* ниже уступа (торч/колонны/пол — Фаза 1 просто их отрисовывает по
* тем же типам, без многоуровневой физики падения). */
static level_t test_level;
#define CHAR_ROW 0 /* ряд, где стоит персонаж (floor-уступ room1) */
#define ROW_Y(r) ((r) * 64) /* room_row_h все по 64 */
#define GROUND_Y ROW_Y(CHAR_ROW + 1) /* низ ряда CHAR_ROW = верх пола */
#define KIDY (GROUND_Y - 16) /* y спрайта (16 px высотой) */
#define SPEED 2 /* px/кадр — заглушка, не авторский темп */
/* Настоящая преграда (Wall/Pillar) слева/справа от кандидата x в
* CHAR_ROW — блокирует движение (грубая проверка по краям хитбокса
* 16px, без под-тайловой подгонки — для PoC достаточно, см.
* PORT_PLAN.md §6). tile_blocks_side(), НЕ tile_is_solid(): Floor —
* тайл, на котором Кид СТОИТ (тот же CHAR_ROW), tile_is_solid() его
* тоже считает "твёрдым" (можно стоять сверху) — если проверять им же
* боковую преграду, Кид не мог сдвинуться с собственного пола (баг,
* найден 2026-07-16). */
static uint8_t col_blocked(int x)
{
uint8_t c0, c1;
if (x < 0 || x + 15 >= ROOM_COLS * ROOM_TILE_W)
return 1;
c0 = (uint8_t)(x / ROOM_TILE_W);
c1 = (uint8_t)((x + 15) / ROOM_TILE_W);
if (tile_blocks_side(level_tile(&test_level, 1, c0, CHAR_ROW)->type))
return 1;
if (tile_blocks_side(level_tile(&test_level, 1, c1, CHAR_ROW)->type))
return 1;
return 0;
}
/* Ленты атласа: dir*3+frame, dir 0=вниз/1=влево/2=вправо/3=вверх,
* 3 кадра маятника на направление (см. tools/gen_kid_placeholder.py). */
#define DIR_DOWN 0
#define DIR_LEFT 1
#define DIR_RIGHT 2
/* Дуга прыжка: своя, приблизительная (не авторская таблица, см. шапку
* файла) — высота над полом (px) по кадрам 0..19, УЖЕ ПОЛНЫЙ горб
* (подъём 2→22 к элементу 10, спуск обратно к 2 к элементу 19) — БЕЗ
* зеркалирования в коде, массив читается один раз целиком. БАГ,
* найденный пользователем 2026-07-15: раньше код ЕЩЁ РАЗ зеркалил
* этот уже полный горб на 40 кадров — получалось два полных прыжка
* подряд от одного триггера (не проблема клавиатуры/декодера, чистая
* рассинхронизация данных и комментария). 20 кадров @ 50 Гц ~= 0.4 с. */
static const uint8_t jump_height[20] = {
2, 4, 7, 10, 13, 16, 18, 20, 21, 22,
22, 21, 20, 18, 16, 13, 10, 7, 4, 2
};
#define JUMP_FRAMES 20
static atlas_t at;
static sprite_t kid;
static uint8_t facing = DIR_DOWN; /* текущее направление анимации */
static uint8_t jumping = 0; /* 0 = на земле */
static uint8_t jump_t = 0; /* кадр дуги, 0..JUMP_FRAMES-1 */
static uint8_t crouching = 0;
/* Прыжок — level-triggered НАМЕРЕННО (не edge-detect): если UP всё ещё
* зажат к моменту приземления — следующий прыжок стартует СРАЗУ (цепочка
* прыжков, пока держишь); отпустил раньше — второй прыжок не начнётся
* сам, только по следующему нажатию. Раньше здесь были up_prev/
* jump_cooldown — попытка "починить" ровно ЭТО поведение, приняв его
* за баг; убрано 2026-07-15 после уточнения желаемого поведения. */
static void draw_room(void)
{
setfillstyle(SOLID_FILL, BLACK);
bar(0, 0, 319, 255);
room_draw(&test_level, 1);
setcolor(LIGHTGRAY);
outtextxy(60, 4, "PoP PoC: hold LEFT/RIGHT to walk, ESC to quit");
outtextxy(4, 14, "(placeholder tiles -- not original PoP art)");
}
/* HUD-плашка состояния (нет отдельной позы прыжка/приседа — статус
* текстом, рисуется банком 0x50, heal спрайтового движка её не
* трогает — как fps-плашка в examples/rpgwalk). */
static void show_state(uint8_t jump, uint8_t crouch)
{
setfillstyle(SOLID_FILL, BLACK);
bar(0, 24, 60, 32);
setcolor(YELLOW);
if (jump)
outtextxy(0, 24, "JUMP");
else if (crouch)
outtextxy(0, 24, "CROUCH");
}
static void set_facing(uint8_t dir)
{
if (facing == dir)
return;
facing = dir;
sprite_anim(&kid, (uint8_t)(dir * 3), (uint8_t)(dir * 3 + 2),
6, ANIM_PINGPONG);
}
int main(void)
{
uint8_t page, hidden;
int x;
if (level_load_room(&test_level, 1, "room1.dat") != 0 &&
level_load_room(&test_level, 1, "a:\\room1.dat") != 0) {
puts("room1.dat not found");
return 1;
}
/* Стартовая позиция. В данных room1 start_location = tileOffset 0
* (row0/col0) — а там EMPTY (провал, без пола); в Фазе 1 нет физики
* падения, поэтому для PoC ставим Кида на floor-уступ (col 3, где он
* реально стоит в оригинале). Когда появится многоуровневая физика —
* брать col из start_location. start_direction: -1 = влево, 0 =
* вправо (level.h). */
x = 3 * ROOM_TILE_W;
facing = (test_level.start_direction < 0) ? DIR_LEFT : DIR_RIGHT;
if (atlas_load(&at, "kid.atl") != 0 &&
atlas_load(&at, "a:\\kid.atl") != 0) {
puts("kid.atl not found");
return 1;
}
if (tile_atlas_load("") == 0 && tile_atlas_load("a:\\") == 0) {
puts("tile atlases not found");
atlas_free(&at);
return 1;
}
initgraph();
/* room.pal = EGA16 + Kid + Floor + Wall — ОДНА палитра на всё,
* собрана tools/build_room_palette.py (см. --seed-pal в
* toolchain/png_strip.py) — Kid и тайлы на экране одновременно,
* их "свои" цвета обязаны жить в одной таблице. */
if (gfx_pal_fload(0, "room.pal") < 0)
gfx_pal_fload(0, "a:\\room.pal");
gfx_pal_sync();
gfx_sprite_clip(0); /* коллизия по краям гарантирует границы */
/* kid.atl — ОДНА лента (12 кадров вертикально: dir*3+кадр, см. шапку
* файла и examples/rpgwalk); индекс atlas_sprite_init — это НОМЕР
* ЛЕНТЫ (персонажа), а не кадра. Лента одна → всегда 0. Стартовый
* кадр направления выставляем sprite_frame (вертикальная лента, fh=16:
* кадр N на sy=N*16). Баг Соннета (найден 2026-07-16): здесь стоял
* facing*3 как индекс ЛЕНТЫ — при старте лицом влево (idx 3) читался
* мусор за каталогом атласа → мусорные w/h/src → блит спрайта заливал
* пол-экрана «снегом». */
atlas_sprite_init(&kid, &at, 0);
sprite_frame(&kid, 0, (int)(facing * 3) * 16);
kid.x = x;
kid.y = KIDY;
sprite_show(&kid);
for (page = 0; page < 2; page++) { /* фон + спрайт на обе страницы */
gfx_set_draw_page(page);
draw_room();
sprite_update(&kid, 1);
}
gfx_set_visible_page(0);
/* kbd_raw требует BSS в W2 (IM2-таблица) — недоступно в --memory small
* (там BSS может уехать в W1 → EINVAL); poc собирается --memory huge
* (CODE в W1, DATA/BSS в W2). closegraph ДО puts — иначе сообщение
* ушло бы в графический режим (невидимо), а программа молча вышла бы
* в prompt (баг Соннета, найден 2026-07-16). */
if (kbd_raw_open() != 0) {
closegraph();
puts("kbd_raw_open failed (need memory mode with BSS in W2)");
atlas_free(&at);
return 1;
}
for (;;) {
uint8_t moving = 0;
int y = KIDY;
if (jumping) {
/* дуга идёт сама; направлением можно скользить вбок,
* поза не меняется (нет отдельного кадра прыжка) */
if (kbd_raw_down(KBD_LEFT)) {
if (!col_blocked(x - SPEED)) x -= SPEED;
} else if (kbd_raw_down(KBD_RIGHT)) {
if (!col_blocked(x + SPEED)) x += SPEED;
}
y = KIDY - jump_height[jump_t];
jump_t++;
if (jump_t >= JUMP_FRAMES) {
jumping = 0;
y = KIDY;
}
} else if (crouching) {
if (!kbd_raw_down(KBD_DOWN))
crouching = 0;
} else if (kbd_raw_down(KBD_UP)) {
jumping = 1;
jump_t = 0;
} else if (kbd_raw_down(KBD_DOWN)) {
crouching = 1;
} else if (kbd_raw_down(KBD_LEFT)) {
if (!col_blocked(x - SPEED)) x -= SPEED;
set_facing(DIR_LEFT);
moving = 1;
} else if (kbd_raw_down(KBD_RIGHT)) {
if (!col_blocked(x + SPEED)) x += SPEED;
set_facing(DIR_RIGHT);
moving = 1;
}
if (!moving && !jumping && (sprite_anim_status(&kid) & SPR_ANIM_ON))
sprite_anim_stop(&kid, (int8_t)(facing * 3));
sprite_move(&kid, x, y);
if (kbd_raw_down(KBD_ESC))
break;
hidden = gfx_get_visible_page() ^ 1;
gfx_set_draw_page(hidden);
show_state(jumping, crouching);
sprite_update(&kid, 1);
gfx_wait_vsync();
gfx_set_visible_page(hidden);
}
kbd_raw_close();
closegraph();
tile_atlas_free();
atlas_free(&at);
return 0;
}
Binary file not shown.
@@ -0,0 +1,32 @@
/* pop_bg_atlas.h — раскладка атласов статического фона PoP.
* Сгенерировано toolchain/pop_pack_bg.py — НЕ править вручную.
*
* Прямая адресация (ноль remap-таблиц в W2):
* ENV фон id N -> atlas env_bg[N>>5], idx N&31
* WALL id N -> atlas wall, idx N
* FORE id N -> atlas fore, idx N
*/
#ifndef POP_BG_ATLAS_H
#define POP_BG_ATLAS_H
#define POP_ENV_SHIFT 5
#define POP_ENV_MASK 31
#define POP_ENV_PAGES 5
/* Палитра: env-слоты, wall-слоты (сприйт-пиксель i -> база+i). */
#define POP_PAL_ENV 0x50
#define POP_PAL_WALL 0x60
/* Имена файлов атласов (грузятся atlas_load). */
static const char *const pop_env_atl[POP_ENV_PAGES] = {
"pop_env0.atl",
"pop_env1.atl",
"pop_env2.atl",
"pop_env3.atl",
"pop_env4.atl",
};
#define POP_WALL_ATL "pop_wall.atl"
#define POP_FORE_ATL "pop_fore.atl"
#define POP_BG_PAL "pop_bg.pal"
#endif
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+39
View File
@@ -0,0 +1,39 @@
/* kid_atlas.h — раскладка атласов Kid. Сгенерировано pop_pack_kid.py. */
#ifndef KID_ATLAS_H
#define KID_ATLAS_H
#define KID_SHIFT 3
#define KID_MASK 7
#define KID_PAGES 28
#define KID_PAL 0x70
static const char *const kid_atl[KID_PAGES] = {
"kid0.atl",
"kid1.atl",
"kid2.atl",
"kid3.atl",
"kid4.atl",
"kid5.atl",
"kid6.atl",
"kid7.atl",
"kid8.atl",
"kid9.atl",
"kid10.atl",
"kid11.atl",
"kid12.atl",
"kid13.atl",
"kid14.atl",
"kid15.atl",
"kid16.atl",
"kid17.atl",
"kid18.atl",
"kid19.atl",
"kid20.atl",
"kid21.atl",
"kid22.atl",
"kid23.atl",
"kid24.atl",
"kid25.atl",
"kid26.atl",
"kid27.atl",
};
#define KID_PAL_FILE "kid.pal"
#endif
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 87 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 631 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 624 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 825 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 832 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 911 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 208 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 208 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 199 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 190 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 698 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 478 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 889 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 764 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 821 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 831 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 825 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 715 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 867 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 650 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 759 B

Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@

Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@

Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@

Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@

Binary file not shown.
Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More