diff --git a/data/map.tmj b/data/map.tmj index 3ad4579..1e39f4c 100644 --- a/data/map.tmj +++ b/data/map.tmj @@ -289,8 +289,8 @@ { "id":3, "template":"templates\/NPC.tx", - "x":6535.25, - "y":6728.5 + "x":6527.97727272727, + "y":6736.13636363636 }, { "id":4, diff --git a/tools/mapcompile/mapcompile.py b/tools/mapcompile/mapcompile.py index 6d5a690..44e6ee1 100644 --- a/tools/mapcompile/mapcompile.py +++ b/tools/mapcompile/mapcompile.py @@ -9,6 +9,8 @@ CHUNK_WIDTH = 8 CHUNK_HEIGHT = 8 CHUNK_TILE_COUNT = CHUNK_WIDTH * CHUNK_HEIGHT CHUNK_ENTITY_COUNT_MAX = 8 +TILE_WIDTH = 16 +TILE_HEIGHT = 16 ENTITY_TYPE_MAP = { "npc": "ENTITY_TYPE_NPC", @@ -78,6 +80,10 @@ if objectLayer is None: print(f"Error: Input file '{inputFile}' does not contain an object layer.") sys.exit(1) +if 'objects' not in objectLayer or not isinstance(objectLayer['objects'], list): + print(f"Error: Object layer in '{inputFile}' does not contain 'objects' key or it is not a list.") + sys.exit(1) + # Tile Layers tileLayers = [] for layer in layers: @@ -176,6 +182,28 @@ for layerIndex, layer in enumerate(tileLayers): layers[layerIndex] = layer + +# Pre generate entity data +nextEntityId = 1 +for obIndex, ob in enumerate(objectLayer['objects']): + if 'x' not in ob or 'y' not in ob: + print(f"Error: Object in object layer does not contain 'x' or 'y' key.") + sys.exit(1) + + ob['x'] -= inputMapLowestX * TILE_WIDTH + ob['y'] -= inputMapLowestY * TILE_HEIGHT + + # Objects are bottom aligned in tiled, so we need to adjust the Y coordinate. + ob['y'] -= TILE_HEIGHT + + # Round off the coordinates + ob['x'] = round(ob['x']) + ob['y'] = round(ob['y']) + ob['id'] = nextEntityId + nextEntityId += 1 + + objectLayer['objects'][obIndex] = ob + mapWidthInTiles = inputMapHighestX - inputMapLowestX mapHeightInTiles = inputMapHighestY - inputMapLowestY mapWidthInRealChunks = math.ceil(float(mapWidthInTiles) / float(CHUNK_WIDTH)) @@ -201,9 +229,8 @@ for chunkY in range(mapHeightInRealChunks): inputTopLeftTileX = math.floor(float(topLeftTileX) / float(inputLayerWidthInTiles)) * inputLayerWidthInTiles inputTopLeftTileY = math.floor(float(topLeftTileY) / float(inputLayerHeightInTiles)) * inputLayerHeightInTiles + # Get the layers for this chunk. chunkLayers = [] - - # For each layer... for layerIndex, layer in enumerate(tileLayers): foundChunk = None if 'chunks' not in layer or not isinstance(layer['chunks'], list): @@ -249,6 +276,24 @@ for chunkY in range(mapHeightInRealChunks): if len(chunkLayers) > 2: print(f"Error: Expected 2 layers for chunk at ({chunkX}, {chunkY}), found {len(chunkLayers)}.") sys.exit(1) + + entities = [] + for ob in objectLayer['objects']: + if 'x' not in ob or 'y' not in ob: + print(f"Error: Object in object layer does not contain 'x' or 'y' key.") + sys.exit(1) + + # Is this object within the chunk? + if ob['x'] < topLeftTileX * TILE_WIDTH: + continue + if ob['x'] >= (topLeftTileX + CHUNK_WIDTH) * TILE_WIDTH: + continue + if ob['y'] < topLeftTileY * TILE_HEIGHT: + continue + if ob['y'] >= (topLeftTileY + CHUNK_HEIGHT) * TILE_HEIGHT: + continue + + entities.append(ob) # Shorthand functions def getInputLocalTileX(absoluteTileX): @@ -295,40 +340,28 @@ for chunkY in range(mapHeightInRealChunks): f.write(f"0x{byte:02x}, ") f.write(f"\n") f.write(" },\n\n") + f.write(f" .layerOverlay = {{}},\n") + f.write(f" .entities = {{\n") + for entity in entities: + # Entities are center aligned in tiled. + localX = entity['x'] - (topLeftTileX * TILE_WIDTH) + localY = entity['y'] - (topLeftTileY * TILE_HEIGHT) + + print(f"Entity at ({entity['x']}, {entity['y']}) in chunk ({chunkX}, {chunkY}) is at local position ({localX}, {localY})") + + f.write(" {\n") + f.write(f" .id = {entity['id']},\n") + f.write(f" .type = ENTITY_TYPE_NPC,\n") + f.write(f" .x = {localX},\n") + f.write(f" .y = {localY},\n") + f.write(f" .dir = ENTITY_DIR_SOUTH,\n") + f.write(" },\n") f.write(f" }},\n") + f.write("};\n\n") - -# f.write(f" .entities = {{\n") -# for entity in entities: -# if 'id' in entity: -# entityId = entity['id'] -# else: -# entityId = entityIdNext -# entityIdNext += 1 - -# if 'type' not in entity: -# print(f"Error: Entity in chunk ({x}, {y}) does not have 'type' key.") -# exit(1) - -# if 'x' not in entity or 'y' not in entity: -# print(f"Error: Entity in chunk ({x}, {y}) does not have 'x' or 'y' key.") -# exit(1) - -# f.write(" {\n") -# f.write(f" .id = {entityId},\n") -# f.write(f" .type = {ENTITY_TYPE_MAP.get(entity['type'], 'ENTITY_TYPE_UNKNOWN')},\n"), -# f.write(f" .x = {entity['x']},\n") -# f.write(f" .y = {entity['y']},\n") -# f.write(f" }},\n") -# pass -# f.write(" },\n\n") - -# f.write("};\n\n") -# pass - # Output header file. headerPath = os.path.join(worldDir, "world.h") with open(headerPath, 'w') as f: