|
@ -3,12 +3,13 @@ import pathlib |
|
|
import subprocess |
|
|
import subprocess |
|
|
import sys |
|
|
import sys |
|
|
import tempfile |
|
|
import tempfile |
|
|
from typing import NoReturn |
|
|
|
|
|
|
|
|
from typing import NoReturn, Tuple |
|
|
|
|
|
|
|
|
from PIL import Image |
|
|
from PIL import Image |
|
|
|
|
|
|
|
|
GREEN = (0, 255, 0) |
|
|
GREEN = (0, 255, 0) |
|
|
RED = (255, 0, 0) |
|
|
RED = (255, 0, 0) |
|
|
|
|
|
BLUE = (0, 0, 255) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def abort(msg: str) -> NoReturn: |
|
|
def abort(msg: str) -> NoReturn: |
|
@ -16,9 +17,12 @@ def abort(msg: str) -> NoReturn: |
|
|
sys.exit(1) |
|
|
sys.exit(1) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
SpawnPoint = Tuple[int, int] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def generate_coll_map( |
|
|
def generate_coll_map( |
|
|
in_path: pathlib.Path, width: int, height: int, compress: bool = False |
|
|
in_path: pathlib.Path, width: int, height: int, compress: bool = False |
|
|
) -> str: |
|
|
|
|
|
|
|
|
) -> Tuple[str, SpawnPoint]: |
|
|
png = Image.open(in_path).convert("RGB") |
|
|
png = Image.open(in_path).convert("RGB") |
|
|
if png.width % 8 != 0 or png.height % 8 != 0: |
|
|
if png.width % 8 != 0 or png.height % 8 != 0: |
|
|
abort(f"file '{in_path}' has invalid dimensions (should be multiple of 8)") |
|
|
abort(f"file '{in_path}' has invalid dimensions (should be multiple of 8)") |
|
@ -28,16 +32,20 @@ def generate_coll_map( |
|
|
|
|
|
|
|
|
out_bytes = [] |
|
|
out_bytes = [] |
|
|
bits = [] |
|
|
bits = [] |
|
|
|
|
|
spawn = None |
|
|
|
|
|
|
|
|
for y in range(png.height // 8): |
|
|
for y in range(png.height // 8): |
|
|
for x in range(png.width // 8): |
|
|
for x in range(png.width // 8): |
|
|
pixel = png.getpixel((x * 8, y * 8)) |
|
|
pixel = png.getpixel((x * 8, y * 8)) |
|
|
|
|
|
|
|
|
bit = None |
|
|
bit = None |
|
|
|
|
|
|
|
|
if pixel == RED: |
|
|
if pixel == RED: |
|
|
bit = 0 |
|
|
bit = 0 |
|
|
elif pixel == GREEN: |
|
|
elif pixel == GREEN: |
|
|
bit = 1 |
|
|
bit = 1 |
|
|
|
|
|
elif pixel == BLUE: |
|
|
|
|
|
bit = 1 |
|
|
|
|
|
spawn = (x, y) |
|
|
else: |
|
|
else: |
|
|
abort(f"unsupported pixel in collision map: {pixel}") |
|
|
abort(f"unsupported pixel in collision map: {pixel}") |
|
|
|
|
|
|
|
@ -51,7 +59,11 @@ def generate_coll_map( |
|
|
out_bytes.append(bit) |
|
|
out_bytes.append(bit) |
|
|
|
|
|
|
|
|
png.close() |
|
|
png.close() |
|
|
return format_bytes(out_bytes, width=width) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if spawn is None: |
|
|
|
|
|
abort(f"no spawn point located") |
|
|
|
|
|
|
|
|
|
|
|
return format_bytes(out_bytes, width=width), spawn |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def format_bytes(data: bytes, width: int = 16) -> str: |
|
|
def format_bytes(data: bytes, width: int = 16) -> str: |
|
@ -74,6 +86,11 @@ def generate_map(pngfile: str, compress: bool = False) -> None: |
|
|
width = png.width // 8 |
|
|
width = png.width // 8 |
|
|
height = png.height // 8 |
|
|
height = png.height // 8 |
|
|
|
|
|
|
|
|
|
|
|
if width > 127 or height > 127: |
|
|
|
|
|
abort( |
|
|
|
|
|
f"file '{pngfile}' has invalid dimensions (width/height greater than 127 tiles)" |
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
png.close() |
|
|
png.close() |
|
|
|
|
|
|
|
|
with tempfile.NamedTemporaryFile() as tilef, tempfile.NamedTemporaryFile() as mapf: |
|
|
with tempfile.NamedTemporaryFile() as tilef, tempfile.NamedTemporaryFile() as mapf: |
|
@ -95,7 +112,7 @@ def generate_map(pngfile: str, compress: bool = False) -> None: |
|
|
section = pngpath.name.replace(".png", "") |
|
|
section = pngpath.name.replace(".png", "") |
|
|
|
|
|
|
|
|
collpath = pngpath.parent / pngpath.name.replace(".png", "_coll.png") |
|
|
collpath = pngpath.parent / pngpath.name.replace(".png", "_coll.png") |
|
|
coll_map = generate_coll_map(collpath, width, height, compress=compress) |
|
|
|
|
|
|
|
|
coll_map, spawn = generate_coll_map(collpath, width, height, compress=compress) |
|
|
|
|
|
|
|
|
with open(incpath, "w") as outf: |
|
|
with open(incpath, "w") as outf: |
|
|
outf.write( |
|
|
outf.write( |
|
@ -111,7 +128,16 @@ ASSERT {section}_MAP_SIZE == {section}_WIDTH * {section}_HEIGHT |
|
|
|
|
|
|
|
|
with open(spath, "w") as outf: |
|
|
with open(spath, "w") as outf: |
|
|
outf.write( |
|
|
outf.write( |
|
|
f"""SECTION "MAP - {section}", ROMX |
|
|
|
|
|
|
|
|
f"""SECTION "MAP - {section}", ROM0 |
|
|
|
|
|
|
|
|
|
|
|
{section}_Data:: |
|
|
|
|
|
{section}_TILE_PTR: DW {section}_TILES |
|
|
|
|
|
{section}_TILE_SIZE: DB ({section}_TILES_end - {section}_TILES) |
|
|
|
|
|
{section}_MAP_PTR: DW {section}_MAP |
|
|
|
|
|
{section}_MAP_WIDTH: DB {width} |
|
|
|
|
|
{section}_MAP_HEIGHT: DB {height} |
|
|
|
|
|
{section}_SPAWN_X: DB {spawn[0]} |
|
|
|
|
|
{section}_SPAWN_Y: DB {spawn[1]} |
|
|
|
|
|
|
|
|
{section}_MAP:: |
|
|
{section}_MAP:: |
|
|
{map_data} |
|
|
{map_data} |
|
|