Core: Add a function to allow worlds to easily allow self-locking items (#1383)
* implement function to allow self locking items for items accessibility * swap some lttp locations to use new functionality * lambda capture `item_name` and `location` * don't lambda capture location * Revert weird visual indent * make location.always_allow additive * fix always_allow rule for multiple items * don't need to lambda capture item_names * oop * move player assignment to the beginning * always_allow should only be for that player so prevent non_local_items * messenger got merged so have it use this * Core: fix doc string indentation for allow_self_locking_items * Core: fix doc string indentation for allow_self_locking_items, number two --------- Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>
This commit is contained in:
parent
060ee926e7
commit
573a1a8402
|
@ -966,7 +966,7 @@ class Location:
|
||||||
self.parent_region = parent
|
self.parent_region = parent
|
||||||
|
|
||||||
def can_fill(self, state: CollectionState, item: Item, check_access=True) -> bool:
|
def can_fill(self, state: CollectionState, item: Item, check_access=True) -> bool:
|
||||||
return (self.always_allow(state, item)
|
return ((self.always_allow(state, item) and item.name not in state.multiworld.non_local_items[item.player])
|
||||||
or ((self.progress_type != LocationProgressType.EXCLUDED or not (item.advancement or item.useful))
|
or ((self.progress_type != LocationProgressType.EXCLUDED or not (item.advancement or item.useful))
|
||||||
and self.item_rule(item)
|
and self.item_rule(item)
|
||||||
and (not check_access or self.can_reach(state))))
|
and (not check_access or self.can_reach(state))))
|
||||||
|
|
|
@ -4,7 +4,7 @@ from typing import Iterator, Set
|
||||||
|
|
||||||
from BaseClasses import Entrance, MultiWorld
|
from BaseClasses import Entrance, MultiWorld
|
||||||
from worlds.generic.Rules import (add_item_rule, add_rule, forbid_item,
|
from worlds.generic.Rules import (add_item_rule, add_rule, forbid_item,
|
||||||
item_in_locations, item_name, set_rule)
|
item_in_locations, location_item_name, set_rule, allow_self_locking_items)
|
||||||
|
|
||||||
from . import OverworldGlitchRules
|
from . import OverworldGlitchRules
|
||||||
from .Bosses import GanonDefeatRule
|
from .Bosses import GanonDefeatRule
|
||||||
|
@ -268,7 +268,7 @@ def global_rules(world, player):
|
||||||
if not (world.smallkey_shuffle[player] and world.bigkey_shuffle[player]):
|
if not (world.smallkey_shuffle[player] and world.bigkey_shuffle[player]):
|
||||||
add_rule(world.get_location('Desert Palace - Prize', player), lambda state: state.multiworld.get_region('Desert Palace Main (Outer)', player).can_reach(state))
|
add_rule(world.get_location('Desert Palace - Prize', player), lambda state: state.multiworld.get_region('Desert Palace Main (Outer)', player).can_reach(state))
|
||||||
|
|
||||||
set_rule(world.get_entrance('Tower of Hera Small Key Door', player), lambda state: state._lttp_has_key('Small Key (Tower of Hera)', player) or item_name(state, 'Tower of Hera - Big Key Chest', player) == ('Small Key (Tower of Hera)', player))
|
set_rule(world.get_entrance('Tower of Hera Small Key Door', player), lambda state: state._lttp_has_key('Small Key (Tower of Hera)', player) or location_item_name(state, 'Tower of Hera - Big Key Chest', player) == ('Small Key (Tower of Hera)', player))
|
||||||
set_rule(world.get_entrance('Tower of Hera Big Key Door', player), lambda state: state.has('Big Key (Tower of Hera)', player))
|
set_rule(world.get_entrance('Tower of Hera Big Key Door', player), lambda state: state.has('Big Key (Tower of Hera)', player))
|
||||||
set_rule(world.get_location('Tower of Hera - Big Chest', player), lambda state: state.has('Big Key (Tower of Hera)', player))
|
set_rule(world.get_location('Tower of Hera - Big Chest', player), lambda state: state.has('Big Key (Tower of Hera)', player))
|
||||||
set_rule(world.get_location('Tower of Hera - Big Key Chest', player), lambda state: has_fire_source(state, player))
|
set_rule(world.get_location('Tower of Hera - Big Key Chest', player), lambda state: has_fire_source(state, player))
|
||||||
|
@ -278,27 +278,27 @@ def global_rules(world, player):
|
||||||
set_rule(world.get_entrance('Swamp Palace Moat', player), lambda state: state.has('Flippers', player) and state.has('Open Floodgate', player))
|
set_rule(world.get_entrance('Swamp Palace Moat', player), lambda state: state.has('Flippers', player) and state.has('Open Floodgate', player))
|
||||||
set_rule(world.get_entrance('Swamp Palace Small Key Door', player), lambda state: state._lttp_has_key('Small Key (Swamp Palace)', player))
|
set_rule(world.get_entrance('Swamp Palace Small Key Door', player), lambda state: state._lttp_has_key('Small Key (Swamp Palace)', player))
|
||||||
set_rule(world.get_entrance('Swamp Palace (Center)', player), lambda state: state.has('Hammer', player))
|
set_rule(world.get_entrance('Swamp Palace (Center)', player), lambda state: state.has('Hammer', player))
|
||||||
set_rule(world.get_location('Swamp Palace - Big Chest', player), lambda state: state.has('Big Key (Swamp Palace)', player) or item_name(state, 'Swamp Palace - Big Chest', player) == ('Big Key (Swamp Palace)', player))
|
set_rule(world.get_location('Swamp Palace - Big Chest', player), lambda state: state.has('Big Key (Swamp Palace)', player))
|
||||||
if world.accessibility[player] != 'locations':
|
if world.accessibility[player] != 'locations':
|
||||||
set_always_allow(world.get_location('Swamp Palace - Big Chest', player), lambda state, item: item.name == 'Big Key (Swamp Palace)' and item.player == player)
|
allow_self_locking_items(world.get_location('Swamp Palace - Big Chest', player), 'Big Key (Swamp Palace)')
|
||||||
set_rule(world.get_entrance('Swamp Palace (North)', player), lambda state: state.has('Hookshot', player))
|
set_rule(world.get_entrance('Swamp Palace (North)', player), lambda state: state.has('Hookshot', player))
|
||||||
if not world.smallkey_shuffle[player] and world.logic[player] not in ['hybridglitches', 'nologic']:
|
if not world.smallkey_shuffle[player] and world.logic[player] not in ['hybridglitches', 'nologic']:
|
||||||
forbid_item(world.get_location('Swamp Palace - Entrance', player), 'Big Key (Swamp Palace)', player)
|
forbid_item(world.get_location('Swamp Palace - Entrance', player), 'Big Key (Swamp Palace)', player)
|
||||||
|
|
||||||
set_rule(world.get_entrance('Thieves Town Big Key Door', player), lambda state: state.has('Big Key (Thieves Town)', player))
|
set_rule(world.get_entrance('Thieves Town Big Key Door', player), lambda state: state.has('Big Key (Thieves Town)', player))
|
||||||
set_rule(world.get_entrance('Blind Fight', player), lambda state: state._lttp_has_key('Small Key (Thieves Town)', player))
|
set_rule(world.get_entrance('Blind Fight', player), lambda state: state._lttp_has_key('Small Key (Thieves Town)', player))
|
||||||
set_rule(world.get_location('Thieves\' Town - Big Chest', player), lambda state: (state._lttp_has_key('Small Key (Thieves Town)', player) or item_name(state, 'Thieves\' Town - Big Chest', player) == ('Small Key (Thieves Town)', player)) and state.has('Hammer', player))
|
set_rule(world.get_location('Thieves\' Town - Big Chest', player), lambda state: (state._lttp_has_key('Small Key (Thieves Town)', player)) and state.has('Hammer', player))
|
||||||
if world.accessibility[player] != 'locations':
|
if world.accessibility[player] != 'locations':
|
||||||
set_always_allow(world.get_location('Thieves\' Town - Big Chest', player), lambda state, item: item.name == 'Small Key (Thieves Town)' and item.player == player and state.has('Hammer', player))
|
allow_self_locking_items(world.get_location('Thieves\' Town - Big Chest', player), 'Small Key (Thieves Town)')
|
||||||
set_rule(world.get_location('Thieves\' Town - Attic', player), lambda state: state._lttp_has_key('Small Key (Thieves Town)', player))
|
set_rule(world.get_location('Thieves\' Town - Attic', player), lambda state: state._lttp_has_key('Small Key (Thieves Town)', player))
|
||||||
|
|
||||||
set_rule(world.get_entrance('Skull Woods First Section South Door', player), lambda state: state._lttp_has_key('Small Key (Skull Woods)', player))
|
set_rule(world.get_entrance('Skull Woods First Section South Door', player), lambda state: state._lttp_has_key('Small Key (Skull Woods)', player))
|
||||||
set_rule(world.get_entrance('Skull Woods First Section (Right) North Door', player), lambda state: state._lttp_has_key('Small Key (Skull Woods)', player))
|
set_rule(world.get_entrance('Skull Woods First Section (Right) North Door', player), lambda state: state._lttp_has_key('Small Key (Skull Woods)', player))
|
||||||
set_rule(world.get_entrance('Skull Woods First Section West Door', player), lambda state: state._lttp_has_key('Small Key (Skull Woods)', player, 2)) # ideally would only be one key, but we may have spent thst key already on escaping the right section
|
set_rule(world.get_entrance('Skull Woods First Section West Door', player), lambda state: state._lttp_has_key('Small Key (Skull Woods)', player, 2)) # ideally would only be one key, but we may have spent thst key already on escaping the right section
|
||||||
set_rule(world.get_entrance('Skull Woods First Section (Left) Door to Exit', player), lambda state: state._lttp_has_key('Small Key (Skull Woods)', player, 2))
|
set_rule(world.get_entrance('Skull Woods First Section (Left) Door to Exit', player), lambda state: state._lttp_has_key('Small Key (Skull Woods)', player, 2))
|
||||||
set_rule(world.get_location('Skull Woods - Big Chest', player), lambda state: state.has('Big Key (Skull Woods)', player) or item_name(state, 'Skull Woods - Big Chest', player) == ('Big Key (Skull Woods)', player))
|
set_rule(world.get_location('Skull Woods - Big Chest', player), lambda state: state.has('Big Key (Skull Woods)', player))
|
||||||
if world.accessibility[player] != 'locations':
|
if world.accessibility[player] != 'locations':
|
||||||
set_always_allow(world.get_location('Skull Woods - Big Chest', player), lambda state, item: item.name == 'Big Key (Skull Woods)' and item.player == player)
|
allow_self_locking_items(world.get_location('Skull Woods - Big Chest', player), 'Big Key (Skull Woods)')
|
||||||
set_rule(world.get_entrance('Skull Woods Torch Room', player), lambda state: state._lttp_has_key('Small Key (Skull Woods)', player, 3) and state.has('Fire Rod', player) and has_sword(state, player)) # sword required for curtain
|
set_rule(world.get_entrance('Skull Woods Torch Room', player), lambda state: state._lttp_has_key('Small Key (Skull Woods)', player, 3) and state.has('Fire Rod', player) and has_sword(state, player)) # sword required for curtain
|
||||||
|
|
||||||
set_rule(world.get_entrance('Ice Palace Entrance Room', player), lambda state: can_melt_things(state, player))
|
set_rule(world.get_entrance('Ice Palace Entrance Room', player), lambda state: can_melt_things(state, player))
|
||||||
|
@ -318,9 +318,9 @@ def global_rules(world, player):
|
||||||
set_rule(world.get_location('Misery Mire - Main Lobby', player), lambda state: state._lttp_has_key('Small Key (Misery Mire)', player, 1) or state._lttp_has_key('Big Key (Misery Mire)', player))
|
set_rule(world.get_location('Misery Mire - Main Lobby', player), lambda state: state._lttp_has_key('Small Key (Misery Mire)', player, 1) or state._lttp_has_key('Big Key (Misery Mire)', player))
|
||||||
# we can place a small key in the West wing iff it also contains/blocks the Big Key, as we cannot reach and softlock with the basement key door yet
|
# we can place a small key in the West wing iff it also contains/blocks the Big Key, as we cannot reach and softlock with the basement key door yet
|
||||||
set_rule(world.get_entrance('Misery Mire (West)', player), lambda state: state._lttp_has_key('Small Key (Misery Mire)', player, 2) if ((
|
set_rule(world.get_entrance('Misery Mire (West)', player), lambda state: state._lttp_has_key('Small Key (Misery Mire)', player, 2) if ((
|
||||||
item_name(state, 'Misery Mire - Compass Chest', player) in [('Big Key (Misery Mire)', player)]) or
|
location_item_name(state, 'Misery Mire - Compass Chest', player) in [('Big Key (Misery Mire)', player)]) or
|
||||||
(
|
(
|
||||||
item_name(state, 'Misery Mire - Big Key Chest', player) in [('Big Key (Misery Mire)', player)])) else state._lttp_has_key('Small Key (Misery Mire)', player, 3))
|
location_item_name(state, 'Misery Mire - Big Key Chest', player) in [('Big Key (Misery Mire)', player)])) else state._lttp_has_key('Small Key (Misery Mire)', player, 3))
|
||||||
set_rule(world.get_location('Misery Mire - Compass Chest', player), lambda state: has_fire_source(state, player))
|
set_rule(world.get_location('Misery Mire - Compass Chest', player), lambda state: has_fire_source(state, player))
|
||||||
set_rule(world.get_location('Misery Mire - Big Key Chest', player), lambda state: has_fire_source(state, player))
|
set_rule(world.get_location('Misery Mire - Big Key Chest', player), lambda state: has_fire_source(state, player))
|
||||||
set_rule(world.get_entrance('Misery Mire (Vitreous)', player), lambda state: state.has('Cane of Somaria', player))
|
set_rule(world.get_entrance('Misery Mire (Vitreous)', player), lambda state: state.has('Cane of Somaria', player))
|
||||||
|
@ -350,12 +350,12 @@ def global_rules(world, player):
|
||||||
set_rule(world.get_location('Palace of Darkness - Big Chest', player), lambda state: state.has('Big Key (Palace of Darkness)', player))
|
set_rule(world.get_location('Palace of Darkness - Big Chest', player), lambda state: state.has('Big Key (Palace of Darkness)', player))
|
||||||
|
|
||||||
set_rule(world.get_entrance('Palace of Darkness Big Key Chest Staircase', player), lambda state: state._lttp_has_key('Small Key (Palace of Darkness)', player, 6) or (
|
set_rule(world.get_entrance('Palace of Darkness Big Key Chest Staircase', player), lambda state: state._lttp_has_key('Small Key (Palace of Darkness)', player, 6) or (
|
||||||
item_name(state, 'Palace of Darkness - Big Key Chest', player) in [('Small Key (Palace of Darkness)', player)] and state._lttp_has_key('Small Key (Palace of Darkness)', player, 3)))
|
location_item_name(state, 'Palace of Darkness - Big Key Chest', player) in [('Small Key (Palace of Darkness)', player)] and state._lttp_has_key('Small Key (Palace of Darkness)', player, 3)))
|
||||||
if world.accessibility[player] != 'locations':
|
if world.accessibility[player] != 'locations':
|
||||||
set_always_allow(world.get_location('Palace of Darkness - Big Key Chest', player), lambda state, item: item.name == 'Small Key (Palace of Darkness)' and item.player == player and state._lttp_has_key('Small Key (Palace of Darkness)', player, 5))
|
set_always_allow(world.get_location('Palace of Darkness - Big Key Chest', player), lambda state, item: item.name == 'Small Key (Palace of Darkness)' and item.player == player and state._lttp_has_key('Small Key (Palace of Darkness)', player, 5))
|
||||||
|
|
||||||
set_rule(world.get_entrance('Palace of Darkness Spike Statue Room Door', player), lambda state: state._lttp_has_key('Small Key (Palace of Darkness)', player, 6) or (
|
set_rule(world.get_entrance('Palace of Darkness Spike Statue Room Door', player), lambda state: state._lttp_has_key('Small Key (Palace of Darkness)', player, 6) or (
|
||||||
item_name(state, 'Palace of Darkness - Harmless Hellway', player) in [('Small Key (Palace of Darkness)', player)] and state._lttp_has_key('Small Key (Palace of Darkness)', player, 4)))
|
location_item_name(state, 'Palace of Darkness - Harmless Hellway', player) in [('Small Key (Palace of Darkness)', player)] and state._lttp_has_key('Small Key (Palace of Darkness)', player, 4)))
|
||||||
if world.accessibility[player] != 'locations':
|
if world.accessibility[player] != 'locations':
|
||||||
set_always_allow(world.get_location('Palace of Darkness - Harmless Hellway', player), lambda state, item: item.name == 'Small Key (Palace of Darkness)' and item.player == player and state._lttp_has_key('Small Key (Palace of Darkness)', player, 5))
|
set_always_allow(world.get_location('Palace of Darkness - Harmless Hellway', player), lambda state, item: item.name == 'Small Key (Palace of Darkness)' and item.player == player and state._lttp_has_key('Small Key (Palace of Darkness)', player, 5))
|
||||||
|
|
||||||
|
@ -369,7 +369,7 @@ def global_rules(world, player):
|
||||||
set_rule(world.get_entrance('Ganons Tower (Tile Room)', player), lambda state: state.has('Cane of Somaria', player))
|
set_rule(world.get_entrance('Ganons Tower (Tile Room)', player), lambda state: state.has('Cane of Somaria', player))
|
||||||
set_rule(world.get_entrance('Ganons Tower (Hookshot Room)', player), lambda state: state.has('Hammer', player) and (state.has('Hookshot', player) or state.has('Pegasus Boots', player)))
|
set_rule(world.get_entrance('Ganons Tower (Hookshot Room)', player), lambda state: state.has('Hammer', player) and (state.has('Hookshot', player) or state.has('Pegasus Boots', player)))
|
||||||
set_rule(world.get_entrance('Ganons Tower (Map Room)', player), lambda state: state._lttp_has_key('Small Key (Ganons Tower)', player, 4) or (
|
set_rule(world.get_entrance('Ganons Tower (Map Room)', player), lambda state: state._lttp_has_key('Small Key (Ganons Tower)', player, 4) or (
|
||||||
item_name(state, 'Ganons Tower - Map Chest', player) in [('Big Key (Ganons Tower)', player), ('Small Key (Ganons Tower)', player)] and state._lttp_has_key('Small Key (Ganons Tower)', player, 3)))
|
location_item_name(state, 'Ganons Tower - Map Chest', player) in [('Big Key (Ganons Tower)', player), ('Small Key (Ganons Tower)', player)] and state._lttp_has_key('Small Key (Ganons Tower)', player, 3)))
|
||||||
if world.accessibility[player] != 'locations':
|
if world.accessibility[player] != 'locations':
|
||||||
set_always_allow(world.get_location('Ganons Tower - Map Chest', player), lambda state, item: item.name == 'Small Key (Ganons Tower)' and item.player == player and state._lttp_has_key('Small Key (Ganons Tower)', player, 3) and state.can_reach('Ganons Tower (Hookshot Room)', 'region', player))
|
set_always_allow(world.get_location('Ganons Tower - Map Chest', player), lambda state, item: item.name == 'Small Key (Ganons Tower)' and item.player == player and state._lttp_has_key('Small Key (Ganons Tower)', player, 3) and state.can_reach('Ganons Tower (Hookshot Room)', 'region', player))
|
||||||
|
|
||||||
|
@ -911,7 +911,7 @@ def set_trock_key_rules(world, player):
|
||||||
# Now we need to set rules based on which entrances we have access to. The most important point is whether we have back access. If we have back access, we
|
# Now we need to set rules based on which entrances we have access to. The most important point is whether we have back access. If we have back access, we
|
||||||
# might open all the locked doors in any order so we need maximally restrictive rules.
|
# might open all the locked doors in any order so we need maximally restrictive rules.
|
||||||
if can_reach_back:
|
if can_reach_back:
|
||||||
set_rule(world.get_location('Turtle Rock - Big Key Chest', player), lambda state: (state._lttp_has_key('Small Key (Turtle Rock)', player, 4) or item_name(state, 'Turtle Rock - Big Key Chest', player) == ('Small Key (Turtle Rock)', player)))
|
set_rule(world.get_location('Turtle Rock - Big Key Chest', player), lambda state: (state._lttp_has_key('Small Key (Turtle Rock)', player, 4) or location_item_name(state, 'Turtle Rock - Big Key Chest', player) == ('Small Key (Turtle Rock)', player)))
|
||||||
set_rule(world.get_entrance('Turtle Rock (Chain Chomp Room) (South)', player), lambda state: state._lttp_has_key('Small Key (Turtle Rock)', player, 4))
|
set_rule(world.get_entrance('Turtle Rock (Chain Chomp Room) (South)', player), lambda state: state._lttp_has_key('Small Key (Turtle Rock)', player, 4))
|
||||||
# Only consider wasting the key on the Trinexx door for going from the front entrance to middle section. If other key doors are accessible, then these doors can be avoided
|
# Only consider wasting the key on the Trinexx door for going from the front entrance to middle section. If other key doors are accessible, then these doors can be avoided
|
||||||
set_rule(world.get_entrance('Turtle Rock (Chain Chomp Room) (North)', player), lambda state: state._lttp_has_key('Small Key (Turtle Rock)', player, 3))
|
set_rule(world.get_entrance('Turtle Rock (Chain Chomp Room) (North)', player), lambda state: state._lttp_has_key('Small Key (Turtle Rock)', player, 3))
|
||||||
|
@ -931,7 +931,7 @@ def set_trock_key_rules(world, player):
|
||||||
def tr_big_key_chest_keys_needed(state):
|
def tr_big_key_chest_keys_needed(state):
|
||||||
# This function handles the key requirements for the TR Big Chest in the situations it having the Big Key should logically require 2 keys, small key
|
# This function handles the key requirements for the TR Big Chest in the situations it having the Big Key should logically require 2 keys, small key
|
||||||
# should logically require no keys, and anything else should logically require 4 keys.
|
# should logically require no keys, and anything else should logically require 4 keys.
|
||||||
item = item_name(state, 'Turtle Rock - Big Key Chest', player)
|
item = location_item_name(state, 'Turtle Rock - Big Key Chest', player)
|
||||||
if item in [('Small Key (Turtle Rock)', player)]:
|
if item in [('Small Key (Turtle Rock)', player)]:
|
||||||
return 0
|
return 0
|
||||||
if item in [('Big Key (Turtle Rock)', player)]:
|
if item in [('Big Key (Turtle Rock)', player)]:
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import collections
|
import collections
|
||||||
import typing
|
import typing
|
||||||
|
|
||||||
from BaseClasses import LocationProgressType, MultiWorld
|
from BaseClasses import LocationProgressType, MultiWorld, Location, Region, Entrance
|
||||||
|
|
||||||
if typing.TYPE_CHECKING:
|
if typing.TYPE_CHECKING:
|
||||||
import BaseClasses
|
import BaseClasses
|
||||||
|
@ -143,14 +143,41 @@ def add_item_rule(location: "BaseClasses.Location", rule: ItemRule, combine: str
|
||||||
def item_in_locations(state: "BaseClasses.CollectionState", item: str, player: int,
|
def item_in_locations(state: "BaseClasses.CollectionState", item: str, player: int,
|
||||||
locations: typing.Sequence["BaseClasses.Location"]) -> bool:
|
locations: typing.Sequence["BaseClasses.Location"]) -> bool:
|
||||||
for location in locations:
|
for location in locations:
|
||||||
if item_name(state, location[0], location[1]) == (item, player):
|
if location_item_name(state, location[0], location[1]) == (item, player):
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def item_name(state: "BaseClasses.CollectionState", location: str, player: int) -> \
|
def location_item_name(state: "BaseClasses.CollectionState", location: str, player: int) -> \
|
||||||
typing.Optional[typing.Tuple[str, int]]:
|
typing.Optional[typing.Tuple[str, int]]:
|
||||||
location = state.multiworld.get_location(location, player)
|
location = state.multiworld.get_location(location, player)
|
||||||
if location.item is None:
|
if location.item is None:
|
||||||
return None
|
return None
|
||||||
return location.item.name, location.item.player
|
return location.item.name, location.item.player
|
||||||
|
|
||||||
|
|
||||||
|
def allow_self_locking_items(spot: typing.Union[Location, Region], *item_names: str) -> None:
|
||||||
|
"""
|
||||||
|
This function sets rules on the supplied spot, such that the supplied item_name(s) can possibly be placed there.
|
||||||
|
|
||||||
|
spot: Location or Region that the item(s) are allowed to be placed in
|
||||||
|
item_names: item name or names that are allowed to be placed in the Location or Region
|
||||||
|
"""
|
||||||
|
player = spot.player
|
||||||
|
|
||||||
|
def add_allowed_rules(area: typing.Union[Location, Entrance], location: Location) -> None:
|
||||||
|
def set_always_allow(location: Location, rule: typing.Callable) -> None:
|
||||||
|
location.always_allow = rule
|
||||||
|
|
||||||
|
for item_name in item_names:
|
||||||
|
add_rule(area, lambda state, item_name=item_name:
|
||||||
|
location_item_name(state, location.name, player) == (item_name, player), "or")
|
||||||
|
set_always_allow(location, lambda state, item:
|
||||||
|
item.player == player and item.name in [item_name for item_name in item_names])
|
||||||
|
|
||||||
|
if isinstance(spot, Region):
|
||||||
|
for entrance in spot.entrances:
|
||||||
|
for location in spot.locations:
|
||||||
|
add_allowed_rules(entrance, location)
|
||||||
|
else:
|
||||||
|
add_allowed_rules(spot, spot)
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
from typing import Dict, Callable, Optional, Tuple, Union, TYPE_CHECKING, List, Iterable
|
from typing import Dict, Callable, TYPE_CHECKING
|
||||||
|
|
||||||
from BaseClasses import CollectionState, MultiWorld, Location, Region, Entrance, Item
|
from BaseClasses import CollectionState, MultiWorld
|
||||||
|
from worlds.generic.Rules import set_rule, allow_self_locking_items
|
||||||
from .Options import MessengerAccessibility, Goal
|
from .Options import MessengerAccessibility, Goal
|
||||||
from .Constants import NOTES, PHOBEKINS
|
from .Constants import NOTES, PHOBEKINS
|
||||||
from ..generic.Rules import add_rule, set_rule
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from . import MessengerWorld
|
from . import MessengerWorld
|
||||||
|
@ -113,39 +113,6 @@ class MessengerRules:
|
||||||
set_self_locking_items(multiworld, self.player)
|
set_self_locking_items(multiworld, self.player)
|
||||||
|
|
||||||
|
|
||||||
def location_item_name(state: CollectionState, location_name: str, player: int) -> Optional[Tuple[str, int]]:
|
|
||||||
location = state.multiworld.get_location(location_name, player)
|
|
||||||
if location.item is None:
|
|
||||||
return None
|
|
||||||
return location.item.name, location.item.player
|
|
||||||
|
|
||||||
|
|
||||||
def allow_self_locking_items(spot: Union[Location, Region], *item_names: str) -> None:
|
|
||||||
"""
|
|
||||||
Sets rules on the supplied spot, such that the supplied item_name(s) can possibly be placed there.
|
|
||||||
:param spot: Location or Region that the item(s) are allowed to be placed in
|
|
||||||
:param item_names: item name or names that are allowed to be placed in the Location or Region
|
|
||||||
"""
|
|
||||||
player = spot.player
|
|
||||||
|
|
||||||
def set_always_allow(location: Location, rule: Callable[[CollectionState, Item], bool]) -> None:
|
|
||||||
location.always_allow = rule
|
|
||||||
|
|
||||||
def add_allowed_rules(area: Union[Location, Entrance], location: Location) -> None:
|
|
||||||
for item_name in item_names:
|
|
||||||
add_rule(area, lambda state, item_name=item_name:
|
|
||||||
location_item_name(state, location.name, player) == (item_name, player), "or")
|
|
||||||
set_always_allow(location, lambda state, item:
|
|
||||||
item.player == player and item.name in [item_name for item_name in item_names])
|
|
||||||
|
|
||||||
if isinstance(spot, Region):
|
|
||||||
for entrance in spot.entrances:
|
|
||||||
for location in spot.locations:
|
|
||||||
add_allowed_rules(entrance, location)
|
|
||||||
else:
|
|
||||||
add_allowed_rules(spot, spot)
|
|
||||||
|
|
||||||
|
|
||||||
def set_self_locking_items(multiworld: MultiWorld, player: int) -> None:
|
def set_self_locking_items(multiworld: MultiWorld, player: int) -> None:
|
||||||
# do the ones for seal shuffle on and off first
|
# do the ones for seal shuffle on and off first
|
||||||
allow_self_locking_items(multiworld.get_location("Key of Strength", player), "Power Thistle")
|
allow_self_locking_items(multiworld.get_location("Key of Strength", player), "Power Thistle")
|
||||||
|
|
Loading…
Reference in New Issue