218 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			218 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
import typing
 | 
						|
 | 
						|
from . import MessengerTestBase
 | 
						|
from ..constants import NOTES, PHOBEKINS
 | 
						|
 | 
						|
 | 
						|
class AccessTest(MessengerTestBase):
 | 
						|
    options = {
 | 
						|
        "shuffle_shards": "true",
 | 
						|
    }
 | 
						|
 | 
						|
    def test_tabi(self) -> None:
 | 
						|
        """locations that hard require the Lightfoot Tabi"""
 | 
						|
        locations = [
 | 
						|
            "Searing Crags - Pyro", "Underworld - Key of Chaos", "Underworld Seal - Sharp and Windy Climb",
 | 
						|
            "Underworld Seal - Spike Wall", "Underworld Seal - Fireball Wave", "Underworld Seal - Rising Fanta",
 | 
						|
            "Sunken Shrine - Sun Crest", "Sunken Shrine - Moon Crest", "Sunken Shrine Seal - Waterfall Paradise",
 | 
						|
            "Sunken Shrine Seal - Tabi Gauntlet", "Mega Shard of the Moon", "Mega Shard of the Sun",
 | 
						|
            "Under Entrance Mega Shard", "Hot Tub Mega Shard", "Projectile Pit Mega Shard"
 | 
						|
        ]
 | 
						|
        items = [["Lightfoot Tabi"]]
 | 
						|
        self.assertAccessDependency(locations, items)
 | 
						|
 | 
						|
    def test_dart(self) -> None:
 | 
						|
        """locations that hard require the Rope Dart"""
 | 
						|
        locations = [
 | 
						|
            "Ninja Village Seal - Tree House",
 | 
						|
            "Autumn Hills - Key of Hope",
 | 
						|
            "Forlorn Temple - Demon King",
 | 
						|
            "Down Under Mega Shard",
 | 
						|
            "Howling Grotto Seal - Crushing Pits",
 | 
						|
            "Glacial Peak Seal - Ice Climbers",
 | 
						|
            "Tower of Time Seal - Time Waster",
 | 
						|
            "Tower of Time Seal - Lantern Climb",
 | 
						|
            "Tower of Time Seal - Arcane Orbs",
 | 
						|
            "Cloud Ruins Seal - Ghost Pit",
 | 
						|
            "Cloud Ruins Seal - Money Farm Room",
 | 
						|
            "Cloud Ruins Seal - Toothbrush Alley",
 | 
						|
            "Money Farm Room Mega Shard 1",
 | 
						|
            "Money Farm Room Mega Shard 2",
 | 
						|
            "Underworld Seal - Rising Fanta",
 | 
						|
            "Elemental Skylands - Key of Symbiosis",
 | 
						|
            "Elemental Skylands Seal - Water",
 | 
						|
            "Elemental Skylands Seal - Fire",
 | 
						|
            "Earth Mega Shard",
 | 
						|
            "Water Mega Shard",
 | 
						|
            "Rescue Phantom",
 | 
						|
        ]
 | 
						|
        items = [["Rope Dart"]]
 | 
						|
        self.assertAccessDependency(locations, items)
 | 
						|
 | 
						|
    def test_wingsuit(self) -> None:
 | 
						|
        """locations that hard require the Wingsuit"""
 | 
						|
        locations = [
 | 
						|
            "Ninja Village - Candle", "Ninja Village Seal - Tree House", "Autumn Hills - Climbing Claws",
 | 
						|
            "Autumn Hills - 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", "Catacombs - Necro",
 | 
						|
            "Catacombs - Ruxxtin's Amulet", "Catacombs Seal - Triple Spike Crushers",
 | 
						|
            "Catacombs Seal - Crusher Gauntlet", "Catacombs Seal - Dirty Pond", "Bamboo Creek - Claustro",
 | 
						|
            "Cloud Ruins - 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",
 | 
						|
            "Forlorn Temple - Demon King", "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", "Elemental Skylands Seal - Water",
 | 
						|
            "Elemental Skylands Seal - Fire", "Elemental Skylands - Key of Symbiosis",
 | 
						|
            "Forlorn Temple Seal - Rocket Maze", "Forlorn Temple Seal - Rocket Sunset", "Ninja Village - Astral Seed",
 | 
						|
            "Searing Crags - Astral Tea Leaves", "Autumn Hills Mega Shard", "Hidden Entrance Mega Shard",
 | 
						|
            "Sunny Day Mega Shard", "Down Under Mega Shard", "Catacombs Mega Shard", "Above Entrance Mega Shard",
 | 
						|
            "Abandoned Mega Shard", "Time Loop Mega Shard", "Earth Mega Shard", "Water Mega Shard",
 | 
						|
            "Money Farm Room Mega Shard 1", "Money Farm Room Mega Shard 2",
 | 
						|
            "Autumn Hills - Leaf Golem", "Catacombs - Ruxxtin", "Howling Grotto - Emerald Golem"
 | 
						|
        ]
 | 
						|
        items = [["Wingsuit"]]
 | 
						|
        self.assertAccessDependency(locations, items)
 | 
						|
 | 
						|
    def test_vertical(self) -> None:
 | 
						|
        """locations that require either the Rope Dart or the Wingsuit"""
 | 
						|
        locations = [
 | 
						|
            "Ninja Village Seal - Tree House", "Howling Grotto Seal - Crushing Pits",
 | 
						|
            "Glacial Peak Seal - Ice Climbers", "Tower of Time Seal - Time Waster",
 | 
						|
            "Underworld Seal - Rising Fanta", "Elemental Skylands - Key of Symbiosis",
 | 
						|
            "Elemental Skylands Seal - Water", "Elemental Skylands Seal - Fire", "Ninja Village - Candle",
 | 
						|
            "Autumn Hills - Climbing Claws", "Autumn Hills - 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", "Catacombs - Necro", "Catacombs - Ruxxtin's Amulet",
 | 
						|
            "Catacombs Seal - Triple Spike Crushers", "Catacombs Seal - Crusher Gauntlet",
 | 
						|
            "Catacombs Seal - Dirty Pond", "Bamboo Creek - Claustro", "Cloud Ruins - 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", "Forlorn Temple - Demon King", "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",
 | 
						|
            "Searing Crags - Power Thistle", "Searing Crags - Key of Strength",
 | 
						|
            "Glacial Peak Seal - Projectile Spike Pit", "Glacial Peak Seal - Glacial Air Swag",
 | 
						|
            "Riviere Turquoise - Butterfly Matriarch", "Riviere Turquoise Seal - Flower Power",
 | 
						|
            "Riviere Turquoise Seal - Launch of Faith",
 | 
						|
            "Searing Crags Seal - Triple Ball Spinner", "Searing Crags Seal - Raining Rocks",
 | 
						|
            "Searing Crags Seal - Rhythm Rocks", "Ninja Village - Astral Seed", "Searing Crags - Astral Tea Leaves",
 | 
						|
            "Rescue Phantom", "Autumn Hills Mega Shard", "Hidden Entrance Mega Shard", "Sunny Day Mega Shard",
 | 
						|
            "Down Under Mega Shard", "Catacombs Mega Shard", "Above Entrance Mega Shard", "Abandoned Mega Shard",
 | 
						|
            "Time Loop Mega Shard", "Searing Crags Mega Shard", "Glacial Peak Mega Shard", "Cloud Entrance Mega Shard",
 | 
						|
            "Time Warp Mega Shard", "Money Farm Room Mega Shard 1", "Money Farm Room Mega Shard 2",
 | 
						|
            "Quick Restock Mega Shard 1", "Quick Restock Mega Shard 2", "Earth Mega Shard", "Water Mega Shard",
 | 
						|
            "Autumn Hills - Leaf Golem", "Catacombs - Ruxxtin", "Howling Grotto - Emerald Golem"
 | 
						|
        ]
 | 
						|
        items = [["Wingsuit", "Rope Dart"]]
 | 
						|
        self.assertAccessDependency(locations, items)
 | 
						|
 | 
						|
    def test_amulet(self) -> None:
 | 
						|
        """Locations that require Ruxxtin's Amulet"""
 | 
						|
        locations = [
 | 
						|
            "Cloud Ruins - Acro", "Cloud Ruins Seal - Ghost Pit", "Cloud Ruins Seal - Toothbrush Alley",
 | 
						|
            "Cloud Ruins Seal - Saw Pit", "Cloud Ruins Seal - Money Farm Room", "Cloud Entrance Mega Shard",
 | 
						|
            "Time Warp Mega Shard", "Money Farm Room Mega Shard 1", "Money Farm Room Mega Shard 2"
 | 
						|
        ]
 | 
						|
        # Cloud Ruins requires Ruxxtin's Amulet
 | 
						|
        items = [["Ruxxtin's Amulet"]]
 | 
						|
        self.assertAccessDependency(locations, items)
 | 
						|
 | 
						|
    def test_firefly(self) -> None:
 | 
						|
        """Elemental Skylands and Corrupted Future require the Magic Firefly"""
 | 
						|
        locations = [
 | 
						|
            "Elemental Skylands - Key of Symbiosis", "Elemental Skylands Seal - Air", "Elemental Skylands Seal - Fire",
 | 
						|
            "Elemental Skylands Seal - Water", "Corrupted Future - Key of Courage", "Earth Mega Shard",
 | 
						|
            "Water Mega Shard"
 | 
						|
        ]
 | 
						|
        items = [["Magic Firefly"]]
 | 
						|
        self.assertAccessDependency(locations, items)
 | 
						|
 | 
						|
    def test_crests(self) -> None:
 | 
						|
        """Test Key of Love nonsense"""
 | 
						|
        locations = ["Sunken Shrine - Key of Love"]
 | 
						|
        items = [["Sun Crest", "Moon Crest"]]
 | 
						|
        self.assertAccessDependency(locations, items)
 | 
						|
        self.collect_all_but("Sun Crest")
 | 
						|
        self.assertEqual(self.can_reach_location("Sunken Shrine - Key of Love"), False)
 | 
						|
        self.remove(self.get_item_by_name("Moon Crest"))
 | 
						|
        self.collect_by_name("Sun Crest")
 | 
						|
        self.assertEqual(self.can_reach_location("Sunken Shrine - Key of Love"), False)
 | 
						|
 | 
						|
    def test_thistle(self) -> None:
 | 
						|
        """I'm a chuckster!"""
 | 
						|
        locations = ["Searing Crags - Key of Strength"]
 | 
						|
        items = [["Power Thistle"]]
 | 
						|
        self.assertAccessDependency(locations, items)
 | 
						|
 | 
						|
    def test_crown(self) -> None:
 | 
						|
        """Crocomire but not"""
 | 
						|
        locations = ["Corrupted Future - Key of Courage"]
 | 
						|
        items = [["Demon King Crown"]]
 | 
						|
        self.assertAccessDependency(locations, items)
 | 
						|
 | 
						|
    def test_dboost(self) -> None:
 | 
						|
        """
 | 
						|
        short for damage boosting, d-boosting is a technique in video games where the player intentionally or
 | 
						|
        unintentionally takes damage and uses the several following frames of invincibility to defeat or get past an
 | 
						|
        enemy or obstacle, most commonly used in platformers such as the Super Mario games
 | 
						|
        """
 | 
						|
        locations = [
 | 
						|
            "Riviere Turquoise Seal - Bounces and Balls", "Searing Crags Seal - Triple Ball Spinner",
 | 
						|
            "Forlorn Temple - Demon King", "Forlorn Temple Seal - Rocket Maze", "Forlorn Temple Seal - Rocket Sunset",
 | 
						|
            "Sunny Day Mega Shard", "Down Under Mega Shard",
 | 
						|
        ]
 | 
						|
        items = [["Path of Resilience", "Meditation", "Second Wind"]]
 | 
						|
        self.assertAccessDependency(locations, items)
 | 
						|
 | 
						|
    def test_currents(self) -> None:
 | 
						|
        """there's one of these but oh man look at it go"""
 | 
						|
        self.assertAccessDependency(["Elemental Skylands Seal - Water"], [["Currents Master"]])
 | 
						|
 | 
						|
    def test_strike(self) -> None:
 | 
						|
        """strike is pretty cool but it doesn't block much"""
 | 
						|
        locations = [
 | 
						|
            "Glacial Peak Seal - Projectile Spike Pit", "Elemental Skylands Seal - Fire",
 | 
						|
        ]
 | 
						|
        items = [["Strike of the Ninja"]]
 | 
						|
        self.assertAccessDependency(locations, items)
 | 
						|
 | 
						|
    def test_goal(self) -> None:
 | 
						|
        """Test some different states to verify goal requires the correct items"""
 | 
						|
        self.collect_all_but([*NOTES, "Do the Thing!"])
 | 
						|
        self.assertEqual(self.can_reach_location("Rescue Phantom"), False)
 | 
						|
        self.collect_all_but(["Key of Love", "Do the Thing!"])
 | 
						|
        self.assertBeatable(False)
 | 
						|
        self.collect_by_name(["Key of Love"])
 | 
						|
        self.assertEqual(self.can_reach_location("Rescue Phantom"), True)
 | 
						|
        self.assertBeatable(True)
 | 
						|
 | 
						|
 | 
						|
class ItemsAccessTest(MessengerTestBase):
 | 
						|
    options = {
 | 
						|
        "shuffle_seals": "false",
 | 
						|
        "accessibility": "items",
 | 
						|
    }
 | 
						|
 | 
						|
    def test_self_locking_items(self) -> None:
 | 
						|
        """Force items that can be self locked to ensure it's valid placement."""
 | 
						|
        location_lock_pairs = {
 | 
						|
            "Searing Crags - Key of Strength": ["Power Thistle"],
 | 
						|
            "Sunken Shrine - Key of Love": ["Sun Crest", "Moon Crest"],
 | 
						|
            "Corrupted Future - Key of Courage": ["Demon King Crown"],
 | 
						|
        }
 | 
						|
 | 
						|
        self.collect_all_but([item for items in location_lock_pairs.values() for item in items])
 | 
						|
        for loc in location_lock_pairs:
 | 
						|
            for item_name in location_lock_pairs[loc]:
 | 
						|
                item = self.get_item_by_name(item_name)
 | 
						|
                with self.subTest("Fulfills Accessibility", location=loc, item=item_name):
 | 
						|
                    location = self.multiworld.get_location(loc, self.player)
 | 
						|
                    self.assertTrue(location.can_fill(self.multiworld.state, item, True))
 | 
						|
                    location.item = item
 | 
						|
                    self.multiworld.state.update_reachable_regions(self.player)
 | 
						|
                    self.assertTrue(self.can_reach_location(loc))
 |