The Messenger: fix logic rule for spike darts and power seal hunt (#2414)

This commit is contained in:
Aaron Wagener 2023-11-10 22:49:55 -06:00 committed by GitHub
parent ac77666f2f
commit 64159a6d0f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 19 additions and 31 deletions

View File

@ -82,7 +82,10 @@ class MessengerWorld(World):
self.shop_prices, self.figurine_prices = shuffle_shop_prices(self) self.shop_prices, self.figurine_prices = shuffle_shop_prices(self)
def create_regions(self) -> None: def create_regions(self) -> None:
self.multiworld.regions += [MessengerRegion(reg_name, self) for reg_name in REGIONS] # MessengerRegion adds itself to the multiworld
for region in [MessengerRegion(reg_name, self) for reg_name in REGIONS]:
if region.name in REGION_CONNECTIONS:
region.add_exits(REGION_CONNECTIONS[region.name])
def create_items(self) -> None: def create_items(self) -> None:
# create items that are always in the item pool # create items that are always in the item pool
@ -136,8 +139,6 @@ class MessengerWorld(World):
self.multiworld.itempool += itempool self.multiworld.itempool += itempool
def set_rules(self) -> None: def set_rules(self) -> None:
for reg_name, connections in REGION_CONNECTIONS.items():
self.multiworld.get_region(reg_name, self.player).add_exits(connections)
logic = self.options.logic_level logic = self.options.logic_level
if logic == Logic.option_normal: if logic == Logic.option_normal:
MessengerRules(self).set_messenger_rules() MessengerRules(self).set_messenger_rules()

View File

@ -68,7 +68,6 @@ MEGA_SHARDS: Dict[str, List[str]] = {
"Quillshroom Marsh": ["Quillshroom Marsh Mega Shard"], "Quillshroom Marsh": ["Quillshroom Marsh Mega Shard"],
"Searing Crags Upper": ["Searing Crags Mega Shard"], "Searing Crags Upper": ["Searing Crags Mega Shard"],
"Glacial Peak": ["Glacial Peak Mega Shard"], "Glacial Peak": ["Glacial Peak Mega Shard"],
"Tower of Time": [],
"Cloud Ruins": ["Cloud Entrance Mega Shard", "Time Warp Mega Shard"], "Cloud Ruins": ["Cloud Entrance Mega Shard", "Time Warp Mega Shard"],
"Cloud Ruins Right": ["Money Farm Room Mega Shard 1", "Money Farm Room Mega Shard 2"], "Cloud Ruins Right": ["Money Farm Room Mega Shard 1", "Money Farm Room Mega Shard 2"],
"Underworld": ["Under Entrance Mega Shard", "Hot Tub Mega Shard", "Projectile Pit Mega Shard"], "Underworld": ["Under Entrance Mega Shard", "Hot Tub Mega Shard", "Projectile Pit Mega Shard"],
@ -84,8 +83,6 @@ REGION_CONNECTIONS: Dict[str, Set[str]] = {
"Menu": {"Tower HQ"}, "Menu": {"Tower HQ"},
"Tower HQ": {"Autumn Hills", "Howling Grotto", "Searing Crags", "Glacial Peak", "Tower of Time", "Tower HQ": {"Autumn Hills", "Howling Grotto", "Searing Crags", "Glacial Peak", "Tower of Time",
"Riviere Turquoise Entrance", "Sunken Shrine", "Corrupted Future", "The Shop", "Music Box"}, "Riviere Turquoise Entrance", "Sunken Shrine", "Corrupted Future", "The Shop", "Music Box"},
"Tower of Time": set(),
"Ninja Village": set(),
"Autumn Hills": {"Ninja Village", "Forlorn Temple", "Catacombs"}, "Autumn Hills": {"Ninja Village", "Forlorn Temple", "Catacombs"},
"Forlorn Temple": {"Catacombs", "Bamboo Creek"}, "Forlorn Temple": {"Catacombs", "Bamboo Creek"},
"Catacombs": {"Autumn Hills", "Bamboo Creek", "Dark Cave"}, "Catacombs": {"Autumn Hills", "Bamboo Creek", "Dark Cave"},
@ -97,11 +94,8 @@ REGION_CONNECTIONS: Dict[str, Set[str]] = {
"Glacial Peak": {"Searing Crags Upper", "Tower HQ", "Cloud Ruins", "Elemental Skylands"}, "Glacial Peak": {"Searing Crags Upper", "Tower HQ", "Cloud Ruins", "Elemental Skylands"},
"Cloud Ruins": {"Cloud Ruins Right"}, "Cloud Ruins": {"Cloud Ruins Right"},
"Cloud Ruins Right": {"Underworld"}, "Cloud Ruins Right": {"Underworld"},
"Underworld": set(),
"Dark Cave": {"Catacombs", "Riviere Turquoise Entrance"}, "Dark Cave": {"Catacombs", "Riviere Turquoise Entrance"},
"Riviere Turquoise Entrance": {"Riviere Turquoise"}, "Riviere Turquoise Entrance": {"Riviere Turquoise"},
"Riviere Turquoise": set(),
"Sunken Shrine": {"Howling Grotto"}, "Sunken Shrine": {"Howling Grotto"},
"Elemental Skylands": set(),
} }
"""Vanilla layout mapping with all Tower HQ portals open. from -> to""" """Vanilla layout mapping with all Tower HQ portals open. from -> to"""

View File

@ -1,10 +1,9 @@
from typing import Callable, Dict, TYPE_CHECKING from typing import Callable, Dict, TYPE_CHECKING
from BaseClasses import CollectionState from BaseClasses import CollectionState
from worlds.generic.Rules import add_rule, allow_self_locking_items, set_rule from worlds.generic.Rules import add_rule, allow_self_locking_items
from .constants import NOTES, PHOBEKINS from .constants import NOTES, PHOBEKINS
from .options import Goal, MessengerAccessibility from .options import MessengerAccessibility
from .subclasses import MessengerShopLocation
if TYPE_CHECKING: if TYPE_CHECKING:
from . import MessengerWorld from . import MessengerWorld
@ -37,7 +36,9 @@ class MessengerRules:
"Forlorn Temple": lambda state: state.has_all({"Wingsuit", *PHOBEKINS}, self.player) and self.can_dboost(state), "Forlorn Temple": lambda state: state.has_all({"Wingsuit", *PHOBEKINS}, self.player) and self.can_dboost(state),
"Glacial Peak": self.has_vertical, "Glacial Peak": self.has_vertical,
"Elemental Skylands": lambda state: state.has("Magic Firefly", self.player) and self.has_wingsuit(state), "Elemental Skylands": lambda state: state.has("Magic Firefly", self.player) and self.has_wingsuit(state),
"Music Box": lambda state: state.has_all(set(NOTES), self.player) and self.has_dart(state), "Music Box": lambda state: (state.has_all(set(NOTES), self.player)
or state.has("Power Seal", self.player, max(1, self.world.required_seals)))
and self.has_dart(state),
} }
self.location_rules = { self.location_rules = {
@ -92,8 +93,6 @@ class MessengerRules:
# corrupted future # corrupted future
"Corrupted Future - Key of Courage": lambda state: state.has_all({"Demon King Crown", "Magic Firefly"}, "Corrupted Future - Key of Courage": lambda state: state.has_all({"Demon King Crown", "Magic Firefly"},
self.player), self.player),
# the shop
"Shop Chest": self.has_enough_seals,
# tower hq # tower hq
"Money Wrench": self.can_shop, "Money Wrench": self.can_shop,
} }
@ -143,14 +142,11 @@ class MessengerRules:
if loc.name in self.location_rules: if loc.name in self.location_rules:
loc.access_rule = self.location_rules[loc.name] loc.access_rule = self.location_rules[loc.name]
if region.name == "The Shop": if region.name == "The Shop":
for loc in [location for location in region.locations if isinstance(location, MessengerShopLocation)]: for loc in region.locations:
loc.access_rule = loc.can_afford loc.access_rule = loc.can_afford
if self.world.options.goal == Goal.option_power_seal_hunt:
set_rule(multiworld.get_entrance("Tower HQ -> Music Box", self.player),
lambda state: state.has("Shop Chest", self.player))
multiworld.completion_condition[self.player] = lambda state: state.has("Rescue Phantom", self.player) multiworld.completion_condition[self.player] = lambda state: state.has("Rescue Phantom", self.player)
if multiworld.accessibility[self.player] > MessengerAccessibility.option_locations: if multiworld.accessibility[self.player]: # not locations accessibility
set_self_locking_items(self.world, self.player) set_self_locking_items(self.world, self.player)
@ -201,8 +197,7 @@ class MessengerHardRules(MessengerRules):
self.extra_rules = { self.extra_rules = {
"Searing Crags - Key of Strength": lambda state: self.has_dart(state) or self.has_windmill(state), "Searing Crags - Key of Strength": lambda state: self.has_dart(state) or self.has_windmill(state),
"Elemental Skylands - Key of Symbiosis": lambda state: self.has_windmill(state) or self.can_dboost(state), "Elemental Skylands - Key of Symbiosis": lambda state: self.has_windmill(state) or self.can_dboost(state),
"Autumn Hills Seal - Spike Ball Darts": lambda state: (self.has_dart(state) and self.has_windmill(state)) "Autumn Hills Seal - Spike Ball Darts": lambda state: self.has_dart(state) or self.has_windmill(state),
or self.has_wingsuit(state),
"Underworld Seal - Fireball Wave": self.has_windmill, "Underworld Seal - Fireball Wave": self.has_windmill,
} }

View File

@ -17,8 +17,6 @@ class MessengerRegion(Region):
super().__init__(name, world.player, world.multiworld) super().__init__(name, world.player, world.multiworld)
locations = [loc for loc in REGIONS[self.name]] locations = [loc for loc in REGIONS[self.name]]
if self.name == "The Shop": if self.name == "The Shop":
if world.options.goal > Goal.option_open_music_box:
locations.append("Shop Chest")
shop_locations = {f"The Shop - {shop_loc}": world.location_name_to_id[f"The Shop - {shop_loc}"] shop_locations = {f"The Shop - {shop_loc}": world.location_name_to_id[f"The Shop - {shop_loc}"]
for shop_loc in SHOP_ITEMS} for shop_loc in SHOP_ITEMS}
shop_locations.update(**{figurine: world.location_name_to_id[figurine] for figurine in FIGURINES}) shop_locations.update(**{figurine: world.location_name_to_id[figurine] for figurine in FIGURINES})
@ -29,9 +27,9 @@ class MessengerRegion(Region):
locations += [seal_loc for seal_loc in SEALS[self.name]] locations += [seal_loc for seal_loc in SEALS[self.name]]
if world.options.shuffle_shards and self.name in MEGA_SHARDS: if world.options.shuffle_shards and self.name in MEGA_SHARDS:
locations += [shard for shard in MEGA_SHARDS[self.name]] locations += [shard for shard in MEGA_SHARDS[self.name]]
loc_dict = {loc: world.location_name_to_id[loc] if loc in world.location_name_to_id else None loc_dict = {loc: world.location_name_to_id.get(loc, None) for loc in locations}
for loc in locations}
self.add_locations(loc_dict, MessengerLocation) self.add_locations(loc_dict, MessengerLocation)
world.multiworld.regions.append(self)
class MessengerLocation(Location): class MessengerLocation(Location):

View File

@ -17,18 +17,18 @@ class AllSealsRequired(MessengerTestBase):
with self.subTest("Access Dependency"): with self.subTest("Access Dependency"):
self.assertEqual(len([seal for seal in self.multiworld.itempool if seal.name == "Power Seal"]), self.assertEqual(len([seal for seal in self.multiworld.itempool if seal.name == "Power Seal"]),
self.multiworld.total_seals[self.player]) self.multiworld.total_seals[self.player])
locations = ["Shop Chest"] locations = ["Rescue Phantom"]
items = [["Power Seal"]] items = [["Power Seal"]]
self.assertAccessDependency(locations, items) self.assertAccessDependency(locations, items)
self.multiworld.state = CollectionState(self.multiworld) self.multiworld.state = CollectionState(self.multiworld)
self.assertEqual(self.can_reach_location("Shop Chest"), False) self.assertEqual(self.can_reach_location("Rescue Phantom"), False)
self.assertBeatable(False) self.assertBeatable(False)
self.collect_all_but(["Power Seal", "Shop Chest", "Rescue Phantom"]) self.collect_all_but(["Power Seal", "Rescue Phantom"])
self.assertEqual(self.can_reach_location("Shop Chest"), False) self.assertEqual(self.can_reach_location("Rescue Phantom"), False)
self.assertBeatable(False) self.assertBeatable(False)
self.collect_by_name("Power Seal") self.collect_by_name("Power Seal")
self.assertEqual(self.can_reach_location("Shop Chest"), True) self.assertEqual(self.can_reach_location("Rescue Phantom"), True)
self.assertBeatable(True) self.assertBeatable(True)