From 1c69fb3c3ca650014179f6a30cf053986123f4f1 Mon Sep 17 00:00:00 2001 From: alwaysintreble Date: Tue, 21 Mar 2023 15:21:27 -0500 Subject: [PATCH] The Messenger: Add more difficult logic options (#1550) --- test/TestBase.py | 8 +- worlds/messenger/Options.py | 18 +++- worlds/messenger/Rules.py | 126 ++++++++++++++++++++++--- worlds/messenger/SubClasses.py | 8 +- worlds/messenger/__init__.py | 21 ++++- worlds/messenger/test/TestAccess.py | 30 ++---- worlds/messenger/test/TestLogic.py | 107 +++++++++++++++++++++ worlds/messenger/test/TestNotes.py | 5 + worlds/messenger/test/TestShopChest.py | 4 +- 9 files changed, 277 insertions(+), 50 deletions(-) create mode 100644 worlds/messenger/test/TestLogic.py diff --git a/test/TestBase.py b/test/TestBase.py index a2c9bc28..17fe6425 100644 --- a/test/TestBase.py +++ b/test/TestBase.py @@ -199,11 +199,15 @@ class WorldTestBase(unittest.TestCase): self.collect_all_but(all_items) for location in self.multiworld.get_locations(): - self.assertEqual(self.multiworld.state.can_reach(location), location.name not in locations) + loc_reachable = self.multiworld.state.can_reach(location) + self.assertEqual(loc_reachable, location.name not in locations, + f"{location.name} is reachable without {all_items}" if loc_reachable + else f"{location.name} is not reachable without {all_items}") for item_names in possible_items: items = self.collect_by_name(item_names) for location in locations: - self.assertTrue(self.can_reach_location(location)) + self.assertTrue(self.can_reach_location(location), + f"{location} not reachable with {item_names}") self.remove(items) def assertBeatable(self, beatable: bool): diff --git a/worlds/messenger/Options.py b/worlds/messenger/Options.py index 1baca12e..47ebf66f 100644 --- a/worlds/messenger/Options.py +++ b/worlds/messenger/Options.py @@ -7,9 +7,19 @@ class MessengerAccessibility(Accessibility): __doc__ = Accessibility.__doc__.replace(f"default {Accessibility.default}", f"default {default}") -class Logic(DefaultOnToggle): - """Whether the seed should be guaranteed completable.""" - display_name = "Use Logic" +class Logic(Choice): + """ + The level of logic to use when determining what locations in your world are accessible. + Normal can require damage boosts, but otherwise approachable for someone who has beaten the game. + Hard has some easier speedrunning tricks in logic. May need to leash. + Challenging contains more medium and hard difficulty speedrunning tricks. + OoB places everything with the minimum amount of rules possible. Expect to do OoB. Not guaranteed completable. + """ + display_name = "Logic Level" + option_normal = 0 + option_hard = 1 + option_challenging = 2 + option_oob = 3 class PowerSeals(DefaultOnToggle): @@ -55,7 +65,7 @@ class RequiredSeals(Range): messenger_options = { "accessibility": MessengerAccessibility, - "enable_logic": Logic, + "logic_level": Logic, "shuffle_seals": PowerSeals, "goal": Goal, "music_box": MusicBox, diff --git a/worlds/messenger/Rules.py b/worlds/messenger/Rules.py index a7e0a1a7..24e03544 100644 --- a/worlds/messenger/Rules.py +++ b/worlds/messenger/Rules.py @@ -1,7 +1,7 @@ from typing import Dict, Callable, TYPE_CHECKING from BaseClasses import CollectionState, MultiWorld -from worlds.generic.Rules import set_rule, allow_self_locking_items +from worlds.generic.Rules import set_rule, allow_self_locking_items, add_rule from .Options import MessengerAccessibility, Goal from .Constants import NOTES, PHOBEKINS @@ -14,12 +14,14 @@ else: class MessengerRules: player: int world: MessengerWorld + region_rules: Dict[str, Callable[[CollectionState], bool]] + location_rules: Dict[str, Callable[[CollectionState], bool]] - def __init__(self, world: MessengerWorld): + def __init__(self, world: MessengerWorld) -> None: self.player = world.player self.world = world - self.region_rules: Dict[str, Callable[[CollectionState], bool]] = { + self.region_rules = { "Ninja Village": self.has_wingsuit, "Autumn Hills": self.has_wingsuit, "Catacombs": self.has_wingsuit, @@ -27,13 +29,13 @@ class MessengerRules: "Searing Crags Upper": self.has_vertical, "Cloud Ruins": lambda state: self.has_wingsuit(state) and state.has("Ruxxtin's Amulet", self.player), "Underworld": self.has_tabi, - "Forlorn Temple": lambda state: state.has_all(PHOBEKINS, self.player) and self.has_wingsuit(state), + "Forlorn Temple": lambda state: state.has_all({"Wingsuit", *PHOBEKINS}, self.player), "Glacial Peak": self.has_vertical, "Elemental Skylands": lambda state: state.has("Fairy Bottle", self.player), - "Music Box": lambda state: state.has_all(NOTES, self.player) + "Music Box": lambda state: state.has_all(set(NOTES), self.player) and self.has_vertical(state) } - self.location_rules: Dict[str, Callable[[CollectionState], bool]] = { + self.location_rules = { # ninja village "Ninja Village Seal - Tree House": self.has_dart, # autumn hills @@ -88,8 +90,11 @@ class MessengerRules: return self.has_wingsuit(state) or self.has_dart(state) def has_enough_seals(self, state: CollectionState) -> bool: - required_seals = state.multiworld.worlds[self.player].required_seals - return state.has("Power Seal", self.player, required_seals) + return not self.world.required_seals or state.has("Power Seal", self.player, self.world.required_seals) + + def true(self, state: CollectionState) -> bool: + """I know this is stupid, but it's easier to read in the dicts.""" + return True def set_messenger_rules(self) -> None: multiworld = self.world.multiworld @@ -105,14 +110,111 @@ class MessengerRules: set_rule(multiworld.get_entrance("Tower HQ -> Music Box", self.player), lambda state: state.has("Shop Chest", self.player)) - if multiworld.enable_logic[self.player]: - multiworld.completion_condition[self.player] = lambda state: state.has("Rescue Phantom", self.player) - else: - multiworld.accessibility[self.player].value = MessengerAccessibility.option_minimal + multiworld.completion_condition[self.player] = lambda state: state.has("Rescue Phantom", self.player) if multiworld.accessibility[self.player] > MessengerAccessibility.option_locations: set_self_locking_items(multiworld, self.player) +class MessengerHardRules(MessengerRules): + extra_rules: Dict[str, Callable[[CollectionState], bool]] + + def __init__(self, world: MessengerWorld) -> None: + super().__init__(world) + + self.region_rules.update({ + "Ninja Village": self.has_vertical, + "Autumn Hills": self.has_vertical, + "Catacombs": self.has_vertical, + "Bamboo Creek": self.has_vertical, + "Forlorn Temple": lambda state: self.has_vertical(state) and state.has_all(set(PHOBEKINS), self.player), + "Searing Crags Upper": self.true, + "Glacial Peak": self.true, + }) + + self.location_rules.update({ + "Howling Grotto Seal - Windy Saws and Balls": self.true, + "Glacial Peak Seal - Projectile Spike Pit": self.true, + }) + + self.extra_rules = { + "Climbing Claws": self.has_dart, + "Astral Seed": self.has_dart, + "Candle": self.has_dart, + "Key of Strength": lambda state: state.has("Power Thistle", self.player) or + self.has_dart(state) or + self.has_windmill(state), + "Key of Symbiosis": self.has_windmill, + "Autumn Hills Seal - Spike Ball Darts": lambda state: (self.has_dart(state) and self.has_windmill(state)) + or self.has_wingsuit(state), + "Glacial Peak Seal - Glacial Air Swag": self.has_windmill, + "Underworld Seal - Fireball Wave": lambda state: self.has_wingsuit(state) + or state.has_all({"Ninja Tabi", "Windmill Shuriken"}, + self.player), + } + + def has_windmill(self, state: CollectionState) -> bool: + return state.has("Windmill Shuriken", self.player) + + def set_messenger_rules(self) -> None: + super().set_messenger_rules() + for loc, rule in self.extra_rules.items(): + add_rule(self.world.multiworld.get_location(loc, self.player), rule, "or") + + +class MessengerChallengeRules(MessengerHardRules): + def __init__(self, world: MessengerWorld) -> None: + super().__init__(world) + + self.region_rules.update({ + "Forlorn Temple": lambda state: (self.has_vertical(state) and state.has_all(set(PHOBEKINS), self.player)) + or state.has_all({"Wingsuit", "Windmill Shuriken"}, self.player), + "Elemental Skylands": lambda state: self.has_wingsuit(state) or state.has("Fairy Bottle", self.player) + }) + + self.location_rules.update({ + "Fairy Bottle": self.true, + "Howling Grotto Seal - Crushing Pits": self.true, + "Underworld Seal - Sharp and Windy Climb": self.true, + "Riviere Turquoise Seal - Flower Power": self.true, + }) + + self.extra_rules.update({ + "Key of Hope": self.has_vertical, + "Key of Symbiosis": lambda state: self.has_vertical(state) or self.has_windmill(state), + }) + + +class MessengerOOBRules(MessengerRules): + def __init__(self, world: MessengerWorld) -> None: + self.world = world + self.player = world.player + + self.region_rules = { + "Elemental Skylands": lambda state: state.has_any({"Wingsuit", "Rope Dart", "Fairy Bottle"}, self.player), + "Music Box": lambda state: state.has_all(set(NOTES), self.player) + } + + self.location_rules = { + "Claustro": self.has_wingsuit, + "Key of Strength": self.has_wingsuit, + "Key of Love": lambda state: state.has_all({"Sun Crest", "Moon Crest"}, self.player), + "Pyro": self.has_tabi, + "Key of Chaos": self.has_tabi, + "Key of Courage": lambda state: state.has_all({"Demon King Crown", "Fairy Bottle"}, self.player), + "Autumn Hills Seal - Spike Ball Darts": self.has_dart, + "Ninja Village Seal - Tree House": self.has_dart, + "Underworld Seal - Fireball Wave": lambda state: state.has_any({"Wingsuit", "Windmill Shuriken"}, + self.player), + "Tower of Time Seal - Time Waster Seal": self.has_dart, + "Shop Chest": self.has_enough_seals + } + + def set_messenger_rules(self) -> None: + super().set_messenger_rules() + self.world.multiworld.completion_condition[self.player] = lambda state: True + self.world.multiworld.accessibility[self.player].value = MessengerAccessibility.option_minimal + + def set_self_locking_items(multiworld: MultiWorld, player: int) -> None: # do the ones for seal shuffle on and off first allow_self_locking_items(multiworld.get_location("Key of Strength", player), "Power Thistle") diff --git a/worlds/messenger/SubClasses.py b/worlds/messenger/SubClasses.py index 32803f5e..1f26a426 100644 --- a/worlds/messenger/SubClasses.py +++ b/worlds/messenger/SubClasses.py @@ -12,7 +12,7 @@ else: class MessengerRegion(Region): - def __init__(self, name: str, world: MessengerWorld): + def __init__(self, name: str, world: MessengerWorld) -> None: super().__init__(name, world.player, world.multiworld) self.add_locations(self.multiworld.worlds[self.player].location_name_to_id) world.multiworld.regions.append(self) @@ -38,7 +38,7 @@ class MessengerRegion(Region): class MessengerLocation(Location): game = "The Messenger" - def __init__(self, name: str, parent: MessengerRegion, loc_id: Optional[int]): + def __init__(self, name: str, parent: MessengerRegion, loc_id: Optional[int]) -> None: super().__init__(parent.player, name, loc_id, parent) if loc_id is None: self.place_locked_item(MessengerItem(name, parent.player, None)) @@ -47,8 +47,8 @@ class MessengerLocation(Location): class MessengerItem(Item): game = "The Messenger" - def __init__(self, name: str, player: int, item_id: Optional[int] = None): - if name in {*NOTES, *PROG_ITEMS, *PHOBEKINS} or item_id is None: + def __init__(self, name: str, player: int, item_id: Optional[int] = None, override_progression: bool = False) -> None: + if name in {*NOTES, *PROG_ITEMS, *PHOBEKINS} or item_id is None or override_progression: item_class = ItemClassification.progression elif name in USEFUL_ITEMS: item_class = ItemClassification.useful diff --git a/worlds/messenger/__init__.py b/worlds/messenger/__init__.py index 1c42b304..495ec80b 100644 --- a/worlds/messenger/__init__.py +++ b/worlds/messenger/__init__.py @@ -3,10 +3,10 @@ from typing import Dict, Any, List, Optional from BaseClasses import Tutorial, ItemClassification from worlds.AutoWorld import World, WebWorld from .Constants import NOTES, PROG_ITEMS, PHOBEKINS, USEFUL_ITEMS, ALWAYS_LOCATIONS, SEALS, ALL_ITEMS -from .Options import messenger_options, NotesNeeded, Goal, PowerSeals +from .Options import messenger_options, NotesNeeded, Goal, PowerSeals, Logic from .Regions import REGIONS, REGION_CONNECTIONS -from .Rules import MessengerRules from .SubClasses import MessengerRegion, MessengerItem +from . import Rules class MessengerWeb(WebWorld): @@ -100,7 +100,15 @@ class MessengerWorld(World): self.multiworld.itempool += itempool def set_rules(self) -> None: - MessengerRules(self).set_messenger_rules() + logic = self.multiworld.logic_level[self.player] + if logic == Logic.option_normal: + Rules.MessengerRules(self).set_messenger_rules() + elif logic == Logic.option_hard: + Rules.MessengerHardRules(self).set_messenger_rules() + elif logic == Logic.option_challenging: + Rules.MessengerChallengeRules(self).set_messenger_rules() + else: + Rules.MessengerOOBRules(self).set_messenger_rules() def fill_slot_data(self) -> Dict[str, Any]: locations: Dict[int, List[str]] = {} @@ -114,7 +122,8 @@ class MessengerWorld(World): "music_box": self.multiworld.music_box[self.player].value, "required_seals": self.required_seals, "locations": locations, - "settings": {"Difficulty": "Basic" if not self.multiworld.shuffle_seals[self.player] else "Advanced"} + "settings": {"Difficulty": "Basic" if not self.multiworld.shuffle_seals[self.player] else "Advanced"}, + "logic": self.multiworld.logic_level[self.player].current_key, } def get_filler_item_name(self) -> str: @@ -122,4 +131,6 @@ class MessengerWorld(World): def create_item(self, name: str) -> MessengerItem: item_id: Optional[int] = self.item_name_to_id.get(name, None) - return MessengerItem(name, self.player, item_id) + override_prog = name in {"Windmill Shuriken"} and getattr(self, "multiworld") is not None \ + and self.multiworld.logic_level[self.player] > Logic.option_normal + return MessengerItem(name, self.player, item_id, override_prog) diff --git a/worlds/messenger/test/TestAccess.py b/worlds/messenger/test/TestAccess.py index eba4ad9b..83bdc611 100644 --- a/worlds/messenger/test/TestAccess.py +++ b/worlds/messenger/test/TestAccess.py @@ -1,6 +1,5 @@ from . import MessengerTestBase from ..Constants import NOTES, PHOBEKINS -from ..Options import MessengerAccessibility class AccessTest(MessengerTestBase): @@ -46,22 +45,22 @@ class AccessTest(MessengerTestBase): "Glacial Peak Seal - Ice Climbers", "Tower of Time Seal - Time Waster Seal", "Underworld Seal - Rising Fanta", "Key of Symbiosis", "Elemental Skylands Seal - Water", "Elemental Skylands Seal - Fire", "Candle", - "Ninja Village Seal - Tree House", "Climbing Claws", "Key of Hope", - "Autumn Hills Seal - Trip Saws", "Autumn Hills Seal - Double Swing Saws", - "Autumn Hills Seal - Spike Ball Swing", "Autumn Hills Seal - Spike Ball Darts", "Necro", - "Ruxxtin's Amulet", "Catacombs Seal - Triple Spike Crushers", "Catacombs Seal - Crusher Gauntlet", + "Climbing Claws", "Key of Hope", "Autumn Hills Seal - Trip Saws", + "Autumn Hills Seal - Double Swing Saws", "Autumn Hills Seal - Spike Ball Swing", + "Autumn Hills Seal - Spike Ball Darts", "Necro", "Ruxxtin's Amulet", + "Catacombs Seal - Triple Spike Crushers", "Catacombs Seal - Crusher Gauntlet", "Catacombs Seal - Dirty Pond", "Claustro", "Acro", "Bamboo Creek Seal - Spike Crushers and Doors", "Bamboo Creek Seal - Spike Ball Pits", "Bamboo Creek Seal - Spike Crushers and Doors v2", "Howling Grotto Seal - Crushing Pits", "Howling Grotto Seal - Windy Saws and Balls", - "Tower of Time Seal - Lantern Climb", "Demon King Crown", "Cloud Ruins Seal - Ghost Pit", - "Cloud Ruins Seal - Toothbrush Alley", "Cloud Ruins Seal - Saw Pit", "Cloud Ruins Seal - Money Farm Room", + "Demon King Crown", "Cloud Ruins Seal - Ghost Pit", "Cloud Ruins Seal - Toothbrush Alley", + "Cloud Ruins Seal - Saw Pit", "Cloud Ruins Seal - Money Farm Room", "Tower of Time Seal - Lantern Climb", "Tower of Time Seal - Arcane Orbs", "Underworld Seal - Sharp and Windy Climb", "Underworld Seal - Fireball Wave", "Elemental Skylands Seal - Air", "Forlorn Temple Seal - Rocket Maze", "Forlorn Temple Seal - Rocket Sunset", "Power Thistle", "Key of Strength", "Glacial Peak Seal - Projectile Spike Pit", "Glacial Peak Seal - Glacial Air Swag", "Fairy Bottle", "Riviere Turquoise Seal - Flower Power", "Searing Crags Seal - Triple Ball Spinner", "Searing Crags Seal - Raining Rocks", - "Searing Crags Seal - Rhythm Rocks", "Astral Seed", "Astral Tea Leaves"] + "Searing Crags Seal - Rhythm Rocks", "Astral Seed", "Astral Tea Leaves", "Rescue Phantom"] items = [["Wingsuit", "Rope Dart"]] self.assertAccessDependency(locations, items) @@ -116,8 +115,8 @@ class AccessTest(MessengerTestBase): class ItemsAccessTest(MessengerTestBase): options = { - "shuffle_seals": False, - "accessibility": MessengerAccessibility.option_items + "shuffle_seals": "false", + "accessibility": "items" } def testSelfLockingItems(self) -> None: @@ -136,14 +135,3 @@ class ItemsAccessTest(MessengerTestBase): with self.subTest("Fulfills Accessibility", location=loc, item=item_name): self.assertTrue(self.multiworld.get_location(loc, self.player).can_fill(self.multiworld.state, item, True)) - -class NoLogicTest(MessengerTestBase): - options = { - "enable_logic": "false" - } - - def testNoLogic(self) -> None: - """Test some funny locations to make sure they aren't reachable but we can still win""" - self.assertEqual(self.can_reach_location("Pyro"), False) - self.assertEqual(self.can_reach_location("Rescue Phantom"), False) - self.assertBeatable(True) diff --git a/worlds/messenger/test/TestLogic.py b/worlds/messenger/test/TestLogic.py new file mode 100644 index 00000000..f12f3bda --- /dev/null +++ b/worlds/messenger/test/TestLogic.py @@ -0,0 +1,107 @@ +from BaseClasses import ItemClassification +from . import MessengerTestBase + + +class HardLogicTest(MessengerTestBase): + options = { + "logic_level": "hard" + } + + def testVertical(self) -> None: + """Test the locations that still require wingsuit or rope dart.""" + locations = [ + # tower of time + "Tower of Time Seal - Time Waster Seal", "Tower of Time Seal - Lantern Climb", + "Tower of Time Seal - Arcane Orbs", + # ninja village + "Candle", "Astral Seed", "Ninja Village Seal - Tree House", + # autumn hills + "Climbing Claws", "Key of Hope", + "Autumn Hills Seal - Trip Saws", "Autumn Hills Seal - Double Swing Saws", + "Autumn Hills Seal - Spike Ball Swing", "Autumn Hills Seal - Spike Ball Darts", + # forlorn temple + "Demon King Crown", + "Forlorn Temple Seal - Rocket Maze", "Forlorn Temple Seal - Rocket Sunset", + # catacombs + "Necro", "Ruxxtin's Amulet", + "Catacombs Seal - Triple Spike Crushers", "Catacombs Seal - Crusher Gauntlet", "Catacombs Seal - Dirty Pond", + # bamboo creek + "Claustro", + "Bamboo Creek Seal - Spike Crushers and Doors", "Bamboo Creek Seal - Spike Ball Pits", + "Bamboo Creek Seal - Spike Crushers and Doors v2", + # howling grotto + "Howling Grotto Seal - Crushing Pits", "Howling Grotto Seal - Crushing Pits", + # glacial peak + "Glacial Peak Seal - Ice Climbers", + # cloud ruins + "Acro", "Cloud Ruins Seal - Ghost Pit", + "Cloud Ruins Seal - Toothbrush Alley", "Cloud Ruins Seal - Saw Pit", "Cloud Ruins Seal - Money Farm Room", + # underworld + "Underworld Seal - Rising Fanta", "Underworld Seal - Sharp and Windy Climb", + # riviere turquoise + "Fairy Bottle", "Riviere Turquoise Seal - Flower Power", + # elemental skylands + "Elemental Skylands Seal - Air", "Elemental Skylands Seal - Water", "Elemental Skylands Seal - Fire", + # phantom + "Rescue Phantom", + ] + items = [["Wingsuit", "Rope Dart"]] + self.assertAccessDependency(locations, items) + + def testWindmill(self) -> None: + """Windmill Shuriken isn't progression on normal difficulty, so test it's marked correctly and required.""" + self.assertEqual(ItemClassification.progression, self.get_item_by_name("Windmill Shuriken").classification) + windmill_locs = [ + "Key of Strength", + "Key of Symbiosis", + "Underworld Seal - Fireball Wave" + ] + for loc in windmill_locs: + with self.subTest("can't reach location with nothing", location=loc): + self.assertFalse(self.can_reach_location(loc)) + + items = self.get_items_by_name(["Windmill Shuriken", "Ninja Tabi", "Fairy Bottle"]) + self.collect(items) + for loc in windmill_locs: + with self.subTest("can reach with Windmill", location=loc): + self.assertTrue(self.can_reach_location(loc)) + + special_loc = "Autumn Hills Seal - Spike Ball Darts" + item = self.get_item_by_name("Wingsuit") + self.collect(item) + self.assertTrue(self.can_reach_location(special_loc)) + self.remove(item) + + item = self.get_item_by_name("Rope Dart") + self.collect(item) + self.assertTrue(self.can_reach_location(special_loc)) + + +class ChallengingLogicTest(MessengerTestBase): + options = { + "logic_level": "challenging" + } + + +class NoLogicTest(MessengerTestBase): + options = { + "logic_level": "oob" + } + + def testAccess(self) -> None: + """Test the locations with rules still require things.""" + all_locations = [ + "Claustro", "Key of Strength", "Key of Symbiosis", "Key of Love", "Pyro", "Key of Chaos", "Key of Courage", + "Autumn Hills Seal - Spike Ball Darts", "Ninja Village Seal - Tree House", "Underworld Seal - Fireball Wave", + "Tower of Time Seal - Time Waster Seal", "Rescue Phantom", "Elemental Skylands Seal - Air", + "Elemental Skylands Seal - Water", "Elemental Skylands Seal - Fire", + ] + for loc in all_locations: + with self.subTest("Default unreachables", location=loc): + self.assertFalse(self.can_reach_location(loc)) + + def testNoLogic(self) -> None: + """Test some funny locations to make sure they aren't reachable, but we can still win""" + self.assertEqual(self.can_reach_location("Pyro"), False) + self.assertEqual(self.can_reach_location("Rescue Phantom"), False) + self.assertBeatable(True) diff --git a/worlds/messenger/test/TestNotes.py b/worlds/messenger/test/TestNotes.py index 07745e33..c4292e49 100644 --- a/worlds/messenger/test/TestNotes.py +++ b/worlds/messenger/test/TestNotes.py @@ -27,4 +27,9 @@ class DefaultGoalTest(MessengerTestBase): def testGoal(self) -> None: self.assertBeatable(False) self.collect_by_name(NOTES) + rope_dart = self.get_item_by_name("Rope Dart") + self.collect(rope_dart) + self.assertBeatable(True) + self.remove(rope_dart) + self.collect_by_name("Wingsuit") self.assertBeatable(True) diff --git a/worlds/messenger/test/TestShopChest.py b/worlds/messenger/test/TestShopChest.py index c3f2c4dd..9289ec99 100644 --- a/worlds/messenger/test/TestShopChest.py +++ b/worlds/messenger/test/TestShopChest.py @@ -4,11 +4,11 @@ from . import MessengerTestBase class NoLogicTest(MessengerTestBase): options = { - "enable_logic": "false", + "logic_level": "oob", "goal": "power_seal_hunt", } - def testChestAccess(self): + def testChestAccess(self) -> None: """Test to make sure we can win even though we can't reach the chest.""" self.assertEqual(self.can_reach_location("Shop Chest"), False) self.assertBeatable(True)