diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..0e66469 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "assets/tinytiled"] + path = assets/tinytiled + url = forgejo@git.planet-casio.com:mibi88/tinytiled.git diff --git a/assets/converters.py b/assets/converters.py index 5592787..5651872 100644 --- a/assets/converters.py +++ b/assets/converters.py @@ -1,17 +1,45 @@ +""" +This is the main converter script. It uses the tiled.py script to handle the +tiled maps. + +We're trying to follow the PEP, so please read PEP 8 (if you haven't already): +https://peps.python.org/pep-0008/, so please write variable names in sneak_case +and class names in PascalCase. + +To improve the lisibility of this code, please document your methods, add +comments (yes, it's hard to add the right amount of comments), and add type +hints, to avoid bugs and make it easy to understand how to use them. + +To document your methods, you should read PEP 257: +https://peps.python.org/pep-0257/. + +Thanks, +Mibi88 +""" + import xml.etree.ElementTree as ET import json import os import sys +# Add the assets folder to the path, to be able to import the tiled script. sys.path.append("../assets/") import fxconv -from tiled import * +from tinytiled import * +# If the output of the converter should be verbose. VERBOSE = 1 +# The sign types, used to find the sign icon. SIGN_TYPES = ["SGN", "INFO"] +# The NPC faces, used to find the face id. FACES = ["MALE", "FEMALE", "MILKMAN", "POLICE"] +# The precision of the fixed point numbers. +# WARNING: The PRECISION define in config.h should contain the same value! PRECISION = 8 -def convert(input, output, params, target): +def convert(input: str, output: str, params: dict, target): + """ + This method gets called by fxconv for each asset to convert. + """ if params["custom-type"] == "tmx": convert_map(input, output, params, target) return 0 diff --git a/assets/tiled.py b/assets/tiled.py deleted file mode 100644 index 03fe645..0000000 --- a/assets/tiled.py +++ /dev/null @@ -1,231 +0,0 @@ -import xml.etree.ElementTree as ET -import os - -# 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) - columns_str = self.root.get("columns") - if columns_str == None: raise Exception("columns not found!") - self.columns = int(columns_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: - self.type = "" - print("WARNING: 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!") diff --git a/assets/tinytiled b/assets/tinytiled new file mode 160000 index 0000000..c2c8f11 --- /dev/null +++ b/assets/tinytiled @@ -0,0 +1 @@ +Subproject commit c2c8f1121656e93ff8ca2e56ce3f966d6586aeb1