diff --git a/CMakeLists.txt b/CMakeLists.txt index 9510886..7b4df23 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,7 +32,8 @@ set(SOURCES ) # Shared assets, fx-9860G-only assets and fx-CG-50-only assets set(ASSETS - assets/WorldRPG.world + #assets/WorldRPG.world + assets/level0.tmx # ... ) diff --git a/assets/converters.py b/assets/converters.py index ebd709b..5373dd4 100644 --- a/assets/converters.py +++ b/assets/converters.py @@ -1,522 +1,375 @@ -from random import randint -from PIL import Image -import fxconv +import xml.etree.ElementTree as ET import json -import pathlib -import csv import os +import sys -DEBUG = 0 +VERBOSE = 1 +SIGN_TYPES = ["INFO", "SGN"] + +# TODO: Add more doc. + +class Tileset: + """ + Handle the tiled tileset. + """ + def __init__(self, element: ET.Element, parent_dir = ""): + firstgid_str = element.get("firstgid") + if firstgid_str == None: raise Exception("firstgid not found!") + self.firstgid = int(firstgid_str) + self.source = element.get("source") + if self.source == None: raise Exception("source not found!") + self.source = parent_dir + self.source + tree = ET.parse(self.source) + self.root = tree.getroot() + tilecount_str = self.root.get("tilecount") + if tilecount_str == None: raise Exception("tilecount not found!") + self.tilecount = int(tilecount_str) + + def is_raw_in_tileset(self, raw: int) -> bool: + if raw >= self.firstgid and raw < self.firstgid+self.tilecount: + return True + return False + def get_tile_from_raw(self, raw: int) -> int: + if not self.is_raw_in_tileset(raw) and raw: + raise Exception(f"Tile {raw} not in tileset!") + return raw-self.firstgid + +class Layer: + """ + A class to handle a tiled map layer + """ + def __init__(self, element: ET.Element): + self.element = element + + def get_width(self) -> int: + """ + Get the layer width + """ + value = self.element.get("width") + if value == None: raise Exception("Layer width not found") + return int(value) + + def get_height(self) -> int: + """ + Get the layer height + """ + value = self.element.get("height") + if value == None: raise Exception("Layer height not found") + return int(value) + + def get_raw_data(self) -> list: + """ + Get the data of the map + """ + data_tag = self.element.find("data") + if data_tag == None: raise Exception("Data not found!") + raw_data = data_tag.text.split(",") + int_data = [] + for tile in raw_data: + int_data.append(int(tile)) + return int_data + def get_data_with_tileset(self, tileset: Tileset): + raw_data = self.get_raw_data() + out_data = [] + for i in raw_data: + out_data.append(tileset.get_tile_from_raw(i)) + return out_data + +class Object: + """ + An group object (see ObjectGroup) object. + """ + def __init__(self, element: ET.Element): + self.element = element + self.name = element.get("name") + if self.name == None: raise Exception("Name attribute missing!") + self.type = element.get("type") + if self.type == None: raise Exception("Type attribute missing!") + x_str = element.get("x") + if x_str == None: raise Exception("X attribute missing!") + self.x = int(float(x_str)) + y_str = element.get("y") + if y_str == None: raise Exception("Y attribute missing!") + self.y = int(float(y_str)) + self.id = element.get("id") + if self.id == None: raise Exception("ID attribute missing!") + + def __get_point(self) -> list: + # Private method to get a point. Used in get_data. + return [self.x, self.y] + + def __get_polyline(self) -> list: + # Private method to get a polyline. Used in get_data. + data = self.element.find("polyline").get("points") + if data == None: raise Exception("Data not found!") + data = data.replace(' ', ',').split(',') + out_data = [] + for i in data: + out_data.append(int(float(i))) + return out_data + + def get_data(self) -> list: + """ + Get the geometric shape of this object. + """ + if self.element.find("point") != None: + # It is a point. + return self.__get_point() + if self.element.find("polyline") != None: + # It is a polyline. + return self.__get_polyline() + raise Exception("Unknown data!") + + def get_data_type(self) -> str: + """ + Get the geometric shape of this object. + """ + if self.element.find("point") != None: + # It is a point. + return "point" + if self.element.find("polyline") != None: + # It is a polyline. + return "polyline" + raise Exception("Unknown data!") + + def get_property(self, property: str) -> str: + """ + Get the value of a property. + """ + properties = self.element.find("properties") + if properties == None: raise Exception("Properties not found!") + for i in properties: + if i.get("name") == property: + value = i.get("value") + if value == None: raise Exception("Property value not found!") + return value + raise Exception(f"Property {property} not found!") + +class ObjectGroup: + """ + Handle tiled object groups. They can contain points, lines and other + geometric shapes that can be very handy to add NPCs, the path they walk on, + as we do it here, in Collab_RPG. + """ + def __init__(self, element: ET.Element): + self.element = element + self.objects = [] + for object in self.element.iterfind("object"): + self.objects.append(Object(object)) + + + +class Map: + """ + A class to handle the tiled maps. + """ + def __init__(self, input: str): + """ + Loads a tmx map made with tiled. + """ + tree = ET.parse(input) + self.root = tree.getroot() + self.parent_dir = os.path.abspath(input).rpartition('/')[0] + + def get_property(self, property: str) -> str: + """ + Get a map property. + """ + properties = self.root.find("properties") + # If properties wasn't found. + if properties == None: + raise Exception("Properties not found!") + for child in properties: + # Look at the name attribute of each property + if child.get("name") == property: + value = child.get("value") + if value == None: raise Exception("Value attribute not found!") + return value + # The dialog file property wasn't found. + raise Exception(f"\"{property}\" property not found!") + + def get_layer_by_id(self, layer_id: str) -> Layer: + """ + Get a layer by its id. + """ + for layer in self.root.iterfind("layer"): + if layer.get("id") == layer_id: + return Layer(layer) + raise Exception("Layer not found!") + + def get_layer_by_name(self, name: str) -> Layer: + """ + Get a layer by its name. + """ + for layer in self.root.iterfind("layer"): + if layer.get("name") == name: + return Layer(layer) + raise Exception("Layer not found!") + + def get_objectgroup_by_id(self, group_id: str) -> Layer: + """ + Get a layer by its id. + """ + for layer in self.root.iterfind("objectgroup"): + if layer.get("id") == group_id: + return ObjectGroup(layer) + raise Exception("Object group not found!") + + def get_objectgroup_by_name(self, name: str) -> Layer: + """ + Get a layer by its name. + """ + for layer in self.root.iterfind("objectgroup"): + if layer.get("name") == name: + return ObjectGroup(layer) + raise Exception("Object group not found!") + + def get_tileset_by_firstgid(self, firstgid: int) -> Tileset: + for tileset in self.root.iterfind("tileset"): + if tileset.get("firstgid") == str(firstgid): + return Tileset(tileset, self.parent_dir + "/") + raise Exception("Tileset not found!") def convert(input, output, params, target): - if params["custom-type"] == "map": - print("ERROR : Asset ", params["name"], " has legacy type map") - return 1 - elif params["custom-type"] == "world": - convert_world(input, output, params, target) + if params["custom-type"] == "tmx": + convert_map(input, output, params, target) return 0 - elif params["custom-type"] == "custom-image": - convert_custom_image(input, output, params, target) + elif params["custom-type"] == "json": + convert_dialog(input, output, params, target) return 0 - elif params["custom-type"] == "font": - convert_font(input, output, params, target) - return 0 - elif params["custom-type"] == "dialogs": - print("ERROR : Asset ", params["name"], " has legacy type dialog") - #convert_dialogs(input, output, params, target) - return 0 - else: - return 1 -def convert_world(input, output, params, target): - print( "WE ARE COMPUTING THE WORLD", input ) - - data = json.load(open(input, "r")) - nbMaps = ["fileName" in i for i in data["maps"]].count(True) - if DEBUG: print( "We have to treat ", nbMaps, " maps") - if DEBUG: print( "So let's go ... ") - - structWorld = fxconv.Structure() - #structExtra = fxconv.Structure() - - for i in range(nbMaps): - nameMap = data["maps"][i]["fileName"].replace(".tmx","") - nameMapFree = nameMap.split("/")[-1] - #count the number of "back" (cd ..) to locate the map on the computer - nbRetour = nameMap.count("..")+1 - #create the map absolute path - - nameTMX = "/".join(input.split("/")[:-nbRetour]) + "/" + nameMap + ".tmx" - nameJSON = "/".join(input.split("/")[:-nbRetour]) + "/" + nameMap + ".json" - - commandline = 'tiled --export-map json ' + nameTMX + ' ' + nameJSON - if DEBUG: print( "TILED COMMAND LINE FOR MAPS : ", commandline ) - os.system( commandline ) - - mapPath = "/".join(input.split("/")[:-nbRetour]) + "/" + nameMap + ".json" - if DEBUG: print("Map ", i , " name : ", mapPath ) - - xmin = data["maps"][i]["x"] - if DEBUG: print( "xmin = ", xmin ) - - ymin = data["maps"][i]["y"] - if DEBUG: print( "ymin = ", ymin ) - - xmax = data["maps"][i]["x"] + data["maps"][i]["width"] - if DEBUG: print( "xmax = ", xmax ) - - ymax = data["maps"][i]["y"] + data["maps"][i]["height"] - if DEBUG: print( "ymax = ", ymax ) - - map = get_tile_map_data( mapPath, output, params, target, xmin, ymin, xmax, ymax) - if DEBUG: print( "Map = ", map ) - structWorld += fxconv.ptr( map ) - - #structWorld += fxconv.u32(0) - - #generate ! - fxconv.elf(structWorld, output, "_" + params["name"], **target) - - -def get_tile_map_data(input, output, params, target, xmin, ymin, xmax, ymax): - print( "WE ARE COMPUTING THE MAP : ", input ) - data = json.load(open(input, "r")) - - #find the tileset in use. it's a relative path (like ../tileset.tsx) - nameTileset = data["tilesets"][0]["source"].replace(".tsx","") - if DEBUG: print(nameTileset) - #the name of the tileset without the .something - nameTilesetFree = nameTileset.split("/")[-1] - #count the number of "back" (cd ..) to locate the tileset on the computer - nbRetour = nameTileset.count("..")+1 - #create the tileset absolute path - tilesetTSX = "/".join(input.split("/")[:-nbRetour]) + "/" + nameTileset + ".tsx" - tilesetJSON = "/".join(input.split("/")[:-nbRetour]) + "/" + nameTileset + ".json" - - commandline = 'tiled --export-tileset json ' + tilesetTSX + ' ' + tilesetJSON - if DEBUG: print( "TILED COMMAND LINE FOR TILESET : ", commandline ) - os.system( commandline ) - - tileset = open(tilesetJSON, "r") - data_tileset = json.load(tileset) - tileset_size = data_tileset.get("columns") - tileset.close() - - #find the ID of the first tile in the walkable tileset () - indexWalkable = data["tilesets"][1]["firstgid"] - if DEBUG: print(indexWalkable) - - #Extract from the json the width, height - w, h = data["width"], data["height"] - - #nbTileLayer is the number of "true" layers (without ObjectsLayer) - nbTilelayer = ["data" in i for i in data["layers"]].count(True) - 1 - if DEBUG: print( nbTilelayer) - - #index of the various layers (may change from one map to another) - layer_walkable = 0 - layer_foreground = 0 - layer_background = 0 - - #create the structure of the map - structMap = fxconv.Structure() - - structMap += fxconv.u32(w) + fxconv.u32(h) + fxconv.u32(nbTilelayer) - structMap += fxconv.u32(tileset_size) - - structMap += fxconv.u32(xmin) + fxconv.u32(ymin) + fxconv.u32(xmax) + fxconv.u32(ymax) - - structMap += fxconv.ref(f"img_{nameTilesetFree}") - - - #extraction of the data contained in the layer "Walkable" of the map - for i in range(nbTilelayer+1): - datavalid = data["layers"][i] - if datavalid["name"]=="Walkable": - layer_walkable = i - if DEBUG: print( "Walkable Tile Data in layer : ", layer_walkable) - break - elif i==nbTilelayer: - print( "ERROR : No Walkable layer data !!!" ) - - walk_data = bytes() - layer = data["layers"][layer_walkable] - for tile in layer["data"]: - #print( tile ) - if tile == 0: walk_data += fxconv.u8(tile) #if walkable_data = 0 then it is a blanck cell so nothing to change - else : walk_data += fxconv.u8(tile-indexWalkable) #if !=0 than we need to shift the tile number by considering the first tileID (given by indexwalkable) - structMap += fxconv.ptr(walk_data) - - - - - nbextra = 0 - extradata = fxconv.Structure() - - nbextra, extradata = get_extra_map_data(input, output, params, target, xmin, ymin, xmax, ymax) - - if (nbextra==0): - structMap += fxconv.u32( 0 ) - structMap += fxconv.u32( 0 ) - else: - structMap += fxconv.u32( int(nbextra) ) - structMap += fxconv.ptr( extradata ) - - - - - nameDialog = data["properties"][0]["value"] - dialogfile = "/".join(input.split("/")[:-nbRetour]) + "/" + nameDialog - if DEBUG: print( "THE DIALOGS ARE CONTAINED IN THE FILE : ", dialogfile ) - - nbdiag = 0 - diagdata = fxconv.Structure() - - nbdiag, diagdata = convert_dialogs(dialogfile, output, params, target) - - if (nbdiag==0): - structMap += fxconv.u32( 0 ) - structMap += fxconv.u32( 0 ) - else: - structMap += fxconv.u32( int(nbdiag) ) - structMap += fxconv.ptr( diagdata ) - - - - #extraction of the data contained in the layer "Background" and "Foreground" of the map - - - #import the Background layer of the map - for i in range(nbTilelayer+1): - datavalid = data["layers"][i] - if datavalid["name"]=="Background": - layer_background = i - if DEBUG: print( "Background Tile Data in layer : ", layer_background) - break - elif i==nbTilelayer: - print( "ERROR : No Background layer data !!!" ) - - layer_data = bytes() - layer = data["layers"][layer_background] - for tile in layer["data"]: - layer_data += fxconv.u16(tile-1) - structMap += fxconv.ptr(layer_data) - - - - #import the foreground layer of the map - for i in range(nbTilelayer+1): - datavalid = data["layers"][i] - if datavalid["name"]=="Foreground": - layer_foreground = i - if DEBUG: print( "Foreground Tile Data in layer : ", layer_foreground) - break - elif i==nbTilelayer: - print( "ERROR : No Foreground layer data !!!" ) - - layer_data = bytes() - layer = data["layers"][layer_foreground] - for tile in layer["data"]: - layer_data += fxconv.u16(tile-1) - structMap += fxconv.ptr(layer_data) - - - return structMap - - - -def get_extra_map_data(input, output, params, target, xmin, ymin, xmax, ymax): - if DEBUG: print( "WE ARE COMPUTING THE EXTRA DATA OF THE MAP : ", input ) - data = json.load(open(input, "r")) - - nblayer = ["id" in i for i in data["layers"]].count(True) - 1 - if DEBUG: print( "I found ", nblayer, " of extradata") - - #index of the various layers (may change from one map to another) - layer_extradata = 0 - - #import the foreground layer of the map - for i in range(nblayer+1): - datavalid = data["layers"][i] - if datavalid["name"]=="ExtraData": - layer_extradata = i - if DEBUG: print( "Extra Data in layer : ", layer_extradata) - break - elif i==nblayer: - print( "ERROR : No ExtraData layer data !!!" ) - return 0, fxconv.u32(0) - - #create the structure of the map - structData = fxconv.Structure() - - nbSign = 0 - nbNPC = 0 - nbPortal = 0 - nbDiag = 0 - - npcs = fxconv.Structure() - signs = fxconv.Structure() - portals = fxconv.Structure() - - layer = data["layers"][layer_extradata] - for i in layer["objects"]: - - #get the type of the item - tpe = i["type"] - - #we check if the type corresponds to a items of type Point in Tiled - if tpe in ("NPC"): - currData = fxconv.Structure() - - x = i["x"] + xmin - y = i["y"] + ymin - nme = i["name"] - - - dialogID = None - needAction = None - path = 0 - path_length = 0 - xdata = None - ydata = None - face_type = "MALE" - - #we now fill all the properties of this item - for j in i["properties"]: - #property "dialog" - if j["name"]=="dialogID": - dialogID = j[ "value" ] - nbDiag += 1 - #property "isQuestion" - elif j["name"]=="needAction": needAction = j[ "value" ] - - else: - #Extra properties for NPCs (path and face) - if tpe=="NPC": - if j["name"]=="face": - face_type = j["value"] - elif j["name"]=="hasPath": - pathID = None - path = j[ "value" ] - if path==1: - if DEBUG: print( "PNJ has path - NOW LOOKING FOR RELEVANT DATA" ) - - # we start looking for path data with first the ID of the path Object - for u in i["properties"]: - if u["name"]=="path": - pathID = u[ "value" ] - if DEBUG: print( "path ID is identified : ID= ", pathID ) - - for v in layer["objects"]: - if v[ "id" ] == pathID: - if DEBUG: print( "path data found : " ) - - xdata = bytes() - ydata = bytes() - - for w in v[ "polyline" ]: - path_length = path_length + 1 - if DEBUG: print( "X= ", w[ "x" ], " Y= ", w[ "y" ] ) - xdata += fxconv.u16( int( w[ "x" ] ) ) - ydata += fxconv.u16( int( w[ "y" ] ) ) - - else: - if DEBUG: print( "PNJ has no Path" ) +def convert_map(input, output, params, target): + if VERBOSE: print(f"INFO: Converting map {input} -> {output}") + input_map = Map(input) + dialog_file = "" + background_layer = [] + foreground_layer = [] + walkable_layer = [] + width = 0 + height = 0 + outdoor_tileset = None + walkable_tileset = None + + npc_paths = {} + npcs = {} + signs = {} + + # Get the dialog file + try: + if VERBOSE: print("INFO: Getting the dialog file") + dialog_file = input_map.get_property("dialogFile") + if VERBOSE: print(f"INFO: Dialog file: {dialog_file}.") + except Exception as e: + sys.stderr.write(f"ERROR: Failed to get the dialog file.\n" + + f" Error message: {e}\n") + sys.exit(1) + + # Get the outdoor tileset + try: + if VERBOSE: print("INFO: Getting the outdoor tileset") + outdoor_tileset = input_map.get_tileset_by_firstgid(1) + except Exception as e: + sys.stderr.write(f"ERROR: Failed to get the outdoor tileset.\n" + + f" Error message: {e}\n") + sys.exit(1) + + # Get the walkable tileset + try: + if VERBOSE: print("INFO: Getting the walkable tileset") + walkable_tileset = input_map.get_tileset_by_firstgid(409) + except Exception as e: + sys.stderr.write(f"ERROR: Failed to get the walkable tileset.\n" + + f" Error message: {e}\n") + sys.exit(1) + + # Get the background + try: + if VERBOSE: print("INFO: Getting the background layer") + bg_layer = input_map.get_layer_by_name("Background") + # The bg layer will be used to set the map width and height. + width = bg_layer.get_width() + height = bg_layer.get_height() + if VERBOSE: print(f"INFO: Map size: ({width}, {height}).") + # Get the layer data himself + background_layer = bg_layer.get_data_with_tileset(outdoor_tileset) + # Check if the size of the layer data is correct. + if len(background_layer) != width*height: + raise Exception("Bad layer size!") + if VERBOSE: print("INFO: Layer data has the right size.") + except Exception as e: + sys.stderr.write(f"ERROR: Failed to get the background layer.\n" + + f" Error message: {e}\n") + sys.exit(1) + + # Get the foreground + try: + if VERBOSE: print("INFO: Getting the foreground layer") + fg_layer = input_map.get_layer_by_name("Foreground") + # Get the layer data himself + foreground_layer = fg_layer.get_data_with_tileset(outdoor_tileset) + # Check if the size of the layer data is correct. + if len(foreground_layer) != width*height: + raise Exception("Bad layer size!") + if VERBOSE: print("INFO: Layer data has the right size.") + except Exception as e: + sys.stderr.write(f"ERROR: Failed to get the foreground layer.\n" + + f" Error message: {e}\n") + sys.exit(1) + + # Get the walkable layer + try: + if VERBOSE: print("INFO: Getting the walkable layer") + wk_layer = input_map.get_layer_by_name("Walkable") + # Get the layer data himself + walkable_layer = wk_layer.get_data_with_tileset(walkable_tileset) + # Check if the size of the layer data is correct. + if len(walkable_layer) != width*height: + raise Exception("Bad layer size!") + if VERBOSE: print("INFO: Layer data has the right size.") + except Exception as e: + sys.stderr.write(f"ERROR: Failed to get the walkable layer.\n" + + f" Error message: {e}\n") + sys.exit(1) + + # Get the extra data + try: + if VERBOSE: print("INFO: Getting the extra data") + ed_objgroup = input_map.get_objectgroup_by_name("ExtraData") + # Get the paths the NPCs take. + for object in ed_objgroup.objects: + if object.get_data_type() == "polyline": + npc_paths[object.id] = object.get_data() + # Get the NPCs + for object in ed_objgroup.objects: + if object.get_data_type() == "point" and object.type == "NPC": + path = None + if int(object.get_property("hasPath")): + if object.get_property("path") in npc_paths: + path = npc_paths[object.get_property("path")] else: - print( "UNIDENTIFIED PROPERTY : ", j["name"]) + raise Exception("Path required but not found!") + data = { + "position": object.get_data(), + "needAction": object.get_property("needAction"), + "dialogID": object.get_property("dialogID"), + #"face": object.get_property("face"), + "path": path + } + npcs[object.id] = data + # Get the signs + for object in ed_objgroup.objects: + if object.get_data_type() == "point" and object.type in SIGN_TYPES: + data = { + "needAction": object.get_property("needAction"), + "dialogID": object.get_property("dialogID") + } + signs[object.id] = data + except Exception as e: + sys.stderr.write(f"ERROR: Failed to get the extra data.\n" + + f" Error message: {e}\n") + sys.exit(1) + # Generate the structs + # - if DEBUG: - print( "OBJECT X= ", x, " Y= ", y, "STR= ", dialogID ) - print( " Type= ", tpe, " Name= ", nme, "Face =", face_type) - print( " Action?= ", needAction ) - - - currData += fxconv.u32(0) - currData += fxconv.u32(0) - currData += fxconv.u32( int(x) ) - currData += fxconv.u32( int(y) ) - - currData += fxconv.u16(0) #TODO : faceid - - currData += fxconv.u8(0) - - currData += fxconv.u8(1) - currData += fxconv.u32( int(dialogID) ) - currData += fxconv.u32( int(needAction) ) - - currData += fxconv.string( nme ) - - if path==0: - currData += fxconv.u32(0) - currData += fxconv.u32(0) - currData += fxconv.u32(0) - currData += fxconv.u32(0) - currData += fxconv.u32(0) - else: - o_xdata = fxconv.Structure() - o_xdata += xdata - o_ydata = fxconv.Structure() - o_ydata += ydata - - currData += fxconv.u32(path) - currData += fxconv.u32(path_length) - currData += fxconv.u32(0) - currData += fxconv.ptr(o_xdata) - currData += fxconv.ptr(o_ydata) - - #TODO - currData += fxconv.i32(0) - currData += fxconv.u8(0) - currData += fxconv.u8(0) - - currData += fxconv.u16(0) - - nbNPC += 1 - signs += currData - - elif tpe in ["SGN", "INFO"]: - currData = fxconv.Structure() - - x = i["x"] + xmin - y = i["y"] + ymin - nme = i["name"] - if tpe == "SIGN": - icon = 0 - else: - icon = 1 - - dialogID = None - needAction = None - - #we now fill all the properties of this item - for j in i["properties"]: - #property "dialog" - if j["name"]=="dialogID": - dialogID = j[ "value" ] - nbDiag += 1 - #property "isQuestion" - elif j["name"]=="needAction": needAction = j[ "value" ] - else: - print( "UNIDENTIFIED PROPERTY : ", j["name"]) - - currData += fxconv.u32( int(x) ) - currData += fxconv.u32( int(y) ) - currData += fxconv.u32(icon) - currData += fxconv.string( nme ) - currData += fxconv.u32( int(dialogID) ) - currData += fxconv.u32( int(needAction) ) - - nbSign += 1 - signs += currData - - elif tpe == "PORTAL": - nbPortal+=1 - currData = fxconv.Structure() - - x = i["x"] + xmin - y = i["y"] + ymin - h = -1 - w = -1 - tp_interior = -1 - tp_to = -1 - - for j in i["properties"]: - if j["name"] == "h": - h = j["value"] - if j["name"] == "w": - w = j["value"] - if j["name"] == "tp_interior": - tp_interior = j["value"] - if j["name"] == "tp_to": - tp_to = j["value"] - - if w==-1 or h==-1 or tp_interior==-1 or tp_to==-1: - print("ERROR : Invalid portal " + i["ID"]) - continue - - currData += fxconv.u32(int(x)) - currData += fxconv.u32(int(y)) - currData += fxconv.u32(int(w)) - currData += fxconv.u32(int(h)) - currData += fxconv.u16(int(tp_interior)) - currData += fxconv.u16(int(tp_to)) - - portals += currData - - #else we do nothing - else: - print( 'Unknown object type "'+tpe+'" !' ) - - structData += fxconv.u32(nbNPC) - if nbNPC: - structData += fxconv.ptr(npcs) - else: - structData += fxconv.u32(0) - - structData += fxconv.u32(nbSign) - if nbSign: - structData += fxconv.ptr(signs) - else: - structData += fxconv.u32(0) - - structData += fxconv.u32(nbPortal) - if nbPortal: - structData += fxconv.ptr(portals) - else: - structData += fxconv.u32(0) - - return nbDiag, structData - - -def convert_custom_image(input, output, params, target): - scale = int(params.get("scale", 1)) - - # Upscale image before converting - im = Image.open(input) - im = im.resize((im.width * scale, im.height * scale), - resample=Image.NEAREST) - - o = fxconv.convert_image_cg(im, params) - fxconv.elf(o, output, "_" + params["name"], **target) - - - -def convert_font(input, output, params, target): - o = fxconv.convert_topti(input, params) - fxconv.elf(o, output, "_" + params["name"], **target) - - - -def convert_dialogs(input, output, params, target): - - if DEBUG: print( "WE ARE COMPUTING THE DIALOGS FROM : ", input ) - data = json.load(open(input, "r")) - - structDialogs = fxconv.Structure() - nbdialogs = 0 - - for d in data["dialogs"]: - if DEBUG: print( int(d[ "ID" ])) - # print( d[ "dialog" ] ) - if DEBUG: print( int(d[ "isQuestion" ]) ) - # print( d[ "choice" ].replace('$', chr(0)) ) - # print( d[ "conclusion1" ] ) - # print( int(d[ "next1" ] ) ) - # print( d[ "conclusion2" ] ) - # print( int(d[ "next2" ] ) ) - # print( int(d[ "nextOther" ]) ) - nbdialogs = nbdialogs + 1 - - structDialogs += fxconv.u32( int(d[ "ID" ] ) ) - structDialogs += fxconv.string( d[ "dialog" ] ) - structDialogs += fxconv.u32( int(d[ "isQuestion" ] ) ) - structDialogs += fxconv.string( d[ "choice" ].replace('$', chr(0)) ) - structDialogs += fxconv.string( d[ "conclusion1" ] ) - structDialogs += fxconv.u32( int(d[ "next1" ] ) ) - structDialogs += fxconv.string( d[ "conclusion2" ] ) - structDialogs += fxconv.u32( int(d[ "next2" ] ) ) - structDialogs += fxconv.u32( int(d[ "nextOther" ] ) ) - - return nbdialogs, structDialogs - - #fxconv.elf(structDialogs, output, "_" + params["name"], **target) +def convert_dialog(input, output, params, target): + if VERBOSE: print(f"INFO: Converting dialog file {input} -> {output}") diff --git a/assets/fxconv-metadata.txt b/assets/fxconv-metadata.txt index 822cad1..07f2018 100644 --- a/assets/fxconv-metadata.txt +++ b/assets/fxconv-metadata.txt @@ -1,7 +1,19 @@ -WorldRPG.world: - custom-type: world - name: worldRPG +level0.tmx: + custom-type: tmx + name: level0 -#DialogsRPG.json: -# custom-type: dialogs -# name: dialogRPG +level1.tmx: + custom-type: tmx + name: level1 + +level2.tmx: + custom-type: tmx + name: level2 + +level3.tmx: + custom-type: tmx + name: level3 + +level4.tmx: + custom-type: tmx + name: level4 diff --git a/assets/tiled.py b/assets/tiled.py new file mode 100644 index 0000000..e69de29