Collab_RPG/assets/converters.py

242 lines
9.1 KiB
Python

import xml.etree.ElementTree as ET
import json
import os
import sys
sys.path.append("../assets/")
import fxconv
from tiled import *
VERBOSE = 1
SIGN_TYPES = ["INFO", "SGN"]
def convert(input, output, params, target):
if params["custom-type"] == "tmx":
convert_map(input, output, params, target)
return 0
elif params["custom-type"] == "dialog":
convert_dialog(input, output, params, target)
return 0
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 = []
map_x = 0
map_y = 0
width = 0
height = 0
outdoor_tileset = None
walkable_tileset = None
dialog_num = 0
dialog_ids = []
npc_paths = {}
npcs = {}
signs = {}
map_struct = fxconv.Structure()
# 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 informations about dialogs
try:
if VERBOSE: print("INFO: Getting informations about dialogs")
with open(f"{input_map.parent_dir}/{dialog_file}", "r") as file:
dialog_data = json.load(file)
dialog_num = len(dialog_data["dialogs"])
for i in dialog_data["dialogs"]:
dialog_ids.append(i["ID"])
except Exception as e:
sys.stderr.write(f"ERROR: Failed to get informations about dialogs.\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:
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
# Map struct
map_struct += fxconv.u32(map_x)
map_struct += fxconv.u32(map_y)
map_struct += fxconv.u32(width)
map_struct += fxconv.u32(height)
map_struct += fxconv.u32(3)
map_struct += fxconv.u32(outdoor_tileset.columns)
tileset_name = os.path.splitext(os.path.basename(outdoor_tileset.source))[0]
map_struct += fxconv.ref(f"img_{tileset_name}")
walkable_data = bytes()
for i in walkable_layer:
if i < 0: i = 0
walkable_data += fxconv.u8(i)
map_struct += fxconv.ptr(walkable_data)
# Load NPCs
map_struct += fxconv.u32(0) # TODO: NPC support in-game
map_struct += fxconv.ptr(bytes())
# Load signs
map_struct += fxconv.u32(0) # TODO: Sign support in-game
map_struct += fxconv.ptr(bytes())
map_struct += fxconv.u32(0) # TODO: Portal support in-game
map_struct += fxconv.ptr(bytes())
map_struct += fxconv.u32(dialog_num)
dialog_name = os.path.splitext(os.path.basename(dialog_file))[0]
map_struct += fxconv.ref(f"_{dialog_name}")
background_data = bytes()
for i in background_layer:
background_data += fxconv.u16(i)
map_struct += fxconv.ptr(background_data)
foreground_data = bytes()
for i in foreground_layer:
foreground_data += fxconv.u16(i)
map_struct += fxconv.ptr(foreground_data)
# Create the fxconv object
name = os.path.splitext(os.path.basename(input))[0]
fxconv.elf(map_struct, output, f"_{name}", **target)
def convert_dialog(input, output, params, target):
if VERBOSE: print(f"INFO: Converting dialog file {input} -> {output}")
dialog_data = None
try:
with open(input, "r") as file:
dialog_data = json.load(file)
except Exception as e:
sys.stderr.write(f"ERROR: Failed parse json.\n"
+ f" Error message: {e}\n")
sys.exit(1)
dialog_struct = fxconv.Structure()
try:
for i in dialog_data["dialogs"]:
dialog_id = i["ID"]
dialog_struct += fxconv.u32(dialog_id)
dialog_struct += fxconv.string(i["dialog"])
dialog_struct += fxconv.u32(i["isQuestion"])
dialog_struct += fxconv.string(i["choice"])
dialog_struct += fxconv.string(i["conclusion1"])
dialog_struct += fxconv.u32(i["next1"])
dialog_struct += fxconv.string(i["conclusion2"])
dialog_struct += fxconv.u32(i["next2"])
dialog_struct += fxconv.u32(i["nextOther"])
# Save this struct
name = os.path.splitext(os.path.basename(input))[0]
fxconv.elf(dialog_struct, output, f"__{name}", **target)
except Exception as e:
sys.stderr.write(f"ERROR: Failed convert dialogs.\n"
+ f" Error message: {e}\n")
sys.exit(1)