#!/usr/bin/env python3 """Конвертер third_party/16x16-RPG-characters (02-bard.png) → ленты атласа + палитра для examples/rpgwalk. Источник: RGBA 192×128 = 8 рядов × 12 картинок 16×16; персонаж = блок 3×4 (4 блока в ряду, 2 ряда блоков = 8 персонажей): строка блока 0 — идёт ВНИЗ (на нас), кадры 0/1/2 (маятник); строка 1 — ВЛЕВО; строка 2 — ВПРАВО; строка 3 — ВВЕРХ. Выход: char0.raw..char7.raw — вертикальные ленты 16×192 (12 кадров: dir*3 + frame — sprite_anim(dir*3, dir*3+2, PINGPONG)); bard.pal — палитра gfx_pal_fload: слоты 0..15 = EGA (как ставит initgraph, таблица из _bgi_mode_set), слоты 16.. = цвета PNG. Пиксели: прозрачное (alpha<128) → 0xFF, цвет → 16 + индекс. """ from PIL import Image SRC = ("../../third_party/16x16-RPG-characters/sprites/" "old-style/02-bard.png") BASE = 16 # цвета PNG кладём после EGA-шестнадцати # B, G, R, pad — как в libbgi/bgi256/_bgi_mode_set.c EGA = [ (0, 0, 0), (168, 0, 0), (0, 168, 0), (168, 168, 0), (0, 0, 168), (168, 0, 168), (0, 84, 168), (168, 168, 168), (84, 84, 84), (255, 84, 84), (84, 255, 84), (255, 255, 84), (84, 84, 255), (255, 84, 255), (84, 255, 255), (255, 255, 255), ] im = Image.open(SRC).convert("RGBA") assert im.size == (192, 128), im.size colors = {} # (r,g,b) -> палитровый индекс def px(x, y): r, g, b, a = im.getpixel((x, y)) if a < 128: return 0xFF key = (r, g, b) if key not in colors: assert BASE + len(colors) < 0xFF, "палитра переполнена" colors[key] = BASE + len(colors) return colors[key] for c in range(8): bx, by = (c % 4) * 48, (c // 4) * 64 data = bytearray() for d in range(4): # вниз/влево/вправо/вверх for f in range(3): # кадры маятника for y in range(16): for x in range(16): data.append(px(bx + f * 16 + x, by + d * 16 + y)) open(f"char{c}.raw", "wb").write(data) pal = bytearray() for b, g, r in EGA: pal += bytes((b, g, r, 0)) for (r, g, b) in colors: # dict сохраняет порядок вставки pal += bytes((b, g, r, 0)) open("bard.pal", "wb").write(pal) print(f"conv_sprites: 8 лент 16x192, палитра EGA+{len(colors)} цветов " f"({len(pal)} Б)")