From 8b3557cd6c1ddb0b5e538ac489a2e672e11950f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Bolduc?= <16137441+Jouramie@users.noreply.github.com> Date: Tue, 4 Aug 2026 18:24:35 -0400 Subject: [PATCH] The Messenger: Various small logic fix (#6337) --- worlds/messenger/connections.py | 17 ++++--- worlds/messenger/portals.py | 6 +-- worlds/messenger/rules.py | 57 ++++++++++++---------- worlds/messenger/test/test_access.py | 73 ++++++++++++++++++++-------- 4 files changed, 98 insertions(+), 55 deletions(-) diff --git a/worlds/messenger/connections.py b/worlds/messenger/connections.py index 490803e959..d3471a8dac 100644 --- a/worlds/messenger/connections.py +++ b/worlds/messenger/connections.py @@ -37,7 +37,7 @@ CONNECTIONS: dict[str, dict[str, list[str]]] = { "Autumn Hills - Lakeside Checkpoint", ], "Dimension Climb Shop": [ - "Autumn Hills - Lakeside Checkpoint", + "Autumn Hills - Lakeside Checkpoint", # Only possible in 16 bits "Autumn Hills - Portal", "Autumn Hills - Double Swing Checkpoint", ], @@ -60,7 +60,7 @@ CONNECTIONS: dict[str, dict[str, list[str]]] = { "Double Swing Checkpoint": [ "Autumn Hills - Dimension Climb Shop", "Autumn Hills - Spike Ball Swing Checkpoint", - "Autumn Hills - Bottom", + "Autumn Hills - Bottom", # Only possible in 16 bits ], "Spike Ball Swing Checkpoint": [ "Autumn Hills - Double Swing Checkpoint", @@ -135,6 +135,7 @@ CONNECTIONS: dict[str, dict[str, list[str]]] = { ], "Triple Spike Crushers Shop": [ "Catacombs - Bottom Left", + "Catacombs - Top Left", "Catacombs - Death Trap Checkpoint", ], "Ruxxtin Shop": [ @@ -153,7 +154,7 @@ CONNECTIONS: dict[str, dict[str, list[str]]] = { "Catacombs - Bottom", "Catacombs - Death Trap Checkpoint", "Catacombs - Crusher Gauntlet Checkpoint", - "Catacombs - Ruxxtin Shop", + "Catacombs - Ruxxtin Shop", # In 16 bits, requires rope dart (to reach the Dirty Pond Seal as well) ], }, "Bamboo Creek": { @@ -486,8 +487,7 @@ CONNECTIONS: dict[str, dict[str, list[str]]] = { "Barm'athaziel Shop": [ "Underworld - Hot Tub Checkpoint", ], - "Key of Chaos Shop": [ - ], + "Key of Chaos Shop": [], "Hot Dip Checkpoint": [ "Underworld - Left Shop", "Underworld - Fireball Wave Shop", @@ -536,8 +536,7 @@ CONNECTIONS: dict[str, dict[str, list[str]]] = { "Restock Shop": [ "Riviere Turquoise - Butterfly Matriarch Shop", ], - "Butterfly Matriarch Shop": [ - ], + "Butterfly Matriarch Shop": [], "Flower Flight Checkpoint": [ "Riviere Turquoise - Waterfall Shop", "Riviere Turquoise - Launch of Faith Shop", @@ -556,6 +555,7 @@ CONNECTIONS: dict[str, dict[str, list[str]]] = { "Elemental Skylands - Air Generator Shop", ], "Air Generator Shop": [ + "Elemental Skylands - Air Seal Checkpoint", "Elemental Skylands - Earth Shmup", ], "Earth Shmup": [ @@ -574,6 +574,7 @@ CONNECTIONS: dict[str, dict[str, list[str]]] = { "Elemental Skylands - Water Generator Shop", ], "Water Generator Shop": [ + "Elemental Skylands - Water Intro Shop", "Elemental Skylands - Fire Shmup", ], "Fire Shmup": [ @@ -639,6 +640,7 @@ CONNECTIONS: dict[str, dict[str, list[str]]] = { }, } +# fmt: off RANDOMIZED_CONNECTIONS: dict[str, str] = { "Ninja Village - Right": "Autumn Hills - Left", "Autumn Hills - Left": "Ninja Village - Right", @@ -678,6 +680,7 @@ RANDOMIZED_CONNECTIONS: dict[str, str] = { "Dark Cave - Left": "Riviere Turquoise - Right", "Sunken Shrine - Left": "Howling Grotto - Bottom", } +# fmt: on TRANSITIONS: list[str] = [ "Ninja Village - Right", diff --git a/worlds/messenger/portals.py b/worlds/messenger/portals.py index 8e46eee17d..9ea1b61290 100644 --- a/worlds/messenger/portals.py +++ b/worlds/messenger/portals.py @@ -96,10 +96,10 @@ SHOP_POINTS: dict[str, list[str]] = { "Air Generator", "Earth Intro", "Earth Generator", - "Fire Intro", - "Fire Generator", "Water Intro", "Water Generator", + "Fire Intro", + "Fire Generator", ], "Sunken Shrine": [ "Above Portal", @@ -107,7 +107,7 @@ SHOP_POINTS: dict[str, list[str]] = { "Sun Path", "Tabi Gauntlet", "Moon Path", - ] + ], } CHECKPOINTS: dict[str, list[str]] = { diff --git a/worlds/messenger/rules.py b/worlds/messenger/rules.py index 23f2bf32c0..babc4cce6c 100644 --- a/worlds/messenger/rules.py +++ b/worlds/messenger/rules.py @@ -1,7 +1,8 @@ from typing import TYPE_CHECKING -from BaseClasses import CollectionState, CollectionRule, Region +from BaseClasses import CollectionRule, CollectionState, Region from worlds.generic.Rules import add_rule, allow_self_locking_items + from .constants import NOTES, PHOBEKINS from .options import MessengerAccessibility @@ -30,6 +31,7 @@ class MessengerRules: self.required_seals = world.required_seals # dict of connection names and requirements to traverse the exit + # fmt: off self.connection_rules = { # from ToTHQ "Artificer's Portal": @@ -131,7 +133,7 @@ class MessengerRules: lambda state: state.has("Magic Firefly", self.player) and state.multiworld.get_location("Quillshroom Marsh - Queen of Quills", self.player) .can_reach(state), - "Glacial Peak - Tower Entrance Shop -> Glacial Peak - Top": + "Glacial Peak - Top -> Cloud Ruins - Left": lambda state: state.has("Ruxxtin's Amulet", self.player), "Glacial Peak - Projectile Spike Pit Checkpoint -> Glacial Peak - Left": lambda state: self.has_dart(state) or (self.can_dboost(state) and self.has_wingsuit(state)), @@ -173,7 +175,7 @@ class MessengerRules: lambda state: self.has_wingsuit(state) and self.can_dboost(state), # Underworld "Underworld - Left -> Underworld - Left Shop": - self.has_tabi, + lambda state: self.has_tabi(state) or self.has_vertical(state), "Underworld - Left Shop -> Underworld - Left": self.has_tabi, "Underworld - Hot Dip Checkpoint -> Underworld - Lava Run Checkpoint": @@ -208,6 +210,10 @@ class MessengerRules: self.has_wingsuit, "Elemental Skylands - Air Intro Shop -> Elemental Skylands - Air Generator Shop": self.has_wingsuit, + "Elemental Skylands - Earth Intro Shop -> Elemental Skylands - Earth Generator Shop": + self.has_dart, + "Elemental Skylands - Water Generator Shop -> Elemental Skylands - Water Intro Shop": + self.can_destroy_projectiles, # Sunken Shrine "Sunken Shrine - Portal -> Sunken Shrine - Sun Path Shop": self.has_tabi, @@ -220,6 +226,7 @@ class MessengerRules: "Sunken Shrine - Tabi Gauntlet Shop -> Sunken Shrine - Sun Path Shop": lambda state: self.can_dboost(state) or self.has_dart(state), } + # fmt: on # dict of connection names and the regions checked in the requirements to traverse the exit self.indirect_conditions = { @@ -231,6 +238,7 @@ class MessengerRules: ], } + # fmt: off self.location_rules = { # hq "Money Wrench": self.can_shop, @@ -261,7 +269,7 @@ class MessengerRules: "Howling Grotto Seal - Windy Saws and Balls": self.has_wingsuit, "Howling Grotto Seal - Crushing Pits": - lambda state: self.has_wingsuit(state) and self.has_dart(state), + self.has_dart, "Howling Grotto - Emerald Golem": self.has_wingsuit, # searing crags @@ -280,7 +288,8 @@ class MessengerRules: "Tower of Time Seal - Time Waster": self.has_dart, # corrupted future - "Corrupted Future - Key of Courage": lambda state: state.has("Magic Firefly", self.player), + "Corrupted Future - Key of Courage": + lambda state: state.has("Magic Firefly", self.player), # cloud ruins "Time Warp Mega Shard": lambda state: self.has_vertical(state) or self.can_dboost(state), @@ -312,21 +321,18 @@ class MessengerRules: "Riviere Turquoise Seal - Bounces and Balls": self.can_dboost, "Riviere Turquoise Seal - Launch of Faith": - lambda state: self.has_vertical(state), + self.has_vertical, # elemental skylands - "Elemental Skylands - Key of Symbiosis": - self.has_dart, "Elemental Skylands Seal - Air": self.has_wingsuit, "Elemental Skylands Seal - Water": - lambda state: self.has_dart(state) and state.has("Currents Master", self.player), + lambda state: state.has("Currents Master", self.player), "Elemental Skylands Seal - Fire": - lambda state: self.has_dart(state) and self.can_destroy_projectiles(state) and self.is_aerobatic(state), + lambda state: self.can_destroy_projectiles(state) and self.is_aerobatic(state), "Earth Mega Shard": self.has_dart, - "Water Mega Shard": - self.has_dart, } + # fmt: on if self.required_seals: self.connection_rules["Shrink Down"] = self.has_enough_seals @@ -393,6 +399,7 @@ class MessengerHardRules(MessengerRules): def __init__(self, world: "MessengerWorld") -> None: super().__init__(world) + # fmt: off self.connection_rules.update( { # Autumn Hills @@ -439,6 +446,8 @@ class MessengerHardRules(MessengerRules): # Elemental Skylands "Elemental Skylands - Air Intro Shop -> Elemental Skylands - Air Generator Shop": self.true, + "Elemental Skylands - Earth Intro Shop -> Elemental Skylands - Earth Generator Shop": + self.true, # Riviere Turquoise "Riviere Turquoise - Waterfall Shop -> Riviere Turquoise - Flower Flight Checkpoint": self.true, @@ -448,29 +457,31 @@ class MessengerHardRules(MessengerRules): self.can_double_dboost, } ) + # fmt: on + # fmt: off self.location_rules.update( { "Autumn Hills Seal - Spike Ball Darts": - lambda state: self.has_vertical(state) and self.has_windmill(state) or self.is_aerobatic(state), + lambda state: (self.has_vertical(state) and self.has_windmill(state)) or self.is_aerobatic(state), "Autumn Hills Seal - Double Swing Saws": lambda state: self.has_vertical(state) or self.can_destroy_projectiles(state), "Bamboo Creek - Claustro": self.has_wingsuit, "Bamboo Creek Seal - Spike Ball Pits": self.true, + "Above Entrance Mega Shard": # Just reset to the menu and you can get it with full health + self.true, "Howling Grotto Seal - Windy Saws and Balls": self.true, + "Howling Grotto Seal - Crushing Pits": + self.has_vertical, "Searing Crags Seal - Triple Ball Spinner": self.true, "Glacial Peak Seal - Ice Climbers": lambda state: self.has_vertical(state) or self.can_dboost(state), "Glacial Peak Seal - Projectile Spike Pit": lambda state: self.can_dboost(state) or self.can_destroy_projectiles(state), - "Glacial Peak Seal - Glacial Air Swag": - lambda state: self.has_windmill(state) or self.has_vertical(state), - "Glacial Peak Mega Shard": - lambda state: self.has_windmill(state) or self.has_vertical(state), "Cloud Ruins Seal - Ghost Pit": self.true, "Cloud Ruins Seal - Toothbrush Alley": @@ -483,26 +494,22 @@ class MessengerHardRules(MessengerRules): self.true, "Riviere Turquoise Seal - Launch of Faith": lambda state: self.can_dboost(state) or self.has_vertical(state), - "Elemental Skylands - Key of Symbiosis": - lambda state: self.has_dart(state) or self.can_dboost(state) or self.has_windmill(state), "Elemental Skylands Seal - Water": - lambda state: self.has_dart(state) or self.can_dboost(state) or self.has_windmill(state), + self.true, "Elemental Skylands Seal - Fire": - lambda state: (self.has_dart(state) or self.can_dboost(state) or self.has_windmill(state)) - and self.can_destroy_projectiles(state), + self.can_destroy_projectiles, "Earth Mega Shard": lambda state: self.has_dart(state) or self.can_dboost(state) or self.has_windmill(state), - "Water Mega Shard": - lambda state: self.has_dart(state) or self.can_dboost(state) or self.has_windmill(state), } ) + # fmt: on def has_windmill(self, state: CollectionState) -> bool: return state.has("Windmill Shuriken", self.player) def can_dboost(self, state: CollectionState) -> bool: return state.has("Second Wind", self.player) # who really needs meditation - + def can_destroy_projectiles(self, state: CollectionState) -> bool: return super().can_destroy_projectiles(state) or self.has_windmill(state) diff --git a/worlds/messenger/test/test_access.py b/worlds/messenger/test/test_access.py index ad2265ffa0..d2fa944560 100644 --- a/worlds/messenger/test/test_access.py +++ b/worlds/messenger/test/test_access.py @@ -1,7 +1,7 @@ import typing -from . import MessengerTestBase from ..constants import NOTES, PHOBEKINS +from . import MessengerTestBase class AccessTest(MessengerTestBase): @@ -52,25 +52,58 @@ class AccessTest(MessengerTestBase): 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" + "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 - 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)