This commit is contained in:
Demur Rumed 2025-07-16 13:10:42 +00:00
commit 1974311423

View file

@ -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))