From 19743114231eceb9e73b38c6f6f5faf64b80b6f8 Mon Sep 17 00:00:00 2001 From: Demur Rumed Date: Wed, 16 Jul 2025 13:10:42 +0000 Subject: [PATCH] rest --- soh/compile_logic.py | 344 +++++++++++++++++++++++++------------------ 1 file changed, 201 insertions(+), 143 deletions(-) diff --git a/soh/compile_logic.py b/soh/compile_logic.py index c004decc0..cd1ed7455 100755 --- a/soh/compile_logic.py +++ b/soh/compile_logic.py @@ -15,6 +15,203 @@ class RR: self.checks = [] self.exits = [] + def gen(self, code): + return self.to_cpp(self.parse(code)) + + def parse(self, code): + if code[0] == "(" and code[-1] == ")": + code = code[1:-1] + stack = [] + ast = [] + balance = 0 + lastidx = 0 + for idx, ch in enumerate(code): + if ch.isspace(): + if idx > lastidx: + ast.append(code[lastidx:idx]) + lastidx = idx+1 + elif ch == "(": + stack.append(ast) + ast = [] + lastidx = idx+1 + elif ch == ")": + if idx > lastidx: + ast.append(code[lastidx:idx]) + subast = ast + ast = stack.pop() + ast.append(subast) + lastidx = idx+1 + if len(code) > lastidx: + ast.append(code[lastidx:]) + return ast + + def to_cpp(self, ast): + result = [] + output = result.append + if ast: + if isinstance(ast, str): + f = ast + ast = [f] + else: + f = ast[0] + if f in LOGIC: + output(f"logic->{f}") + elif f in logicFUNC: + output(f"logic->{f}(") + output(", ".join(map(self.to_cpp, ast[1:]))) + output(")") + elif f in ctxFUNC: + output(f"ctx->{f}(") + output(", ".join(map(self.to_cpp, ast[1:]))) + output(")") + elif f in FUNC: + output(f"{f}(") + output(", ".join(map(self.to_cpp, ast[1:]))) + output(")") + elif f in binOP: + output("(") + output(binOP[f].join(map(self.to_cpp, ast[1:]))) + output(")") + elif f == "not": + output("!") + output(self.to_cpp(ast[1])) + elif f == "if": + output("(") + output(self.to_cpp(ast[1])) + output(" ? ") + output(self.to_cpp(ast[2])) + output(" : ") + output(self.to_cpp(ast[3])) + output(")") + elif f.startswith("RSK_"): + output(f"ctx->GetOption(f{f})") + elif f.startswith("RT_"): + output(f"ctx->GetTrickOption(f{f})") + elif f == "IsDungeonVanilla": + output(f"ctx->GetDungeon(f{self.to_cpp(ast[1])})->IsVanilla()") + elif f == "IsDungeonMQ": + output(f"ctx->GetDungeon(f{self.to_cpp(ast[1])})->IsMQ()") + elif f == "IsTrialSkipped": + output(f"ctx->GetTrial(f{self.to_cpp(ast[1])})->IsSkipped()") + elif f == "TriforcePiecesCollected": + output("gSaveContext.ship.quest.data.randomizer.triforcePiecesCollected") + elif f.startswith("HasProjectileAge"): + output(f.replace("HasProjectileAge", "HasProjectileAge::")) + elif f in RANDO: + output(f"Rando::{f}") + elif f == "Here": + output("Here(f{self.name}, []{return f{self.to_cpp(ast[1])};})") + elif f != "--": + if len(ast) != 1: + print("expected atom, got tree", ast) + elif f.isupper() or f.isdigit() or f in ("true", "false"): + output(f) + else: + print("invalid atom", f) + return "".join(result) + +binOP = { "==": " == ", "and": " && ", "or": " || ", ">=": " >= ", "!=": " != ", ">": " > ", "<": " < ", "add": " + " } + +LOGIC = { + "IsChild", + "IsAdult", + "AtDay", + "AtNight", + "LoweredWaterInBotw", + "BigPoes", +} + +RANDO = { + "DEKU_TREE", + "DODONGOS_CAVERN", + "JABU_JABUS_BELLY", + "FOREST_TEMPLE", + "FIRE_TEMPLE", + "WATER_TEMPLE", + "SPIRIT_TEMPLE", + "SHADOW_TEMPLE", + "BOTTOM_OF_THE_WELL", + "ICE_CAVERN", + "GERUDO_TRAINING_GROUND", + "GANONS_CASTLE", +} + +FUNC = { + "MQSpiritSharedStatueRoom", + "MQSpiritSharedBrokenWallRoom", + "CanPlantBean", + "BothAges", + "ChildCanAccess", + "AdultCanAccess", + "HasAccessTo", +} + +logicFUNC = { + "BlueFire", + "CanBreakMudWalls", + "CanBuyCheck", + "HasItem", + "HasBossSoul", + "HasFireSource", + "HasFireSourceWithTorch", + "CanUse", + "CanPassEnemy", + "CanKillEnemy", + "CanGetEnemyDrop", + "CanGetDekuBabaSticks", + "CanGetDekuBabaNuts", + "CanBreakPots", + "CanBorrowMasks", + "CanShield", + "CanStandingShield", + "CanReflectNuts", + "CanStunDeku", + "CanSpawnSoilSkull", + "CanGetNightTimeGS", + "CanOpenUnderwaterChest", + "CanHitSwitch", + "CanHitEyeTargets", + "CanDetonateUprightBombFlower", + "CanDetonateBombFlowers", + "CanUseProjectile", + "CanBreakLowerBeehives", + "CanBreakUpperBeehives", + "CallGossipFairy", + "CallGossipFairyExceptSuns", + "HasExplosives", + "HasProjectile", + "CanCutShrubs", + "CanBreakCrates", + "CanBreakSmallCrates", + "StoneCount", + "CanBuildRainbowBridge", + "TradeQuestStep", + "GetGSCount", + "BlastOrSmash", + "HookshotOrBoomerang", + "TakeDamage", + "CanAttack", + "CanDamage", + "CanUseSword", + "CanJumpslash", + "CanJumpslashExceptHammer", + "HasBottle", + "SmallKeys", + "OcarinaButtons", + "Hearts", + "EffectiveHealth", + "FireTimer", + "WaterTimer", + "MQWaterLevel", + "CanTriggerLACS", + "BombchusEnabled", +} + +ctxFUNC = { + "GetTrickOption", + "GetOption", +} + RRs = [] active_rr = None buf = "" @@ -49,149 +246,10 @@ for line in open(argv[1]): elif thing.startswith("RC_"): active_rr.checks.append((thing, code)) else: + LOGIC.add(thing) active_rr.events.append((thing, code)) buf = "" -def parse(code): - if code[0] == "(" and code[-1] == ")": - code = code[1:-1] - stack = [] - ast = [] - balance = 0 - lastidx = 0 - for idx, ch in enumerate(code): - if ch.isspace(): - if idx > lastidx: - ast.append(code[lastidx:idx]) - lastidx = idx+1 - elif ch == "(": - stack.append(ast) - ast = [] - lastidx = idx+1 - elif ch == ")": - if idx > lastidx: - ast.append(code[lastidx:idx]) - subast = ast - ast = stack.pop() - ast.append(subast) - lastidx = idx+1 - if len(code) > lastidx: - ast.append(code[lastidx:]) - return ast - -def to_cpp(ast): - result = [] - output = result.append - if ast: - if isinstance(ast, str): - f = ast - ast = [f] - else: - f = ast[0] - if f in LOGIC: - output(f"logic->{f}") - elif f in logicFUNC: - output(f"logic->{f}(") - output(", ".join(map(to_cpp, ast[1:]))) - output(")") - elif f in ctxFUNC: - output(f"ctx->{f}(") - output(", ".join(map(to_cpp, ast[1:]))) - output(")") - elif f in binOP: - output("(") - output(binOP[f].join(map(to_cpp, ast[1:]))) - output(")") - elif f == "not": - output("!") - output(to_cpp(ast[1])) - elif f == "if": - output("(") - output(to_cpp(ast[1])) - output(" ? ") - output(to_cpp(ast[2])) - output(" : ") - output(to_cpp(ast[3])) - output(")") - else: - if not (f.isupper() or f.isdigit() or f in ("true", "false")): - print("cannot convert", f, ast) - output(f) - return "".join(result) - -binOP = { "==": " == ", "and": " && ", "or": " || ", ">=": " >= ", "!=": " != ", ">": " > ", "<": " < ", "add": " + " } - -LOGIC = set(( - "IsChild", - "IsAdult", - "AtDay", - "AtNight", - "LoweredWaterInBotw", - "TriforcePiecesCollected", -)) - -logicFUNC = set(( - "HasAccessTo", - "BlueFire", - "CanBreakMudWalls", - "HasItem", - "HasBossSoul", - "HasFireSource", - "HasFireSourceWithTorch", - "CanUse", - "CanPassEnemy", - "CanKillEnemy", - "CanGetEnemyDrop", - "CanGetDekuBabaSticks", - "CanGetDekuBabaNuts", - "CanBreakPots", - "CanBorrowMasks", - "CanShield", - "CanReflectNuts", - "CanStunDeku", - "CanSpawnSoilSkull", - "CanGetNightTimeGS", - "CanHitSwitch", - "CanHitEyeTargets", - "CanDetonateUprightBombFlower", - "CanDetonateBombFlowers", - "CanUseProjectile", - "CanBreakLowerBeehives", - "CanBreakUpperBeehives", - "CallGossipFairy", - "CallGossipFairyExceptSuns", - "HasExplosives", - "CanCutShrubs", - "CanBreakCrates", - "CanBreakSmallCrates", - "CanPlantBean", - "StoneCount", - "CanBuildRainbowBridge", - "TradeQuestStep", - "GetGSCount", - "BlastOrSmash", - "HookshotOrBoomerang", - "TakeDamage", - "CanAttack", - "CanUseSword", - "CanJumpslash", - "CanJumpslashExceptHammer", - "HasBottle", - "SmallKeys", - "OcarinaButtons", - "Hearts", - "EffectiveHealth", - "FireTimer", - "WaterTimer", -)) - -ctxFUNC = set(( - "GetTrickOption", - "GetOption" -)) - -def gen(code): - return to_cpp(parse(code)) result = [] output = result.append @@ -200,19 +258,19 @@ for rr in RRs: if rr.events: output("\n") for name, code in rr.events: - output(f"\tEventAccess(&logic->{name}, []{{return {gen(code)};}}),\n") + output(f"\tEventAccess(&logic->{name}, []{{return {rr.gen(code)};}}),\n") output("}, {") if rr.checks: output("\n") for name, code in rr.checks: - output(f"\tLOCATION({name}, {gen(code)}),\n") + output(f"\tLOCATION({name}, {rr.gen(code)}),\n") output("}, {") if rr.exits: output("\n") for name, code in rr.events: - output(f"\tEntrance({name}, []{{return {gen(code)};}}),\n") + output(f"\tEntrance({name}, []{{return {rr.gen(code)};}}),\n") output("});\n") print("".join(result))