The Messenger: fix logic rule for spike darts and power seal hunt (#2414)
This commit is contained in:
parent
ac77666f2f
commit
64159a6d0f
|
@ -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()
|
||||||
|
|
|
@ -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"""
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue