#!/usr/bin/env python3 from argparse import ArgumentParser import subprocess import os import json __version__ = "1.0" ld = os.environ.get("LD", "i586-pc-msdosdjgpp-ld") strip = os.environ.get("STRIP", "i586-pc-msdosdjgpp-strip") entity_types = ( "Player", "Snake", "Bat", "Old", "Bones", "Time", "Bonus", "Pickaxe", "GoldKey", "SilverKey", ) def get_layer(data, name): for layer in data["layers"]: if layer["name"] == name: return layer raise ValueError("Layer %r not found" % name) def get_prop(data, name, default): if "properties" not in data: return default for prop in data["properties"]: if prop["name"] == name: return prop["value"] return default def main(): parser = ArgumentParser( description="Tiled JSON Map to .o", epilog="Copyright (C) 2023 Juan J Martinez ", ) parser.add_argument( "--version", action="version", version="%(prog)s " + __version__ ) parser.add_argument("file_json", help="JSON map to convert") parser.add_argument("output", help="object name for the map data") args = parser.parse_args() with open(args.file_json, "rt") as fd: data = json.load(fd) if len(data["tilesets"]) != 1: parser.error("Unsupported number of tilesets %d" % len(data["tilesets"])) tileset = data["tilesets"][0] map_layer = get_layer(data, "Map") out = list(map(lambda x: (x - tileset["firstgid"]) & 0xFF, map_layer["data"])) gold_layer = get_layer(data, "Gold") total_gold = 0 for t in gold_layer["data"]: if t != 0: total_gold += 1 if total_gold > 255: parser.error("There are more than 255 gold pieces on the screen") out.extend(map(lambda x: (x - tileset["firstgid"]) & 0xFF, gold_layer["data"])) entity_layer = get_layer(data, "Entities") # some entities will never change their y coordinate, so sorting them by y # should help the drawing order in the game objs_sorted = sorted(entity_layer["objects"], key=lambda o: o["y"]) for ent in objs_sorted: try: typ = entity_types.index(ent["name"]) except ValueError: parser.error("Entity in map %r not found in entity types" % ent["name"]) x = ent["x"] // tileset["tilewidth"] y = ent["y"] // tileset["tileheight"] flags = 0 dir = get_prop(ent, "dir", "right") if dir not in ("left", "right"): parser.error("Invalid value for property dir: %r" % dir) if dir == "left": flags |= 1 out.extend([typ, x, y, flags]) # end of entity list out.append(0xFF) tmp = args.output.removesuffix(".o") with open(tmp, "wb") as fd: fd.write(bytearray(out)) fd.flush() # create an object file from the binary rc = subprocess.call( [ ld, "-r", "-b", "binary", "-o", args.output, tmp, ] ) os.unlink(tmp) if rc != 0: parser.error("Failed to run %s" % ld) # strip unwanted symbols rc = subprocess.call([strip, "-w", "-K", "*_%s_*" % tmp, args.output]) if rc != 0: parser.error("Failed to run %s" % ld) if __name__ == "__main__": main()