mirror of
https://github.com/pmret/papermario.git
synced 2024-11-09 12:32:38 +01:00
173 lines
6.7 KiB
Python
173 lines
6.7 KiB
Python
|
#!/usr/bin/env python3
|
||
|
|
||
|
import yaml
|
||
|
import argparse
|
||
|
from pathlib import Path
|
||
|
from typing import List, Dict
|
||
|
|
||
|
|
||
|
class DoubleRecipe:
|
||
|
def __init__(self, entry: List[str], order: Dict[str, int]):
|
||
|
order0 = order.get(entry[0], 99999)
|
||
|
order1 = order.get(entry[1], 99999)
|
||
|
if order0 <= order1 or order0 == 99999 or order1 == 99999:
|
||
|
self.i = order0
|
||
|
self.j = order1
|
||
|
self.in1 = entry[0]
|
||
|
self.in2 = entry[1]
|
||
|
else:
|
||
|
self.i = order1
|
||
|
self.j = order0
|
||
|
self.in1 = entry[1]
|
||
|
self.in2 = entry[0]
|
||
|
self.result = entry[2]
|
||
|
self.used = False
|
||
|
|
||
|
|
||
|
def generate(in_yaml: Path, out_c: Path):
|
||
|
with open(in_yaml) as f:
|
||
|
data = yaml.load(f.read(), Loader=yaml.SafeLoader)
|
||
|
|
||
|
products = data["Products"]
|
||
|
mystery_products = data["MysteryProducts"]
|
||
|
single_recipes = data["SingleRecipes"]
|
||
|
double_recipes = data["DoubleRecipes"]
|
||
|
records = data["CookingRecords"]
|
||
|
|
||
|
dim = len(single_recipes)
|
||
|
|
||
|
input_idx: Dict[str, int] = {}
|
||
|
for idx, entry in enumerate(single_recipes):
|
||
|
input_idx[entry[0]] = idx
|
||
|
|
||
|
product_idx: Dict[str, int] = {}
|
||
|
for idx, entry in enumerate(products):
|
||
|
product_idx[entry[0]] = idx
|
||
|
|
||
|
for recipe in single_recipes:
|
||
|
if len(recipe) != 2 and len(recipe) != 3:
|
||
|
raise Exception(f"Invaid format for ExtraDoubleRecipe: {str(recipe)}")
|
||
|
if not recipe[1] in product_idx:
|
||
|
raise Exception(f"Product {recipe[1]} for SingleRecipe {recipe[0]} not listed in Products")
|
||
|
if len(recipe) == 3 and not recipe[2] in product_idx:
|
||
|
raise Exception(f"Product {recipe[2]} for SingleRecipe {recipe[0]} not listed in Products")
|
||
|
|
||
|
# double recipes with inputs not found in SingleRecipes are automatically treated as an ExtraDoubleRecipe
|
||
|
for recipe in double_recipes:
|
||
|
if len(recipe) != 3:
|
||
|
raise Exception(f"Invaid format for ExtraDoubleRecipe: {str(recipe)}")
|
||
|
# if not recipe[0] in input_idx:
|
||
|
# raise Exception(f"Ingredient {recipe[0]} for DoubleRecipe ({recipe[0]}, {recipe[1]}) not listed in SingleRecipes")
|
||
|
# if not recipe[1] in input_idx:
|
||
|
# raise Exception(f"Ingredient {recipe[1]} for DoubleRecipe ({recipe[0]}, {recipe[1]}) not listed in SingleRecipes")
|
||
|
if not recipe[2] in product_idx:
|
||
|
raise Exception(f"Product {recipe[2]} for DoubleRecipe ({recipe[0]}, {recipe[1]}) not listed in Products")
|
||
|
|
||
|
# for recipe in extra_recipes:
|
||
|
# if len(recipe) != 3:
|
||
|
# raise Exception(f"Invaid format for ExtraDoubleRecipe: {str(recipe)}")
|
||
|
# if not recipe[2] in product_idx:
|
||
|
# raise Exception(f"Product {recipe[2]} for ExtraDoubleRecipe ({recipe[0]}, {recipe[1]}) not listed in Products")
|
||
|
|
||
|
with open(out_c, "w") as f:
|
||
|
f.write("/* This file is auto-generated. Do not edit. */\n\n")
|
||
|
f.write('#include "common.h"\n\n')
|
||
|
|
||
|
f.write(f"#define NUM_INGREDIENTS {dim}\n\n")
|
||
|
|
||
|
f.write("s32 CookingIngredients[] = {\n")
|
||
|
for recipe in single_recipes:
|
||
|
f.write(f" {recipe[0]},\n")
|
||
|
f.write(" -1,\n")
|
||
|
f.write("};\n\n")
|
||
|
|
||
|
f.write("CookingResult CookingResults[] = {\n")
|
||
|
for product in products:
|
||
|
f.write(f" {{ {product[1] + ',':15} {product[0]} }},\n")
|
||
|
f.write(" { -1, -1 },\n")
|
||
|
f.write("};\n\n")
|
||
|
|
||
|
f.write("s8 SingleRecipesWithoutCookbook[] = {\n")
|
||
|
for recipe in single_recipes:
|
||
|
f.write(f" {product_idx[recipe[1]]:-2}, // {recipe[0]:20} --> {recipe[1]}\n")
|
||
|
f.write("};\n\n")
|
||
|
|
||
|
f.write("s8 SingleRecipesWithCookbook[] = {\n")
|
||
|
for recipe in single_recipes:
|
||
|
if len(recipe) == 3:
|
||
|
f.write(f" {product_idx[recipe[2]]:-2}, // {recipe[0]:20} --> {recipe[2]}\n")
|
||
|
else:
|
||
|
f.write(f" {product_idx[recipe[1]]:-2}, // {recipe[0]:20} --> {recipe[1]}\n")
|
||
|
f.write("};\n\n")
|
||
|
|
||
|
recipe_map: Dict[int, DoubleRecipe] = {}
|
||
|
recipe_list: List[DoubleRecipe] = []
|
||
|
|
||
|
def combine_ids(i, j):
|
||
|
return i * dim + j
|
||
|
|
||
|
for entry in double_recipes:
|
||
|
r = DoubleRecipe(entry, input_idx)
|
||
|
if r.i < 99999 and r.j < 99999:
|
||
|
id_pair = combine_ids(r.i, r.j)
|
||
|
if id_pair in recipe_map:
|
||
|
raise Exception(f"Duplicate recipe for {r.in1} and {r.in2} in DoubleRecipes")
|
||
|
recipe_map[id_pair] = r
|
||
|
recipe_list.append(r)
|
||
|
|
||
|
f.write("s8 DoubleRecipesMatrix[] = {\n")
|
||
|
for i in range(0, dim):
|
||
|
f.write(" ")
|
||
|
for j in range(0, dim):
|
||
|
if j < i:
|
||
|
# ignore lower diagonal
|
||
|
id = -1
|
||
|
elif combine_ids(i, j) in recipe_map:
|
||
|
# recipe is defined, get product id
|
||
|
recipe = recipe_map[combine_ids(i, j)]
|
||
|
# this special combination COULD be defined in the matrix, but isn't in vanilla
|
||
|
# so we need to grant it a special exception, forcing it to generate in ExtraDoubleRecipes
|
||
|
if recipe.in1 == "ITEM_STRANGE_LEAF" and recipe.in2 == "ITEM_WHACKAS_BUMP":
|
||
|
id = 0
|
||
|
else:
|
||
|
id = product_idx[recipe.result]
|
||
|
recipe.used = True
|
||
|
else:
|
||
|
# no recipe for this (i,j) -> default to ITEM_MISTAKE
|
||
|
id = 0
|
||
|
f.write(f" {id:-2},")
|
||
|
f.write("\n")
|
||
|
f.write("};\n\n")
|
||
|
|
||
|
f.write("ExtraCookingPair ExtraDoubleRecipes[] = {\n")
|
||
|
# for entry in extra_recipes:
|
||
|
# f.write(f" {{ {entry[0]}, {entry[1]}, {product_idx[entry[2]]} }},\n")
|
||
|
for entry in recipe_list:
|
||
|
if not entry.used:
|
||
|
f.write(f" {{ {entry.in1}, {entry.in2}, {product_idx[entry.result]} }},\n")
|
||
|
f.write("};\n\n")
|
||
|
|
||
|
f.write("s32 MysteryResultOptions[] = {\n")
|
||
|
for product in mystery_products:
|
||
|
f.write(f" {product},\n")
|
||
|
f.write("};\n\n")
|
||
|
|
||
|
f.write("const s32 CookableItemIDs[] = {\n")
|
||
|
for rec in records:
|
||
|
f.write(f" {rec[0]},\n")
|
||
|
f.write("};\n\n")
|
||
|
|
||
|
f.write("const s32 CookableDiscoveredFlags[] = {\n")
|
||
|
for rec in records:
|
||
|
f.write(f" {rec[1]},\n")
|
||
|
f.write("};\n\n")
|
||
|
|
||
|
|
||
|
if __name__ == "__main__":
|
||
|
parser = argparse.ArgumentParser(description="Generates Tayce T cooking data")
|
||
|
parser.add_argument("in_yaml", type=Path, help="input yaml file path")
|
||
|
parser.add_argument("out", help="output file to generate")
|
||
|
args = parser.parse_args()
|
||
|
|
||
|
generate(args.in_yaml, args.out)
|