mirror of
https://git.planet-casio.com/Slyvtt/Collab_RPG.git
synced 2024-12-28 04:23:42 +01:00
Started writing a new converter
This commit is contained in:
parent
a06977469c
commit
bc8382ac65
4 changed files with 385 additions and 519 deletions
|
@ -32,7 +32,8 @@ set(SOURCES
|
||||||
)
|
)
|
||||||
# Shared assets, fx-9860G-only assets and fx-CG-50-only assets
|
# Shared assets, fx-9860G-only assets and fx-CG-50-only assets
|
||||||
set(ASSETS
|
set(ASSETS
|
||||||
assets/WorldRPG.world
|
#assets/WorldRPG.world
|
||||||
|
assets/level0.tmx
|
||||||
# ...
|
# ...
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,522 +1,375 @@
|
||||||
from random import randint
|
import xml.etree.ElementTree as ET
|
||||||
from PIL import Image
|
|
||||||
import fxconv
|
|
||||||
import json
|
import json
|
||||||
import pathlib
|
|
||||||
import csv
|
|
||||||
import os
|
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):
|
def convert(input, output, params, target):
|
||||||
if params["custom-type"] == "map":
|
if params["custom-type"] == "tmx":
|
||||||
print("ERROR : Asset ", params["name"], " has legacy type map")
|
convert_map(input, output, params, target)
|
||||||
return 1
|
|
||||||
elif params["custom-type"] == "world":
|
|
||||||
convert_world(input, output, params, target)
|
|
||||||
return 0
|
return 0
|
||||||
elif params["custom-type"] == "custom-image":
|
elif params["custom-type"] == "json":
|
||||||
convert_custom_image(input, output, params, target)
|
convert_dialog(input, output, params, target)
|
||||||
return 0
|
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):
|
def convert_map(input, output, params, target):
|
||||||
print( "WE ARE COMPUTING THE WORLD", input )
|
if VERBOSE: print(f"INFO: Converting map {input} -> {output}")
|
||||||
|
input_map = Map(input)
|
||||||
data = json.load(open(input, "r"))
|
dialog_file = ""
|
||||||
nbMaps = ["fileName" in i for i in data["maps"]].count(True)
|
background_layer = []
|
||||||
if DEBUG: print( "We have to treat ", nbMaps, " maps")
|
foreground_layer = []
|
||||||
if DEBUG: print( "So let's go ... ")
|
walkable_layer = []
|
||||||
|
width = 0
|
||||||
structWorld = fxconv.Structure()
|
height = 0
|
||||||
#structExtra = fxconv.Structure()
|
outdoor_tileset = None
|
||||||
|
walkable_tileset = None
|
||||||
for i in range(nbMaps):
|
|
||||||
nameMap = data["maps"][i]["fileName"].replace(".tmx","")
|
npc_paths = {}
|
||||||
nameMapFree = nameMap.split("/")[-1]
|
npcs = {}
|
||||||
#count the number of "back" (cd ..) to locate the map on the computer
|
signs = {}
|
||||||
nbRetour = nameMap.count("..")+1
|
|
||||||
#create the map absolute path
|
# Get the dialog file
|
||||||
|
try:
|
||||||
nameTMX = "/".join(input.split("/")[:-nbRetour]) + "/" + nameMap + ".tmx"
|
if VERBOSE: print("INFO: Getting the dialog file")
|
||||||
nameJSON = "/".join(input.split("/")[:-nbRetour]) + "/" + nameMap + ".json"
|
dialog_file = input_map.get_property("dialogFile")
|
||||||
|
if VERBOSE: print(f"INFO: Dialog file: {dialog_file}.")
|
||||||
commandline = 'tiled --export-map json ' + nameTMX + ' ' + nameJSON
|
except Exception as e:
|
||||||
if DEBUG: print( "TILED COMMAND LINE FOR MAPS : ", commandline )
|
sys.stderr.write(f"ERROR: Failed to get the dialog file.\n"
|
||||||
os.system( commandline )
|
+ f" Error message: {e}\n")
|
||||||
|
sys.exit(1)
|
||||||
mapPath = "/".join(input.split("/")[:-nbRetour]) + "/" + nameMap + ".json"
|
|
||||||
if DEBUG: print("Map ", i , " name : ", mapPath )
|
# Get the outdoor tileset
|
||||||
|
try:
|
||||||
xmin = data["maps"][i]["x"]
|
if VERBOSE: print("INFO: Getting the outdoor tileset")
|
||||||
if DEBUG: print( "xmin = ", xmin )
|
outdoor_tileset = input_map.get_tileset_by_firstgid(1)
|
||||||
|
except Exception as e:
|
||||||
ymin = data["maps"][i]["y"]
|
sys.stderr.write(f"ERROR: Failed to get the outdoor tileset.\n"
|
||||||
if DEBUG: print( "ymin = ", ymin )
|
+ f" Error message: {e}\n")
|
||||||
|
sys.exit(1)
|
||||||
xmax = data["maps"][i]["x"] + data["maps"][i]["width"]
|
|
||||||
if DEBUG: print( "xmax = ", xmax )
|
# Get the walkable tileset
|
||||||
|
try:
|
||||||
ymax = data["maps"][i]["y"] + data["maps"][i]["height"]
|
if VERBOSE: print("INFO: Getting the walkable tileset")
|
||||||
if DEBUG: print( "ymax = ", ymax )
|
walkable_tileset = input_map.get_tileset_by_firstgid(409)
|
||||||
|
except Exception as e:
|
||||||
map = get_tile_map_data( mapPath, output, params, target, xmin, ymin, xmax, ymax)
|
sys.stderr.write(f"ERROR: Failed to get the walkable tileset.\n"
|
||||||
if DEBUG: print( "Map = ", map )
|
+ f" Error message: {e}\n")
|
||||||
structWorld += fxconv.ptr( map )
|
sys.exit(1)
|
||||||
|
|
||||||
#structWorld += fxconv.u32(0)
|
# Get the background
|
||||||
|
try:
|
||||||
#generate !
|
if VERBOSE: print("INFO: Getting the background layer")
|
||||||
fxconv.elf(structWorld, output, "_" + params["name"], **target)
|
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()
|
||||||
def get_tile_map_data(input, output, params, target, xmin, ymin, xmax, ymax):
|
height = bg_layer.get_height()
|
||||||
print( "WE ARE COMPUTING THE MAP : ", input )
|
if VERBOSE: print(f"INFO: Map size: ({width}, {height}).")
|
||||||
data = json.load(open(input, "r"))
|
# Get the layer data himself
|
||||||
|
background_layer = bg_layer.get_data_with_tileset(outdoor_tileset)
|
||||||
#find the tileset in use. it's a relative path (like ../tileset.tsx)
|
# Check if the size of the layer data is correct.
|
||||||
nameTileset = data["tilesets"][0]["source"].replace(".tsx","")
|
if len(background_layer) != width*height:
|
||||||
if DEBUG: print(nameTileset)
|
raise Exception("Bad layer size!")
|
||||||
#the name of the tileset without the .something
|
if VERBOSE: print("INFO: Layer data has the right size.")
|
||||||
nameTilesetFree = nameTileset.split("/")[-1]
|
except Exception as e:
|
||||||
#count the number of "back" (cd ..) to locate the tileset on the computer
|
sys.stderr.write(f"ERROR: Failed to get the background layer.\n"
|
||||||
nbRetour = nameTileset.count("..")+1
|
+ f" Error message: {e}\n")
|
||||||
#create the tileset absolute path
|
sys.exit(1)
|
||||||
tilesetTSX = "/".join(input.split("/")[:-nbRetour]) + "/" + nameTileset + ".tsx"
|
|
||||||
tilesetJSON = "/".join(input.split("/")[:-nbRetour]) + "/" + nameTileset + ".json"
|
# Get the foreground
|
||||||
|
try:
|
||||||
commandline = 'tiled --export-tileset json ' + tilesetTSX + ' ' + tilesetJSON
|
if VERBOSE: print("INFO: Getting the foreground layer")
|
||||||
if DEBUG: print( "TILED COMMAND LINE FOR TILESET : ", commandline )
|
fg_layer = input_map.get_layer_by_name("Foreground")
|
||||||
os.system( commandline )
|
# Get the layer data himself
|
||||||
|
foreground_layer = fg_layer.get_data_with_tileset(outdoor_tileset)
|
||||||
tileset = open(tilesetJSON, "r")
|
# Check if the size of the layer data is correct.
|
||||||
data_tileset = json.load(tileset)
|
if len(foreground_layer) != width*height:
|
||||||
tileset_size = data_tileset.get("columns")
|
raise Exception("Bad layer size!")
|
||||||
tileset.close()
|
if VERBOSE: print("INFO: Layer data has the right size.")
|
||||||
|
except Exception as e:
|
||||||
#find the ID of the first tile in the walkable tileset ()
|
sys.stderr.write(f"ERROR: Failed to get the foreground layer.\n"
|
||||||
indexWalkable = data["tilesets"][1]["firstgid"]
|
+ f" Error message: {e}\n")
|
||||||
if DEBUG: print(indexWalkable)
|
sys.exit(1)
|
||||||
|
|
||||||
#Extract from the json the width, height
|
# Get the walkable layer
|
||||||
w, h = data["width"], data["height"]
|
try:
|
||||||
|
if VERBOSE: print("INFO: Getting the walkable layer")
|
||||||
#nbTileLayer is the number of "true" layers (without ObjectsLayer)
|
wk_layer = input_map.get_layer_by_name("Walkable")
|
||||||
nbTilelayer = ["data" in i for i in data["layers"]].count(True) - 1
|
# Get the layer data himself
|
||||||
if DEBUG: print( nbTilelayer)
|
walkable_layer = wk_layer.get_data_with_tileset(walkable_tileset)
|
||||||
|
# Check if the size of the layer data is correct.
|
||||||
#index of the various layers (may change from one map to another)
|
if len(walkable_layer) != width*height:
|
||||||
layer_walkable = 0
|
raise Exception("Bad layer size!")
|
||||||
layer_foreground = 0
|
if VERBOSE: print("INFO: Layer data has the right size.")
|
||||||
layer_background = 0
|
except Exception as e:
|
||||||
|
sys.stderr.write(f"ERROR: Failed to get the walkable layer.\n"
|
||||||
#create the structure of the map
|
+ f" Error message: {e}\n")
|
||||||
structMap = fxconv.Structure()
|
sys.exit(1)
|
||||||
|
|
||||||
structMap += fxconv.u32(w) + fxconv.u32(h) + fxconv.u32(nbTilelayer)
|
# Get the extra data
|
||||||
structMap += fxconv.u32(tileset_size)
|
try:
|
||||||
|
if VERBOSE: print("INFO: Getting the extra data")
|
||||||
structMap += fxconv.u32(xmin) + fxconv.u32(ymin) + fxconv.u32(xmax) + fxconv.u32(ymax)
|
ed_objgroup = input_map.get_objectgroup_by_name("ExtraData")
|
||||||
|
# Get the paths the NPCs take.
|
||||||
structMap += fxconv.ref(f"img_{nameTilesetFree}")
|
for object in ed_objgroup.objects:
|
||||||
|
if object.get_data_type() == "polyline":
|
||||||
|
npc_paths[object.id] = object.get_data()
|
||||||
#extraction of the data contained in the layer "Walkable" of the map
|
# Get the NPCs
|
||||||
for i in range(nbTilelayer+1):
|
for object in ed_objgroup.objects:
|
||||||
datavalid = data["layers"][i]
|
if object.get_data_type() == "point" and object.type == "NPC":
|
||||||
if datavalid["name"]=="Walkable":
|
path = None
|
||||||
layer_walkable = i
|
if int(object.get_property("hasPath")):
|
||||||
if DEBUG: print( "Walkable Tile Data in layer : ", layer_walkable)
|
if object.get_property("path") in npc_paths:
|
||||||
break
|
path = npc_paths[object.get_property("path")]
|
||||||
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" )
|
|
||||||
else:
|
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:
|
def convert_dialog(input, output, params, target):
|
||||||
print( "OBJECT X= ", x, " Y= ", y, "STR= ", dialogID )
|
if VERBOSE: print(f"INFO: Converting dialog file {input} -> {output}")
|
||||||
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)
|
|
||||||
|
|
|
@ -1,7 +1,19 @@
|
||||||
WorldRPG.world:
|
level0.tmx:
|
||||||
custom-type: world
|
custom-type: tmx
|
||||||
name: worldRPG
|
name: level0
|
||||||
|
|
||||||
#DialogsRPG.json:
|
level1.tmx:
|
||||||
# custom-type: dialogs
|
custom-type: tmx
|
||||||
# name: dialogRPG
|
name: level1
|
||||||
|
|
||||||
|
level2.tmx:
|
||||||
|
custom-type: tmx
|
||||||
|
name: level2
|
||||||
|
|
||||||
|
level3.tmx:
|
||||||
|
custom-type: tmx
|
||||||
|
name: level3
|
||||||
|
|
||||||
|
level4.tmx:
|
||||||
|
custom-type: tmx
|
||||||
|
name: level4
|
||||||
|
|
0
assets/tiled.py
Normal file
0
assets/tiled.py
Normal file
Loading…
Reference in a new issue