Files
dockipelago/worlds/tloz_ph/data/LogicPredicates.py
Jonathan Tinney 7971961166
Some checks failed
Analyze modified files / flake8 (push) Failing after 2m28s
Build / build-win (push) Has been cancelled
Build / build-ubuntu2204 (push) Has been cancelled
ctest / Test C++ ubuntu-latest (push) Has been cancelled
ctest / Test C++ windows-latest (push) Has been cancelled
Analyze modified files / mypy (push) Has been cancelled
Build and Publish Docker Images / Push Docker image to Docker Hub (push) Successful in 5m4s
Native Code Static Analysis / scan-build (push) Failing after 5m2s
type check / pyright (push) Successful in 1m7s
unittests / Test Python 3.11.2 ubuntu-latest (push) Failing after 16m23s
unittests / Test Python 3.12 ubuntu-latest (push) Failing after 28m19s
unittests / Test Python 3.13 ubuntu-latest (push) Failing after 14m49s
unittests / Test hosting with 3.13 on ubuntu-latest (push) Successful in 5m0s
unittests / Test Python 3.13 macos-latest (push) Has been cancelled
unittests / Test Python 3.11 windows-latest (push) Has been cancelled
unittests / Test Python 3.13 windows-latest (push) Has been cancelled
add schedule I, sonic 1/frontiers/heroes, spirit island
2026-04-02 23:46:36 -07:00

3156 lines
96 KiB
Python

from math import floor, ceil
from BaseClasses import CollectionState
from Options import Accessibility
from .Constants import *
# =========== Item States =============
def ph_has_sword(state: CollectionState, player: int, *args):
return any([
state.has("Sword (Progressive)", player),
state.has("Oshus' Sword", player)
])
def ph_has_phantom_sword(state: CollectionState, player: int, *args):
return any([
state.has("Sword (Progressive)", player, 2),
all([
ph_has_sword(state, player),
state.has("Phantom Sword", player)
])
])
def ph_has_shield(state: CollectionState, player: int, *args):
# Shield can be bought from shop
return True
def ph_has_shovel(state: CollectionState, player: int, *args):
return state.has("Shovel", player)
def ph_has_bow(state: CollectionState, player: int, *args):
return state.has("Bow (Progressive)", player)
def ph_has_bombs(state: CollectionState, player: int, *args):
return state.has("Bombs (Progressive)", player)
def ph_has_chus(state: CollectionState, player: int, *args):
return state.has("Bombchus (Progressive)", player)
def ph_has_grapple(state: CollectionState, player: int):
return state.has("Grappling Hook", player)
def ph_has_hammer(state: CollectionState, player: int):
return state.has("Hammer", player)
def ph_has_boomerang(state: CollectionState, player: int):
return state.has("Boomerang", player)
def ph_has_spirit(state: CollectionState, player: int, spirit: str, count: int = 1):
return state.has(f"Spirit of {spirit} (Progressive)", player, count)
def ph_has_spirit_gems(state: CollectionState, player: int, spirit: str, count: int = 1):
pack_size = state.multiworld.worlds[player].options.spirit_gem_packs
return all([
ph_has_spirit(state, player, spirit),
any([
state.has(f"{spirit} Gem", player, count),
state.has(f"{spirit} Gem Pack", player, ceil(count / pack_size)),
])
])
def ph_has_phantom_hourglass(state, player):
return state.has("Phantom Hourglass", player)
def ph_has_sun_key(state: CollectionState, player: int):
return state.has("Sun Key", player)
def ph_has_ghost_key(state: CollectionState, player: int):
return state.has("Ghost Key", player)
def ph_has_kings_key(state: CollectionState, player: int):
return state.has("King's Key", player)
def ph_has_regal_necklace(state: CollectionState, player: int):
return all([
state.has("Regal Necklace", player),
ph_require_sea_chart(state, player, "NE")
])
def ph_has_phantom_blade(state: CollectionState, player: int):
return state.has("Phantom Blade", player)
def ph_has_heros_new_clothes(state: CollectionState, player: int):
return state.has("Hero's New Clothes", player)
def ph_has_guard_notebook(state: CollectionState, player: int):
return state.has("Guard Notebook", player)
def ph_has_kaleidoscope(state: CollectionState, player: int):
return state.has("Kaleidoscope", player)
def ph_has_wood_heart(state: CollectionState, player: int):
return state.has("Wood Heart", player)
def ph_has_triforce_crest(state: CollectionState, player: int):
return any([state.has("Triforce Crest", player),
not ph_option_triforce_crest(state, player)])
def ph_require_sea_chart(state, player, chart):
return any([
not ph_option_boat_requires_sea_chart(state, player),
ph_has_sea_chart(state, player, chart)
])
# ========= Sea Items =============
def ph_has_sea_chart(state: CollectionState, player: int, quadrant: str):
return state.has(f"{quadrant} Sea Chart", player)
def ph_has_courage_crest(state: CollectionState, player: int):
return state.has("Courage Crest", player)
def ph_has_cannon(state: CollectionState, player: int):
return state.has("Cannon", player)
def ph_has_salvage(state: CollectionState, player: int):
return state.has("Salvage Arm", player)
def ph_has_fishing_rod(state, player):
return state.has("Fishing Rod", player)
def ph_has_big_catch_lure(state, player):
return state.has("Big Catch Lure", player)
def ph_has_swordfish_shadows(state, player):
return state.has("Swordfish Shadows", player) and ph_has_big_catch_lure(state, player)
def ph_can_catch_rsf(state, player):
return ph_has_big_catch_lure(state, player)
def ph_ut_can_stowfish(state, player):
return all([
ph_has_swordfish_shadows(state, player),
any([
ph_UT_glitched_logic(state, player),
ph_has_big_catch_lure(state, player)
])
])
def ph_has_loovar(state, player):
return state.has("Fish: Loovar", player)
def ph_has_rsf(state, player):
return state.has("Fish: Rusty Swordfish", player)
def ph_has_neptoona(state, player):
return state.has("Fish: Legendary Neptoona", player)
def ph_has_stowfish(state, player):
return state.has("Fish: Stowfish", player)
def ph_has_jolene_letter(state, player):
return state.has("Jolene's Letter", player)
# ============== Frogs =======================
def ph_has_cyclone_slate(state: CollectionState, player: int):
return state.has("Cyclone Slate", player)
# Does not mean you can logically get back
def ph_has_frog(state: CollectionState, player: int, glyph: str, quadrant: str):
return all([
ph_has_sea_chart(state, player, quadrant),
ph_has_cyclone_slate(state, player),
any([
state.has(f"Golden Frog Glyph {glyph}", player),
ph_option_start_with_frogs(state, player)
])
])
def ph_has_frog_x(state: CollectionState, player: int):
return ph_has_frog(state, player, "X", "SW")
def ph_has_frog_phi(state: CollectionState, player: int):
return all([
ph_has_frog(state, player, "Phi", "SW"),
])
def ph_has_frog_n(state: CollectionState, player: int):
return ph_has_frog(state, player, "N", "NW")
def ph_has_frog_omega(state: CollectionState, player: int):
return ph_has_frog(state, player, "Omega", "SE")
def ph_has_frog_w(state: CollectionState, player: int):
return ph_has_frog(state, player, "W", "SE")
def ph_has_frog_square(state: CollectionState, player: int):
return ph_has_frog(state, player, "Square", "NE")
def ph_has_se_frogs(state, player):
return any([
ph_has_frog_omega(state, player),
ph_has_frog_w(state, player)
])
def ph_has_treasure_map(state, player, number):
map_name = TREASURE_MAPS[number - 1]
return state.has(map_name, player)
# =========== Combined item states ================
def ph_has_explosives(state: CollectionState, player: int, *args):
return state.has_any(["Bombs (Progressive)", "Bombchus (Progressive)"], player)
def ph_has_damage(state: CollectionState, player: int):
return any([
state.has("Sword (Progressive)", player),
ph_has_explosives(state, player),
state.has("Bow (Progressive)", player),
state.has("Grappling Hook", player),
state.has("Hammer", player)
])
def ph_has_cave_damage(state: CollectionState, player: int):
return any([
state.has("Sword (Progressive)", player),
ph_has_bombs(state, player),
state.has("Bow (Progressive)", player),
state.has("Grappling Hook", player),
state.has("Hammer", player)
])
def ph_can_kill_bat(state: CollectionState, player: int):
return any([
ph_has_damage(state, player),
ph_has_boomerang(state, player)
])
def ph_can_kill_yook(state: CollectionState, player: int):
return any([
ph_can_kill_dark_yook(state, player),
ph_option_hard_logic(state, player)
])
def ph_can_kill_dark_yook(state, player):
return any([
ph_has_sword(state, player),
ph_has_bow(state, player),
ph_has_hammer(state, player),
ph_has_grapple(state, player),
])
def ph_can_kill_blue_chu(state: CollectionState, player: int):
return any([
ph_has_bombs(state, player), # Only place this is relevant is in "cave"
ph_has_bow(state, player),
ph_has_grapple(state, player),
ph_has_hammer(state, player),
ph_has_beam_sword(state, player),
all([
ph_has_sword(state, player),
any([
ph_has_boomerang(state, player),
ph_has_super_shield(state, player),
])
])
])
def ph_can_kill_phantom_eyes(state, player):
return any([
ph_clever_pots(state, player),
ph_has_hammer(state, player),
ph_has_phantom_sword(state, player),
ph_has_explosives(state, player),
ph_has_bow(state, player),
ph_has_grapple(state, player)
])
def ph_can_kill_eye_brute(state: CollectionState, player: int):
return any([
ph_option_hard_logic(state, player),
ph_has_hammer(state, player),
ph_has_chus(state, player),
all([
ph_has_bow(state, player),
ph_has_sword(state, player)
]),
])
def ph_can_kill_bubble(state: CollectionState, player: int):
return any([
ph_has_hammer(state, player),
ph_has_explosives(state, player),
ph_has_bow(state, player),
ph_has_grapple(state, player),
ph_has_fire_sword(state, player),
all([
ph_has_sword(state, player), any([
ph_has_boomerang(state, player),
ph_has_super_shield(state, player) # This is the one logical use for shield!!!
])
])
])
def ph_totok_phantom_steal_object(state, player):
return any([
ph_clever_pots(state, player),
ph_can_kill_bat(state, player)
])
def ph_has_range(state: CollectionState, player: int):
return state.has_any(["Boomerang", "Bow (Progressive)", "Grappling Hook"], player)
def ph_has_short_range(state: CollectionState, player: int):
return any([ph_has_mid_range(state, player),
ph_clever_bombs(state, player), ])
def ph_has_mid_range(state: CollectionState, player: int):
return any([ph_has_range(state, player),
ph_has_hammer(state, player),
ph_has_beam_sword(state, player)])
def ph_cuccoo_dig(state, player):
return all([
ph_has_shovel(state, player),
ph_has_grapple(state, player)
])
def ph_has_mid_range_pots(state, player):
return any([
ph_has_mid_range(state, player),
ph_clever_pots(state, player)
])
def ph_has_fire_sword(state: CollectionState, player: int):
return all([
ph_has_sword(state, player),
ph_has_spirit(state, player, "Power", 2)
])
def ph_has_super_shield(state: CollectionState, player: int):
return all([
ph_has_shield(state, player),
ph_has_spirit(state, player, "Wisdom", 2)
])
def ph_has_beam_sword(state: CollectionState, player: int):
return all([
ph_has_sword(state, player),
ph_has_spirit(state, player, "Courage", 2)
])
def ph_can_make_phantom_sword(state, player):
return all([
ph_has_phantom_blade(state, player),
ph_has_phantom_hourglass(state, player)
])
def ph_can_hit_spin_switches(state: CollectionState, player: int):
return any([
ph_has_sword(state, player),
all([
ph_option_hard_logic(state, player),
any([
ph_has_explosives(state, player),
ph_has_boomerang(state, player)
])
])
])
def ph_spiral_wall_switches(state: CollectionState, player: int):
return any([
ph_has_boomerang(state, player),
ph_has_hammer(state, player),
ph_has_explosives(state, player)
])
def ph_quick_switches(state, player):
return any([
ph_has_boomerang(state, player),
all([
ph_has_bow(state, player),
ph_option_hard_logic(state, player)
])
])
def ph_can_cut_small_trees(state: CollectionState, player: int):
return any([ph_has_sword(state, player), ph_has_explosives(state, player)])
# ================ Rupee States ==================
def ph_has_rupees(state: CollectionState, player: int, cost: int):
# If has a farmable minigame and the means to sell, expensive things are in logic.
if ph_can_farm_rupees(state, player) or ph_UT_glitched_logic(state, player):
return True
# Count up regular rupee items
rupees = state.count("Green Rupee (1)", player)
rupees += state.count("Blue Rupee (5)", player) * 5
rupees += state.count("Red Rupee (20)", player) * 20
rupees += state.count("Big Green Rupee (100)", player) * 100
rupees += state.count("Big Red Rupee (200)", player) * 200
rupees += state.count("Gold Rupee (300)", player) * 300
# Sell Treasure
if state.has("_has_treasure_teller", player):
treasure_index = state.multiworld.worlds[player].treasure_price_index
for treasure in ITEM_GROUPS["Treasure Items"]:
rupees += state.count(treasure, player) * TREASURE_PRICES[treasure][treasure_index]
return rupees >= cost
def ph_can_farm_rupees(state: CollectionState, player: int):
return any([
all([
state.has("_has_treasure_teller", player), # Can Sell Treasure
any([
all([
state.has("_can_farm_totok", player),
ph_has_phantom_sword(state, player) # QoL require sword for logic
]),
all([ # Can Farm Minigames
ph_option_randomize_minigames(state, player),
any([
state.has("_can_play_archery", player),
state.has("_can_play_cannon_game", player),
state.has("_can_play_goron_race", player),
])
])
]),
]),
all([ # Can farm harrow (and chooses to play with harrow)
state.has("_can_play_harrow", player),
ph_option_randomize_harrow(state, player)
]),
])
def ph_island_shop(state, player, price):
other_costs = 0
if ph_has_sea_chart(state, player, "SW"):
# Includes cannon island, but not salvage arm cause that also unlocks treasure shop
other_costs += 1550
if ph_option_randomize_masked_beedle(state, player):
other_costs += 1500
other_costs *= 0.7 # Cost multiplier, cause the chance of all checks being useful is low
return ph_has_rupees(state, player, price + other_costs)
def ph_has_freebie_card(state, player):
return state.has("Freebie Card", player)
def ph_beedle_shop(state, player, price):
# Multiplier only applies to non-linear items
multiplier = 0.7 if ph_option_shop_hints(state, player) else 1
other_costs = 500 * multiplier + 50
discount = ph_count_beedle_discount(state, player) # Discount from points
# Island shop items
if ph_has_bow(state, player):
other_costs += 1000
if ph_has_chus(state, player):
other_costs += 3000
if ph_has_bombs(state, player):
other_costs += 1000 * discount * multiplier # Bomb bag is effected by discount
if ph_option_randomize_masked_beedle(state, player):
other_costs += 1500 * multiplier
if ph_has_freebie_card(state, player):
other_costs -= 500 * discount # Freebie card assumed to be used for the 500r wisdom gem.
return ph_has_rupees(state, player, price * discount + other_costs)
def ph_count_beedle_points(state, player):
return (state.count("Beedle Points (10)", player) * 10 +
state.count("Beedle Points (20)", player) * 20 +
state.count("Beedle Points (50)", player) * 50)
def ph_count_beedle_discount(state, player):
thresholds = {20: 0.9, 50: 0.8, 100: 0.7}
res = 1
points = ph_count_beedle_points(state, player)
for threshold, discount in thresholds.items():
if points >= threshold:
res = discount
return res
def ph_option_shop_hints(state, player):
return state.multiworld.worlds[player].options.shop_hints
def ph_has_beedle_points_buyable(state, player, points):
points_res = points - ph_count_beedle_points(state, player)
if points_res > 0:
cost = points_res * 100
else:
return True
if ph_has_bombs(state, player):
cost -= 1000 * ph_count_beedle_discount(state, player)
return ph_beedle_shop(state, player, cost)
def ph_has_beedle_points(state: CollectionState, player, points):
option = state.multiworld.worlds[player].options.randomize_beedle_membership
if ph_UT_glitched_logic(state, player):
return True
elif option == "randomize":
if points <= 20: # Buying 20 points is always in logic
return ph_has_beedle_points_buyable(state, player, points)
return ph_count_beedle_points(state, player) >= points
elif option == "randomize_with_grinding":
return ph_has_beedle_points_buyable(state, player, points)
return False
def ph_can_get_beedle_bronze(state, player):
return any([ph_has_rupees(state, player, 80), ph_has_beedle_points(state, player, 1)])
def ph_can_buy_gem(state: CollectionState, player: int):
return all([ph_island_shop(state, player, 500)])
def ph_can_buy_quiver(state: CollectionState, player: int):
return all([ph_has_bow(state, player), ph_island_shop(state, player, 1500)])
def ph_can_buy_chu_bag(state: CollectionState, player: int):
return all([ph_has_chus(state, player), ph_has_bow(state, player), ph_island_shop(state, player, 2500)])
def ph_can_buy_heart(state: CollectionState, player: int):
return all([ph_has_chus(state, player), ph_has_bow(state, player), ph_island_shop(state, player, 4500)])
def ph_can_buy_bomb_bag(state: CollectionState, player: int):
return all([ph_beedle_shop(state, player, 500), ph_has_bombs(state, player)])
# ============ Option states =============
def ph_option_glitched_logic(state: CollectionState, player: int):
return state.multiworld.worlds[player].options.logic == "glitched" or state.has("_UT_Glitched_Logic", player)
def ph_option_normal_logic(state: CollectionState, player: int):
return state.multiworld.worlds[player].options.logic == "normal"
def ph_option_hard_logic(state: CollectionState, player: int):
return (state.multiworld.worlds[player].options.logic in ["hard", "glitched"]
or state.has("_UT_Glitched_Logic", player))
def ph_option_not_glitched_logic(state: CollectionState, player: int):
return state.multiworld.worlds[player].options.logic in ["hard", "normal"]
def ph_option_keysanity(state: CollectionState, player: int):
return state.multiworld.worlds[player].options.keysanity == "anywhere"
def ph_option_smart_key_logic(state: CollectionState, player: int):
return ph_is_ut(state, player) and state.multiworld.worlds[player].options.ut_smart_keys
def ph_option_keys_vanilla(state: CollectionState, player: int):
return state.multiworld.worlds[player].options.keysanity == "vanilla"
def ph_option_keys_in_own_dungeon(state: CollectionState, player: int):
return state.multiworld.worlds[player].options.keysanity in ["in_own_dungeon", "vanilla"]
def ph_option_phantoms_hard(state: CollectionState, player: int):
return all([
any([
state.multiworld.worlds[player].options.phantom_combat_difficulty in ["require_weapon"],
ph_UT_glitched_logic(state, player)
]),
any([
ph_has_grapple(state, player),
ph_has_boomerang(state, player)
]),
])
def ph_option_phantoms_med(state: CollectionState, player: int):
return all([
any([
state.multiworld.worlds[player].options.phantom_combat_difficulty in ["require_weapon", "require_stun"],
ph_UT_glitched_logic(state, player)
]),
any([
ph_has_bow(state, player),
ph_has_hammer(state, player),
ph_has_fire_sword(state, player)
])
])
def ph_option_phantoms_easy(state: CollectionState, player: int):
return any([state.multiworld.worlds[player].options.phantom_combat_difficulty in
["require_weapon", "require_stun", "require_traps"],
ph_UT_glitched_logic(state, player)])
def ph_option_phantoms_sword_only(state: CollectionState, player: int):
return ph_has_phantom_sword(state, player)
def ph_clever_pots(state: CollectionState, player: int):
return ph_option_hard_logic(state, player)
def ph_can_hit_switches(state: CollectionState, player: int):
return any([ph_option_hard_logic(state, player), ph_can_kill_bat(state, player)])
def ph_clever_bombs(state: CollectionState, player: int):
return all([ph_has_bombs(state, player),
ph_option_hard_logic(state, player)])
def ph_option_randomize_minigames(state: CollectionState, player: int):
return state.multiworld.worlds[player].options.randomize_minigames
def ph_option_randomize_frogs(state: CollectionState, player: int):
return state.multiworld.worlds[player].options.randomize_frogs == "randomize"
def ph_option_start_with_frogs(state: CollectionState, player: int):
return state.multiworld.worlds[player].options.randomize_frogs == "start_with"
def ph_option_triforce_crest(state, player):
return state.multiworld.worlds[player].options.randomize_triforce_crest
def ph_has_required_metals(state: CollectionState, player: int):
current_metals = state.count_from_list(ITEM_GROUPS["Metals"], player)
return any([
all([
ph_option_goal_metal_hunt(state, player),
current_metals >= state.multiworld.worlds[player].options.metal_hunt_required
]),
all([
ph_option_goal_dungeons(state, player),
current_metals >= state.multiworld.worlds[player].options.dungeons_required
])
])
# pedestal options
def ph_option_pedestals_vanilla(state, player):
return state.multiworld.worlds[player].options.randomize_pedestal_items.value == 0
def ph_option_pedestals_abstract_vanilla(state, player):
return state.multiworld.worlds[player].options.randomize_pedestal_items.value == 1
def ph_option_pedestals_vanilla_any(state, player):
return state.multiworld.worlds[player].options.randomize_pedestal_items.value in [0, 1]
def ph_option_pedestals_local(state, player):
return state.multiworld.worlds[player].options.randomize_pedestal_items.value == 2
def ph_option_pedestals_anywhere(state, player):
return state.multiworld.worlds[player].options.randomize_pedestal_items.value in [2, 3]
def ph_zauz_required_metals(state: CollectionState, player: int):
current_metals = ITEM_GROUPS["Metals"]
# print(f"Zauz {state.multiworld.worlds[player].options.zauz_required_metals} have {state.count_from_list(
# current_metals, player)}")
return state.has_from_list(current_metals, player,
state.multiworld.worlds[player].options.zauz_required_metals)
def ph_option_randomize_masked_beedle(state: CollectionState, player: int):
return state.multiworld.worlds[player].options.randomize_masked_beedle
def ph_goal_option_phantom_door(state: CollectionState, player: int):
return state.multiworld.worlds[player].options.bellum_access == "spawn_phantoms_on_b13"
def ph_goal_option_staircase(state: CollectionState, player: int):
return True # All goal options unlock staircase on goal req...
def ph_goal_option_warp(state: CollectionState, player: int):
return state.multiworld.worlds[player].options.bellum_access == "warp_to_bellum"
def ph_goal_option_spawn_bellumbeck(state: CollectionState, player: int):
return state.multiworld.worlds[player].options.bellum_access == "spawn_bellumbeck"
def ph_goal_option_instant_goal(state, player):
return state.multiworld.worlds[player].options.bellum_access == "win"
def ph_option_boat_requires_sea_chart(state: CollectionState, player: int):
return state.multiworld.worlds[player].options.boat_requires_sea_chart
def ph_option_fog_vanilla(state: CollectionState, player: int):
return state.multiworld.worlds[player].options.fog_settings in ["vanilla_fog", "no_fog"]
def ph_option_fog_open(state: CollectionState, player: int):
return state.multiworld.worlds[player].options.fog_settings == "open_ghost_ship"
def ph_option_randomize_harrow(state: CollectionState, player: int):
return state.multiworld.worlds[player].options.randomize_harrow
def ph_option_goal_dungeons(state: CollectionState, player: int):
return state.multiworld.worlds[player].options.goal_requirements == "defeat_bosses"
def ph_option_goal_metal_hunt(state: CollectionState, player: int):
return state.multiworld.worlds[player].options.goal_requirements == "metal_hunt"
def ph_option_goal_midway(state: CollectionState, player: int):
return state.multiworld.worlds[player].options.goal_requirements == "triforce_door"
def ph_option_island_shuffle(state, player):
return state.multiworld.worlds[player].options.shuffle_ports
def ph_can_pass_sea_monsters(state, player):
return any([
ph_has_cannon(state, player),
state.multiworld.worlds[player].options.skip_ocean_fights
])
def ph_charted_sea_monsters(state, player, chart):
return all([
ph_can_pass_sea_monsters(state, player),
ph_require_sea_chart(state, player, chart)
])
def ph_option_time_no_logic(state, player):
time_option = state.multiworld.worlds[player].options.ph_time_logic
return any([
time_option == "no_logic",
ph_UT_glitched_logic(state, player),
])
def ph_option_ph_required(state, player):
return state.multiworld.worlds[player].options.ph_required
def ph_option_floor_time(state, player, room):
time_option = state.multiworld.worlds[player].options.ph_time_logic
if time_option.value not in [3, 4]:
return False
elif (time_option == "ph_only_b1" and room > 0) or (time_option == "ph_only_b4" and room > 3):
return ph_has_phantom_hourglass(state, player)
return True
def ph_option_time_divider(state, player):
time_option = state.multiworld.worlds[player].options.ph_time_logic.value
# print(f"Time option {time_option}")
time_lookup = {0: 1, 1: 2, 2: 4, -1: 0.5}
return time_lookup.get(time_option, 1)
def ph_has_time(state: CollectionState, player, time, room=4):
# No time logic of floor + ph based time logic
if ph_option_time_no_logic(state, player):
return True
time_option = state.multiworld.worlds[player].options.ph_time_logic.value
if time_option > 2:
return ph_option_floor_time(state, player, room)
else:
# Heart logic for if ph is required
heart_time = state.multiworld.worlds[player].options.ph_heart_time.value
heart_total = heart_time * (state.count("Heart Containers", player) + 2)
multiplier = ph_option_time_divider(state, player)
if ph_option_ph_required(state, player) and not ph_has_phantom_hourglass(state, player):
return heart_total >= time // multiplier
# Time calculations for proper time logic
ph_time = state.multiworld.worlds[player].options.ph_starting_time.value
sand_time = state.multiworld.worlds[player].options.ph_time_increment.value
total_time = (ph_time * state.count("Phantom Hourglass", player) +
sand_time * state.count("Sand of Hours", player) +
60 * state.count("Sand of Hours (Small)", player) +
120 * state.count("Sand of Hours (Boss)", player) +
heart_total)
return total_time >= time // multiplier
# For doing sneaky stuff with universal tracker UT
def ph_is_ut(state: CollectionState, player: int):
return getattr(state.multiworld, "generation_is_fake", False)
def ph_UT_glitched_logic(state, player):
return state.has("_UT_Glitched_Logic", player)
# ============== ER Options =============
def ph_option_vanilla_caves(state, player):
return state.multiworld.worlds[player].options.shuffle_caves in ["no_shuffle"]
# ============= Key logic ==============
def ph_has_small_keys(state: CollectionState, player: int, dung_name: str, amount: int = 1):
return state.has(f"Small Key ({dung_name})", player, amount)
def ph_has_boss_key(state: CollectionState, player: int, dung_name: str):
return state.has(f"Boss Key ({dung_name})", player)
def ph_has_boss_key_simple(state: CollectionState, player: int, dung_name: str):
return any([
ph_has_boss_key(state, player, dung_name),
all([
ph_option_smart_key_logic(state, player),
state.multiworld.worlds[player].options.randomize_boss_keys == "vanilla"
])
])
def ph_has_force_gems(state, player, floor, count=3):
return any([
state.has(f"Force Gem (B{floor})", player, count),
state.has(f"Force Gems", player, 1),
])
def ph_has_shape_crystal(state: CollectionState, player: int, dung_name: str, shape: str, diff: str=""):
return any([
state.has(f"{shape} Crystal ({dung_name})", player),
state.has(f"{shape} Crystals", player),
state.has(f"{shape} Pedestal {diff} ({dung_name})", player),
])
def ph_ut_small_key_vanilla_location(state, player):
return all([
ph_option_smart_key_logic(state, player),
ph_option_keys_vanilla(state, player)
])
def ph_ut_small_key_own_dungeon(state, player):
return all([
ph_option_smart_key_logic(state, player),
ph_option_keys_in_own_dungeon(state, player)
])
def ph_option_boss_key_in_own_dungeon(state, player):
return state.multiworld.worlds[player].options.randomize_boss_keys in ["vanilla", "in_own_dungeon"]
def ph_ut_boss_key_own_dungeon(state, player):
return all([
ph_option_smart_key_logic(state, player),
ph_option_boss_key_in_own_dungeon(state, player)
])
# ======== Harder Logic ===========
def ph_can_kill_phantoms(state: CollectionState, player: int):
return any([
ph_option_phantoms_hard(state, player),
ph_option_phantoms_med(state, player),
ph_option_phantoms_sword_only(state, player)
])
def ph_can_kill_phantoms_traps(state: CollectionState, player: int):
return any([
ph_option_phantoms_hard(state, player),
ph_option_phantoms_med(state, player),
ph_option_phantoms_easy(state, player),
ph_option_phantoms_sword_only(state, player)
])
def ph_can_hit_tricky_switches(state: CollectionState, player: int):
return any([
ph_clever_pots(state, player),
ph_has_short_range(state, player)
])
def ph_can_hammer_clip(state: CollectionState, player: int):
return all([ph_has_hammer(state, player), ph_option_glitched_logic(state, player)])
def ph_can_hit_bombchu_switches(state: CollectionState, player: int):
return any([
ph_can_hammer_clip(state, player),
ph_has_chus(state, player)
])
def ph_can_boomerang_return(state: CollectionState, player: int):
return all([
ph_has_boomerang(state, player),
ph_option_glitched_logic(state, player)
])
def ph_can_arrow_despawn(state: CollectionState, player: int):
return all([
ph_has_bow(state, player),
ph_option_glitched_logic(state, player)
])
def ph_can_bcl(state, player):
# Bombchu Camera Lock
return all([
ph_has_chus(state, player),
ph_option_glitched_logic(state, player)
])
def ph_can_sword_glitch(state, player):
return all([
ph_has_sword(state, player),
ph_option_glitched_logic(state, player)
])
def ph_can_grapple_glitch(state, player):
return all([
ph_has_grapple(state, player),
ph_option_glitched_logic(state, player)
])
def ph_can_sword_scroll_clip(state, player):
return all([
ph_has_sword(state, player),
state.has("Swordsman's Scroll", player),
ph_option_glitched_logic(state, player)
])
def ph_ember_grapple_chest(state, player):
return any([ph_has_grapple(state, player), ph_can_sword_glitch(state, player)])
# ====== Specific locations =============
# TotOK
def ph_totok_b1_all_checks_ut(state, player):
return all([
ph_ut_small_key_own_dungeon(state, player),
ph_has_spirit(state, player, "Power"),
ph_totok_b1_bow(state, player),
ph_totok_b1_key(state, player),
ph_totok_b1_phantom(state, player),
])
def ph_totok_b2_all_checks_ut(state, player):
return all([
ph_totok_b1_all_checks_ut(state, player),
ph_totok_b2_phantom(state, player),
ph_totok_b2_key(state, player),
ph_totok_b2_chu(state, player),
])
def ph_totok_b4_all_checks_ut(state, player):
return all([
ph_totok_b2_all_checks_ut(state, player),
ph_has_spirit(state, player, "Wisdom"),
# B3
ph_totok_b3_phantom(state, player),
ph_totok_b3_bow(state, player),
# B4
ph_totok_b4_phantom(state, player),
ph_totok_b4_eyes(state, player),
ph_totok_b4_key(state, player),
])
def ph_totok_b10_all_checks_ut(state, player):
return all([
ph_totok_b4_all_checks_ut(state, player),
ph_has_triforce_crest(state, player),
ph_has_sea_chart(state, player, "SW"),
ph_has_hammer(state, player),
ph_has_explosives(state, player),
ph_has_shovel(state, player)
])
def ph_totok_b13_door(state: CollectionState, player: int):
# Required to enter the phantom door
return all([
ph_has_phantom_sword(state, player),
ph_totok_has_floor_time(state, player, 13, 30),
any([
all([ph_goal_option_phantom_door(state, player),
ph_has_required_metals(state, player)]),
ph_goal_option_staircase(state, player)
])
])
# Overworld
def ph_boat_access(state, player):
return any([
not ph_option_boat_requires_sea_chart(state, player),
ph_has_sea_chart(state, player, "SW"),
ph_option_island_shuffle(state, player)
])
# Handles keylocking due to lack of locations
def ph_can_reach_mp2(state: CollectionState, player: int):
return any([
ph_has_small_keys(state, player, "Mountain Passage", 2),
all([
ph_option_keys_in_own_dungeon(state, player),
any([
all([
any([
ph_option_smart_key_logic(state, player),
not ph_is_ut(state, player)
]),
ph_mercay_passage_rat(state, player)
]),
all([
ph_has_small_keys(state, player, "Mountain Passage", 1),
ph_option_vanilla_caves(state, player)
])
])
]),
all([
ph_UT_glitched_logic(state, player),
ph_has_small_keys(state, player, "Mountain Passage", 1)
])
])
def ph_can_reach_mp2_top(state, player):
return any([
ph_has_small_keys(state, player, "Mountain Passage", 2),
all([
ph_UT_glitched_logic(state, player),
ph_has_small_keys(state, player, "Mountain Passage", 1)
])
])
def ph_mp2_bypass(state, player):
return any([
ph_has_small_keys(state, player, "Mountain Passage", 3),
all([
ph_UT_glitched_logic(state, player),
ph_has_small_keys(state, player, "Mountain Passage", 2)
]),
ph_option_hard_logic(state, player) # Savewarp
])
def ph_mp2_bypass_fore(state, player):
return any([
ph_has_small_keys(state, player, "Mountain Passage", 3),
all([
ph_UT_glitched_logic(state, player),
ph_has_small_keys(state, player, "Mountain Passage", 2)
]),
all([
any([
ph_option_vanilla_caves(state, player),
ph_option_keys_in_own_dungeon(state, player)
]),
ph_has_small_keys(state, player, "Mountain Passage", 2),
any([
not ph_is_ut(state, player),
ph_option_smart_key_logic(state, player)
])
]),
])
def ph_mp3(state, player):
return any([
ph_has_small_keys(state, player, "Mountain Passage", 3),
all([ # use key
ph_UT_glitched_logic(state, player),
ph_has_small_keys(state, player, "Mountain Passage", 1)
]),
all([ # smart keys
ph_option_smart_key_logic(state, player),
ph_has_small_keys(state, player, "Mountain Passage", 1),
ph_option_keys_in_own_dungeon(state, player)
]),
all([ # logic assumes accessible
ph_option_keys_in_own_dungeon(state, player),
not ph_is_ut(state, player),
ph_mercay_passage_rat(state, player)
])
])
def ph_mp3_back(state, player):
return any([
ph_has_small_keys(state, player, "Mountain Passage", 3),
all([
any([
ph_option_vanilla_caves(state, player),
ph_option_keys_in_own_dungeon(state, player)
]),
ph_has_small_keys(state, player, "Mountain Passage", 2),
]),
all([
ph_UT_glitched_logic(state, player),
ph_has_small_keys(state, player, "Mountain Passage", 1),
]),
])
def ph_mercay_passage_rat(state, player):
return any([
ph_can_kill_bat(state, player),
all([
ph_clever_pots(state, player), # only if not ER
ph_option_vanilla_caves(state, player)
]),
])
def ph_nyave_fight(state, player):
return any([ph_has_cave_damage(state, player), ph_clever_pots(state, player)])
def ph_bannan_scroll(state, player):
return all([
state.has("_wayfarer_trade", player),
ph_can_pass_sea_monsters(state, player),
])
def ph_bannan_sea_monster(state, player):
return all([
ph_require_sea_chart(state, player, "NW"),
any([
ph_can_pass_sea_monsters(state, player),
ph_UT_glitched_logic(state, player),
not state.has("_wayfarer_trade", player)
])
])
def ph_ss_wayfarer(state, player):
return all([
ph_has_wood_heart(state, player),
state.has("_wayfarer_gift", player),
])
def ph_salvage_courage_crest(state: CollectionState, player: int):
return all([
ph_has_courage_crest(state, player),
ph_has_salvage(state, player),
# The sea monster is disabled, otherwise add cannon to reqs
])
def ph_can_enter_ocean_sw_west(state, player):
return any([
ph_has_cannon(state, player),
ph_has_frog_phi(state, player), # Includes return data, and NW way back
])
def ph_enter_se_ocean(state, player):
return ph_has_sea_chart(state, player, "SE")
def ph_salvage_behind_bannan(state, player):
return all([
ph_has_salvage(state, player),
ph_has_sea_chart(state, player, "NW")])
def ph_oshus_gem(state, player):
return any([
ph_can_make_phantom_sword(state, player),
all([
state.has("_beat_tow", player),
"Temple of Wind" not in state.multiworld.worlds[player].excluded_dungeons
])
])
def ph_ice_field(state, player):
return any([
all([
ph_can_kill_dark_yook(state, player),
ph_has_bombs(state, player)
]),
state.has("_beat_toi", player)
])
def ph_ruins_lower_water(state, player):
return state.has("_ruins_lower_water", player)
def ph_ruins_geozards(state, player):
return any([
ph_has_cave_damage(state, player),
ph_ruins_lower_water(state, player)
])
def ph_ruins_stalfos_n(state, player):
return any([
ph_ruins_stalfos_s(state, player),
ph_option_hard_logic(state, player)
])
def ph_ruins_stalfos_s(state, player):
return any([
ph_ruins_lower_water(state, player),
ph_can_kill_bat(state, player),
])
# Tof
def ph_tof_maze(state, player):
return any([
ph_has_small_keys(state, player, "Temple of Fire", 1),
ph_tof_1f_key_ut(state, player)])
def ph_tof_1f_key_ut(state, player):
return all([
ph_ut_small_key_own_dungeon(state, player),
ph_can_kill_bat(state, player)
])
def ph_tof_3f(state, player):
return all([
any([
ph_has_small_keys(state, player, "Temple of Fire", 2),
ph_ut_small_key_own_dungeon(state, player)]),
any([
ph_has_boomerang(state, player),
ph_has_hammer(state, player),
ph_clever_bombs(state, player),
all([
ph_option_hard_logic(state, player),
ph_has_chus(state, player),
any([
ph_has_bow(state, player),
ph_has_grapple(state, player)
])
])
])
])
def ph_tof_key_drop(state, player):
return any([
ph_has_boomerang(state, player),
all([
ph_has_grapple(state, player),
ph_option_hard_logic(state, player)
])
])
def ph_tof_3f_key_door(state, player):
return all([
any([
ph_has_small_keys(state, player, "Temple of Fire", 3),
all([
ph_ut_small_key_own_dungeon(state, player),
ph_tof_key_drop(state, player)
])
])
])
def ph_tof_enter_blaaz(state, player):
return any([
ph_has_boss_key(state, player, "Temple of Fire"),
all([
ph_ut_boss_key_own_dungeon(state, player),
ph_has_boomerang(state, player)
])
])
def ph_tof_blaaz(state, player):
return all([
ph_has_sword(state, player),
ph_has_boomerang(state, player)
])
# Wind
def ph_tow_b1(state, player):
return any([
ph_can_hammer_clip(state, player),
ph_can_kill_bat(state, player)])
def ph_tow_key_door(state, player):
return any([
ph_has_small_keys(state, player, "Temple of Wind"),
ph_wind_temple_key_ut(state, player)])
def ph_tow_enter_cyclok(state, player):
return all([
ph_has_bombs(state, player),
any([
ph_has_boss_key(state, player, "Temple of Wind"),
all([
ph_ut_boss_key_own_dungeon(state, player),
ph_has_shovel(state, player),
ph_wind_temple_key_ut(state, player)
]),
])
])
def ph_wind_temple_key_ut(state, player):
return all([
ph_has_shovel(state, player),
any([
all([
ph_has_bombs(state, player),
ph_ut_small_key_own_dungeon(state, player)]),
ph_ut_small_key_own_dungeon(state, player)
])
])
# Toc
def ph_can_enter_toc(state, player):
return all([
ph_has_damage(state, player),
any([
ph_has_boomerang(state, player),
ph_has_bow(state, player)
])
])
def ph_toc_grapple_chest(state, player):
return any([ph_has_grapple(state, player), ph_can_boomerang_return(state, player)]) # Hardhatt dboost
# Can reach toc 1f west needing explosives and range
def ph_toc_switch_1(state, player):
return all([
ph_has_explosives(state, player),
ph_has_mid_range(state, player)
])
def ph_toc_beamos_ut(state, player):
return all([
ph_ut_pedestals_vanilla(state, player),
ph_has_bow(state, player)])
def ph_toc_crystal_south_abstract(state, player):
return all([
not ph_option_pedestals_vanilla(state, player),
ph_has_shape_crystal(state, player, "Temple of Courage", "Square", "South")
])
def ph_toc_crystal_south(state, player):
return all([
ph_has_bow(state, player),
ph_has_shape_crystal(state, player, "Temple of Courage", "Square", "South")])
def ph_toc_spike_corridor(state, player):
return all([ph_has_explosives(state, player), ph_has_bow(state, player)])
def ph_toc_key_door_1(state, player):
return all([
ph_has_damage(state, player),
any([
ph_toc_key_doors(state, player, 3, 1),
# UT Keys
all([
ph_option_not_glitched_logic(state, player),
ph_ut_small_key_own_dungeon(state, player),
any([
ph_has_explosives(state, player),
ph_option_keys_vanilla(state, player)
])
]),
])
])
def ph_toc_key_door_2(state, player):
return any([
ph_toc_key_doors(state, player, 3, 3),
all([
ph_toc_key_doors(state, player, 3, 2),
any([
ph_option_pedestals_vanilla_any(state, player),
not ph_has_shape_crystal(state, player, "Temple of Courage", "North")
])
]),
# UT stuff
all([ # savescumming keys
ph_UT_glitched_logic(state, player),
ph_has_hammer(state, player),
ph_toc_key_doors(state, player, 1, 2),
]),
all([
ph_option_not_glitched_logic(state, player),
ph_option_smart_key_logic(state, player),
any([
# Keys in own dungeon
all([
ph_ut_small_key_own_dungeon(state, player),
ph_has_explosives(state, player),
ph_has_grapple(state, player),
ph_has_bow(state, player)
]),
# Keys vanilla
all([
ph_ut_small_key_vanilla_location(state, player),
any([
ph_has_explosives(state, player),
all([
ph_has_bow(state, player),
ph_has_grapple(state, player)
])
])
])
])
])
])
def ph_toc_key_door_3(state, player):
return any([
ph_has_small_keys(state, player, "Temple of Courage", 3),
# UT
all([
ph_option_smart_key_logic(state, player),
ph_toc_all_checks_door_3(state, player),
]),
all([
ph_UT_glitched_logic(state, player),
ph_has_small_keys(state, player, "Temple of Courage", 1),
ph_has_hammer(state, player)
]),
all([
ph_UT_glitched_logic(state, player),
ph_has_small_keys(state, player, "Temple of Courage", 2),
ph_has_grapple(state, player)
])
])
def ph_toc_all_checks_door_3(state, player):
return any([
all([
ph_ut_small_key_own_dungeon(state, player),
ph_has_bow(state, player),
ph_has_explosives(state, player)
]),
all([
ph_ut_small_key_vanilla_location(state, player),
any([
ph_can_hammer_clip(state, player),
all([
ph_has_bow(state, player),
any([
ph_has_grapple(state, player),
ph_has_explosives(state, player),
])
])
])
])
])
def ph_toc_boss_key(state, player):
return any([
ph_has_boss_key(state, player, "Temple of Courage"),
all([
ph_ut_boss_key_own_dungeon(state, player),
ph_toc_all_checks_door_3
])
])
def ph_toc_key_doors(state, player, glitched: int, not_glitched: int):
return any([
all([
ph_option_glitched_logic(state, player),
ph_has_small_keys(state, player, "Temple of Courage", glitched)
]),
all([
ph_option_not_glitched_logic(state, player),
ph_has_small_keys(state, player, "Temple of Courage", not_glitched)
])
])
def ph_toc_final_switch_state(state, player):
return any([
ph_has_bow(state, player),
ph_toc_key_doors(state, player, 2, 1),
])
# Ghost Ship
def ph_has_ghost_ship_access(state, player):
return all([
ph_require_sea_chart(state, player, "NW"),
any([
all([
ph_has_spirit(state, player, "Power"),
ph_has_spirit(state, player, "Wisdom"),
ph_has_spirit(state, player, "Courage"),
ph_option_fog_vanilla(state, player)
]),
ph_option_fog_open(state, player)
])
])
def ph_has_gs_triangle_crystal(state, player):
return any([
ph_has_shape_crystal(state, player, "Ghost Ship", "Triangle"),
all([
ph_option_smart_key_logic(state, player),
ph_option_pedestals_vanilla_any(state, player)
])
])
def ph_ghost_ship_barrel(state, player):
return any([
all([
ph_has_bombs(state, player),
ph_option_hard_logic(state, player)
]),
ph_has_hammer(state, player),
ph_has_boomerang(state, player),
ph_has_grapple(state, player),
ph_has_shape_crystal(state, player, "Ghost Ship", "Round")
])
def ph_beat_ghost_ship(state: CollectionState, player):
return state.has("_beat_ghost_ship", player)
# Goron
def ph_goron_shortcut(state, player):
# print(f"\tHas goron shortcut event: {state.has('_goron_shortcut_bridge', player)}")
return any([
ph_can_hammer_clip(state, player),
])
def ph_goron_south_reverse(state, player):
return any([
ph_has_explosives(state, player),
])
def ph_goron_entrance(state, player):
return all([
ph_has_shovel(state, player),
any([
ph_has_explosives(state, player),
ph_has_hammer(state, player)
])
])
def ph_goron_chus(state, player):
return all([
ph_has_shovel(state, player),
any([
all([
ph_has_hammer(state, player),
ph_option_hard_logic(state, player)
]),
ph_has_bow(state, player),
ph_has_grapple(state, player),
])
])
def ph_meet_all_gorons(state, player):
return all([
state.has("_goron_chus", player),
state.has("_goron_bridge", player),
])
def ph_gt_b1(state, player):
return all([
ph_has_explosives(state, player),
ph_can_kill_eye_brute(state, player),
ph_has_sword(state, player)])
def ph_gt_b2_back(state, player):
return any([
ph_has_explosives(state, player),
ph_has_boomerang(state, player)])
def ph_gt_enter_dongo(state, player):
return any([
ph_has_boss_key(state, player, "Goron Temple"),
all([
ph_ut_boss_key_own_dungeon(state, player),
ph_has_chus(state, player)
])
])
def ph_can_beat_dongo(state, player):
return all([
ph_has_sword(state, player),
ph_has_chus(state, player)
])
# Toi
def ph_toi_2f(state, player):
return any([
ph_has_explosives(state, player),
ph_has_boomerang(state, player)])
def ph_toi_3f(state, player):
return any([
ph_has_range(state, player),
ph_has_bombs(state, player)])
def ph_toi_3f_switch(state, player):
return any([
ph_has_bombs(state, player),
all([
ph_option_hard_logic(state, player),
any([
ph_has_chus(state, player),
ph_has_boomerang(state, player)
])
])
])
def ph_toi_shortcut(state, player):
return all([
ph_can_hammer_clip(state, player),
ph_has_grapple(state, player)])
def ph_toi_b1(state, player):
return any([
all([
ph_has_explosives(state, player),
ph_has_grapple(state, player)
]),
ph_has_hammer(state, player)
])
def ph_toi_3f_boomerang(state, player):
return all([
ph_quick_switches(state, player),
any([
ph_has_boomerang(state, player),
ph_has_grapple(state, player)
])
])
def ph_toi_b2(state, player):
return all([
ph_has_bow(state, player),
ph_has_grapple(state, player),
any([
all([
ph_quick_switches(state, player),
state.has("_toi_b1_switch", player)
]),
all([
ph_can_bcl(state, player),
ph_has_boomerang(state, player)
])
])
])
def ph_toi_miniboss(state, player):
return all([ph_has_grapple(state, player),
ph_can_kill_dark_yook(state, player)])
def ph_toi_key_door_1_ut(state, player):
return any([
ph_toi_all_key_doors_ut(state, player),
all([
ph_option_not_glitched_logic(state, player),
ph_quick_switches(state, player),
any([
ph_has_boomerang(state, player),
ph_has_grapple(state, player)
]),
any([
ph_ut_small_key_vanilla_location(state, player),
all([
ph_ut_small_key_own_dungeon(state, player),
ph_has_explosives(state, player)
])
]),
])
])
def ph_toi_key_door_1(state, player):
return any([
ph_toi_key_doors(state, player, 3, 1),
all([
ph_option_smart_key_logic(state, player),
ph_toi_key_door_1_ut(state, player)
]),
all([
ph_UT_glitched_logic(state, player),
ph_has_small_keys(state, player, "Temple of Ice", 1)
])
])
def ph_toi_all_key_doors_ut(state, player):
return all([
ph_option_smart_key_logic(state, player),
ph_ut_small_key_own_dungeon(state, player),
ph_has_grapple(state, player),
ph_has_explosives(state, player),
ph_has_bow(state, player),
ph_quick_switches(state, player)
])
def ph_toi_boss_door(state, player):
return any([
ph_has_boss_key(state, player, "Temple of Ice"),
all([
ph_ut_boss_key_own_dungeon(state, player),
ph_toi_all_key_doors_ut(state, player)
])
])
def ph_toi_b2_switch_room(state, player):
return any([
ph_has_boomerang(state, player),
ph_has_hammer(state, player),
ph_has_explosives(state, player),
])
def ph_toi_key_doors(state, player, glitched: int, not_glitched: int = None):
not_glitched = glitched if not_glitched is None else not_glitched
return any([
all([
ph_option_glitched_logic(state, player),
ph_has_small_keys(state, player, "Temple of Ice", glitched)
]),
all([
ph_option_not_glitched_logic(state, player),
ph_has_small_keys(state, player, "Temple of Ice", not_glitched)
])
])
def ph_toi_key_door_2(state, player):
return any([
ph_toi_key_doors(state, player, 3, 2),
ph_toi_all_key_doors_ut(state, player), # smart keys
all([
ph_option_not_glitched_logic(state, player),
ph_ut_small_key_own_dungeon(state, player),
ph_quick_switches(state, player)
]),
all([ # Keyscumming
ph_UT_glitched_logic(state, player),
ph_has_small_keys(state, player, "Temple of Ice", 1)
])
])
def ph_toi_key_door_3(state, player):
return any([
ph_toi_key_doors(state, player, 3),
# UT
ph_toi_all_key_doors_ut(state, player),
all([
ph_UT_glitched_logic(state, player),
ph_has_small_keys(state, player, "Temple of Ice", 1)
])
])
def ph_toi_b2_north(state, player):
return all([
ph_can_kill_yook(state, player),
ph_has_grapple(state, player),
ph_can_hit_spin_switches(state, player)
])
# Mutoh's
def ph_mutoh_entrance(state, player):
return any([
ph_can_hammer_clip(state, player),
ph_has_explosives(state, player),
all([
ph_has_hammer(state, player),
ph_option_hard_logic(state, player)
]),
all([
ph_has_boomerang(state, player),
any([
ph_has_bow(state, player),
ph_has_sword(state, player)
])
])
])
def ph_mutoh_water(state, player):
return any([
all([
any([
ph_mutoh_key_doors(state, player, 2, 1),
ph_ut_small_key_own_dungeon(state, player) # This should account for all chests
]),
ph_has_bow(state, player),
any([
ph_has_boomerang(state, player),
ph_has_beam_sword(state, player)
])
]),
ph_can_arrow_despawn(state, player),
all([
ph_has_beam_sword(state, player),
ph_has_explosives(state, player),
ph_option_glitched_logic(state, player)
])
])
def ph_mutoh_key_doors(state, player, glitched: int, not_glitched: int):
return any([
all([
ph_option_glitched_logic(state, player),
ph_has_small_keys(state, player, "Mutoh's Temple", glitched)
]),
all([
ph_option_not_glitched_logic(state, player),
ph_has_small_keys(state, player, "Mutoh's Temple", not_glitched)
]),
all([
ph_UT_glitched_logic(state, player),
ph_has_small_keys(state, player, "Mutoh's Temple", 1)
])
])
def ph_mutoh_bk_chest(state, player):
return any([
ph_has_small_keys(state, player, "Mutoh's Temple", 2),
ph_ut_small_key_own_dungeon(state, player),
all([
ph_has_small_keys(state, player, "Mutoh's Temple", 1),
ph_UT_glitched_logic(state, player)
])
])
def ph_mutoh_boss_door(state, player):
return any([
ph_has_boss_key(state, player, "Mutoh's Temple"),
all([
ph_ut_boss_key_own_dungeon(state, player),
ph_mutoh_bk_chest(state, player),
])
])
# Goal Stuff
def ph_totok_blue_warp(state: CollectionState, player: int):
return all([
ph_goal_option_warp(state, player),
ph_has_required_metals(state, player)
])
def ph_totok_bellum_staircase(state, player):
return ph_has_required_metals(state, player)
def ph_can_beat_bellum(state, player):
return all([
ph_has_grapple(state, player),
ph_has_phantom_sword(state, player),
ph_has_bow(state, player),
ph_has_spirit(state, player, "Courage")
])
def ph_can_beat_ghost_ship_fight(state, player):
return ph_has_cannon(state, player)
def ph_can_beat_bellumbeck(state, player):
return all([
ph_has_phantom_sword(state, player),
ph_has_spirit(state, player, "Courage")
])
def ph_bellumbeck_quick_finish(state, player):
return all([
ph_can_beat_bellumbeck(state, player),
ph_has_required_metals(state, player),
ph_goal_option_spawn_bellumbeck(state, player)
])
def ph_win_on_metals(state, player):
return all([
ph_has_required_metals(state, player),
ph_goal_option_instant_goal(state, player)
])
def ph_temp_goal(state, player):
return all([ph_has_sea_chart(state, player, "SW"),
ph_has_phantom_sword(state, player),
ph_has_courage_crest(state, player)])
# TotOK New Time Logic
def ph_time_1f(state, player):
return 0
def ph_time_b1(state, player):
return ph_time_1f(state, player) + 1
def ph_time_b2(state, player):
return ph_time_b1(state, player) + 6
def ph_time_b3(state, player):
if ph_can_hit_switches(state, player):
return ph_time_b2(state, player) + 10
elif ph_clever_pots(state, player):
return ph_time_b2(state, player) + 30
return 6000
def ph_totok_small_keys(state, player, base_count):
sub = 0
if base_count >= 2 and ph_UT_glitched_logic(state, player) and not state.has("_UT_got_chart", player):
sub += 1
if all([
base_count >= 5,
any([
ph_has_grapple(state, player),
all([
not ph_option_pedestals_vanilla(state, player),
any([
ph_UT_glitched_logic(state, player),
ph_option_hard_logic(state, player),
not ph_option_pedestals_abstract_vanilla(state, player),
])
])
])
]):
sub += 1
return ph_has_small_keys(state, player, "Temple of the Ocean King", base_count-sub)
def ph_time_b4(state, player):
if ph_has_grapple(state, player):
return ph_time_b3(state, player) + 8
elif ph_option_pedestals_vanilla_any(state, player):
if all([
any([
ph_totok_small_keys(state, player, 4),
all([
ph_option_hard_logic(state, player),
ph_option_pedestals_abstract_vanilla(state, player),
])
]),
any([
ph_has_force_gems(state, player, 3, 3),
ph_option_smart_key_logic(state, player)
])
]):
if ph_option_pedestals_vanilla_any(state, player):
return ph_time_b3(state, player) + 60
elif ph_option_hard_logic(state, player):
return ph_time_b3(state, player) + 5
else:
return ph_time_b3(state, player) + 40
elif ph_option_pedestals_anywhere(state, player) and ph_has_force_gems(state, player, 3, 3):
return ph_time_b3(state, player) + 5
return 6000
def ph_time_b5(state, player):
if ph_has_bow(state, player):
return ph_time_b4(state, player) + 12
elif ph_has_mid_range_pots(state, player):
return ph_time_b4(state, player) + 25
return 6000
def ph_time_b6(state, player):
# Alt path
if ph_can_hit_bombchu_switches(state, player):
return ph_time_b5(state, player) + 15
# normal path
elif all([
ph_can_kill_bubble(state, player),
any([
ph_has_mid_range(state, player),
ph_clever_bombs(state, player)])
]):
return ph_time_b5(state, player) + 25
return 6000
def ph_time_b7(state, player):
return ph_time_b6(state, player) + 10
def ph_time_b7_g(state, player):
# Needs logic because of min statement later
if ph_has_grapple(state, player):
return ph_time_b7(state, player) + 10
return 6000
def ph_time_b8(state, player):
return min(ph_time_b7(state, player) + 20,
ph_time_b8_shortcut(state, player))
def ph_time_b8_shortcut(state, player):
comp = [6000]
if ph_totok_small_keys(state, player, 6):
comp += [ph_time_b7_g(state, player) + 5]
# comp += [ph_time_b7_e(state, player) + 20] Invalid, causes loop
return min(comp)
def ph_time_b9_shortcut(state, player):
return ph_time_b8_shortcut(state, player) + 2
def ph_time_b9(state, player):
return min(ph_time_b8(state, player) + 10,
ph_time_b9_shortcut(state, player))
def ph_time_b7_e(state, player):
return ph_time_b8(state, player) + 7
def ph_time_b8_1c(state, player):
comp = [ph_time_b7_g(state, player) + 20]
if ph_can_hit_switches(state, player):
comp.append(ph_time_b7_e(state, player) + 35)
return min(comp)
def ph_time_b8_2c(state, player):
return ph_time_b8_1c(state, player) + 20
def ph_time_b9_1c(state, player):
comp = [6000]
if ph_can_hit_bombchu_switches(state, player):
comp += [ph_time_b8_1c(state, player) + 10]
comp += [ph_time_b9_shortcut(state, player)]
if ph_has_explosives(state, player) or ph_can_hit_bombchu_switches(state, player):
comp += [ph_time_b8_2c(state, player) + 40]
return min(comp)
def ph_time_b9_2c(state, player):
comp = [6000]
if (ph_has_explosives(state, player)
or ph_can_hit_bombchu_switches(state, player)
or ph_totok_b9_abstract_triangle(state, player)):
comp.append(ph_time_b8_2c(state, player) + 70),
if ph_totok_phantom_steal_object(state, player):
comp.append(ph_time_b9_1c(state, player) + 25)
if ph_has_shape_crystal(state, player, "Temple of the Ocean King", "Square", "West"):
comp.append(ph_time_b8_2c(state, player))
return min(comp)
def ph_totok_b9_all_crystals(state, player):
return all([
ph_has_shape_crystal(state, player, "Temple of the Ocean King", "Round", "B9"),
ph_has_shape_crystal(state, player, "Temple of the Ocean King", "Triangle", "B9"),
ph_totok_b9_square_crystal(state, player, "Center")
])
def ph_time_b10(state, player):
return min([
ph_time_b9_2c(state, player) + 35,
ph_time_b9_1c(state, player) + 50 if ph_totok_b9_square_crystal(state, player, "Center") else 6000,
ph_time_b9_2c(state, player) + 5 if ph_totok_b9_all_crystals(state, player) and not ph_option_pedestals_vanilla(state, player) else 6000
])
def ph_time_b11(state, player):
time = 25 if ph_has_chus(state, player) else 40
return ph_time_b10(state, player) + time
def ph_time_b12(state, player):
if ph_has_shovel(state, player):
return ph_time_b11(state, player) + 55
return 6000
def ph_time_b12_h(state, player):
if ph_has_hammer(state, player):
return ph_time_b11(state, player) + 2
return 6000
def ph_time_b13(state, player):
return min(
ph_time_b12(state, player) + 60,
ph_time_b12_h(state, player) + 50,
ph_time_b12(state, player) + 20 if ph_totok_b12_abstract_pedestals(state, player, 2) else 6000,
ph_time_b12_h(state, player) + 10 if ph_totok_b12_abstract_pedestals(state, player, 2) else 6000,
)
floor_lookup = {0: ph_time_1f,
1: ph_time_b1,
2: ph_time_b2,
3: ph_time_b3,
4: ph_time_b4,
5: ph_time_b5,
6: ph_time_b6,
7: ph_time_b7,
8: ph_time_b8,
9: ph_time_b9,
'7_g': ph_time_b7_g,
'7_e': ph_time_b7_e,
'8_1c': ph_time_b8_1c,
'8_2c': ph_time_b8_2c,
'9_1c': ph_time_b9_1c,
'9_2c': ph_time_b9_2c,
10: ph_time_b10,
11: ph_time_b11,
12: ph_time_b12,
'12_h': ph_time_b12_h,
13: ph_time_b13}
def ph_totok_has_floor_time(state, player, room, time=0):
floor_time = floor_lookup[room](state, player)
# print(f"Floor time {room} {time}")
if floor_time >= 6000:
return False
room = 7 if type(room) is str else room
return ph_has_time(state, player, floor_lookup[room](state, player) + time, room)
# Totok Floor logic
def ph_totok_1f(state, player):
return ph_totok_has_floor_time(state, player, 0)
def ph_totok_1f_chest(state, player):
return ph_totok_has_floor_time(state, player, 0, 5)
def ph_totok_1f_chart(state, player):
return all([
ph_totok_has_floor_time(state, player, 0, 15),
any([
ph_totok_small_keys(state, player, 1),
ph_totok_b1_all_checks_ut(state, player) # UT Bypass
])
])
# B1
def ph_totok_b1(state, player):
return all([
ph_totok_has_floor_time(state, player, 1),
ph_has_spirit(state, player, "Power")
])
def ph_totok_b1_key(state, player):
if ph_has_explosives(state, player) or ph_has_grapple(state, player):
time = 15
elif ph_has_boomerang(state, player):
time = 25
else:
return False
return ph_totok_has_floor_time(state, player, 1, time)
def ph_totok_b1_phantom(state, player):
return any([
all([
ph_has_phantom_sword(state, player),
ph_totok_has_floor_time(state, player, 1, 10)
]),
all([
ph_can_kill_phantoms(state, player),
ph_totok_has_floor_time(state, player, 1, 30)
])
])
def ph_totok_b1_bow(state, player):
return all([
ph_totok_has_floor_time(state, player, 1, 12),
ph_has_bow(state, player),
ph_has_grapple(state, player)
])
# B2
def ph_totok_b2(state, player):
return all([
ph_totok_has_floor_time(state, player, 2),
any([
ph_totok_small_keys(state, player, 2),
ph_totok_b1_all_checks_ut(state, player),
])
])
def ph_totok_b2_key(state, player):
if ph_has_explosives(state, player):
time = 15
elif ph_can_boomerang_return(state, player):
time = 20
elif ph_clever_pots(state, player):
time = 70
else:
return False
return ph_totok_has_floor_time(state, player, 2, time)
def ph_totok_b2_phantom(state, player):
return all([
ph_has_phantom_sword(state, player),
any([
ph_has_mid_range(state, player),
ph_has_explosives(state, player)
]),
ph_totok_has_floor_time(state, player, 2, 20)
])
def ph_totok_b2_chu(state, player):
return all([
ph_can_hit_bombchu_switches(state, player),
ph_totok_has_floor_time(state, player, 2, 20)
])
def ph_totok_b3(state, player):
return all([
ph_totok_has_floor_time(state, player, 3), # Includes switch logic
any([
ph_totok_small_keys(state, player, 3),
ph_totok_b2_all_checks_ut(state, player),
])
])
def ph_totok_b3_nw(state, player):
return ph_totok_has_floor_time(state, player, 3, 5)
def ph_totok_b3_se(state, player):
return ph_totok_has_floor_time(state, player, 3, 10)
def ph_totok_b3_sw(state, player):
return all([
ph_totok_has_floor_time(state, player, 3, 7),
any([
ph_totok_small_keys(state, player, 4),
ph_totok_b4_all_checks_ut(state, player)
])
])
def ph_totok_b3_bow(state, player):
if ph_has_bow(state, player):
if ph_has_shovel(state, player):
time = 20
else:
time = 25
return ph_totok_has_floor_time(state, player, 3, time)
return False
def ph_totok_b3_key(state, player):
return all([
ph_totok_has_floor_time(state, player, 3, 5),
ph_totok_phantom_steal_object(state, player)])
def ph_totok_b3_phantom(state, player):
if ph_has_grapple(state, player):
if ph_has_phantom_sword(state, player):
if ph_has_shovel(state, player):
time = 15
else:
time = 20
elif ph_can_kill_phantoms_traps(state, player):
time = 35
else:
return False
return ph_totok_has_floor_time(state, player, 3, time)
return False
def ph_totok_b35(state, player):
return ph_totok_has_floor_time(state, player, 4)
def ph_totok_b4(state, player):
return all([
ph_totok_has_floor_time(state, player, 4),
ph_has_spirit(state, player, "Wisdom")
])
def ph_totok_b4_key(state, player):
time = 0
if ph_can_boomerang_return(state, player):
time = 6
elif ph_can_hit_bombchu_switches(state, player):
if ph_has_bow(state, player):
time = 12
elif ph_has_mid_range_pots(state, player):
time = 20
elif ph_has_bombs(state, player):
if ph_has_bow(state, player):
time = 20
elif ph_has_mid_range_pots(state, player):
time = 40
if not time:
return False
return ph_totok_has_floor_time(state, player, 4, time)
def ph_totok_b4_eyes(state, player):
time = 0
if ph_can_kill_phantom_eyes(state, player):
if ph_has_bow(state, player):
time = 25
elif ph_has_mid_range_pots(state, player):
time = 40
if not time:
return False
return ph_totok_has_floor_time(state, player, 4, time)
def ph_totok_b4_phantom(state, player):
time = 0
if ph_has_phantom_sword(state, player):
if ph_has_bow(state, player):
time = 15
elif ph_has_mid_range_pots(state, player):
time = 25
if not time:
return False
return ph_totok_has_floor_time(state, player, 4, time)
def ph_totok_b5(state, player):
return all([
ph_totok_has_floor_time(state, player, 5),
any([
ph_totok_b4_all_checks_ut(state, player),
ph_totok_b5_key_count(state, player)
])
])
def ph_totok_b5_key_count(state, player):
return ph_totok_small_keys(state, player, 5)
def ph_totok_b5_alt(state, player):
return all([
ph_totok_has_floor_time(state, player, 5),
ph_can_hit_bombchu_switches(state, player),
any([
ph_totok_b4_all_checks_ut(state, player),
ph_totok_b5_key_count(state, player)
])
])
def ph_totok_b5_chest(state, player):
return all([
ph_can_kill_bubble(state, player),
any([
ph_has_mid_range_pots(state, player),
ph_clever_bombs(state, player)
]),
ph_totok_has_floor_time(state, player, 5, 25)
])
def ph_totok_b5_alt_chest(state, player):
return all([
any([
ph_has_shovel(state, player),
ph_has_grapple(state, player)
]),
ph_totok_has_floor_time(state, player, 5, 7),
])
def ph_totok_b6(state, player):
return ph_totok_has_floor_time(state, player, 6)
def ph_totok_b6_bow(state, player):
return all([
ph_has_bow(state, player),
ph_totok_has_floor_time(state, player, 6, 10)
])
def ph_totok_b6_phantom(state, player):
return all([
ph_has_phantom_sword(state, player),
ph_totok_has_floor_time(state, player, 6, 15)
])
def ph_totok_b6_crest(state, player):
return all([
ph_has_sea_chart(state, player, "SW"),
ph_totok_has_floor_time(state, player, 6, 10)
])
def ph_totok_b7(state, player):
return all([
ph_has_triforce_crest(state, player),
ph_totok_has_floor_time(state, player, 7)
])
def ph_totok_b7_crystal(state, player):
return any([
all([
ph_has_grapple(state, player),
ph_totok_has_floor_time(state, player, '7_g')
]),
all([
ph_can_hit_switches(state, player),
ph_totok_has_floor_time(state, player, '7_e', 15)
])
])
def ph_totok_b7_switch_chest(state, player):
return all([
ph_has_range(state, player),
any([
ph_totok_has_floor_time(state, player, '7_g', 15),
ph_totok_has_floor_time(state, player, '7_e', 30)
])
])
def ph_totok_b8(state, player):
return ph_totok_has_floor_time(state, player, 8)
def ph_totok_b8_phantom(state, player):
return any([
all([
ph_has_phantom_sword(state, player),
ph_totok_has_floor_time(state, player, 8, 25)
]),
all([
ph_can_kill_phantoms(state, player),
ph_totok_has_floor_time(state, player, 8, 45)
])
])
def ph_totok_b9(state, player):
return any([
all([
ph_can_hit_bombchu_switches(state, player),
ph_totok_has_floor_time(state, player, '9_1c')
]),
all([
ph_totok_has_floor_time(state, player, '9_2c'),
any([
ph_has_shape_crystal(state, player, "Temple of the Ocean King", "Triangle", "B8"),
ph_ut_pedestals_vanilla(state, player)
]),
any([
ph_has_explosives(state, player),
not ph_option_pedestals_vanilla(state, player)
])
]),
all([
ph_totok_has_floor_time(state, player, '8_2c', 5),
not ph_option_pedestals_vanilla(state, player),
ph_has_shape_crystal(state, player, "Temple of the Ocean King", "Square", "West"),
any([
ph_has_shape_crystal(state, player, "Temple of the Ocean King", "Round", "B8"),
ph_has_hammer(state, player),
])
])
])
def ph_totok_b7_phantom(state, player):
return any([
all([
ph_has_phantom_sword(state, player),
ph_totok_has_floor_time(state, player, '7_e', 20)
]),
all([
ph_can_kill_phantoms(state, player),
ph_totok_has_floor_time(state, player, '7_e', 70)
])
])
def ph_totok_b9_abstract_triangle(state, player):
return all([
ph_has_shape_crystal(state, player, "Temple of the Ocean King", "Triangle", "B8"),
not ph_option_pedestals_vanilla(state, player)
])
def ph_totok_b9_phantom(state, player):
room = 9 if ph_can_hit_bombchu_switches(state, player) or ph_totok_b9_abstract_triangle(state, player) else '9_1c'
return any([
all([
ph_has_phantom_sword(state, player),
ph_totok_has_floor_time(state, player, room, 12)
]),
all([
ph_can_kill_phantoms_traps(state, player),
ph_has_hammer(state, player),
ph_totok_has_floor_time(state, player, room, 17)
]),
all([
ph_can_kill_phantoms_traps(state, player),
ph_has_bow(state, player),
ph_has_boomerang(state, player),
ph_totok_has_floor_time(state, player, room, 20)
]),
])
def ph_totok_b9_ghosts(state, player):
room = 9 if ph_can_hit_bombchu_switches(state, player) else '9_1c'
return ph_totok_has_floor_time(state, player, room, 30)
def ph_ut_pedestals_vanilla(state, player):
return all([
ph_option_smart_key_logic(state, player),
ph_option_pedestals_vanilla(state, player)
])
def ph_totok_b9_square_crystal(state, player, diff):
return any([
ph_has_shape_crystal(state, player, "Temple of the Ocean King", "Square", diff),
ph_totok_phantom_steal_object(state, player)
])
def ph_totok_b9_corner_chest(state, player):
return any([
all([
ph_totok_has_floor_time(state, player, '8_2c'),
any([
ph_has_shape_crystal(state, player, "Temple of the Ocean King", "Round", "B8"),
ph_has_hammer(state, player),
ph_ut_pedestals_vanilla(state, player)
])
]),
all([
any([
ph_totok_has_floor_time(state, player, 9, 25),
ph_totok_has_floor_time(state, player, '9_2c'),
]),
ph_totok_b9_square_crystal(state, player, "West")
])
])
def ph_totok_b8_2_crystal_chest(state, player):
time = 30 if ph_option_pedestals_vanilla(state, player) else 15
return all([
any([
ph_has_explosives(state, player),
not ph_option_pedestals_vanilla(state, player)
]),
ph_totok_has_floor_time(state, player, '8_2c', time),
any([
ph_ut_pedestals_vanilla(state, player),
all([
ph_has_shape_crystal(state, player, "Temple of the Ocean King", "Round", "B8"),
ph_has_shape_crystal(state, player, "Temple of the Ocean King", "Triangle", "B8"),
])
])
])
def ph_totok_b10(state, player):
return all([
ph_totok_has_floor_time(state, player, 10),
any([
ph_ut_pedestals_vanilla(state, player),
ph_totok_b9_all_crystals(state, player)
])
])
def ph_totok_b10_key(state, player):
return all([
ph_totok_has_floor_time(state, player, 10, 10),
ph_totok_phantom_steal_object(state, player)
])
def ph_totok_b10_phantom(state, player):
time = 15
if ph_has_phantom_sword(state, player):
time += 15
elif ph_can_kill_phantoms_traps(state, player):
time += 30
else:
return False
return all([
ph_has_explosives(state, player),
ph_totok_has_floor_time(state, player, 10, time)
])
def ph_totok_b10_eye(state, player):
if ph_has_explosives(state, player) and ph_has_grapple(state, player):
if ph_has_chus(state, player):
return ph_totok_has_floor_time(state, player, 10, 40)
return ph_totok_has_floor_time(state, player, 10, 45)
return False
def ph_totok_b10_hammer(state, player):
if ph_has_explosives(state, player) and ph_has_hammer(state, player):
if ph_has_chus(state, player):
return ph_totok_has_floor_time(state, player, 10, 20)
return ph_totok_has_floor_time(state, player, 10, 35)
return False
def ph_totok_b11(state, player):
return all([
ph_has_explosives(state, player),
ph_totok_has_floor_time(state, player, 11),
any([
ph_totok_b10_all_checks_ut(state, player), # Assume that time is enough
ph_totok_small_keys(state, player, 6),
])
])
def ph_totok_b11_phantom(state, player):
return all([
ph_has_phantom_sword(state, player),
ph_totok_has_floor_time(state, player, 11, 10)
])
def ph_totok_b11_eyes(state, player):
return ph_totok_has_floor_time(state, player, 11, 25)
def ph_totok_b12(state, player):
return any([
ph_totok_has_floor_time(state, player, 12),
ph_totok_has_floor_time(state, player, '12_h')
])
def ph_totok_b12_nw(state, player):
return any([
ph_totok_has_floor_time(state, player, 12, 12),
ph_totok_has_floor_time(state, player, '12_h', 15)
])
def ph_totok_b12_ne(state, player):
return any([
ph_totok_has_floor_time(state, player, 12, 35),
ph_totok_has_floor_time(state, player, '12_h', 15)
])
def ph_totok_b12_phantom(state, player):
return all([
ph_has_phantom_sword(state, player),
any([
ph_totok_has_floor_time(state, player, 12, 55),
ph_totok_has_floor_time(state, player, '12_h', 40)
])
])
def ph_totok_b12_abstract_pedestals(state, player, count=2):
return all([
not ph_option_pedestals_vanilla(state, player),
any([
ph_has_force_gems(state, player, 12, 2),
])
])
def ph_totok_b12_ghost(state, player):
return any([
ph_totok_has_floor_time(state, player, '12_h', 20) if ph_totok_b12_abstract_pedestals(state, player) else False,
ph_totok_has_floor_time(state, player, 12, 20) if ph_totok_b12_abstract_pedestals(state, player) else False,
ph_totok_has_floor_time(state, player, '12_h', 50),
ph_totok_has_floor_time(state, player, 12, 70),
])
def ph_totok_b12_hammer(state, player):
return ph_totok_has_floor_time(state, player, '12_h', 10)
def ph_totok_b13(state, player):
return all([
ph_totok_has_floor_time(state, player, 13),
any([
all([
ph_has_force_gems(state, player, 12, 2),
any([
ph_totok_phantom_steal_object(state, player), # Redundant since bombs are needed to get here
ph_has_force_gems(state, player, 12, 3),
])
]),
ph_ut_pedestals_vanilla(state, player)
])
])
def ph_totok_b13_chest(state, player):
return ph_totok_has_floor_time(state, player, 13, 5)
# State rules
def ph_has(state, player, item):
return state.has(item, player)
# Switch States
def ph_option_global_switch_state(state, player):
return state.multiworld.worlds[player].options.switch_state_behaviour.value == 2
def ph_option_local_switch_state(state, player):
return not ph_option_global_switch_state(state, player)
def ph_get_switch_state(state: "CollectionState", player, entrance):
if ph_option_local_switch_state(state, player):
dungeon = entrance.split(None, 1)[0]
return state.multiworld.worlds[player].get_entrance(entrance).switch_state[dungeon]
else:
return state.multiworld.worlds[player].get_entrance(entrance).global_switch_state
def ph_switch_state_red(state, player, entrance):
return ph_get_switch_state(state, player, entrance) & 0x1
# This is pretty stupid, but is niceish when writing logic. Was originally intended for exporting logic to
# poptracker but with the advancements in UT tracker that probably won't be necessary any more
RULE_DICT = {
"sword": ph_has_sword,
"phantom_sword": ph_has_sword,
"shield": ph_has_shield,
"shovel": ph_has_shovel,
"spade": ph_has_shovel,
"bow": ph_has_bow,
"bombs": ph_has_bombs,
"chus": ph_has_chus,
"bombchus": ph_has_chus,
"grapple": ph_has_grapple,
"grappling_hook": ph_has_grapple,
"hammer": ph_has_hammer,
"boomerang": ph_has_boomerang,
"spirit": ph_has_spirit,
"spirit_gems": ph_has_spirit_gems,
"gems": ph_has_spirit_gems,
"hourglass": ph_has_phantom_hourglass,
"phantom_hourglass": ph_has_phantom_hourglass,
"ph": ph_has_phantom_hourglass,
"sun_key": ph_has_sun_key,
"ghost_key": ph_has_ghost_key,
"kings_key": ph_has_kings_key,
"king's_key": ph_has_kings_key,
"regal_necklace": ph_has_regal_necklace,
"phantom_blade": ph_has_phantom_blade,
"heroes_new_clothes": ph_has_heros_new_clothes,
"guard_notebook": ph_has_guard_notebook,
"kaleidoscope": ph_has_kaleidoscope,
"wood_heart": ph_has_wood_heart,
"triforce_crest": ph_has_triforce_crest,
# Sea Items
"sea_chart": ph_has_sea_chart,
"courage_crest": ph_has_courage_crest,
"cannon": ph_has_cannon,
"salvage": ph_has_salvage,
"salvage_arm": ph_has_salvage,
"fishing_rod": ph_has_fishing_rod,
"rod": ph_has_fishing_rod,
"fishing": ph_has_fishing_rod,
"lure": ph_has_big_catch_lure,
"big_catch_lure": ph_has_big_catch_lure,
"swordfish_shadows": ph_has_swordfish_shadows,
"fish_shadows": ph_has_swordfish_shadows,
"can_catch_rsf": ph_can_catch_rsf,
"ut_can_stowfish": ph_ut_can_stowfish,
"loovar": ph_has_loovar,
"rsf": ph_has_rsf,
"rusty_swrodfish": ph_has_rsf,
"neptoona": ph_has_neptoona,
"legendary_neptoona": ph_has_neptoona,
"stowfish": ph_has_stowfish,
"jolene_letter": ph_has_jolene_letter,
# Frogs
"cyclone_slate": ph_has_cyclone_slate,
"frog": ph_has_frog,
"frog_x": ph_has_frog_x,
"frog_phi": ph_has_frog_phi,
"frog_n": ph_has_frog_n,
"frog_omega": ph_has_frog_omega,
"frog_w": ph_has_frog_w,
"frog_square": ph_has_frog_square,
"frog_se": ph_has_se_frogs,
"treasure_map": ph_has_treasure_map,
# Combined States
"explosives": ph_has_explosives,
"boom": ph_has_explosives,
"damage": ph_has_damage,
"cave_damage": ph_has_cave_damage,
"can_kill_bat": ph_can_kill_bat,
"can_kill_blue_chu": ph_can_kill_blue_chu,
"can_kill_phantom_eye": ph_can_kill_phantom_eyes,
"can_kill_eye_brute": ph_can_kill_eye_brute,
"can_kill_bubble": ph_can_kill_bubble,
"can_kill_yook": ph_can_kill_yook,
"yook": ph_can_kill_yook,
"hard_yook": ph_can_kill_dark_yook,
"dark_yook": ph_can_kill_dark_yook,
"can_steal_from_phantom": ph_totok_phantom_steal_object,
"range": ph_has_range,
"long_range": ph_has_range,
"short_range": ph_has_short_range,
"mid_range": ph_has_mid_range,
"mid_range_pots": ph_has_mid_range_pots,
"fire_sword": ph_has_fire_sword,
"super_shield": ph_has_super_shield,
"beam_sword": ph_has_beam_sword,
"sword_beams": ph_has_beam_sword,
"cuccoo_dig": ph_cuccoo_dig,
"can_make_phantom_sword": ph_can_make_phantom_sword,
"can_hit_spin_switches": ph_can_hit_spin_switches,
"can_hit_spiral_wall_switches": ph_spiral_wall_switches,
"quick_switches": ph_quick_switches,
"can_cut_trees": ph_can_cut_small_trees,
"can_cut_bamboo": ph_can_cut_small_trees,
# Rupee Logic
"rupees": ph_has_rupees,
"can_farm_rupees": ph_can_farm_rupees,
"island_shop": ph_island_shop,
"freebie_card": ph_has_freebie_card,
"beedle_shop": ph_beedle_shop,
"has_beedle_points": ph_has_beedle_points,
"can_get_beedle_bronze": ph_can_get_beedle_bronze,
"can_buy_gem": ph_can_buy_gem,
"can_buy_quiver": ph_can_buy_quiver,
"can_buy_chu_bag": ph_can_buy_chu_bag,
"can_buy_heart": ph_can_buy_heart,
"can_buy_bomb_bag": ph_can_buy_bomb_bag,
# Options
"glitched_logic": ph_option_glitched_logic,
"glitched": ph_option_glitched_logic,
"normal_logic": ph_option_normal_logic,
"hard_logic": ph_option_hard_logic,
"not_glitched_logic": ph_option_not_glitched_logic,
"keysanity": ph_option_keysanity,
"vanilla_keys": ph_option_keys_vanilla,
"keys_in_own_dungeon": ph_option_keys_in_own_dungeon,
"phantoms_hard": ph_option_phantoms_hard,
"phantoms_med": ph_option_phantoms_med,
"phantoms_easy": ph_option_phantoms_easy,
"phantoms_sword_only": ph_option_phantoms_sword_only,
"clever_pots": ph_clever_pots,
"can_hit_switches": ph_can_hit_switches,
"clever_bombs": ph_clever_bombs,
"randomize_minigames": ph_option_randomize_minigames,
"randomize_frogs": ph_option_randomize_frogs,
"start_with_frogs": ph_option_start_with_frogs,
"randomize_triforce_crest": ph_option_triforce_crest,
"has_required_metals": ph_has_required_metals,
"has_zauz_required_metals": ph_zauz_required_metals,
"randomize_masked_beedle": ph_option_randomize_masked_beedle,
"bellum_access_phantom_door": ph_goal_option_phantom_door,
"bellum_access_staircase": ph_goal_option_staircase,
"bellum_access_warp": ph_goal_option_warp,
"bellum_access_bellumbeck": ph_goal_option_spawn_bellumbeck,
"instant_goal": ph_goal_option_instant_goal,
"boat_needs_sea_chart": ph_option_boat_requires_sea_chart,
"require_chart": ph_require_sea_chart,
"require_sea_chart": ph_require_sea_chart,
"vanilla_fog": ph_option_fog_vanilla,
"open_ghost_ship": ph_option_fog_open,
"randomize_harrow": ph_option_randomize_harrow,
"goal_dungeons": ph_option_goal_dungeons,
"goal_metal_hunt": ph_option_goal_metal_hunt,
"goal_midway": ph_option_goal_midway,
"can_pass_sea_monsters": ph_can_pass_sea_monsters,
"charty_sea_monster": ph_charted_sea_monsters,
"no_time_logic": ph_option_time_no_logic,
"require_ph": ph_option_ph_required,
"has_time": ph_has_time,
"is_ut": ph_is_ut,
"ut_glitched": ph_UT_glitched_logic,
"ut_pedestals_vanilla": ph_ut_pedestals_vanilla,
# Key Logic
"small_keys": ph_has_small_keys,
"boss_key": ph_has_boss_key,
"simple_boss_key": ph_has_boss_key_simple,
"force_gems": ph_has_force_gems,
"shape_crystal": ph_has_shape_crystal,
# Harder Logic
"can_kill_phantoms": ph_can_kill_phantoms,
"can_kill_phantoms_traps": ph_can_kill_phantoms_traps,
"tricky_switches": ph_can_hit_tricky_switches,
"hammer_clip": ph_can_hammer_clip,
"bombchu_switches": ph_can_hit_bombchu_switches,
"boomerang_return": ph_can_boomerang_return,
"arrow_despawn": ph_can_arrow_despawn,
"bombchu_camera_lock": ph_can_bcl,
"bcl": ph_can_bcl,
"sword_glitch": ph_can_sword_glitch,
"scroll_clip": ph_can_sword_scroll_clip,
"sword_scroll_clip": ph_can_sword_scroll_clip,
"grapple_glitch": ph_can_grapple_glitch,
# Specific Location
# Overworld
"boat_access": ph_boat_access,
"can_reach_mp2": ph_can_reach_mp2,
"can_reach_mp2_top": ph_can_reach_mp2_top,
"mp2_bypass": ph_mp2_bypass,
"mp2_bypass_fore": ph_mp2_bypass_fore,
"mp3": ph_mp3,
"mp3_back": ph_mp3_back,
"mp_rat": ph_mercay_passage_rat,
"mercay_passage_rat": ph_mercay_passage_rat,
"ember_grapple": ph_ember_grapple_chest,
"bannan_scroll": ph_bannan_scroll,
"bannan_sea_monster": ph_bannan_sea_monster,
"salvage_courage_crest": ph_salvage_courage_crest,
"ocean_sw_west": ph_can_enter_ocean_sw_west,
"ss_wayfarer": ph_ss_wayfarer,
"nyave_fight": ph_nyave_fight,
"se_ocean": ph_enter_se_ocean,
"salvage_behind_bannan": ph_salvage_behind_bannan,
"oshus_gem": ph_oshus_gem,
"ruins_geozards": ph_ruins_geozards,
"ruins_water": ph_ruins_lower_water,
"ruins_stalfos_n": ph_ruins_stalfos_n,
"ruins_stalfos_s": ph_ruins_stalfos_n,
"ice_field": ph_ice_field,
# ToF
"tof_3f": ph_tof_3f,
"tof_maze": ph_tof_maze,
"tof_key_drop": ph_tof_key_drop,
"tof_3f_key_door": ph_tof_3f_key_door,
"tof_bk": ph_tof_enter_blaaz,
"tof_blaaz": ph_tof_blaaz,
# ToW
"tow_b1": ph_tow_b1,
"tow_key": ph_tow_key_door,
"tow_cyclok": ph_tow_enter_cyclok,
# ToC
"enter_toc": ph_can_enter_toc,
"toc_door_1": ph_toc_key_door_1,
"toc_door_2": ph_toc_key_door_2,
"toc_door_3": ph_toc_key_door_3,
"toc_1f_west": ph_toc_switch_1,
"toc_grapple": ph_toc_grapple_chest,
"toc_beamos_ut": ph_toc_beamos_ut,
"toc_crystal_south": ph_toc_crystal_south,
"toc_crystal_south_abstract": ph_toc_crystal_south_abstract,
"toc_spike_corridor": ph_toc_spike_corridor,
"toc_switch_state": ph_toc_final_switch_state,
"toc_boss_key": ph_toc_boss_key,
# gs
"ghost_ship": ph_has_ghost_ship_access,
"enter_gs": ph_has_ghost_ship_access,
"gs_triangle": ph_has_gs_triangle_crystal,
"gs_barrel": ph_ghost_ship_barrel,
"beat_gs": ph_beat_ghost_ship,
# GT
"goron_shortcut": ph_goron_shortcut,
"goron_south_reverse": ph_goron_south_reverse,
"goron_entrance": ph_goron_entrance,
"goron_chus": ph_goron_chus,
"meet_gorons": ph_meet_all_gorons,
"gt_b1": ph_gt_b1,
"gt_b2_back": ph_gt_b2_back,
"gt_enter_dongo": ph_gt_enter_dongo,
"gt_dongo": ph_can_beat_dongo,
# ToI
"toi_3f_boomerang": ph_toi_3f_boomerang,
"toi_b2": ph_toi_b2,
"toi_key_doors": ph_toi_key_doors,
"toi_key_door_1": ph_toi_key_door_1,
"toi_key_door_2": ph_toi_key_door_2,
"toi_key_door_3": ph_toi_key_door_3,
"toi_2f": ph_toi_2f,
"toi_3f": ph_toi_3f,
"toi_3f_switch": ph_toi_3f_switch,
"toi_miniboss": ph_toi_miniboss,
"toi_shortcut": ph_toi_shortcut,
"toi_b1": ph_toi_b1,
"toi_key_1_ut": ph_toi_key_door_1_ut,
"toi_b1_switch": ph_toi_b2_switch_room,
"toi_b2_north": ph_toi_b2_north,
"toi_boss_door": ph_toi_boss_door,
# MT
"mutoh_entrance": ph_mutoh_entrance,
"mutoh_water": ph_mutoh_water,
"mutoh_key_doors": ph_mutoh_key_doors,
"mutoh_bk_chest": ph_mutoh_bk_chest,
"mutoh_boss_door": ph_mutoh_boss_door,
# Goal
"bellum_warp": ph_totok_blue_warp,
"bellum_staircase": ph_totok_bellum_staircase,
"can_beat_bellum": ph_can_beat_bellum,
"can_beat_ghost_ship_fight": ph_can_beat_ghost_ship_fight,
"can_beat_bellumbeck": ph_can_beat_bellumbeck,
"bellumbeck_quick_finish": ph_bellumbeck_quick_finish,
"win_on_metals": ph_win_on_metals,
# Time Logic
"totok_1f": ph_totok_1f,
"totok_1f_chest": ph_totok_1f_chest,
"totok_1f_chart": ph_totok_1f_chart,
"totok_b1": ph_totok_b1,
"totok_b1_key": ph_totok_b1_key,
"totok_b1_phantom": ph_totok_b1_phantom,
"totok_b1_bow": ph_totok_b1_bow,
"totok_b2": ph_totok_b2,
"totok_b2_key": ph_totok_b2_key,
"totok_b2_phantom": ph_totok_b2_phantom,
"totok_b2_chu": ph_totok_b2_chu,
"totok_b3": ph_totok_b3,
"totok_b3_nw": ph_totok_b3_nw,
"totok_b3_se": ph_totok_b3_se,
"totok_b3_sw": ph_totok_b3_sw,
"totok_b3_bow": ph_totok_b3_bow,
"totok_b3_key": ph_totok_b3_key,
"totok_b3_phantom": ph_totok_b3_phantom,
"totok_b35": ph_totok_b35,
"totok_b4": ph_totok_b4,
"totok_b4_key": ph_totok_b4_key,
"totok_b4_eyes": ph_totok_b4_eyes,
"totok_b4_phantom": ph_totok_b4_phantom,
"totok_b5": ph_totok_b5,
"totok_b5_alt": ph_totok_b5_alt,
"totok_b5_chest": ph_totok_b5_chest,
"totok_b5_alt_chest": ph_totok_b5_alt_chest,
"totok_b6": ph_totok_b6,
"totok_b6_bow": ph_totok_b6_bow,
"totok_b6_phantom": ph_totok_b6_phantom,
"totok_b6_crest": ph_totok_b6_crest,
"totok_b7": ph_totok_b7,
"totok_b7_crystal": ph_totok_b7_crystal,
"totok_b7_switch_chest": ph_totok_b7_switch_chest,
"totok_b8": ph_totok_b8,
"totok_b8_phantom": ph_totok_b8_phantom,
"totok_b9": ph_totok_b9,
"totok_b7_phantom": ph_totok_b7_phantom,
"totok_b9_phantom": ph_totok_b9_phantom,
"totok_b9_ghosts": ph_totok_b9_ghosts,
"totok_b9_corner_chest": ph_totok_b9_corner_chest,
"totok_b8_2_crystal_chest": ph_totok_b8_2_crystal_chest,
"totok_b10": ph_totok_b10,
"totok_b10_key": ph_totok_b10_key,
"totok_b10_phantom": ph_totok_b10_phantom,
"totok_b10_eye": ph_totok_b10_eye,
"totok_b10_hammer": ph_totok_b10_hammer,
"totok_b11": ph_totok_b11,
"totok_b11_phantom": ph_totok_b11_phantom,
"totok_b11_eyes": ph_totok_b11_eyes,
"totok_b12": ph_totok_b12,
"totok_b12_nw": ph_totok_b12_nw,
"totok_b12_ne": ph_totok_b12_ne,
"totok_b12_phantom": ph_totok_b12_phantom,
"totok_b12_ghost": ph_totok_b12_ghost,
"totok_b12_hammer": ph_totok_b12_hammer,
"totok_b13": ph_totok_b13,
"totok_b13_chest": ph_totok_b13_chest,
"b13_door": ph_totok_b13_door,
# State Rules
"has": ph_has
}