mirror of https://github.com/bgiraudr/Adoranda.git
410 lines
13 KiB
Python
410 lines
13 KiB
Python
from random import randint
|
|
import fxconv
|
|
import json
|
|
import pathlib
|
|
import csv
|
|
|
|
def convert(input, output, params, target):
|
|
if params["custom-type"] == "map":
|
|
convert_map(input, output, params, target)
|
|
return 0
|
|
elif params["custom-type"] == "capacities":
|
|
convert_capa(input, output, params, target)
|
|
return 0
|
|
elif params["custom-type"] == "monster":
|
|
convert_monster(input, output, params, target)
|
|
return 0
|
|
elif params["custom-type"] == "player_moves":
|
|
convert_player_moves(input, output, params, target)
|
|
return 0
|
|
elif params["custom-type"] == "items":
|
|
convert_items(input, output, params, target)
|
|
return 0
|
|
elif params["custom-type"] == "table_type":
|
|
convert_table_type(input, output, params, target)
|
|
return 0
|
|
else:
|
|
return 1
|
|
|
|
def convert_map(input, output, params, target):
|
|
TILE_BRIDGE = -1 #only for bridge detection to avoid solid behind
|
|
TILE_AIR = 0
|
|
TILE_SOLID = 1
|
|
TILE_DOOR_IN = 2
|
|
TILE_DOOR_OUT = 3
|
|
TILE_TALKABLE = 4
|
|
TILE_TELEPORTER = 5
|
|
TILE_GRASS = 6
|
|
TILE_ICE = 7
|
|
|
|
DIALOG_LAYOUT = "dialog"
|
|
TELEPORTER_LAYOUT = "teleporter"
|
|
ZONE_LAYOUT = "zone"
|
|
|
|
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","")
|
|
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
|
|
tilesetPath = "/".join(input.split("/")[:-nbRetour]) + "/" + nameTileset + ".json"
|
|
|
|
tileset = open(tilesetPath, "r")
|
|
data_tileset = json.load(tileset)
|
|
tileset_size = data_tileset.get("columns")
|
|
tileset.close()
|
|
|
|
tile_value = {}
|
|
tile_type = {
|
|
"air":TILE_AIR,
|
|
"solid":TILE_SOLID,
|
|
"door_in":TILE_DOOR_IN,
|
|
"door_out":TILE_DOOR_OUT,
|
|
"talkable":TILE_TALKABLE,
|
|
"bridge":TILE_BRIDGE,
|
|
"teleporter":TILE_TELEPORTER,
|
|
"grass":TILE_GRASS,
|
|
"ice":TILE_ICE
|
|
}
|
|
#create a dictionnary {tile id:type}
|
|
for i in data_tileset["tiles"]:
|
|
id = i["id"]+1
|
|
type = i["class"] if "class" in i else i["type"]
|
|
|
|
value = tile_type.get(type) if type in tile_type else TILE_AIR
|
|
tile_value[id] = value
|
|
|
|
#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)
|
|
objectLayers = data["layers"][nbTilelayer:len(data["layers"])]
|
|
|
|
nbDialog = 0
|
|
nbTelep = 0
|
|
nbZone = 0
|
|
structMap = fxconv.Structure()
|
|
dialogs = fxconv.Structure()
|
|
teleporter = fxconv.Structure()
|
|
zone = fxconv.Structure()
|
|
|
|
try:
|
|
idmap = data["properties"][0]["value"]
|
|
except KeyError:
|
|
raise Exception("La carte n'a pas d'identifiant")
|
|
|
|
for layer in objectLayers:
|
|
if layer.get("name") == DIALOG_LAYOUT:
|
|
nbDialog = len(layer["objects"])
|
|
dialogs = parseDialog(layer, idmap)
|
|
elif layer.get("name") == TELEPORTER_LAYOUT:
|
|
nbTelep = len(layer["objects"])
|
|
teleporter = parseTeleporter(layer)
|
|
elif layer.get("name") == ZONE_LAYOUT:
|
|
nbZone = len(layer["objects"])
|
|
zone = parseZone(layer, idmap)
|
|
else:
|
|
print("UNKNOWN LAYER FOUND : " + layer.get("name"))
|
|
|
|
structMap += fxconv.u32(w) + fxconv.u32(h) + fxconv.u32(nbTilelayer) + fxconv.u32(nbDialog) + fxconv.u32(nbTelep) + fxconv.u32(nbZone)
|
|
structMap += fxconv.ref(f"img_{nameTilesetFree}")
|
|
structMap += fxconv.u32(tileset_size)
|
|
structMap += fxconv.ptr(dialogs)
|
|
structMap += fxconv.ptr(teleporter)
|
|
structMap += fxconv.ptr(zone)
|
|
|
|
#generation of the collision map (take the maximum of the layer except for bridges)
|
|
#bridges are always walkable
|
|
info_map = bytes()
|
|
|
|
maxValue = 0
|
|
bridge = False
|
|
for x in range(w*h):
|
|
for i in range(nbTilelayer):
|
|
value = tile_value.get(data["layers"][i]["data"][x])
|
|
#attention : priorité aux valeurs hautes : un bloc d'herbe sera prioritaire sur un bloc solide
|
|
if value == None: value = TILE_AIR
|
|
if value > maxValue: maxValue = value
|
|
if value == TILE_BRIDGE:
|
|
maxValue = TILE_AIR
|
|
bridge = True
|
|
if bridge:
|
|
if value != TILE_AIR:
|
|
maxValue = value
|
|
info_map += fxconv.u16(maxValue)
|
|
maxValue = 0
|
|
bridge = False
|
|
structMap += fxconv.ptr(info_map)
|
|
|
|
#generate the array of tiles from the layer
|
|
for i in range(nbTilelayer):
|
|
layer_data = bytes()
|
|
layer = data["layers"][i]
|
|
for tile in layer["data"]:
|
|
layer_data += fxconv.u16(tile)
|
|
|
|
structMap += fxconv.ptr(layer_data)
|
|
|
|
#generate !
|
|
fxconv.elf(structMap, output, "_" + params["name"], **target)
|
|
|
|
def parseDialog(layer, idmap):
|
|
dialogs = fxconv.Structure()
|
|
idDialog = 0
|
|
|
|
base_dialog = [
|
|
"Encore toi ? Tu n'as pas quelque chose d'autre à faire ?",
|
|
"Mais... Tu vas me lacher oui ?",
|
|
"re-bonjour, comment vas-tu depuis la dernière fois ?",
|
|
"Tu reviens me voir après tout ce temps ?",
|
|
"Toujours un plaisir de te revoir.",
|
|
"La vie est pleine de surprise, je ne m'attendais pas à te revoir !",
|
|
"Salut ! Belle journée n'est-ce pas ?",
|
|
"Il faut savoir apprécier les bonnes choses de la vie.",
|
|
"La dernière fois je suis tombé sur une horde de monstre, quelle panique !",
|
|
"As-tu visité notre belle région depuis la dernière fois ?",
|
|
"Prend le temps, on n'a qu'une seule vie n'est-ce pas !",
|
|
"Pour être honnête, je ne t'apprécie pas beaucoup."
|
|
]
|
|
|
|
|
|
for i in layer["objects"]:
|
|
dialogs += fxconv.u32(int(i["x"]/i["width"]))
|
|
#Tiled seem to start at the bottom y of the object
|
|
dialogs += fxconv.u32(int(i["y"]/i["width"])-1)
|
|
|
|
try:
|
|
dialogs += fxconv.u32(int(f"{idmap}{idDialog}{idmap}"))
|
|
listProper = set((a['name']) for a in i["properties"])
|
|
idDialog += 1
|
|
stoText = ""
|
|
for j in i["properties"]:
|
|
if(j["name"] == "name"): dialogs += fxconv.string(j["value"])
|
|
if(j["name"] == "text"):
|
|
dialogs += fxconv.string(j["value"])
|
|
stoText = j["value"]
|
|
if(j["name"] == "text2"): dialogs += fxconv.string(j["value"])
|
|
if not "text2" in listProper:
|
|
if "~" in stoText: dialogs += fxconv.string(base_dialog[randint(0, len(base_dialog)-1)])
|
|
else: dialogs += fxconv.string("")
|
|
if("exclusive" in listProper):
|
|
for j in i["properties"]:
|
|
if(j["name"] == "exclusive"):
|
|
if j["value"]: dialogs += fxconv.u32(1)
|
|
else: dialogs += fxconv.u32(0)
|
|
else:
|
|
if "~" in stoText: dialogs += fxconv.u32(1)
|
|
else: dialogs += fxconv.u32(0)
|
|
except KeyError:
|
|
dialogs += fxconv.string("default name")
|
|
dialogs += fxconv.string("default text")
|
|
dialogs += fxconv.string("default text2")
|
|
dialogs += fxconv.u32(0)
|
|
|
|
return dialogs
|
|
|
|
def parseTeleporter(layer):
|
|
teleporter = fxconv.Structure()
|
|
for i in layer["objects"]:
|
|
teleporter += fxconv.u32(int(i["x"]/i["width"]))
|
|
#Tiled seem to start at the bottom y of the object
|
|
teleporter += fxconv.u32(int(i["y"]/i["width"])-1)
|
|
|
|
try:
|
|
if len(i["properties"]) < 2:
|
|
raise Exception("parseTeleporter() : Un téléporteur est mal configuré")
|
|
if len(i["properties"]) == 2:
|
|
print("parseTeleporter() : passage automatique idMap = -1 sur téléporteur x = " + str(i["properties"][0]["value"]) + ", y = " + str(i["properties"][1]["value"]))
|
|
teleporter += fxconv.u32(-1)
|
|
for j in i["properties"]:
|
|
teleporter += fxconv.u32(j["value"])
|
|
except KeyError :
|
|
raise Exception("parseTeleporter() : Un téléporteur est mal configuré")
|
|
return teleporter
|
|
|
|
def parseZone(layer, idmap):
|
|
zone = fxconv.Structure()
|
|
idZone = 0
|
|
for i in layer["objects"]:
|
|
origin = (int(i['x']/16), int(i['y']/16))
|
|
to = (int(origin[0]+i['width']/16)-1, int(origin[1]+i['height']/16)-1)
|
|
if len(i["properties"][0]["value"]) != 0:
|
|
zone += fxconv.u32(int(f"{idmap}{idZone}{idmap}")) #id zone is {mapid}{idzone}{mapid}
|
|
idZone+=1
|
|
else: zone += fxconv.u32(0)
|
|
zone += fxconv.u32(origin[0])
|
|
zone += fxconv.u32(origin[1])
|
|
zone += fxconv.u32(to[0])
|
|
zone += fxconv.u32(to[1])
|
|
|
|
|
|
event = bytes(i["properties"][0]["value"], "utf-8")
|
|
event += bytes(128 - len(event))
|
|
zone += event #event
|
|
|
|
monsters = bytes()
|
|
zone += fxconv.u32(int(i["properties"][1]["value"]) if i["properties"][1]["value"] != "" else -1) #level
|
|
monster_list_raw = []
|
|
if i["properties"][2]["value"] != "": monster_list_raw = i["properties"][2]["value"].split(";") #monster list
|
|
monster_list = []
|
|
#x-y notation generate an array
|
|
for i in monster_list_raw:
|
|
if "-" in i:
|
|
a = i.split("-")
|
|
monster_list.extend(list(range(int(a[0]),int(a[1])+1)))
|
|
else:
|
|
monster_list.append(int(i))
|
|
zone += fxconv.u32(len(monster_list))
|
|
|
|
for j in monster_list:
|
|
monsters += fxconv.u16(int(j))
|
|
|
|
zone += fxconv.ptr(monsters)
|
|
return zone
|
|
|
|
def convert_capa(input, output, params, target):
|
|
liste_file = list(pathlib.Path(input).parent.glob('*.json'))
|
|
|
|
capacities = fxconv.Structure()
|
|
capacities += fxconv.u32(len(liste_file))
|
|
for f in liste_file:
|
|
file = open(f,"r")
|
|
data = json.load(file)
|
|
move = fxconv.Structure()
|
|
|
|
try:
|
|
categorie = data["categorie"]
|
|
id_categorie = ["STATUT", "PHYSICAL", "SPECIAL"]
|
|
|
|
move += fxconv.string(data["name"])
|
|
move += fxconv.string(data["type"])
|
|
move += fxconv.u32(data["id"])
|
|
move += fxconv.u32(id_categorie.index(categorie))
|
|
move += fxconv.u32(data["pp"])
|
|
move += fxconv.u32(data["pp"])
|
|
|
|
if categorie=="PHYSICAL" or categorie=="SPECIAL":
|
|
move += fxconv.u32(data["atk"])
|
|
move += fxconv.u32(data["precision"])
|
|
move += fxconv.u32(0) + fxconv.u32(0) + fxconv.u32(0)
|
|
elif categorie=="STATUT":
|
|
move += fxconv.u32(0) + fxconv.u32(100)
|
|
move += fxconv.u32(data["boost_atk"])
|
|
move += fxconv.u32(data["boost_def"])
|
|
move += fxconv.u32(data["boost_hp"])
|
|
except KeyError:
|
|
raise Exception(f"convert_capa() : La capacité {data['name']} est mal configurée")
|
|
|
|
capacities += fxconv.ptr(move)
|
|
|
|
fxconv.elf(capacities, output, "_" + params["name"], **target)
|
|
|
|
def convert_monster(input, output, params, target):
|
|
liste_file = list(pathlib.Path(input).parent.glob('*.json'))
|
|
|
|
monsters = fxconv.Structure()
|
|
monsters += fxconv.u32(len(liste_file))
|
|
for f in liste_file:
|
|
file = open(f,"r")
|
|
data = json.load(file)
|
|
stats = fxconv.Structure()
|
|
|
|
if len(data["stats"]) != 6: raise Exception(f"convert_monster : Les statistiques de {data['name']} sont mauvaises")
|
|
stats+=fxconv.string(data["type"])
|
|
stats+=fxconv.u32(data["stats"]["atk"])
|
|
stats+=fxconv.u32(data["stats"]["def"])
|
|
stats+=fxconv.u32(data["stats"]["pv"])
|
|
stats+=fxconv.u32(data["stats"]["spe_atk"])
|
|
stats+=fxconv.u32(data["stats"]["spe_def"])
|
|
stats+=fxconv.u32(1) # level, will be calculated later
|
|
stats+=fxconv.u32(data["stats"]["xp"])
|
|
stats+=fxconv.u32(data["stats"]["pv"])
|
|
|
|
moves = bytes()
|
|
for i in data["moves"]:
|
|
moves+=fxconv.u16(i)
|
|
|
|
monster = fxconv.Structure()
|
|
monster += fxconv.string(data["name"])
|
|
monster += fxconv.ptr(f"img_{data['sprite']}")
|
|
monster += fxconv.u32(data["id"])
|
|
monster += fxconv.u32(len(data["moves"]))
|
|
monster += fxconv.ptr(stats)
|
|
monster += fxconv.ptr(moves)
|
|
|
|
monsters += fxconv.ptr(monster)
|
|
|
|
fxconv.elf(monsters, output, "_" + params["name"], **target)
|
|
|
|
def convert_player_moves(input, output, params, target):
|
|
levelupplayer = fxconv.Structure()
|
|
data = open(input, 'r').readlines()
|
|
levelupplayer += fxconv.u32(len(data))
|
|
for i in data:
|
|
levelup = fxconv.Structure()
|
|
levelup += fxconv.u32(int(i.split(":")[0]))
|
|
levelup += fxconv.u32(int(i.split(":")[1]))
|
|
|
|
levelupplayer += fxconv.ptr(levelup)
|
|
fxconv.elf(levelupplayer, output, "_" + params["name"], **target)
|
|
|
|
def convert_items(input, output, params, target):
|
|
liste_file = list(pathlib.Path(input).parent.glob('*.json'))
|
|
|
|
items = fxconv.Structure()
|
|
items += fxconv.u32(len(liste_file))
|
|
for f in liste_file:
|
|
file = open(f,"r")
|
|
data = json.load(file)
|
|
item = fxconv.Structure()
|
|
try:
|
|
item += fxconv.string(data["name"])
|
|
item += fxconv.u32(data["id"])
|
|
item += fxconv.string(data["description"])
|
|
item += fxconv.ptr(f"img_{data['sprite']}")
|
|
item += fxconv.string(";".join(data["action"]))
|
|
items += fxconv.ptr(item)
|
|
except KeyError:
|
|
raise Exception(f"convert_items() : L'item {data['name']} est mal configuré")
|
|
|
|
fxconv.elf(items, output, "_" + params["name"], **target)
|
|
|
|
def convert_table_type(input, output, params, target):
|
|
data = csv.DictReader(open(input,'r'))
|
|
|
|
table_type = fxconv.Structure()
|
|
for i in data:
|
|
type = fxconv.Structure()
|
|
type += fxconv.string(i["type"])
|
|
type += fxconv.u32(list(i).index(i["type"]))
|
|
taille = len(i)-1 #-1 because of the "color" column
|
|
b,l,n = [],[],[]
|
|
for j in i:
|
|
id = list(i).index(j)
|
|
if(i[j]=="2"): b.append(id)
|
|
if(i[j]=="0,5"): l.append(id)
|
|
if(i[j]=="0"): n.append(id)
|
|
if(j=="Couleur"): color=i[j]
|
|
for a in range(len(b),taille):b.append(0)
|
|
for a in range(len(l),taille):l.append(0)
|
|
for a in range(len(n),taille):n.append(0)
|
|
|
|
if(color == None):
|
|
raise Exception(f"Pas de couleur pour le type: {i['type']}")
|
|
if(len(color.strip()) != 5):
|
|
raise Exception(f"Mauvaise couleur pour le type {i['type']} : {color}")
|
|
|
|
color = int(color.strip()[1:], 16)
|
|
type += b"".join(fxconv.u32(value) for value in b)
|
|
type += b"".join(fxconv.u32(value) for value in l)
|
|
type += b"".join(fxconv.u32(value) for value in n)
|
|
type += fxconv.u16(color)
|
|
|
|
table_type += fxconv.ptr(type)
|
|
|
|
fxconv.elf(table_type, output, "_" + params["name"], **target) |