try:
import sys
sys.path.insert(0, r"C:\Users\admin\AppData\Local\Programs\Python\Python36\Lib\site-packages")
# os.environ["PYTHONPATH"] =
import ujson as json
print("Using UJSON")
except ImportError:
import json
print("Using JSON")
import os
from time import time
# from dprint import dprint
# FIXME: Running this script as a standalone breaks everything
[docs]def remove_digits(input_string: str) -> str:
remove_digits_translation_table = str.maketrans('', '', "0123456789")
output_string = input_string.translate(remove_digits_translation_table)
return output_string
[docs]def translate_jp_to_en_dict(input_dict, english_data, tag="id_tag", prefix="MSID_", old_prefix="SID_", is_skill=False):
# this was the result of like 4 days with no sleep, constantly coding, I have no idea how it works
if is_skill:
output = None
try:
if input_dict["refined"]:
output = str(translate_jp_to_en_dict(input_dict, english_data, tag="refine_base")) + "_" + (
input_dict["id_tag"].split("_")[-1])
else:
try:
output = translate_jp_to_en_dict(input_dict, english_data)
except KeyError:
# dprint("\n")
if input_dict["beast_effect_id"] is not None and input_dict["category"] == 8:
# output = translate_jp_to_en_dict(input_dict, english_data, prefix="MSID_H_")
return None
# dprint("Beast effect id:", input_dict["beast_effect_id"], "Category:", input_dict["category"])
# this means it's a duo effect or something similar (beast effect?), doesn't catch all duos
if input_dict["beast_effect_id"] is None and input_dict["category"] == 8:
# duo skills don't have names, but they do have descriptions
# skillsDict[skill].roman_name = english_data[skillsDict[skill].id_tag.replace("SID_", "MSID_")]
if input_dict["wep_equip"] == 0 and input_dict["skill_range"] == 0:
# print("Weird beast thing, not touching it")
return None
# dprint("Duo Effect:", english_data[input_dict["id_tag"].replace("SID_", "MSID_H_")])
# print(skillsDict[skill].id_tag.replace("SID_", "MSID_H_"))
return None
if input_dict["id_tag"] == "SID_無し":
return "blank"
# category 7 refers to refined weapon skill effects, these normally have an R in them
# these also do not have a translation because they are simply an additional effect that is
# added onto the base weapon
# you could find the base weapon by iterating through all skill dicts and checking if they have
# an entry in their "refine_id" key and creating a dict that links all "refine_id" values to
# the value/entry in their "id_tag" key (so dicts would take form key = refine_id value,
# value = id_tag value)
if input_dict["category"] != 7:
output = translate_jp_to_en_dict(input_dict, english_data, prefix="MSID_H_")
# dprint("\n Yo")
pass
return output
except KeyError as e:
print("Error:", e)
pass
else:
return english_data[input_dict[tag].replace(old_prefix, prefix)]
raise Exception("How did you get here")
[docs]def translate_jp_to_en_class(input_class, english_data, attribute="id_tag", prefix="MSID_", old_prefix="SID_",
is_skill=False):
# this was the result of like 4 days with no sleep, constantly coding, I have no idea how it works
if is_skill:
output = None
try:
if getattr(input_class, "refined"):
output = str(translate_jp_to_en_class(input_class, english_data, attribute="refine_base")) + "_" + (
getattr(input_class, "id_tag").split("_")[-1])
else:
try:
output = translate_jp_to_en_class(input_class, english_data)
except KeyError:
# dprint("\n")
if getattr(input_class, "beast_effect_id") is not None and getattr(input_class, "category") == 8:
# output = translate_jp_to_en_class(input_class, english_data, prefix="MSID_H_")
return None
# dprint("Beast effect id:", input_dict["beast_effect_id"], "Category:", input_dict["category"])
# this means it's a duo effect or something similar (beast effect?), doesn't catch all duos
if getattr(input_class, "beast_effect_id") is None and getattr(input_class, "category") == 8:
# duo skills don't have names, but they do have descriptions
# skillsDict[skill].roman_name = english_data[skillsDict[skill].id_tag.replace("SID_", "MSID_")]
if getattr(input_class, "wep_equip") == 0 and getattr(input_class, "skill_range") == 0:
# print("Weird beast thing, not touching it")
return None
# dprint("Duo Effect:", english_data[getattr(input_class, "id_tag").replace("SID_", "MSID_H_")])
# print(skillsDict[skill].id_tag.replace("SID_", "MSID_H_"))
return None
if getattr(input_class, "id_tag") == "SID_無し":
return "blank"
# category 7 refers to refined weapon skill effects, these normally have an R in them
# these also do not have a translation because they are simply an additional effect that is
# added onto the base weapon
# you could find the base weapon by iterating through all skill dicts and checking if they have
# an entry in their "refine_id" key and creating a dict that links all "refine_id" values to
# the value/entry in their "id_tag" key (so dicts would take form key = refine_id value,
# value = id_tag value)
if getattr(input_class, "category") != 7:
output = translate_jp_to_en_class(input_class, english_data, prefix="MSID_H_")
# dprint("\n")
pass
return output
except KeyError as e:
print("Error:", e)
pass
else:
return english_data[getattr(input_class, attribute).replace(old_prefix, prefix)]
raise Exception("How did you get here")
[docs]def my_merger(list_of_dicts):
my_dict = {}
for idict in list_of_dicts:
my_dict[idict["key"]] = idict["value"]
return my_dict
[docs]def load_files(skill_class, player_class, enemy_class, weapon_class, output_as_class=True, get_english_data=True,
get_skills=True, get_characters=True, get_weapons=True, get_growth=True, get_move=True,
get_stage_encount=True, get_terrain=True, check_for_update=False, get_simple_names=False):
# print("Starting")
start = time()
english_data = {}
if get_english_data:
os.chdir(r"C:\Users\admin\PycharmProjects\FireEmblemClone\HertzDevil_JSON_assets\USEN\Message\Data")
total = int()
for file in os.listdir():
# dprint("Processing:", file)
with open(file, "r", encoding="utf-8") as english_json_data:
english_data[file.replace(".json", "")] = json.load(english_json_data)
# dprint(len(english_data[file.replace(".json", "")]))
total += len(english_data[file.replace(".json", "")])
# dprint("Total:", total)
my_list = []
for english_data_entry in english_data:
my_list.extend(english_data[english_data_entry])
english_data = my_merger(my_list)
def my_merger2(list_of_dicts, output_class):
my_dict = {}
my_dict2 = {}
to_return = [my_dict, my_dict2]
if get_simple_names:
name_set = set()
to_return.append(name_set)
weapon_index_dict = {k: v for k, v in zip([i for i in range(24)], [
"Sword", "Lance", "Axe", "Red bow", "Blue bow", "Green bow", "Colorless bow", "Red Dagger", "Blue Dagger",
"Green Dagger", "Colorless Dagger", "Red Tome", "Blue Tome", "Green Tome", "Colorless Tome", "Staff",
"Red Breath",
"Blue Breath", "Green Breath", "Colorless Breath", "Red Beast", "Blue Beast", "Green Beast",
"Colorless Beast"
])}
# CHECK: Keep as "Flier" or change to "Flying"?
move_index_dict = {0: "Infantry", 1: "Armored", 2: "Cavalry", 3: "Flier"}
for idict in list_of_dicts:
if idict["id_tag"] == "PID_無し" or idict["id_tag"] == "EID_無し":
# maybe insert something that just uses these as blanks?
continue
if output_class == player_class:
simple_name = translate_jp_to_en_dict(idict, english_data, prefix="MPID", old_prefix="PID")
if get_simple_names:
name_set.add(simple_name)
simple_name = simple_name.replace(" ", "_")
unit_identifiers = remove_digits(str(idict["roman"])).split("_")[1:]
# suffix that identifies unit as male version (mainly used for protagonists)
if "M" in unit_identifiers:
suffix = "_M"
# suffix that identifies unit as female version (mainly used for protagonists)
elif "F" in unit_identifiers:
suffix = "_F"
# elif "A" in unit_identifiers:
# suffix = "_A"
else:
suffix = ""
prefix_dict = {
"A": "Adult_", # prefix that identifies hero as an adult alt
"POPULARITY": "Brave_", # prefix that identifies hero as a brave alt
"DANCE": "Dancer_", # prefix that identifies hero as a dancer alt
"PAIR": "Duo_", # prefix that identifies hero as a duo unit
"LEGEND": "Legendary_", # prefix that identifies hero as a legendary hero
"GOD": "Mythic_", # prefix that identifies hero as a mythic hero
"BRIDE": "Bridal_", # prefix that identifies hero as a bridal alt
"DARK": "Fallen_", # prefix that identifies hero as a fallen alt
"HALLOWEEN": "Halloween_", # prefix that identifies hero as a halloween alt
"SUMMER": "Summer_", # prefix that identifies hero as a summer alt
"PICNIC": "Picnic_", # prefix that identifies hero as a picnic alt
"SPRING": "Spring_", # prefix that identifies hero as a spring alt
"VALENTINE": "Valentine_", # prefix that identifies hero as a valentine alt
"WINTER": "Winter_", # prefix that identifies hero as a winter alt
"ONSEN": "HotSprings_", # prefix that identifies hero as a Hot Springs alt
"DREAM": "Adrift_", # prefix that identifies hero as an adrift alt
"MIKATA": "Ally_", # prefix that identifies hero as a playable alt of a NPC
"BON": "HoshidanSummer_", # prefix that identifies hero as a Hoshidan Summer alt
"NEWYEAR": "NewYears_", # prefix that identifies hero as a New Years alt
"KAKUSEI": "Awakening_", # prefix that identifies hero as an Awakening alt (only Anna so far)
"ECHOES": "Echoes_", # prefix that identifies hero as an Echoes alt (only Catria so far)
"BEFORE": "Young_", # prefix that identifies hero as a young alt
}
prefix = ""
for identifier in prefix_dict:
if identifier in unit_identifiers:
prefix += prefix_dict[identifier]
translated_name = ("PID_" + prefix + simple_name + suffix).strip()
if translated_name not in my_dict:
if output_as_class:
my_dict[translated_name] = output_class.from_dict(input_dict=idict)
else:
my_dict[translated_name] = idict
else:
# If weapon-type and move-type doesn't make these units unique then I give up
# if output_as_class:
# # creates new entry that includes id_num in key for old entry
# my_dict["PID_" + str(my_dict[translated_name].id_num).replace(" ", "")
# + "_" + str(translated_name).replace("PID_", "")] = my_dict[translated_name]
#
# # creates new entry that includes id_num in key for duplicate entry
# my_dict["PID_" + str(idict["id_num"]).replace(" ", "") + "_" +
# str(translated_name).replace("PID_", "")] = output_class.from_dict(input_dict=idict)
# else:
# # creates new entry that includes id_num in key for old entry
# my_dict["PID_" + str(my_dict[translated_name]["id_num"])
# .replace(" ", "") + "_" + str(translated_name).replace("PID_", "")] \
# = my_dict[translated_name]
#
# # creates new entry that includes id_num in key for duplicate entry
# my_dict["PID_" + str(idict["id_num"]).replace(" ", "") + "_" +
# str(translated_name).replace("PID_", "")] = idict
def get_gender(dictionary: dict):
gender = [i for i in str(dictionary["face_name"]).split("_") if i.upper() in ["M", "F"]]
# print(gender)
if len(gender) == 0:
return ""
elif len(gender) == 1:
return gender[0].strip()
else:
raise ValueError(
"Face_name of unit {0} contains more than one gender".format(idict["id_num"]))
if output_as_class:
# creates new entry name that includes id_num in key for old entry
old_entry = str(
"PID_" +
str(weapon_index_dict[my_dict[translated_name].weapon_type]).replace(" ", "_") +
"_" +
str(move_index_dict[my_dict[translated_name].move_type]) +
"_" +
str(translated_name).replace("PID_", ""))
# creates new entry name that includes id_num in key for duplicate entry
duplicate_entry = str(
"PID_" +
str(weapon_index_dict[idict["weapon_type"]]).replace(" ", "_") +
"_" +
str(move_index_dict[idict["move_type"]]) +
"_" +
str(translated_name).replace("PID_", ""))
if old_entry == duplicate_entry:
old_entry += "_" + get_gender(my_dict[translated_name])
duplicate_entry += "_" + get_gender(idict)
my_dict[old_entry] = my_dict[translated_name]
my_dict[duplicate_entry] = output_class.from_dict(input_dict=idict)
else:
# creates new entry name that includes id_num in key for old entry
old_entry = str(
"PID_" +
str(weapon_index_dict[my_dict[translated_name]["weapon_type"]]).replace(" ", "_") +
"_" +
str(move_index_dict[my_dict[translated_name]["move_type"]]) +
"_" +
str(translated_name).replace("PID_", ""))
# creates new entry name that includes id_num in key for duplicate entry
duplicate_entry = str("PID_" +
str(weapon_index_dict[idict["weapon_type"]]).replace(" ", "_") +
"_" +
str(move_index_dict[idict["move_type"]]) +
"_" +
str(translated_name).replace("PID_", ""))
if old_entry == duplicate_entry:
old_entry += "_" + get_gender(my_dict[translated_name])
duplicate_entry += "_" + get_gender(idict)
my_dict[old_entry] = my_dict[translated_name]
my_dict[duplicate_entry] = idict
# deletes old entry without id_num in name
del my_dict[translated_name]
if output_class == enemy_class:
translated_name = translate_jp_to_en_dict(idict, english_data, prefix="MEID", old_prefix="EID")
if output_as_class:
my_dict[translated_name] = output_class.from_dict(input_dict=idict)
else:
my_dict[translated_name] = idict
if output_class == skill_class:
translate_output = translate_jp_to_en_dict(idict, english_data=english_data, is_skill=True)
if translate_output is not None:
if output_as_class:
my_dict[translate_output] = output_class.from_dict(input_dict=idict)
else:
my_dict[translate_output] = idict
if output_as_class:
my_dict2[idict["id_tag"]] = output_class.from_dict(input_dict=idict)
else:
my_dict2[idict["id_tag"]] = idict
# dprint("\n")
return to_return
def process_data(data_loc, output, output_class):
total_entries = int()
if output_class is not None:
output_name = str(output_class.__name__)
else:
output_name = "\b"
pass
single_file = False
try:
for file in os.listdir(data_loc):
# dprint("Processing:", file)
with open(data_loc + "/" + file, "r", encoding="utf-8") as json_data:
# FIXME: change to output.update()
# But why though? What do you know that I don't, past me?
output[file.replace(".json", "")] = json.load(json_data)
# dprint(len(output[file.replace(".json", "")]), output_name, "entries found")
total_entries += len(output[file.replace(".json", "")])
except NotADirectoryError:
single_file = True
# dprint("Processing:", data_loc)
with open(data_loc, "r", encoding="utf-8") as json_data:
output = json.load(json_data)
# dprint(len(output), output_name, "entries found")
total_entries += len(output)
# if output_class:
# dprint("Total:", total_entries, "entries for", output_name)
# else:
# dprint("Total:", total_entries, "entries")
# dprint("\n")
if output_class:
if not single_file:
# dictionary to list of dictionary's values
dict_values_list = []
for key in output:
dict_values_list.extend(output[key])
else:
dict_values_list = output
output = my_merger2(dict_values_list, output_class)
return output
os.chdir(r"C:\Users\admin\PycharmProjects\FireEmblemClone\HertzDevil_JSON_assets\Common\SRPG")
# dprint(os.listdir())
# dictionary of json files converted to dicts
# keys are json file names strings, values are lists of dictionaries which contain FEH skills
skills = {}
players = {}
enemies = {}
weapons = {}
growth = {}
move = {}
stage_encount = {}
terrain = {}
# maybe do something like:
# for k, v in [_ for _ in locals().items()]:
# if k:
# var = process_data(parse k for string here, list here, and class here
if get_skills:
skills = process_data("Skill", skills, skill_class)
if get_characters:
players = process_data("Person", players, player_class)
# ===========================================
enemies = process_data("Enemy", enemies, enemy_class)
if get_weapons:
weapons = process_data("Weapon.json", weapons, weapon_class)
if get_growth:
growth = process_data("Grow.json", growth, None)
if get_move:
move = process_data("Move.json", move, None)
if get_stage_encount:
stage_encount = process_data("StageEncount.json", stage_encount, None)
if get_terrain:
terrain = process_data("Terrain.json", terrain, None)
if check_for_update:
print("Checking player data")
for xitem in players[1]:
item_in_english = False
for yitem in players[0]:
if players[0][yitem]["id_tag"] == xitem:
item_in_english = True
if not item_in_english:
print(xitem)
print("\nChecking enemy data")
for xitem in enemies[1]:
item_in_english = False
for yitem in enemies[0]:
if enemies[0][yitem]["id_tag"] == xitem:
item_in_english = True
if not item_in_english:
print(xitem)
print("{0}/{1} player entries translated".format(len(players[0]), len(players[1])))
print("{0}/{1} enemy entries translated".format(len(enemies[0]), len(enemies[1])))
stop = time()
print("Time elapsed during file loading:", stop - start, "secs")
return skills, players, enemies, weapons, english_data, growth, move, stage_encount, terrain
if __name__ == "__main__":
from Code.FireEmblemCombatV2 import Skill, Weapon, Enemy, Player
skills_output, players_output, enemies_output, weapons_output, english_data_output, growth_output, \
move_output, stage_encount_output, terrain_output = load_files(Skill, Player, Enemy, Weapon,
output_as_class=False,
get_simple_names=True)
[docs]def main():
from Code.FireEmblemCombatV2 import Skill, Weapon, Enemy, Player
skills_output, players_output, enemies_output, weapons_output, english_data_output, growth_output, \
move_output, stage_encount_output, terrain_output = load_files(Skill, Player, Enemy, Weapon,
output_as_class=False,
get_simple_names=True)
# print(players_output[0]["MARTH"].skills)
# CONCLUSION: some things, like Falchion, get overridden, others cannot be translated by current translation method
# List: 3515, Set: 3400 --> 3400 translated normally; 96 untranslated, set as None; 11 overridden Falchion items;
# 7 Umbra Burst? Also 1 Missiletainn, but I think that's because the game has 2 separate Missiletainn weapons,
# those being the sword (used by Owain) and the tome (used by Ophelia), so that one doesn't count
# pprint([i for i in skills])
# print(len(skills["00_first"]))
# for i in skills["00_first"]:
# print("")
# print(i)
# for j in i:
# try:
# print(j, ":", i[j])
# except TypeError as e:
# # print(e)
# pass
# print("")
# pprint([i for i in characters])
# pprint([i for i in weapons])