From 6dad2fe4903f7147f7cd3c0d403a633758494bb3 Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Sat, 17 Aug 2024 13:17:45 -0400 Subject: [PATCH] Fix bug in ladder storage rules --- worlds/tunic/er_rules.py | 10 ++++----- worlds/tunic/rules.py | 3 +-- worlds/tunic/test/test_access.py | 35 ++++++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+), 7 deletions(-) diff --git a/worlds/tunic/er_rules.py b/worlds/tunic/er_rules.py index 7172893ef1..0aae5319e2 100644 --- a/worlds/tunic/er_rules.py +++ b/worlds/tunic/er_rules.py @@ -3,7 +3,7 @@ from worlds.generic.Rules import set_rule, add_rule, forbid_item from .options import IceGrappling, LadderStorage, CombatLogic from .rules import (has_ability, has_sword, has_melee, has_ice_grapple_logic, has_lantern, has_mask, can_ladder_storage, laurels_zip, bomb_walls) -from .er_data import Portal +from .er_data import Portal, get_portal_outlet_region from .ladder_storage_data import ow_ladder_groups, region_ladders, easy_ls, medium_ls, hard_ls from .combat_logic import has_combat_reqs from BaseClasses import Region, CollectionState @@ -44,14 +44,14 @@ def set_er_region_rules(world: "TunicWorld", regions: Dict[str, Region], portal_ player = world.player options = world.options - # input scene destination tag, returns portal's name and paired portal's region + # input scene destination tag, returns portal's name and paired portal's outlet region or region def get_portal_info(portal_sd: str) -> Tuple[str, str]: for portal1, portal2 in portal_pairs.items(): if portal1.scene_destination() == portal_sd: - return portal1.name, portal2.region + return portal1.name, get_portal_outlet_region(portal2, world) if portal2.scene_destination() == portal_sd: - return portal2.name, portal1.region - raise Exception("no matches found in get_portal_info") + return portal2.name, get_portal_outlet_region(portal1, world) + raise Exception("No matches found in get_portal_info") # input scene destination tag, returns paired portal's name and region def get_paired_portal(portal_sd: str) -> Tuple[str, str]: diff --git a/worlds/tunic/rules.py b/worlds/tunic/rules.py index 31a5361b17..c87cff4b95 100644 --- a/worlds/tunic/rules.py +++ b/worlds/tunic/rules.py @@ -56,8 +56,7 @@ def has_ability(ability: str, state: CollectionState, world: "TunicWorld") -> bo # a check to see if you can whack things in melee at all def has_melee(state: CollectionState, player: int) -> bool: - return (state.has("Stick", player) or state.has("Sword Upgrade", player, 1) - or state.has("Sword", player)) + return state.has_any({"Stick", "Sword", "Sword Upgrade"}, player) def has_sword(state: CollectionState, player: int) -> bool: diff --git a/worlds/tunic/test/test_access.py b/worlds/tunic/test/test_access.py index 289b5733c7..a47f4a9a00 100644 --- a/worlds/tunic/test/test_access.py +++ b/worlds/tunic/test/test_access.py @@ -94,6 +94,41 @@ class TestERSpecial(TunicTestBase): # with these plando connections, you need to ice grapple from the back of lower zig to the front to get laurels +# ensure that ladder storage connections connect to the outlet region, not the portal's region +class TestLadderStorage(TunicTestBase): + options = {options.EntranceRando.internal_name: options.EntranceRando.option_yes, + options.AbilityShuffling.internal_name: options.AbilityShuffling.option_true, + options.HexagonQuest.internal_name: options.HexagonQuest.option_false, + options.FixedShop.internal_name: options.FixedShop.option_false, + options.LadderStorage.internal_name: options.LadderStorage.option_hard, + options.LadderStorageWithoutItems.internal_name: options.LadderStorageWithoutItems.option_false, + "plando_connections": [ + { + "entrance": "Fortress Courtyard Shop", + # "exit": "Ziggurat Portal Room Exit" + "exit": "Spawn to Far Shore" + }, + { + "entrance": "Fortress Courtyard to Beneath the Vault", + "exit": "Stick House Exit" + }, + { + "entrance": "Stick House Entrance", + "exit": "Fortress Courtyard to Overworld" + }, + { + "entrance": "Old House Waterfall Entrance", + "exit": "Ziggurat Portal Room Entrance" + }, + ]} + + def test_ls_to_shop_entrance(self) -> None: + self.collect_by_name(["Magic Orb"]) + self.assertFalse(self.can_reach_location("Fortress Courtyard - Page Near Cave")) + self.collect_by_name(["Pages 24-25 (Prayer)"]) + self.assertTrue(self.can_reach_location("Fortress Courtyard - Page Near Cave")) + + # check that it still functions if in decoupled and every single normal entrance leads to a shop class TestERDecoupledPlando(TunicTestBase): options = {options.EntranceRando.internal_name: options.EntranceRando.option_yes,