parent
9fa1f4e85f
commit
a4b61118cf
|
@ -14,7 +14,7 @@ class LocationData(NamedTuple):
|
||||||
rule: Callable[[CollectionState], bool] = lambda state: True
|
rule: Callable[[CollectionState], bool] = lambda state: True
|
||||||
|
|
||||||
|
|
||||||
def get_locations(world: Optional[MultiWorld], player: Optional[int],
|
def get_location_datas(world: Optional[MultiWorld], player: Optional[int],
|
||||||
precalculated_weights: PreCalculatedWeights) -> Tuple[LocationData, ...]:
|
precalculated_weights: PreCalculatedWeights) -> Tuple[LocationData, ...]:
|
||||||
|
|
||||||
flooded: PreCalculatedWeights = precalculated_weights
|
flooded: PreCalculatedWeights = precalculated_weights
|
||||||
|
|
|
@ -1,64 +1,64 @@
|
||||||
from typing import List, Set, Dict, Tuple, Optional, Callable
|
from typing import List, Set, Dict, Tuple, Optional, Callable
|
||||||
from BaseClasses import CollectionState, MultiWorld, Region, Entrance, Location
|
from BaseClasses import CollectionState, MultiWorld, Region, Entrance, Location
|
||||||
from .Options import is_option_enabled
|
from .Options import is_option_enabled
|
||||||
from .Locations import LocationData
|
from .Locations import LocationData, get_location_datas
|
||||||
from .PreCalculatedWeights import PreCalculatedWeights
|
from .PreCalculatedWeights import PreCalculatedWeights
|
||||||
from .LogicExtensions import TimespinnerLogic
|
from .LogicExtensions import TimespinnerLogic
|
||||||
|
|
||||||
|
|
||||||
def create_regions(world: MultiWorld, player: int, locations: Tuple[LocationData, ...], location_cache: List[Location],
|
def create_regions_and_locations(world: MultiWorld, player: int, precalculated_weights: PreCalculatedWeights):
|
||||||
precalculated_weights: PreCalculatedWeights):
|
locationn_datas: Tuple[LocationData] = get_location_datas(world, player, precalculated_weights)
|
||||||
|
|
||||||
locations_per_region = get_locations_per_region(locations)
|
locations_per_region: Dict[str, List[LocationData]] = split_location_datas_per_region(locationn_datas)
|
||||||
|
|
||||||
regions = [
|
regions = [
|
||||||
create_region(world, player, locations_per_region, location_cache, 'Menu'),
|
create_region(world, player, locations_per_region, 'Menu'),
|
||||||
create_region(world, player, locations_per_region, location_cache, 'Tutorial'),
|
create_region(world, player, locations_per_region, 'Tutorial'),
|
||||||
create_region(world, player, locations_per_region, location_cache, 'Lake desolation'),
|
create_region(world, player, locations_per_region, 'Lake desolation'),
|
||||||
create_region(world, player, locations_per_region, location_cache, 'Upper lake desolation'),
|
create_region(world, player, locations_per_region, 'Upper lake desolation'),
|
||||||
create_region(world, player, locations_per_region, location_cache, 'Lower lake desolation'),
|
create_region(world, player, locations_per_region, 'Lower lake desolation'),
|
||||||
create_region(world, player, locations_per_region, location_cache, 'Eastern lake desolation'),
|
create_region(world, player, locations_per_region, 'Eastern lake desolation'),
|
||||||
create_region(world, player, locations_per_region, location_cache, 'Library'),
|
create_region(world, player, locations_per_region, 'Library'),
|
||||||
create_region(world, player, locations_per_region, location_cache, 'Library top'),
|
create_region(world, player, locations_per_region, 'Library top'),
|
||||||
create_region(world, player, locations_per_region, location_cache, 'Varndagroth tower left'),
|
create_region(world, player, locations_per_region, 'Varndagroth tower left'),
|
||||||
create_region(world, player, locations_per_region, location_cache, 'Varndagroth tower right (upper)'),
|
create_region(world, player, locations_per_region, 'Varndagroth tower right (upper)'),
|
||||||
create_region(world, player, locations_per_region, location_cache, 'Varndagroth tower right (lower)'),
|
create_region(world, player, locations_per_region, 'Varndagroth tower right (lower)'),
|
||||||
create_region(world, player, locations_per_region, location_cache, 'Varndagroth tower right (elevator)'),
|
create_region(world, player, locations_per_region, 'Varndagroth tower right (elevator)'),
|
||||||
create_region(world, player, locations_per_region, location_cache, 'Sealed Caves (Sirens)'),
|
create_region(world, player, locations_per_region, 'Sealed Caves (Sirens)'),
|
||||||
create_region(world, player, locations_per_region, location_cache, 'Military Fortress'),
|
create_region(world, player, locations_per_region, 'Military Fortress'),
|
||||||
create_region(world, player, locations_per_region, location_cache, 'Military Fortress (hangar)'),
|
create_region(world, player, locations_per_region, 'Military Fortress (hangar)'),
|
||||||
create_region(world, player, locations_per_region, location_cache, 'The lab'),
|
create_region(world, player, locations_per_region, 'The lab'),
|
||||||
create_region(world, player, locations_per_region, location_cache, 'The lab (power off)'),
|
create_region(world, player, locations_per_region, 'The lab (power off)'),
|
||||||
create_region(world, player, locations_per_region, location_cache, 'The lab (upper)'),
|
create_region(world, player, locations_per_region, 'The lab (upper)'),
|
||||||
create_region(world, player, locations_per_region, location_cache, 'Emperors tower'),
|
create_region(world, player, locations_per_region, 'Emperors tower'),
|
||||||
create_region(world, player, locations_per_region, location_cache, 'Skeleton Shaft'),
|
create_region(world, player, locations_per_region, 'Skeleton Shaft'),
|
||||||
create_region(world, player, locations_per_region, location_cache, 'Sealed Caves (upper)'),
|
create_region(world, player, locations_per_region, 'Sealed Caves (upper)'),
|
||||||
create_region(world, player, locations_per_region, location_cache, 'Sealed Caves (Xarion)'),
|
create_region(world, player, locations_per_region, 'Sealed Caves (Xarion)'),
|
||||||
create_region(world, player, locations_per_region, location_cache, 'Refugee Camp'),
|
create_region(world, player, locations_per_region, 'Refugee Camp'),
|
||||||
create_region(world, player, locations_per_region, location_cache, 'Forest'),
|
create_region(world, player, locations_per_region, 'Forest'),
|
||||||
create_region(world, player, locations_per_region, location_cache, 'Left Side forest Caves'),
|
create_region(world, player, locations_per_region, 'Left Side forest Caves'),
|
||||||
create_region(world, player, locations_per_region, location_cache, 'Upper Lake Serene'),
|
create_region(world, player, locations_per_region, 'Upper Lake Serene'),
|
||||||
create_region(world, player, locations_per_region, location_cache, 'Lower Lake Serene'),
|
create_region(world, player, locations_per_region, 'Lower Lake Serene'),
|
||||||
create_region(world, player, locations_per_region, location_cache, 'Caves of Banishment (upper)'),
|
create_region(world, player, locations_per_region, 'Caves of Banishment (upper)'),
|
||||||
create_region(world, player, locations_per_region, location_cache, 'Caves of Banishment (Maw)'),
|
create_region(world, player, locations_per_region, 'Caves of Banishment (Maw)'),
|
||||||
create_region(world, player, locations_per_region, location_cache, 'Caves of Banishment (Sirens)'),
|
create_region(world, player, locations_per_region, 'Caves of Banishment (Sirens)'),
|
||||||
create_region(world, player, locations_per_region, location_cache, 'Castle Ramparts'),
|
create_region(world, player, locations_per_region, 'Castle Ramparts'),
|
||||||
create_region(world, player, locations_per_region, location_cache, 'Castle Keep'),
|
create_region(world, player, locations_per_region, 'Castle Keep'),
|
||||||
create_region(world, player, locations_per_region, location_cache, 'Castle Basement'),
|
create_region(world, player, locations_per_region, 'Castle Basement'),
|
||||||
create_region(world, player, locations_per_region, location_cache, 'Royal towers (lower)'),
|
create_region(world, player, locations_per_region, 'Royal towers (lower)'),
|
||||||
create_region(world, player, locations_per_region, location_cache, 'Royal towers'),
|
create_region(world, player, locations_per_region, 'Royal towers'),
|
||||||
create_region(world, player, locations_per_region, location_cache, 'Royal towers (upper)'),
|
create_region(world, player, locations_per_region, 'Royal towers (upper)'),
|
||||||
create_region(world, player, locations_per_region, location_cache, 'Temporal Gyre'),
|
create_region(world, player, locations_per_region, 'Temporal Gyre'),
|
||||||
create_region(world, player, locations_per_region, location_cache, 'Ancient Pyramid (entrance)'),
|
create_region(world, player, locations_per_region, 'Ancient Pyramid (entrance)'),
|
||||||
create_region(world, player, locations_per_region, location_cache, 'Ancient Pyramid (left)'),
|
create_region(world, player, locations_per_region, 'Ancient Pyramid (left)'),
|
||||||
create_region(world, player, locations_per_region, location_cache, 'Ancient Pyramid (right)'),
|
create_region(world, player, locations_per_region, 'Ancient Pyramid (right)'),
|
||||||
create_region(world, player, locations_per_region, location_cache, 'Space time continuum')
|
create_region(world, player, locations_per_region, 'Space time continuum')
|
||||||
]
|
]
|
||||||
|
|
||||||
if is_option_enabled(world, player, "GyreArchives"):
|
if is_option_enabled(world, player, "GyreArchives"):
|
||||||
regions.extend([
|
regions.extend([
|
||||||
create_region(world, player, locations_per_region, location_cache, 'Ravenlord\'s Lair'),
|
create_region(world, player, locations_per_region, 'Ravenlord\'s Lair'),
|
||||||
create_region(world, player, locations_per_region, location_cache, 'Ifrit\'s Lair'),
|
create_region(world, player, locations_per_region, 'Ifrit\'s Lair'),
|
||||||
])
|
])
|
||||||
|
|
||||||
if __debug__:
|
if __debug__:
|
||||||
|
@ -70,127 +70,126 @@ def create_regions(world: MultiWorld, player: int, locations: Tuple[LocationData
|
||||||
|
|
||||||
flooded: PreCalculatedWeights = precalculated_weights
|
flooded: PreCalculatedWeights = precalculated_weights
|
||||||
logic = TimespinnerLogic(world, player, precalculated_weights)
|
logic = TimespinnerLogic(world, player, precalculated_weights)
|
||||||
names: Dict[str, int] = {}
|
|
||||||
|
|
||||||
connect(world, player, names, 'Lake desolation', 'Lower lake desolation', lambda state: logic.has_timestop(state) or state.has('Talaria Attachment', player) or flooded.flood_lake_desolation)
|
connect(world, player, 'Lake desolation', 'Lower lake desolation', lambda state: logic.has_timestop(state) or state.has('Talaria Attachment', player) or flooded.flood_lake_desolation)
|
||||||
connect(world, player, names, 'Lake desolation', 'Upper lake desolation', lambda state: logic.has_fire(state) and state.can_reach('Upper Lake Serene', 'Region', player))
|
connect(world, player, 'Lake desolation', 'Upper lake desolation', lambda state: logic.has_fire(state) and state.can_reach('Upper Lake Serene', 'Region', player))
|
||||||
connect(world, player, names, 'Lake desolation', 'Skeleton Shaft', lambda state: logic.has_doublejump(state) or flooded.flood_lake_desolation)
|
connect(world, player, 'Lake desolation', 'Skeleton Shaft', lambda state: logic.has_doublejump(state) or flooded.flood_lake_desolation)
|
||||||
connect(world, player, names, 'Lake desolation', 'Space time continuum', logic.has_teleport)
|
connect(world, player, 'Lake desolation', 'Space time continuum', logic.has_teleport)
|
||||||
connect(world, player, names, 'Upper lake desolation', 'Lake desolation')
|
connect(world, player, 'Upper lake desolation', 'Lake desolation')
|
||||||
connect(world, player, names, 'Upper lake desolation', 'Eastern lake desolation')
|
connect(world, player, 'Upper lake desolation', 'Eastern lake desolation')
|
||||||
connect(world, player, names, 'Lower lake desolation', 'Lake desolation')
|
connect(world, player, 'Lower lake desolation', 'Lake desolation')
|
||||||
connect(world, player, names, 'Lower lake desolation', 'Eastern lake desolation')
|
connect(world, player, 'Lower lake desolation', 'Eastern lake desolation')
|
||||||
connect(world, player, names, 'Eastern lake desolation', 'Space time continuum', logic.has_teleport)
|
connect(world, player, 'Eastern lake desolation', 'Space time continuum', logic.has_teleport)
|
||||||
connect(world, player, names, 'Eastern lake desolation', 'Library')
|
connect(world, player, 'Eastern lake desolation', 'Library')
|
||||||
connect(world, player, names, 'Eastern lake desolation', 'Lower lake desolation')
|
connect(world, player, 'Eastern lake desolation', 'Lower lake desolation')
|
||||||
connect(world, player, names, 'Eastern lake desolation', 'Upper lake desolation', lambda state: logic.has_fire(state) and state.can_reach('Upper Lake Serene', 'Region', player))
|
connect(world, player, 'Eastern lake desolation', 'Upper lake desolation', lambda state: logic.has_fire(state) and state.can_reach('Upper Lake Serene', 'Region', player))
|
||||||
connect(world, player, names, 'Library', 'Eastern lake desolation')
|
connect(world, player, 'Library', 'Eastern lake desolation')
|
||||||
connect(world, player, names, 'Library', 'Library top', lambda state: logic.has_doublejump(state) or state.has('Talaria Attachment', player))
|
connect(world, player, 'Library', 'Library top', lambda state: logic.has_doublejump(state) or state.has('Talaria Attachment', player))
|
||||||
connect(world, player, names, 'Library', 'Varndagroth tower left', logic.has_keycard_D)
|
connect(world, player, 'Library', 'Varndagroth tower left', logic.has_keycard_D)
|
||||||
connect(world, player, names, 'Library', 'Space time continuum', logic.has_teleport)
|
connect(world, player, 'Library', 'Space time continuum', logic.has_teleport)
|
||||||
connect(world, player, names, 'Library top', 'Library')
|
connect(world, player, 'Library top', 'Library')
|
||||||
connect(world, player, names, 'Varndagroth tower left', 'Library')
|
connect(world, player, 'Varndagroth tower left', 'Library')
|
||||||
connect(world, player, names, 'Varndagroth tower left', 'Varndagroth tower right (upper)', logic.has_keycard_C)
|
connect(world, player, 'Varndagroth tower left', 'Varndagroth tower right (upper)', logic.has_keycard_C)
|
||||||
connect(world, player, names, 'Varndagroth tower left', 'Varndagroth tower right (lower)', logic.has_keycard_B)
|
connect(world, player, 'Varndagroth tower left', 'Varndagroth tower right (lower)', logic.has_keycard_B)
|
||||||
connect(world, player, names, 'Varndagroth tower left', 'Sealed Caves (Sirens)', lambda state: logic.has_keycard_B(state) and state.has('Elevator Keycard', player))
|
connect(world, player, 'Varndagroth tower left', 'Sealed Caves (Sirens)', lambda state: logic.has_keycard_B(state) and state.has('Elevator Keycard', player))
|
||||||
connect(world, player, names, 'Varndagroth tower left', 'Refugee Camp', lambda state: state.has('Timespinner Wheel', player) and state.has('Timespinner Spindle', player))
|
connect(world, player, 'Varndagroth tower left', 'Refugee Camp', lambda state: state.has('Timespinner Wheel', player) and state.has('Timespinner Spindle', player))
|
||||||
connect(world, player, names, 'Varndagroth tower right (upper)', 'Varndagroth tower left')
|
connect(world, player, 'Varndagroth tower right (upper)', 'Varndagroth tower left')
|
||||||
connect(world, player, names, 'Varndagroth tower right (upper)', 'Varndagroth tower right (elevator)', lambda state: state.has('Elevator Keycard', player))
|
connect(world, player, 'Varndagroth tower right (upper)', 'Varndagroth tower right (elevator)', lambda state: state.has('Elevator Keycard', player))
|
||||||
connect(world, player, names, 'Varndagroth tower right (elevator)', 'Varndagroth tower right (upper)')
|
connect(world, player, 'Varndagroth tower right (elevator)', 'Varndagroth tower right (upper)')
|
||||||
connect(world, player, names, 'Varndagroth tower right (elevator)', 'Varndagroth tower right (lower)')
|
connect(world, player, 'Varndagroth tower right (elevator)', 'Varndagroth tower right (lower)')
|
||||||
connect(world, player, names, 'Varndagroth tower right (lower)', 'Varndagroth tower left', logic.has_keycard_B)
|
connect(world, player, 'Varndagroth tower right (lower)', 'Varndagroth tower left', logic.has_keycard_B)
|
||||||
connect(world, player, names, 'Varndagroth tower right (lower)', 'Varndagroth tower right (elevator)', lambda state: state.has('Elevator Keycard', player))
|
connect(world, player, 'Varndagroth tower right (lower)', 'Varndagroth tower right (elevator)', lambda state: state.has('Elevator Keycard', player))
|
||||||
connect(world, player, names, 'Varndagroth tower right (lower)', 'Sealed Caves (Sirens)', lambda state: logic.has_keycard_B(state) and state.has('Elevator Keycard', player))
|
connect(world, player, 'Varndagroth tower right (lower)', 'Sealed Caves (Sirens)', lambda state: logic.has_keycard_B(state) and state.has('Elevator Keycard', player))
|
||||||
connect(world, player, names, 'Varndagroth tower right (lower)', 'Military Fortress', logic.can_kill_all_3_bosses)
|
connect(world, player, 'Varndagroth tower right (lower)', 'Military Fortress', logic.can_kill_all_3_bosses)
|
||||||
connect(world, player, names, 'Varndagroth tower right (lower)', 'Space time continuum', logic.has_teleport)
|
connect(world, player, 'Varndagroth tower right (lower)', 'Space time continuum', logic.has_teleport)
|
||||||
connect(world, player, names, 'Sealed Caves (Sirens)', 'Varndagroth tower left', lambda state: state.has('Elevator Keycard', player))
|
connect(world, player, 'Sealed Caves (Sirens)', 'Varndagroth tower left', lambda state: state.has('Elevator Keycard', player))
|
||||||
connect(world, player, names, 'Sealed Caves (Sirens)', 'Varndagroth tower right (lower)', lambda state: state.has('Elevator Keycard', player))
|
connect(world, player, 'Sealed Caves (Sirens)', 'Varndagroth tower right (lower)', lambda state: state.has('Elevator Keycard', player))
|
||||||
connect(world, player, names, 'Sealed Caves (Sirens)', 'Space time continuum', logic.has_teleport)
|
connect(world, player, 'Sealed Caves (Sirens)', 'Space time continuum', logic.has_teleport)
|
||||||
connect(world, player, names, 'Military Fortress', 'Varndagroth tower right (lower)', logic.can_kill_all_3_bosses)
|
connect(world, player, 'Military Fortress', 'Varndagroth tower right (lower)', logic.can_kill_all_3_bosses)
|
||||||
connect(world, player, names, 'Military Fortress', 'Temporal Gyre', lambda state: state.has('Timespinner Wheel', player))
|
connect(world, player, 'Military Fortress', 'Temporal Gyre', lambda state: state.has('Timespinner Wheel', player))
|
||||||
connect(world, player, names, 'Military Fortress', 'Military Fortress (hangar)', logic.has_doublejump)
|
connect(world, player, 'Military Fortress', 'Military Fortress (hangar)', logic.has_doublejump)
|
||||||
connect(world, player, names, 'Military Fortress (hangar)', 'Military Fortress')
|
connect(world, player, 'Military Fortress (hangar)', 'Military Fortress')
|
||||||
connect(world, player, names, 'Military Fortress (hangar)', 'The lab', lambda state: logic.has_keycard_B(state) and logic.has_doublejump(state))
|
connect(world, player, 'Military Fortress (hangar)', 'The lab', lambda state: logic.has_keycard_B(state) and logic.has_doublejump(state))
|
||||||
connect(world, player, names, 'Temporal Gyre', 'Military Fortress')
|
connect(world, player, 'Temporal Gyre', 'Military Fortress')
|
||||||
connect(world, player, names, 'The lab', 'Military Fortress')
|
connect(world, player, 'The lab', 'Military Fortress')
|
||||||
connect(world, player, names, 'The lab', 'The lab (power off)', logic.has_doublejump_of_npc)
|
connect(world, player, 'The lab', 'The lab (power off)', logic.has_doublejump_of_npc)
|
||||||
connect(world, player, names, 'The lab (power off)', 'The lab')
|
connect(world, player, 'The lab (power off)', 'The lab')
|
||||||
connect(world, player, names, 'The lab (power off)', 'The lab (upper)', logic.has_forwarddash_doublejump)
|
connect(world, player, 'The lab (power off)', 'The lab (upper)', logic.has_forwarddash_doublejump)
|
||||||
connect(world, player, names, 'The lab (upper)', 'The lab (power off)')
|
connect(world, player, 'The lab (upper)', 'The lab (power off)')
|
||||||
connect(world, player, names, 'The lab (upper)', 'Emperors tower', logic.has_forwarddash_doublejump)
|
connect(world, player, 'The lab (upper)', 'Emperors tower', logic.has_forwarddash_doublejump)
|
||||||
connect(world, player, names, 'The lab (upper)', 'Ancient Pyramid (entrance)', lambda state: state.has_all({'Timespinner Wheel', 'Timespinner Spindle', 'Timespinner Gear 1', 'Timespinner Gear 2', 'Timespinner Gear 3'}, player))
|
connect(world, player, 'The lab (upper)', 'Ancient Pyramid (entrance)', lambda state: state.has_all({'Timespinner Wheel', 'Timespinner Spindle', 'Timespinner Gear 1', 'Timespinner Gear 2', 'Timespinner Gear 3'}, player))
|
||||||
connect(world, player, names, 'Emperors tower', 'The lab (upper)')
|
connect(world, player, 'Emperors tower', 'The lab (upper)')
|
||||||
connect(world, player, names, 'Skeleton Shaft', 'Lake desolation')
|
connect(world, player, 'Skeleton Shaft', 'Lake desolation')
|
||||||
connect(world, player, names, 'Skeleton Shaft', 'Sealed Caves (upper)', logic.has_keycard_A)
|
connect(world, player, 'Skeleton Shaft', 'Sealed Caves (upper)', logic.has_keycard_A)
|
||||||
connect(world, player, names, 'Skeleton Shaft', 'Space time continuum', logic.has_teleport)
|
connect(world, player, 'Skeleton Shaft', 'Space time continuum', logic.has_teleport)
|
||||||
connect(world, player, names, 'Sealed Caves (upper)', 'Skeleton Shaft')
|
connect(world, player, 'Sealed Caves (upper)', 'Skeleton Shaft')
|
||||||
connect(world, player, names, 'Sealed Caves (upper)', 'Sealed Caves (Xarion)', lambda state: logic.has_teleport(state) or logic.has_doublejump(state))
|
connect(world, player, 'Sealed Caves (upper)', 'Sealed Caves (Xarion)', lambda state: logic.has_teleport(state) or logic.has_doublejump(state))
|
||||||
connect(world, player, names, 'Sealed Caves (Xarion)', 'Sealed Caves (upper)', logic.has_doublejump)
|
connect(world, player, 'Sealed Caves (Xarion)', 'Sealed Caves (upper)', logic.has_doublejump)
|
||||||
connect(world, player, names, 'Sealed Caves (Xarion)', 'Space time continuum', logic.has_teleport)
|
connect(world, player, 'Sealed Caves (Xarion)', 'Space time continuum', logic.has_teleport)
|
||||||
connect(world, player, names, 'Refugee Camp', 'Forest')
|
connect(world, player, 'Refugee Camp', 'Forest')
|
||||||
#connect(world, player, names, 'Refugee Camp', 'Library', lambda state: not is_option_enabled(world, player, "Inverted"))
|
#connect(world, player, 'Refugee Camp', 'Library', lambda state: not is_option_enabled(world, player, "Inverted"))
|
||||||
connect(world, player, names, 'Refugee Camp', 'Space time continuum', logic.has_teleport)
|
connect(world, player, 'Refugee Camp', 'Space time continuum', logic.has_teleport)
|
||||||
connect(world, player, names, 'Forest', 'Refugee Camp')
|
connect(world, player, 'Forest', 'Refugee Camp')
|
||||||
connect(world, player, names, 'Forest', 'Left Side forest Caves', lambda state: state.has('Talaria Attachment', player) or logic.has_timestop(state))
|
connect(world, player, 'Forest', 'Left Side forest Caves', lambda state: state.has('Talaria Attachment', player) or logic.has_timestop(state))
|
||||||
connect(world, player, names, 'Forest', 'Caves of Banishment (Sirens)')
|
connect(world, player, 'Forest', 'Caves of Banishment (Sirens)')
|
||||||
connect(world, player, names, 'Forest', 'Castle Ramparts')
|
connect(world, player, 'Forest', 'Castle Ramparts')
|
||||||
connect(world, player, names, 'Left Side forest Caves', 'Forest')
|
connect(world, player, 'Left Side forest Caves', 'Forest')
|
||||||
connect(world, player, names, 'Left Side forest Caves', 'Upper Lake Serene', logic.has_timestop)
|
connect(world, player, 'Left Side forest Caves', 'Upper Lake Serene', logic.has_timestop)
|
||||||
connect(world, player, names, 'Left Side forest Caves', 'Lower Lake Serene', lambda state: state.has('Water Mask', player) or flooded.dry_lake_serene)
|
connect(world, player, 'Left Side forest Caves', 'Lower Lake Serene', lambda state: state.has('Water Mask', player) or flooded.dry_lake_serene)
|
||||||
connect(world, player, names, 'Left Side forest Caves', 'Space time continuum', logic.has_teleport)
|
connect(world, player, 'Left Side forest Caves', 'Space time continuum', logic.has_teleport)
|
||||||
connect(world, player, names, 'Upper Lake Serene', 'Left Side forest Caves')
|
connect(world, player, 'Upper Lake Serene', 'Left Side forest Caves')
|
||||||
connect(world, player, names, 'Upper Lake Serene', 'Lower Lake Serene', lambda state: state.has('Water Mask', player))
|
connect(world, player, 'Upper Lake Serene', 'Lower Lake Serene', lambda state: state.has('Water Mask', player))
|
||||||
connect(world, player, names, 'Lower Lake Serene', 'Upper Lake Serene')
|
connect(world, player, 'Lower Lake Serene', 'Upper Lake Serene')
|
||||||
connect(world, player, names, 'Lower Lake Serene', 'Left Side forest Caves')
|
connect(world, player, 'Lower Lake Serene', 'Left Side forest Caves')
|
||||||
connect(world, player, names, 'Lower Lake Serene', 'Caves of Banishment (upper)')
|
connect(world, player, 'Lower Lake Serene', 'Caves of Banishment (upper)')
|
||||||
connect(world, player, names, 'Caves of Banishment (upper)', 'Upper Lake Serene', lambda state: state.has('Water Mask', player) or flooded.dry_lake_serene)
|
connect(world, player, 'Caves of Banishment (upper)', 'Upper Lake Serene', lambda state: state.has('Water Mask', player) or flooded.dry_lake_serene)
|
||||||
connect(world, player, names, 'Caves of Banishment (upper)', 'Caves of Banishment (Maw)', lambda state: logic.has_doublejump(state) or state.has_any({'Gas Mask', 'Twin Pyramid Key'}, player))
|
connect(world, player, 'Caves of Banishment (upper)', 'Caves of Banishment (Maw)', lambda state: logic.has_doublejump(state) or state.has_any({'Gas Mask', 'Twin Pyramid Key'}, player))
|
||||||
connect(world, player, names, 'Caves of Banishment (upper)', 'Space time continuum', logic.has_teleport)
|
connect(world, player, 'Caves of Banishment (upper)', 'Space time continuum', logic.has_teleport)
|
||||||
connect(world, player, names, 'Caves of Banishment (Maw)', 'Caves of Banishment (upper)', lambda state: logic.has_doublejump(state) if not flooded.flood_maw else state.has('Water Mask', player))
|
connect(world, player, 'Caves of Banishment (Maw)', 'Caves of Banishment (upper)', lambda state: logic.has_doublejump(state) if not flooded.flood_maw else state.has('Water Mask', player))
|
||||||
connect(world, player, names, 'Caves of Banishment (Maw)', 'Caves of Banishment (Sirens)', lambda state: state.has('Gas Mask', player))
|
connect(world, player, 'Caves of Banishment (Maw)', 'Caves of Banishment (Sirens)', lambda state: state.has_any({'Gas Mask', 'Talaria Attachment'}, player) )
|
||||||
connect(world, player, names, 'Caves of Banishment (Maw)', 'Space time continuum', logic.has_teleport)
|
connect(world, player, 'Caves of Banishment (Maw)', 'Space time continuum', logic.has_teleport)
|
||||||
connect(world, player, names, 'Caves of Banishment (Sirens)', 'Forest')
|
connect(world, player, 'Caves of Banishment (Sirens)', 'Forest')
|
||||||
connect(world, player, names, 'Castle Ramparts', 'Forest')
|
connect(world, player, 'Castle Ramparts', 'Forest')
|
||||||
connect(world, player, names, 'Castle Ramparts', 'Castle Keep')
|
connect(world, player, 'Castle Ramparts', 'Castle Keep')
|
||||||
connect(world, player, names, 'Castle Ramparts', 'Space time continuum', logic.has_teleport)
|
connect(world, player, 'Castle Ramparts', 'Space time continuum', logic.has_teleport)
|
||||||
connect(world, player, names, 'Castle Keep', 'Castle Ramparts')
|
connect(world, player, 'Castle Keep', 'Castle Ramparts')
|
||||||
connect(world, player, names, 'Castle Keep', 'Castle Basement', lambda state: state.has('Water Mask', player) or not flooded.flood_basement)
|
connect(world, player, 'Castle Keep', 'Castle Basement', lambda state: state.has('Water Mask', player) or not flooded.flood_basement)
|
||||||
connect(world, player, names, 'Castle Keep', 'Royal towers (lower)', logic.has_doublejump)
|
connect(world, player, 'Castle Keep', 'Royal towers (lower)', logic.has_doublejump)
|
||||||
connect(world, player, names, 'Castle Keep', 'Space time continuum', logic.has_teleport)
|
connect(world, player, 'Castle Keep', 'Space time continuum', logic.has_teleport)
|
||||||
connect(world, player, names, 'Royal towers (lower)', 'Castle Keep')
|
connect(world, player, 'Royal towers (lower)', 'Castle Keep')
|
||||||
connect(world, player, names, 'Royal towers (lower)', 'Royal towers', lambda state: state.has('Timespinner Wheel', player) or logic.has_forwarddash_doublejump(state))
|
connect(world, player, 'Royal towers (lower)', 'Royal towers', lambda state: state.has('Timespinner Wheel', player) or logic.has_forwarddash_doublejump(state))
|
||||||
connect(world, player, names, 'Royal towers (lower)', 'Space time continuum', logic.has_teleport)
|
connect(world, player, 'Royal towers (lower)', 'Space time continuum', logic.has_teleport)
|
||||||
connect(world, player, names, 'Royal towers', 'Royal towers (lower)')
|
connect(world, player, 'Royal towers', 'Royal towers (lower)')
|
||||||
connect(world, player, names, 'Royal towers', 'Royal towers (upper)', logic.has_doublejump)
|
connect(world, player, 'Royal towers', 'Royal towers (upper)', logic.has_doublejump)
|
||||||
connect(world, player, names, 'Royal towers (upper)', 'Royal towers')
|
connect(world, player, 'Royal towers (upper)', 'Royal towers')
|
||||||
#connect(world, player, names, 'Ancient Pyramid (entrance)', 'The lab (upper)', lambda state: not is_option_enabled(world, player, "EnterSandman"))
|
#connect(world, player, 'Ancient Pyramid (entrance)', 'The lab (upper)', lambda state: not is_option_enabled(world, player, "EnterSandman"))
|
||||||
connect(world, player, names, 'Ancient Pyramid (entrance)', 'Ancient Pyramid (left)', logic.has_doublejump)
|
connect(world, player, 'Ancient Pyramid (entrance)', 'Ancient Pyramid (left)', logic.has_doublejump)
|
||||||
connect(world, player, names, 'Ancient Pyramid (left)', 'Ancient Pyramid (entrance)')
|
connect(world, player, 'Ancient Pyramid (left)', 'Ancient Pyramid (entrance)')
|
||||||
connect(world, player, names, 'Ancient Pyramid (left)', 'Ancient Pyramid (right)', lambda state: logic.has_upwarddash(state) or flooded.flood_pyramid_shaft)
|
connect(world, player, 'Ancient Pyramid (left)', 'Ancient Pyramid (right)', lambda state: logic.has_upwarddash(state) or flooded.flood_pyramid_shaft)
|
||||||
connect(world, player, names, 'Ancient Pyramid (right)', 'Ancient Pyramid (left)', lambda state: logic.has_upwarddash(state) or flooded.flood_pyramid_shaft)
|
connect(world, player, 'Ancient Pyramid (right)', 'Ancient Pyramid (left)', lambda state: logic.has_upwarddash(state) or flooded.flood_pyramid_shaft)
|
||||||
connect(world, player, names, 'Space time continuum', 'Lake desolation', lambda state: logic.can_teleport_to(state, "Present", "GateLakeDesolation"))
|
connect(world, player, 'Space time continuum', 'Lake desolation', lambda state: logic.can_teleport_to(state, "Present", "GateLakeDesolation"))
|
||||||
connect(world, player, names, 'Space time continuum', 'Lower lake desolation', lambda state: logic.can_teleport_to(state, "Present", "GateKittyBoss"))
|
connect(world, player, 'Space time continuum', 'Lower lake desolation', lambda state: logic.can_teleport_to(state, "Present", "GateKittyBoss"))
|
||||||
connect(world, player, names, 'Space time continuum', 'Library', lambda state: logic.can_teleport_to(state, "Present", "GateLeftLibrary"))
|
connect(world, player, 'Space time continuum', 'Library', lambda state: logic.can_teleport_to(state, "Present", "GateLeftLibrary"))
|
||||||
connect(world, player, names, 'Space time continuum', 'Varndagroth tower right (lower)', lambda state: logic.can_teleport_to(state, "Present", "GateMilitaryGate"))
|
connect(world, player, 'Space time continuum', 'Varndagroth tower right (lower)', lambda state: logic.can_teleport_to(state, "Present", "GateMilitaryGate"))
|
||||||
connect(world, player, names, 'Space time continuum', 'Skeleton Shaft', lambda state: logic.can_teleport_to(state, "Present", "GateSealedCaves"))
|
connect(world, player, 'Space time continuum', 'Skeleton Shaft', lambda state: logic.can_teleport_to(state, "Present", "GateSealedCaves"))
|
||||||
connect(world, player, names, 'Space time continuum', 'Sealed Caves (Sirens)', lambda state: logic.can_teleport_to(state, "Present", "GateSealedSirensCave"))
|
connect(world, player, 'Space time continuum', 'Sealed Caves (Sirens)', lambda state: logic.can_teleport_to(state, "Present", "GateSealedSirensCave"))
|
||||||
connect(world, player, names, 'Space time continuum', 'Upper Lake Serene', lambda state: logic.can_teleport_to(state, "Past", "GateLakeSereneLeft"))
|
connect(world, player, 'Space time continuum', 'Upper Lake Serene', lambda state: logic.can_teleport_to(state, "Past", "GateLakeSereneLeft"))
|
||||||
connect(world, player, names, 'Space time continuum', 'Left Side forest Caves', lambda state: logic.can_teleport_to(state, "Past", "GateLakeSereneRight"))
|
connect(world, player, 'Space time continuum', 'Left Side forest Caves', lambda state: logic.can_teleport_to(state, "Past", "GateLakeSereneRight"))
|
||||||
connect(world, player, names, 'Space time continuum', 'Refugee Camp', lambda state: logic.can_teleport_to(state, "Past", "GateAccessToPast"))
|
connect(world, player, 'Space time continuum', 'Refugee Camp', lambda state: logic.can_teleport_to(state, "Past", "GateAccessToPast"))
|
||||||
connect(world, player, names, 'Space time continuum', 'Castle Ramparts', lambda state: logic.can_teleport_to(state, "Past", "GateCastleRamparts"))
|
connect(world, player, 'Space time continuum', 'Castle Ramparts', lambda state: logic.can_teleport_to(state, "Past", "GateCastleRamparts"))
|
||||||
connect(world, player, names, 'Space time continuum', 'Castle Keep', lambda state: logic.can_teleport_to(state, "Past", "GateCastleKeep"))
|
connect(world, player, 'Space time continuum', 'Castle Keep', lambda state: logic.can_teleport_to(state, "Past", "GateCastleKeep"))
|
||||||
connect(world, player, names, 'Space time continuum', 'Royal towers (lower)', lambda state: logic.can_teleport_to(state, "Past", "GateRoyalTowers"))
|
connect(world, player, 'Space time continuum', 'Royal towers (lower)', lambda state: logic.can_teleport_to(state, "Past", "GateRoyalTowers"))
|
||||||
connect(world, player, names, 'Space time continuum', 'Caves of Banishment (Maw)', lambda state: logic.can_teleport_to(state, "Past", "GateMaw"))
|
connect(world, player, 'Space time continuum', 'Caves of Banishment (Maw)', lambda state: logic.can_teleport_to(state, "Past", "GateMaw"))
|
||||||
connect(world, player, names, 'Space time continuum', 'Caves of Banishment (upper)', lambda state: logic.can_teleport_to(state, "Past", "GateCavesOfBanishment"))
|
connect(world, player, 'Space time continuum', 'Caves of Banishment (upper)', lambda state: logic.can_teleport_to(state, "Past", "GateCavesOfBanishment"))
|
||||||
connect(world, player, names, 'Space time continuum', 'Ancient Pyramid (entrance)', lambda state: logic.can_teleport_to(state, "Time", "GateGyre") or (not is_option_enabled(world, player, "UnchainedKeys") and is_option_enabled(world, player, "EnterSandman")))
|
connect(world, player, 'Space time continuum', 'Ancient Pyramid (entrance)', lambda state: logic.can_teleport_to(state, "Time", "GateGyre") or (not is_option_enabled(world, player, "UnchainedKeys") and is_option_enabled(world, player, "EnterSandman")))
|
||||||
connect(world, player, names, 'Space time continuum', 'Ancient Pyramid (left)', lambda state: logic.can_teleport_to(state, "Time", "GateLeftPyramid"))
|
connect(world, player, 'Space time continuum', 'Ancient Pyramid (left)', lambda state: logic.can_teleport_to(state, "Time", "GateLeftPyramid"))
|
||||||
connect(world, player, names, 'Space time continuum', 'Ancient Pyramid (right)', lambda state: logic.can_teleport_to(state, "Time", "GateRightPyramid"))
|
connect(world, player, 'Space time continuum', 'Ancient Pyramid (right)', lambda state: logic.can_teleport_to(state, "Time", "GateRightPyramid"))
|
||||||
|
|
||||||
if is_option_enabled(world, player, "GyreArchives"):
|
if is_option_enabled(world, player, "GyreArchives"):
|
||||||
connect(world, player, names, 'The lab (upper)', 'Ravenlord\'s Lair', lambda state: state.has('Merchant Crow', player))
|
connect(world, player, 'The lab (upper)', 'Ravenlord\'s Lair', lambda state: state.has('Merchant Crow', player))
|
||||||
connect(world, player, names, 'Ravenlord\'s Lair', 'The lab (upper)')
|
connect(world, player, 'Ravenlord\'s Lair', 'The lab (upper)')
|
||||||
connect(world, player, names, 'Library top', 'Ifrit\'s Lair', lambda state: state.has('Kobo', player) and state.can_reach('Refugee Camp', 'Region', player))
|
connect(world, player, 'Library top', 'Ifrit\'s Lair', lambda state: state.has('Kobo', player) and state.can_reach('Refugee Camp', 'Region', player))
|
||||||
connect(world, player, names, 'Ifrit\'s Lair', 'Library top')
|
connect(world, player, 'Ifrit\'s Lair', 'Library top')
|
||||||
|
|
||||||
|
|
||||||
def throwIfAnyLocationIsNotAssignedToARegion(regions: List[Region], regionNames: Set[str]):
|
def throwIfAnyLocationIsNotAssignedToARegion(regions: List[Region], regionNames: Set[str]):
|
||||||
|
@ -203,7 +202,7 @@ def throwIfAnyLocationIsNotAssignedToARegion(regions: List[Region], regionNames:
|
||||||
raise Exception("Timespinner: the following regions are used in locations: {}, but no such region exists".format(regionNames - existingRegions))
|
raise Exception("Timespinner: the following regions are used in locations: {}, but no such region exists".format(regionNames - existingRegions))
|
||||||
|
|
||||||
|
|
||||||
def create_location(player: int, location_data: LocationData, region: Region, location_cache: List[Location]) -> Location:
|
def create_location(player: int, location_data: LocationData, region: Region) -> Location:
|
||||||
location = Location(player, location_data.name, location_data.code, region)
|
location = Location(player, location_data.name, location_data.code, region)
|
||||||
location.access_rule = location_data.rule
|
location.access_rule = location_data.rule
|
||||||
|
|
||||||
|
@ -211,17 +210,15 @@ def create_location(player: int, location_data: LocationData, region: Region, lo
|
||||||
location.event = True
|
location.event = True
|
||||||
location.locked = True
|
location.locked = True
|
||||||
|
|
||||||
location_cache.append(location)
|
|
||||||
|
|
||||||
return location
|
return location
|
||||||
|
|
||||||
|
|
||||||
def create_region(world: MultiWorld, player: int, locations_per_region: Dict[str, List[LocationData]], location_cache: List[Location], name: str) -> Region:
|
def create_region(world: MultiWorld, player: int, locations_per_region: Dict[str, List[LocationData]], name: str) -> Region:
|
||||||
region = Region(name, player, world)
|
region = Region(name, player, world)
|
||||||
|
|
||||||
if name in locations_per_region:
|
if name in locations_per_region:
|
||||||
for location_data in locations_per_region[name]:
|
for location_data in locations_per_region[name]:
|
||||||
location = create_location(player, location_data, region, location_cache)
|
location = create_location(player, location_data, region)
|
||||||
region.locations.append(location)
|
region.locations.append(location)
|
||||||
|
|
||||||
return region
|
return region
|
||||||
|
@ -250,19 +247,13 @@ def connectStartingRegion(world: MultiWorld, player: int):
|
||||||
space_time_continuum.exits.append(teleport_back_to_start)
|
space_time_continuum.exits.append(teleport_back_to_start)
|
||||||
|
|
||||||
|
|
||||||
def connect(world: MultiWorld, player: int, used_names: Dict[str, int], source: str, target: str,
|
def connect(world: MultiWorld, player: int, source: str, target: str,
|
||||||
rule: Optional[Callable[[CollectionState], bool]] = None):
|
rule: Optional[Callable[[CollectionState], bool]] = None):
|
||||||
|
|
||||||
sourceRegion = world.get_region(source, player)
|
sourceRegion = world.get_region(source, player)
|
||||||
targetRegion = world.get_region(target, player)
|
targetRegion = world.get_region(target, player)
|
||||||
|
|
||||||
if target not in used_names:
|
connection = Entrance(player, "", sourceRegion)
|
||||||
used_names[target] = 1
|
|
||||||
name = target
|
|
||||||
else:
|
|
||||||
used_names[target] += 1
|
|
||||||
name = target + (' ' * used_names[target])
|
|
||||||
|
|
||||||
connection = Entrance(player, name, sourceRegion)
|
|
||||||
|
|
||||||
if rule:
|
if rule:
|
||||||
connection.access_rule = rule
|
connection.access_rule = rule
|
||||||
|
@ -271,7 +262,7 @@ def connect(world: MultiWorld, player: int, used_names: Dict[str, int], source:
|
||||||
connection.connect(targetRegion)
|
connection.connect(targetRegion)
|
||||||
|
|
||||||
|
|
||||||
def get_locations_per_region(locations: Tuple[LocationData, ...]) -> Dict[str, List[LocationData]]:
|
def split_location_datas_per_region(locations: Tuple[LocationData, ...]) -> Dict[str, List[LocationData]]:
|
||||||
per_region: Dict[str, List[LocationData]] = {}
|
per_region: Dict[str, List[LocationData]] = {}
|
||||||
|
|
||||||
for location in locations:
|
for location in locations:
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
from typing import Dict, List, Set, Tuple, TextIO
|
from typing import Dict, List, Set, Tuple, TextIO, Union
|
||||||
from BaseClasses import Item, MultiWorld, Location, Tutorial, ItemClassification
|
from BaseClasses import Item, MultiWorld, Tutorial, ItemClassification
|
||||||
from .Items import get_item_names_per_category, item_table, starter_melee_weapons, starter_spells, filler_items
|
from .Items import get_item_names_per_category, item_table, starter_melee_weapons, starter_spells, filler_items
|
||||||
from .Locations import get_locations, EventId
|
from .Locations import get_location_datas, EventId
|
||||||
from .Options import is_option_enabled, get_option_value, timespinner_options
|
from .Options import is_option_enabled, get_option_value, timespinner_options
|
||||||
from .PreCalculatedWeights import PreCalculatedWeights
|
from .PreCalculatedWeights import PreCalculatedWeights
|
||||||
from .Regions import create_regions
|
from .Regions import create_regions_and_locations
|
||||||
from worlds.AutoWorld import World, WebWorld
|
from worlds.AutoWorld import World, WebWorld
|
||||||
|
|
||||||
class TimespinnerWebWorld(WebWorld):
|
class TimespinnerWebWorld(WebWorld):
|
||||||
|
@ -29,7 +29,6 @@ class TimespinnerWebWorld(WebWorld):
|
||||||
|
|
||||||
tutorials = [setup, setup_de]
|
tutorials = [setup, setup_de]
|
||||||
|
|
||||||
|
|
||||||
class TimespinnerWorld(World):
|
class TimespinnerWorld(World):
|
||||||
"""
|
"""
|
||||||
Timespinner is a beautiful metroidvania inspired by classic 90s action-platformers.
|
Timespinner is a beautiful metroidvania inspired by classic 90s action-platformers.
|
||||||
|
@ -44,21 +43,16 @@ class TimespinnerWorld(World):
|
||||||
required_client_version = (0, 3, 7)
|
required_client_version = (0, 3, 7)
|
||||||
|
|
||||||
item_name_to_id = {name: data.code for name, data in item_table.items()}
|
item_name_to_id = {name: data.code for name, data in item_table.items()}
|
||||||
location_name_to_id = {location.name: location.code for location in get_locations(None, None, None)}
|
location_name_to_id = {location.name: location.code for location in get_location_datas(None, None, None)}
|
||||||
item_name_groups = get_item_names_per_category()
|
item_name_groups = get_item_names_per_category()
|
||||||
|
|
||||||
locked_locations: List[str]
|
|
||||||
location_cache: List[Location]
|
|
||||||
precalculated_weights: PreCalculatedWeights
|
precalculated_weights: PreCalculatedWeights
|
||||||
|
|
||||||
def __init__(self, world: MultiWorld, player: int):
|
def __init__(self, world: MultiWorld, player: int):
|
||||||
super().__init__(world, player)
|
super().__init__(world, player)
|
||||||
|
|
||||||
self.locked_locations = []
|
|
||||||
self.location_cache = []
|
|
||||||
self.precalculated_weights = PreCalculatedWeights(world, player)
|
self.precalculated_weights = PreCalculatedWeights(world, player)
|
||||||
|
|
||||||
def generate_early(self):
|
def generate_early(self) -> None:
|
||||||
# in generate_early the start_inventory isnt copied over to precollected_items yet, so we can still modify the options directly
|
# in generate_early the start_inventory isnt copied over to precollected_items yet, so we can still modify the options directly
|
||||||
if self.multiworld.start_inventory[self.player].value.pop('Meyef', 0) > 0:
|
if self.multiworld.start_inventory[self.player].value.pop('Meyef', 0) > 0:
|
||||||
self.multiworld.StartWithMeyef[self.player].value = self.multiworld.StartWithMeyef[self.player].option_true
|
self.multiworld.StartWithMeyef[self.player].value = self.multiworld.StartWithMeyef[self.player].option_true
|
||||||
|
@ -67,44 +61,27 @@ class TimespinnerWorld(World):
|
||||||
if self.multiworld.start_inventory[self.player].value.pop('Jewelry Box', 0) > 0:
|
if self.multiworld.start_inventory[self.player].value.pop('Jewelry Box', 0) > 0:
|
||||||
self.multiworld.StartWithJewelryBox[self.player].value = self.multiworld.StartWithJewelryBox[self.player].option_true
|
self.multiworld.StartWithJewelryBox[self.player].value = self.multiworld.StartWithJewelryBox[self.player].option_true
|
||||||
|
|
||||||
def create_regions(self):
|
def create_regions(self) -> None:
|
||||||
locations = get_locations(self.multiworld, self.player, self.precalculated_weights)
|
create_regions_and_locations(self.multiworld, self.player, self.precalculated_weights)
|
||||||
create_regions(self.multiworld, self.player, locations, self.location_cache, self.precalculated_weights)
|
|
||||||
|
|
||||||
def create_item(self, name: str) -> Item:
|
def create_items(self) -> None:
|
||||||
return create_item_with_correct_settings(self.multiworld, self.player, name)
|
self.create_and_assign_event_items()
|
||||||
|
|
||||||
def get_filler_item_name(self) -> str:
|
excluded_items: Set[str] = self.get_excluded_items()
|
||||||
trap_chance: int = get_option_value(self.multiworld, self.player, "TrapChance")
|
|
||||||
enabled_traps: List[str] = get_option_value(self.multiworld, self.player, "Traps")
|
|
||||||
|
|
||||||
if self.multiworld.random.random() < (trap_chance / 100) and enabled_traps:
|
self.assign_starter_items(excluded_items)
|
||||||
return self.multiworld.random.choice(enabled_traps)
|
|
||||||
else:
|
|
||||||
return self.multiworld.random.choice(filler_items)
|
|
||||||
|
|
||||||
def set_rules(self):
|
self.multiworld.itempool += self.get_item_pool(excluded_items)
|
||||||
setup_events(self.player, self.locked_locations, self.location_cache)
|
|
||||||
|
|
||||||
|
def set_rules(self) -> None:
|
||||||
final_boss: str
|
final_boss: str
|
||||||
if is_option_enabled(self.multiworld, self.player, "DadPercent"):
|
if self.is_option_enabled("DadPercent"):
|
||||||
final_boss = "Killed Emperor"
|
final_boss = "Killed Emperor"
|
||||||
else:
|
else:
|
||||||
final_boss = "Killed Nightmare"
|
final_boss = "Killed Nightmare"
|
||||||
|
|
||||||
self.multiworld.completion_condition[self.player] = lambda state: state.has(final_boss, self.player)
|
self.multiworld.completion_condition[self.player] = lambda state: state.has(final_boss, self.player)
|
||||||
|
|
||||||
def generate_basic(self):
|
|
||||||
excluded_items: Set[str] = get_excluded_items(self, self.multiworld, self.player)
|
|
||||||
|
|
||||||
assign_starter_items(self.multiworld, self.player, excluded_items, self.locked_locations)
|
|
||||||
|
|
||||||
pool = get_item_pool(self.multiworld, self.player, excluded_items)
|
|
||||||
|
|
||||||
fill_item_pool_with_dummy_items(self, self.multiworld, self.player, self.locked_locations, self.location_cache, pool)
|
|
||||||
|
|
||||||
self.multiworld.itempool += pool
|
|
||||||
|
|
||||||
def fill_slot_data(self) -> Dict[str, object]:
|
def fill_slot_data(self) -> Dict[str, object]:
|
||||||
slot_data: Dict[str, object] = {}
|
slot_data: Dict[str, object] = {}
|
||||||
|
|
||||||
|
@ -112,12 +89,12 @@ class TimespinnerWorld(World):
|
||||||
|
|
||||||
for option_name in timespinner_options:
|
for option_name in timespinner_options:
|
||||||
if (option_name not in ap_specific_settings):
|
if (option_name not in ap_specific_settings):
|
||||||
slot_data[option_name] = get_option_value(self.multiworld, self.player, option_name)
|
slot_data[option_name] = self.get_option_value(option_name)
|
||||||
|
|
||||||
slot_data["StinkyMaw"] = True
|
slot_data["StinkyMaw"] = True
|
||||||
slot_data["ProgressiveVerticalMovement"] = False
|
slot_data["ProgressiveVerticalMovement"] = False
|
||||||
slot_data["ProgressiveKeycards"] = False
|
slot_data["ProgressiveKeycards"] = False
|
||||||
slot_data["PersonalItems"] = get_personal_items(self.player, self.location_cache)
|
slot_data["PersonalItems"] = self.get_personal_items()
|
||||||
slot_data["PyramidKeysGate"] = self.precalculated_weights.pyramid_keys_unlock
|
slot_data["PyramidKeysGate"] = self.precalculated_weights.pyramid_keys_unlock
|
||||||
slot_data["PresentGate"] = self.precalculated_weights.present_key_unlock
|
slot_data["PresentGate"] = self.precalculated_weights.present_key_unlock
|
||||||
slot_data["PastGate"] = self.precalculated_weights.past_key_unlock
|
slot_data["PastGate"] = self.precalculated_weights.past_key_unlock
|
||||||
|
@ -135,17 +112,17 @@ class TimespinnerWorld(World):
|
||||||
|
|
||||||
return slot_data
|
return slot_data
|
||||||
|
|
||||||
def write_spoiler_header(self, spoiler_handle: TextIO):
|
def write_spoiler_header(self, spoiler_handle: TextIO) -> None:
|
||||||
if is_option_enabled(self.multiworld, self.player, "UnchainedKeys"):
|
if self.is_option_enabled("UnchainedKeys"):
|
||||||
spoiler_handle.write(f'Modern Warp Beacon unlock: {self.precalculated_weights.present_key_unlock}\n')
|
spoiler_handle.write(f'Modern Warp Beacon unlock: {self.precalculated_weights.present_key_unlock}\n')
|
||||||
spoiler_handle.write(f'Timeworn Warp Beacon unlock: {self.precalculated_weights.past_key_unlock}\n')
|
spoiler_handle.write(f'Timeworn Warp Beacon unlock: {self.precalculated_weights.past_key_unlock}\n')
|
||||||
|
|
||||||
if is_option_enabled(self.multiworld, self.player, "EnterSandman"):
|
if self.is_option_enabled("EnterSandman"):
|
||||||
spoiler_handle.write(f'Mysterious Warp Beacon unlock: {self.precalculated_weights.time_key_unlock}\n')
|
spoiler_handle.write(f'Mysterious Warp Beacon unlock: {self.precalculated_weights.time_key_unlock}\n')
|
||||||
else:
|
else:
|
||||||
spoiler_handle.write(f'Twin Pyramid Keys unlock: {self.precalculated_weights.pyramid_keys_unlock}\n')
|
spoiler_handle.write(f'Twin Pyramid Keys unlock: {self.precalculated_weights.pyramid_keys_unlock}\n')
|
||||||
|
|
||||||
if is_option_enabled(self.multiworld, self.player, "RisingTides"):
|
if self.is_option_enabled("RisingTides"):
|
||||||
flooded_areas: List[str] = []
|
flooded_areas: List[str] = []
|
||||||
|
|
||||||
if self.precalculated_weights.flood_basement:
|
if self.precalculated_weights.flood_basement:
|
||||||
|
@ -177,36 +154,72 @@ class TimespinnerWorld(World):
|
||||||
|
|
||||||
spoiler_handle.write(f'Flooded Areas: {flooded_areas_string}\n')
|
spoiler_handle.write(f'Flooded Areas: {flooded_areas_string}\n')
|
||||||
|
|
||||||
|
def create_item(self, name: str) -> Item:
|
||||||
|
data = item_table[name]
|
||||||
|
|
||||||
def get_excluded_items(self: TimespinnerWorld, world: MultiWorld, player: int) -> Set[str]:
|
if data.useful:
|
||||||
|
classification = ItemClassification.useful
|
||||||
|
elif data.progression:
|
||||||
|
classification = ItemClassification.progression
|
||||||
|
elif data.trap:
|
||||||
|
classification = ItemClassification.trap
|
||||||
|
else:
|
||||||
|
classification = ItemClassification.filler
|
||||||
|
|
||||||
|
item = Item(name, classification, data.code, self.player)
|
||||||
|
|
||||||
|
if not item.advancement:
|
||||||
|
return item
|
||||||
|
|
||||||
|
if (name == 'Tablet' or name == 'Library Keycard V') and not self.is_option_enabled("DownloadableItems"):
|
||||||
|
item.classification = ItemClassification.filler
|
||||||
|
elif name == 'Oculus Ring' and not self.is_option_enabled("EyeSpy"):
|
||||||
|
item.classification = ItemClassification.filler
|
||||||
|
elif (name == 'Kobo' or name == 'Merchant Crow') and not self.is_option_enabled("GyreArchives"):
|
||||||
|
item.classification = ItemClassification.filler
|
||||||
|
elif name in {"Timeworn Warp Beacon", "Modern Warp Beacon", "Mysterious Warp Beacon"} \
|
||||||
|
and not self.is_option_enabled("UnchainedKeys"):
|
||||||
|
item.classification = ItemClassification.filler
|
||||||
|
|
||||||
|
return item
|
||||||
|
|
||||||
|
def get_filler_item_name(self) -> str:
|
||||||
|
trap_chance: int = self.get_option_value("TrapChance")
|
||||||
|
enabled_traps: List[str] = self.get_option_value("Traps")
|
||||||
|
|
||||||
|
if self.multiworld.random.random() < (trap_chance / 100) and enabled_traps:
|
||||||
|
return self.multiworld.random.choice(enabled_traps)
|
||||||
|
else:
|
||||||
|
return self.multiworld.random.choice(filler_items)
|
||||||
|
|
||||||
|
def get_excluded_items(self) -> Set[str]:
|
||||||
excluded_items: Set[str] = set()
|
excluded_items: Set[str] = set()
|
||||||
|
|
||||||
if is_option_enabled(world, player, "StartWithJewelryBox"):
|
if self.is_option_enabled("StartWithJewelryBox"):
|
||||||
excluded_items.add('Jewelry Box')
|
excluded_items.add('Jewelry Box')
|
||||||
if is_option_enabled(world, player, "StartWithMeyef"):
|
if self.is_option_enabled("StartWithMeyef"):
|
||||||
excluded_items.add('Meyef')
|
excluded_items.add('Meyef')
|
||||||
if is_option_enabled(world, player, "QuickSeed"):
|
if self.is_option_enabled("QuickSeed"):
|
||||||
excluded_items.add('Talaria Attachment')
|
excluded_items.add('Talaria Attachment')
|
||||||
|
|
||||||
if is_option_enabled(world, player, "UnchainedKeys"):
|
if self.is_option_enabled("UnchainedKeys"):
|
||||||
excluded_items.add('Twin Pyramid Key')
|
excluded_items.add('Twin Pyramid Key')
|
||||||
|
|
||||||
if not is_option_enabled(world, player, "EnterSandman"):
|
if not self.is_option_enabled("EnterSandman"):
|
||||||
excluded_items.add('Mysterious Warp Beacon')
|
excluded_items.add('Mysterious Warp Beacon')
|
||||||
else:
|
else:
|
||||||
excluded_items.add('Timeworn Warp Beacon')
|
excluded_items.add('Timeworn Warp Beacon')
|
||||||
excluded_items.add('Modern Warp Beacon')
|
excluded_items.add('Modern Warp Beacon')
|
||||||
excluded_items.add('Mysterious Warp Beacon')
|
excluded_items.add('Mysterious Warp Beacon')
|
||||||
|
|
||||||
for item in world.precollected_items[player]:
|
for item in self.multiworld.precollected_items[self.player]:
|
||||||
if item.name not in self.item_name_groups['UseItem']:
|
if item.name not in self.item_name_groups['UseItem']:
|
||||||
excluded_items.add(item.name)
|
excluded_items.add(item.name)
|
||||||
|
|
||||||
return excluded_items
|
return excluded_items
|
||||||
|
|
||||||
|
def assign_starter_items(self, excluded_items: Set[str]) -> None:
|
||||||
def assign_starter_items(world: MultiWorld, player: int, excluded_items: Set[str], locked_locations: List[str]):
|
non_local_items: Set[str] = self.multiworld.non_local_items[self.player].value
|
||||||
non_local_items = world.non_local_items[player].value
|
|
||||||
|
|
||||||
local_starter_melee_weapons = tuple(item for item in starter_melee_weapons if item not in non_local_items)
|
local_starter_melee_weapons = tuple(item for item in starter_melee_weapons if item not in non_local_items)
|
||||||
if not local_starter_melee_weapons:
|
if not local_starter_melee_weapons:
|
||||||
|
@ -222,88 +235,50 @@ def assign_starter_items(world: MultiWorld, player: int, excluded_items: Set[str
|
||||||
else:
|
else:
|
||||||
local_starter_spells = ('Lightwall',)
|
local_starter_spells = ('Lightwall',)
|
||||||
|
|
||||||
assign_starter_item(world, player, excluded_items, locked_locations, 'Tutorial: Yo Momma 1', local_starter_melee_weapons)
|
self.assign_starter_item(excluded_items, 'Tutorial: Yo Momma 1', local_starter_melee_weapons)
|
||||||
assign_starter_item(world, player, excluded_items, locked_locations, 'Tutorial: Yo Momma 2', local_starter_spells)
|
self.assign_starter_item(excluded_items, 'Tutorial: Yo Momma 2', local_starter_spells)
|
||||||
|
|
||||||
|
def assign_starter_item(self, excluded_items: Set[str], location: str, item_list: Tuple[str, ...]) -> None:
|
||||||
def assign_starter_item(world: MultiWorld, player: int, excluded_items: Set[str], locked_locations: List[str],
|
item_name = self.multiworld.random.choice(item_list)
|
||||||
location: str, item_list: Tuple[str, ...]):
|
|
||||||
|
|
||||||
item_name = world.random.choice(item_list)
|
|
||||||
|
|
||||||
excluded_items.add(item_name)
|
excluded_items.add(item_name)
|
||||||
|
|
||||||
item = create_item_with_correct_settings(world, player, item_name)
|
item = self.create_item(item_name)
|
||||||
|
|
||||||
world.get_location(location, player).place_locked_item(item)
|
self.multiworld.get_location(location, self.player).place_locked_item(item)
|
||||||
|
|
||||||
locked_locations.append(location)
|
def get_item_pool(self, excluded_items: Set[str]) -> List[Item]:
|
||||||
|
|
||||||
|
|
||||||
def get_item_pool(world: MultiWorld, player: int, excluded_items: Set[str]) -> List[Item]:
|
|
||||||
pool: List[Item] = []
|
pool: List[Item] = []
|
||||||
|
|
||||||
for name, data in item_table.items():
|
for name, data in item_table.items():
|
||||||
if name not in excluded_items:
|
if name not in excluded_items:
|
||||||
for _ in range(data.count):
|
for _ in range(data.count):
|
||||||
item = create_item_with_correct_settings(world, player, name)
|
item = self.create_item(name)
|
||||||
|
pool.append(item)
|
||||||
|
|
||||||
|
for _ in range(len(self.multiworld.get_unfilled_locations(self.player)) - len(pool)):
|
||||||
|
item = self.create_item(self.get_filler_item_name())
|
||||||
pool.append(item)
|
pool.append(item)
|
||||||
|
|
||||||
return pool
|
return pool
|
||||||
|
|
||||||
|
def create_and_assign_event_items(self) -> None:
|
||||||
def fill_item_pool_with_dummy_items(self: TimespinnerWorld, world: MultiWorld, player: int, locked_locations: List[str],
|
for location in self.multiworld.get_locations(self.player):
|
||||||
location_cache: List[Location], pool: List[Item]):
|
|
||||||
for _ in range(len(location_cache) - len(locked_locations) - len(pool)):
|
|
||||||
item = create_item_with_correct_settings(world, player, self.get_filler_item_name())
|
|
||||||
pool.append(item)
|
|
||||||
|
|
||||||
|
|
||||||
def create_item_with_correct_settings(world: MultiWorld, player: int, name: str) -> Item:
|
|
||||||
data = item_table[name]
|
|
||||||
|
|
||||||
if data.useful:
|
|
||||||
classification = ItemClassification.useful
|
|
||||||
elif data.progression:
|
|
||||||
classification = ItemClassification.progression
|
|
||||||
elif data.trap:
|
|
||||||
classification = ItemClassification.trap
|
|
||||||
else:
|
|
||||||
classification = ItemClassification.filler
|
|
||||||
|
|
||||||
item = Item(name, classification, data.code, player)
|
|
||||||
|
|
||||||
if not item.advancement:
|
|
||||||
return item
|
|
||||||
|
|
||||||
if (name == 'Tablet' or name == 'Library Keycard V') and not is_option_enabled(world, player, "DownloadableItems"):
|
|
||||||
item.classification = ItemClassification.filler
|
|
||||||
elif name == 'Oculus Ring' and not is_option_enabled(world, player, "EyeSpy"):
|
|
||||||
item.classification = ItemClassification.filler
|
|
||||||
elif (name == 'Kobo' or name == 'Merchant Crow') and not is_option_enabled(world, player, "GyreArchives"):
|
|
||||||
item.classification = ItemClassification.filler
|
|
||||||
elif name in {"Timeworn Warp Beacon", "Modern Warp Beacon", "Mysterious Warp Beacon"} \
|
|
||||||
and not is_option_enabled(world, player, "UnchainedKeys"):
|
|
||||||
item.classification = ItemClassification.filler
|
|
||||||
|
|
||||||
return item
|
|
||||||
|
|
||||||
|
|
||||||
def setup_events(player: int, locked_locations: List[str], location_cache: List[Location]):
|
|
||||||
for location in location_cache:
|
|
||||||
if location.address == EventId:
|
if location.address == EventId:
|
||||||
item = Item(location.name, ItemClassification.progression, EventId, player)
|
item = Item(location.name, ItemClassification.progression, EventId, self.player)
|
||||||
|
|
||||||
locked_locations.append(location.name)
|
|
||||||
|
|
||||||
location.place_locked_item(item)
|
location.place_locked_item(item)
|
||||||
|
|
||||||
|
def get_personal_items(self) -> Dict[int, int]:
|
||||||
def get_personal_items(player: int, locations: List[Location]) -> Dict[int, int]:
|
|
||||||
personal_items: Dict[int, int] = {}
|
personal_items: Dict[int, int] = {}
|
||||||
|
|
||||||
for location in locations:
|
for location in self.multiworld.get_locations(self.player):
|
||||||
if location.address and location.item and location.item.code and location.item.player == player:
|
if location.address and location.item and location.item.code and location.item.player == self.player:
|
||||||
personal_items[location.address] = location.item.code
|
personal_items[location.address] = location.item.code
|
||||||
|
|
||||||
return personal_items
|
return personal_items
|
||||||
|
|
||||||
|
def is_option_enabled(self, option: str) -> bool:
|
||||||
|
return is_option_enabled(self.multiworld, self.player, option)
|
||||||
|
|
||||||
|
def get_option_value(self, option: str) -> Union[int, Dict, List]:
|
||||||
|
return get_option_value(self.multiworld, self.player, option)
|
||||||
|
|
Loading…
Reference in New Issue