[Timespinner] New seed options and new locations checks (#140)
This commit is contained in:
		
							parent
							
								
									b3ae4b86e4
								
							
						
					
					
						commit
						8363d1749b
					
				| 
						 | 
				
			
			@ -38,26 +38,29 @@
 | 
			
		|||
                <td><img src="{{ icons['Gas Mask'] }}" class="{{ 'acquired' if 'Gas Mask' in acquired_items }}" title="Gas Mask" /></td>
 | 
			
		||||
            </tr>
 | 
			
		||||
            <tr>
 | 
			
		||||
                {% if 'Fire Orb' in acquired_items %}
 | 
			
		||||
                <td><img src="{{ icons['Kobo'] }}" class="{{ 'acquired' if 'Kobo' in acquired_items }}" title="Kobo" /></td>
 | 
			
		||||
                <td><img src="{{ icons['Merchant Crow'] }}" class="{{ 'acquired' if 'Merchant Crow' in acquired_items }}" title="Merchant Crow" /></td>
 | 
			
		||||
 | 
			
		||||
                {% if 'Djinn Inferno' in acquired_items %}
 | 
			
		||||
                    <td><img src="{{ icons['Djinn Inferno'] }}" class="acquired" title="Djinn Inferno" /></td>
 | 
			
		||||
                {% elif 'Pyro Ring' in acquired_items %}
 | 
			
		||||
                    <td><img src="{{ icons['Pyro Ring'] }}" class="acquired" title="Pyro Ring" /></td>
 | 
			
		||||
                {% elif 'Fire Orb' in acquired_items %}
 | 
			
		||||
                    <td><img src="{{ icons['Fire Orb'] }}" class="acquired" title="Fire Orb" /></td>
 | 
			
		||||
                {% elif 'Infernal Flames' in acquired_items %}
 | 
			
		||||
                    <td><img src="{{ icons['Infernal Flames'] }}" class="acquired" title="Infernal Flames" /></td>
 | 
			
		||||
                {% elif 'Pyro Ring' in acquired_items %}
 | 
			
		||||
                    <td><img src="{{ icons['Pyro Ring'] }}" class="acquired" title="Pyro Ring" /></td>
 | 
			
		||||
                {% elif 'Pyro Ring' in acquired_items %}
 | 
			
		||||
                    <td><img src="{{ icons['Djinn Inferno'] }}" class="acquired" title="Djinn Inferno" /></td>
 | 
			
		||||
                {% else %}
 | 
			
		||||
                    <td><img src="{{ icons['Fire Orb'] }}" title="Fire Orb" /></td>
 | 
			
		||||
                    <td><img src="{{ icons['Djinn Inferno'] }}" title="Djinn Inferno" /></td>
 | 
			
		||||
                {% endif %}
 | 
			
		||||
 | 
			
		||||
                {% if 'Plasma Orb' in acquired_items %}
 | 
			
		||||
                    <td><img src="{{ icons['Plasma Orb'] }}" class="acquired" title="Plasma Orb" /></td>
 | 
			
		||||
                {% if 'Royal Ring' in acquired_items %}
 | 
			
		||||
                    <td><img src="{{ icons['Royal Ring'] }}" class="acquired" title="Royal Ring" /></td>
 | 
			
		||||
                {% elif 'Plasma Geyser' in acquired_items %}
 | 
			
		||||
                    <td><img src="{{ icons['Plasma Geyser'] }}" class="acquired" title="Plasma Geyser" /></td>
 | 
			
		||||
                {% elif 'Royal Ring' in acquired_items %}
 | 
			
		||||
                    <td><img src="{{ icons['Royal Ring'] }}" class="acquired" title="Royal Ring" /></td>
 | 
			
		||||
                {% elif 'Plasma Orb' in acquired_items %}
 | 
			
		||||
                    <td><img src="{{ icons['Plasma Orb'] }}" class="acquired" title="Plasma Orb" /></td>
 | 
			
		||||
                {% else %}
 | 
			
		||||
                    <td><img src="{{ icons['Plasma Orb'] }}" title="Plasma Orb" /></td>
 | 
			
		||||
                    <td><img src="{{ icons['Royal Ring'] }}" title="Royal Ring" /></td>
 | 
			
		||||
                {% endif %}
 | 
			
		||||
            </tr>
 | 
			
		||||
        </table>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -712,6 +712,8 @@ def __renderTimespinnerTracker(multisave: Dict[str, Any], room: Room, locations:
 | 
			
		|||
        "Royal Ring":           "https://timespinnerwiki.com/mediawiki/images/f/f3/Royal_Ring.png",
 | 
			
		||||
        "Plasma Geyser":        "https://timespinnerwiki.com/mediawiki/images/1/12/Plasma_Geyser.png",
 | 
			
		||||
        "Plasma Orb":           "https://timespinnerwiki.com/mediawiki/images/4/44/Plasma_Orb.png",
 | 
			
		||||
        "Kobo":                 "https://timespinnerwiki.com/mediawiki/images/c/c6/Familiar_Kobo.png",
 | 
			
		||||
        "Merchant Crow":        "https://timespinnerwiki.com/mediawiki/images/4/4e/Familiar_Crow.png",
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    timespinner_location_ids = {
 | 
			
		||||
| 
						 | 
				
			
			@ -726,7 +728,7 @@ def __renderTimespinnerTracker(multisave: Dict[str, Any], room: Room, locations:
 | 
			
		|||
            1337070, 1337071, 1337072, 1337073, 1337074, 1337075, 1337076, 1337077, 1337078, 1337079,
 | 
			
		||||
            1337080, 1337081, 1337082, 1337083, 1337084, 1337085, 1337156, 1337157,          1337159, 
 | 
			
		||||
            1337160, 1337161, 1337162, 1337163, 1337164, 1337165, 1337166, 1337167, 1337168, 1337169, 
 | 
			
		||||
            1337170],
 | 
			
		||||
            1337170, 1337237, 1337238],
 | 
			
		||||
        "Past": [
 | 
			
		||||
            1337086, 1337087, 1337088, 1337089,
 | 
			
		||||
            1337090, 1337091, 1337092, 1337093, 1337094, 1337095, 1337096, 1337097, 1337098, 1337099,
 | 
			
		||||
| 
						 | 
				
			
			@ -735,7 +737,8 @@ def __renderTimespinnerTracker(multisave: Dict[str, Any], room: Room, locations:
 | 
			
		|||
            1337120, 1337121, 1337122, 1337123, 1337124, 1337125, 1337126, 1337127, 1337128, 1337129,
 | 
			
		||||
            1337130, 1337131, 1337132, 1337133, 1337134, 1337135, 1337136, 1337137, 1337138, 1337139,
 | 
			
		||||
            1337140, 1337141, 1337142, 1337143, 1337144, 1337145, 1337146, 1337147, 1337148, 1337149,
 | 
			
		||||
            1337150, 1337151, 1337152, 1337153, 1337154, 1337155],
 | 
			
		||||
            1337150, 1337151, 1337152, 1337153, 1337154, 1337155,
 | 
			
		||||
            1337171, 1337172, 1337173, 1337174, 1337175, 1337176],
 | 
			
		||||
        "Ancient Pyramid": [1337246, 1337247, 1337248, 1337249]
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,9 +24,9 @@ item_table: Dict[str, ItemData] = {
 | 
			
		|||
    'Lab Glasses': ItemData('Equipment', 1337012),
 | 
			
		||||
    'Empire Crown': ItemData('Equipment', 1337013),
 | 
			
		||||
    'Viletian Crown': ItemData('Equipment', 1337014),
 | 
			
		||||
    'Sunglasses': ItemData('Equipment', 1337015, 0),
 | 
			
		||||
    'Sunglasses': ItemData('Equipment', 1337015),
 | 
			
		||||
    'Old Coat': ItemData('Equipment', 1337016),
 | 
			
		||||
    'Trendy Jacket': ItemData('Equipment', 1337017, 0),
 | 
			
		||||
    'Trendy Jacket': ItemData('Equipment', 1337017),
 | 
			
		||||
    'Security Vest': ItemData('Equipment', 1337018, 0),
 | 
			
		||||
    'Leather Jerkin': ItemData('Equipment', 1337019, 0),
 | 
			
		||||
    'Copper Breastplate': ItemData('Equipment', 1337020, 0),
 | 
			
		||||
| 
						 | 
				
			
			@ -53,15 +53,15 @@ item_table: Dict[str, ItemData] = {
 | 
			
		|||
    'Filigree Clasp': ItemData('Equipment', 1337041),
 | 
			
		||||
    'Azure Stole': ItemData('Equipment', 1337042, 0),
 | 
			
		||||
    'Ancient Coin': ItemData('Equipment', 1337043),
 | 
			
		||||
    'Shiny Rock': ItemData('Equipment', 1337044, 0),
 | 
			
		||||
    'Shiny Rock': ItemData('Equipment', 1337044),
 | 
			
		||||
    'Galaxy Earrings': ItemData('Equipment', 1337045, never_exclude=True),
 | 
			
		||||
    'Selen\'s Bangle': ItemData('Equipment', 1337046, never_exclude=True),
 | 
			
		||||
    'Glass Pumpkin': ItemData('Equipment', 1337047, never_exclude=True),
 | 
			
		||||
    'Gilded Egg': ItemData('Equipment', 1337048, never_exclude=True),
 | 
			
		||||
    'Meyef': ItemData('Familiar', 1337049),
 | 
			
		||||
    'Griffin': ItemData('Familiar', 1337050),
 | 
			
		||||
    'Merchant Crow': ItemData('Familiar', 1337051),
 | 
			
		||||
    'Kobo': ItemData('Familiar', 1337052),
 | 
			
		||||
    'Merchant Crow': ItemData('Familiar', 1337051, progression=True),
 | 
			
		||||
    'Kobo': ItemData('Familiar', 1337052, progression=True),
 | 
			
		||||
    'Sprite': ItemData('Familiar', 1337053),
 | 
			
		||||
    'Demon': ItemData('Familiar', 1337054),
 | 
			
		||||
    'Potion': ItemData('UseItem', 1337055, 0),
 | 
			
		||||
| 
						 | 
				
			
			@ -93,7 +93,7 @@ item_table: Dict[str, ItemData] = {
 | 
			
		|||
    'Filigree Tea': ItemData('UseItem', 1337081),
 | 
			
		||||
    'Empress Cake': ItemData('UseItem', 1337082, 0),
 | 
			
		||||
    'Rotten Tail': ItemData('UseItem', 1337083, 0),
 | 
			
		||||
    'Alchemy Tools': ItemData('UseItem', 1337084, 0),
 | 
			
		||||
    'Alchemy Tools': ItemData('UseItem', 1337084),
 | 
			
		||||
    'Galaxy Stone': ItemData('UseItem', 1337085),
 | 
			
		||||
    # 1337086 Used interally
 | 
			
		||||
    'Essence Crystal': ItemData('UseItem', 1337087, 0),
 | 
			
		||||
| 
						 | 
				
			
			@ -101,7 +101,7 @@ item_table: Dict[str, ItemData] = {
 | 
			
		|||
    'Gold Necklace': ItemData('UseItem', 1337089, 0),
 | 
			
		||||
    'Herb': ItemData('UseItem', 1337090),
 | 
			
		||||
    'Mushroom': ItemData('UseItem', 1337091, 0),
 | 
			
		||||
    'Plasma Crystal': ItemData('UseItem', 1337092, 0),
 | 
			
		||||
    'Plasma Crystal': ItemData('UseItem', 1337092),
 | 
			
		||||
    'Plasma IV Bag': ItemData('UseItem', 1337093),
 | 
			
		||||
    'Cheveur Drumstick': ItemData('UseItem', 1337094, 0),
 | 
			
		||||
    'Wyvern Tail': ItemData('UseItem', 1337095, 0),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
from typing import Tuple, Optional, Callable, NamedTuple
 | 
			
		||||
from typing import List, Tuple, Optional, Callable, NamedTuple
 | 
			
		||||
from BaseClasses import MultiWorld
 | 
			
		||||
from .Options import is_option_enabled
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -11,7 +11,7 @@ class LocationData(NamedTuple):
 | 
			
		|||
    rule: Callable = lambda state: True
 | 
			
		||||
 | 
			
		||||
def get_locations(world: Optional[MultiWorld], player: Optional[int]) -> Tuple[LocationData, ...]:
 | 
			
		||||
    location_table: Tuple[LocationData, ...] = (
 | 
			
		||||
    location_table: List[LocationData] = [
 | 
			
		||||
        # PresentItemLocations
 | 
			
		||||
        LocationData('Tutorial', 'Yo Momma 1',  1337000),
 | 
			
		||||
        LocationData('Tutorial', 'Yo Momma 2',  1337001),
 | 
			
		||||
| 
						 | 
				
			
			@ -29,8 +29,8 @@ def get_locations(world: Optional[MultiWorld], player: Optional[int]) -> Tuple[L
 | 
			
		|||
        LocationData('Upper lake desolation', 'Upper desolation double jump cave platform',  1337013),
 | 
			
		||||
        LocationData('Upper lake desolation', 'Fire-Locked sparrow chest',  1337014),
 | 
			
		||||
        LocationData('Upper lake desolation', 'Crash site pedestal',  1337015),
 | 
			
		||||
        LocationData('Upper lake desolation', 'Crash site chest 1',  1337016, lambda state: state.has_all(['Killed Maw', 'Gas Mask'], player)),
 | 
			
		||||
        LocationData('Upper lake desolation', 'Crash site chest 2',  1337017, lambda state: state.has_all(['Killed Maw', 'Gas Mask'], player)),
 | 
			
		||||
        LocationData('Upper lake desolation', 'Crash site chest 1',  1337016, lambda state: state.has_all({'Killed Maw', 'Gas Mask'}, player)),
 | 
			
		||||
        LocationData('Upper lake desolation', 'Crash site chest 2',  1337017, lambda state: state.has_all({'Killed Maw', 'Gas Mask'}, player)),
 | 
			
		||||
        LocationData('Upper lake desolation', 'Kitty Boss',  1337018),
 | 
			
		||||
        LocationData('Library', 'Library Basement',  1337019),
 | 
			
		||||
        LocationData('Library', 'Library warp gate',  1337020),
 | 
			
		||||
| 
						 | 
				
			
			@ -118,8 +118,10 @@ def get_locations(world: Optional[MultiWorld], player: Optional[int]) -> Tuple[L
 | 
			
		|||
        LocationData('Upper Lake Serene', 'Upper Serene double jump cave platform',  1337100, lambda state: state._timespinner_has_doublejump(world, player)),
 | 
			
		||||
        LocationData('Upper Lake Serene', 'Upper Serene double jump cave floor',  1337101),
 | 
			
		||||
        LocationData('Upper Lake Serene', 'Upper Serene cave secret',  1337102, lambda state: state._timespinner_can_break_walls(world, player)),
 | 
			
		||||
        LocationData('Upper Lake Serene', 'Before Big Bird', 1337175),
 | 
			
		||||
        LocationData('Upper Lake Serene', 'Serene behind the vines',  1337103),
 | 
			
		||||
        LocationData('Upper Lake Serene', 'Pyramid keys room',  1337104),
 | 
			
		||||
        LocationData('Upper Lake Serene', 'Chicken ledge', 1337174),
 | 
			
		||||
        LocationData('Lower Lake Serene', 'Deep dive',  1337105),
 | 
			
		||||
        LocationData('Lower Lake Serene', 'Under the eels',  1337106),
 | 
			
		||||
        LocationData('Lower Lake Serene', 'Water spikes room',  1337107),
 | 
			
		||||
| 
						 | 
				
			
			@ -137,12 +139,14 @@ def get_locations(world: Optional[MultiWorld], player: Optional[int]) -> Tuple[L
 | 
			
		|||
        LocationData('Caves of Banishment (upper)', 'Banishment jackpot room chest 4',  1337119, lambda state: state._timespinner_has_forwarddash_doublejump(world, player)),
 | 
			
		||||
        LocationData('Caves of Banishment (upper)', 'Banishment pedestal',  1337120),
 | 
			
		||||
        LocationData('Caves of Banishment (Maw)', 'Last chance before Maw',  1337121, lambda state: state._timespinner_has_doublejump(world, player)),
 | 
			
		||||
        LocationData('Caves of Banishment (Maw)', 'Plasma Crystal', 1337173, lambda state: state.has_any({'Gas Mask', 'Talaria Attachment'}, player)),
 | 
			
		||||
        LocationData('Caves of Banishment (Maw)', 'Killed Maw',  EventId, lambda state: state.has('Gas Mask', player)),
 | 
			
		||||
        LocationData('Caves of Banishment (Maw)', 'Mineshaft',  1337122, lambda state: state.has('Gas Mask', player)),
 | 
			
		||||
        LocationData('Caves of Banishment (Sirens)', 'Wyvern room',  1337123),
 | 
			
		||||
        LocationData('Caves of Banishment (Sirens)', 'Upper banishment above sirens',  1337124),
 | 
			
		||||
        LocationData('Caves of Banishment (Sirens)', 'Under banishment sirens left',  1337125, lambda state: state.has('Water Mask', player)),
 | 
			
		||||
        LocationData('Caves of Banishment (Sirens)', 'Under banishment sirens right',  1337126, lambda state: state.has('Water Mask', player)),
 | 
			
		||||
        LocationData('Caves of Banishment (Sirens)', 'Underwater banishment sirens right ground', 1337172, lambda state: state.has('Water Mask', player)),
 | 
			
		||||
        LocationData('Caves of Banishment (Sirens)', 'Banishment water hook',  1337127, lambda state: state.has('Water Mask', player)),
 | 
			
		||||
        LocationData('Castle Ramparts', 'Castle bomber chest',  1337128, lambda state: state._timespinner_has_multiple_small_jumps_of_npc(world, player)),
 | 
			
		||||
        LocationData('Castle Ramparts', 'Ramparts Freeze the engineer',  1337129, lambda state: state.has('Talaria Attachment', player) or state._timespinner_has_timestop(world, player)),
 | 
			
		||||
| 
						 | 
				
			
			@ -157,6 +161,7 @@ def get_locations(world: Optional[MultiWorld], player: Optional[int]) -> Tuple[L
 | 
			
		|||
        LocationData('Castle Keep', 'Just an egg',  1337138),
 | 
			
		||||
        LocationData('Castle Keep', 'Under the twins',  1337139),
 | 
			
		||||
        LocationData('Castle Keep', 'Killed Twins',  EventId, lambda state: state._timespinner_has_timestop(world, player)),
 | 
			
		||||
        LocationData('Castle Keep', 'Advisor jump', 1337171, lambda state: state._timespinner_has_timestop(world, player)),
 | 
			
		||||
        LocationData('Castle Keep', 'Twins',  1337140, lambda state: state._timespinner_has_timestop(world, player)),
 | 
			
		||||
        LocationData('Castle Keep', 'Royal guard tiny room',  1337141, lambda state: state._timespinner_has_doublejump(world, player) or state._timespinner_has_fastjump_on_npc(world,player)),
 | 
			
		||||
        LocationData('Royal towers (lower)', 'Royal tower floor secret',  1337142, lambda state: state._timespinner_has_doublejump(world, player) and state._timespinner_can_break_walls(world, player)),
 | 
			
		||||
| 
						 | 
				
			
			@ -175,34 +180,35 @@ def get_locations(world: Optional[MultiWorld], player: Optional[int]) -> Tuple[L
 | 
			
		|||
        LocationData('Royal towers (upper)', 'Aelana\'s pedestal',  1337154),
 | 
			
		||||
        LocationData('Royal towers (upper)', 'Aelana\'s chest',  1337155),
 | 
			
		||||
 | 
			
		||||
        # 1337157 - 1337170 Downloads
 | 
			
		||||
        # 1337176 - 1337176 Cantoran
 | 
			
		||||
 | 
			
		||||
        # 1337171 - 1337238 Reserved
 | 
			
		||||
        # 1337177 - 1337236 Reserved
 | 
			
		||||
 | 
			
		||||
        # 1337237 - 1337238 GyreArchives
 | 
			
		||||
 | 
			
		||||
        # PyramidItemLocations
 | 
			
		||||
        #LocationData('Temporal Gyre', 'Transition chest 1',  1337239),
 | 
			
		||||
        #LocationData('Temporal Gyre', 'Transition chest 2',  1337240),
 | 
			
		||||
        #LocationData('Temporal Gyre', 'Transition chest 3',  1337241),
 | 
			
		||||
        #LocationData('Temporal Gyre', 'Ravenlord pre fight',  1337242),
 | 
			
		||||
        #LocationData('Temporal Gyre', 'Ravenlord post fight',  1337243),
 | 
			
		||||
        #LocationData('Temporal Gyre', 'Ifrid pre fight',  1337244),
 | 
			
		||||
        #LocationData('Temporal Gyre', 'Ifrid post fight',  1337245),
 | 
			
		||||
        LocationData('Ancient Pyramid (right)', 'Transition chest 1',  1337239),
 | 
			
		||||
        LocationData('Ancient Pyramid (right)', 'Transition chest 2',  1337240),
 | 
			
		||||
        LocationData('Ancient Pyramid (right)', 'Transition chest 3',  1337241),
 | 
			
		||||
 | 
			
		||||
        # 1337242 - 1337245 GyreArchives
 | 
			
		||||
 | 
			
		||||
        LocationData('Ancient Pyramid (left)', 'Why not it\'s right there',  1337246),
 | 
			
		||||
        LocationData('Ancient Pyramid (left)', 'Conviction guarded room',  1337247),
 | 
			
		||||
        LocationData('Ancient Pyramid (right)', 'Pit secret room',  1337248, lambda state: state._timespinner_can_break_walls(world, player)),
 | 
			
		||||
        LocationData('Ancient Pyramid (right)', 'Regret chest',  1337249, lambda state: state._timespinner_can_break_walls(world, player)),
 | 
			
		||||
        LocationData('Ancient Pyramid (right)', 'Killed Nightmare',  EventId)
 | 
			
		||||
    )
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    downloadable_items: Tuple[LocationData, ...] = (
 | 
			
		||||
    downloadable_locations: Tuple[LocationData, ...] = (
 | 
			
		||||
        # DownloadTerminals
 | 
			
		||||
        LocationData('Library', 'Library terminal 1',  1337157, lambda state: state.has('Tablet', player)),
 | 
			
		||||
        LocationData('Library', 'Library terminal 2',  1337156, lambda state: state.has('Tablet', player)),
 | 
			
		||||
        # 1337158 Is Lost in time
 | 
			
		||||
        LocationData('Library', 'Library terminal 3',  1337159, lambda state: state.has('Tablet', player)),
 | 
			
		||||
        LocationData('Library', 'V terminal 1',  1337160, lambda state: state.has_all(['Tablet', 'Library Keycard V'], player)),
 | 
			
		||||
        LocationData('Library', 'V terminal 2',  1337161, lambda state: state.has_all(['Tablet', 'Library Keycard V'], player)),
 | 
			
		||||
        LocationData('Library', 'V terminal 3',  1337162, lambda state: state.has_all(['Tablet', 'Library Keycard V'], player)),
 | 
			
		||||
        LocationData('Library', 'V terminal 1',  1337160, lambda state: state.has_all({'Tablet', 'Library Keycard V'}, player)),
 | 
			
		||||
        LocationData('Library', 'V terminal 2',  1337161, lambda state: state.has_all({'Tablet', 'Library Keycard V'}, player)),
 | 
			
		||||
        LocationData('Library', 'V terminal 3',  1337162, lambda state: state.has_all({'Tablet', 'Library Keycard V'}, player)),
 | 
			
		||||
        LocationData('Library top', 'Backer room terminal',  1337163, lambda state: state.has('Tablet', player)),
 | 
			
		||||
        LocationData('Varndagroth tower right (elevator)', 'Medbay',  1337164, lambda state: state.has('Tablet', player) and state._timespinner_has_keycard_B(world, player)),
 | 
			
		||||
        LocationData('The lab (upper)', 'Chest and download terminal',  1337165, lambda state: state.has('Tablet', player)),
 | 
			
		||||
| 
						 | 
				
			
			@ -213,10 +219,30 @@ def get_locations(world: Optional[MultiWorld], player: Optional[int]) -> Tuple[L
 | 
			
		|||
        LocationData('The lab (power off)', 'Lab terminal right',  1337170, lambda state: state.has('Tablet', player))
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    if not world or is_option_enabled(world, player, "DownloadableItems"):
 | 
			
		||||
        return ( *location_table, *downloadable_items )
 | 
			
		||||
    else:
 | 
			
		||||
        return location_table
 | 
			
		||||
    gyre_archives_locations: Tuple[LocationData, ...] = (
 | 
			
		||||
        LocationData('The lab (upper)', 'Ravenlord post fight (pedestal)',  1337237, lambda state: state.has('Merchant Crow', player)),
 | 
			
		||||
        LocationData('Library top', 'Ifrit post fight (pedestal)',  1337238, lambda state: state.has('Kobo', player)),
 | 
			
		||||
        LocationData('The lab (upper)', 'Ravenlord pre fight',  1337242, lambda state: state.has('Merchant Crow', player)),
 | 
			
		||||
        LocationData('The lab (upper)', 'Ravenlord post fight (chest)',  1337243, lambda state: state.has('Merchant Crow', player)),
 | 
			
		||||
        LocationData('Library top', 'Ifrit pre fight',  1337244, lambda state: state.has('Kobo', player)),
 | 
			
		||||
        LocationData('Library top', 'Ifrit post fight (chest)',  1337245, lambda state: state.has('Kobo', player)),
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    cantoran_locations: Tuple[LocationData, ...] = (
 | 
			
		||||
        LocationData('Left Side forest Caves', 'Cantoran',  1337176),
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    if not world:
 | 
			
		||||
        return ( *location_table, *downloadable_locations, *gyre_archives_locations, *cantoran_locations )
 | 
			
		||||
 | 
			
		||||
    if is_option_enabled(world, player, "DownloadableItems"):
 | 
			
		||||
        location_table.extend(downloadable_locations)
 | 
			
		||||
    if is_option_enabled(world, player, "GyreArchives"):
 | 
			
		||||
        location_table.extend(gyre_archives_locations)
 | 
			
		||||
    if is_option_enabled(world, player, "Cantoran"):
 | 
			
		||||
        location_table.extend(cantoran_locations)
 | 
			
		||||
 | 
			
		||||
    return tuple(location_table)
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
starter_progression_locations: Tuple[str, ...] = (
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,10 +4,10 @@ from .Options import is_option_enabled
 | 
			
		|||
 | 
			
		||||
class TimespinnerLogic(LogicMixin):
 | 
			
		||||
    def _timespinner_has_timestop(self, world: MultiWorld, player: int) -> bool:
 | 
			
		||||
        return self.has_any(['Timespinner Wheel', 'Succubus Hairpin', 'Lightwall', 'Celestial Sash'], player)
 | 
			
		||||
        return self.has_any({'Timespinner Wheel', 'Succubus Hairpin', 'Lightwall', 'Celestial Sash'}, player)
 | 
			
		||||
 | 
			
		||||
    def _timespinner_has_doublejump(self, world: MultiWorld, player: int) -> bool:
 | 
			
		||||
        return self.has_any(['Succubus Hairpin', 'Lightwall', 'Celestial Sash'], player)
 | 
			
		||||
        return self.has_any({'Succubus Hairpin', 'Lightwall', 'Celestial Sash'}, player)
 | 
			
		||||
 | 
			
		||||
    def _timespinner_has_forwarddash_doublejump(self, world: MultiWorld, player: int) -> bool:
 | 
			
		||||
        return self._timespinner_has_upwarddash(world, player) or (self.has('Talaria Attachment', player) and self._timespinner_has_doublejump(world, player))
 | 
			
		||||
| 
						 | 
				
			
			@ -16,19 +16,19 @@ class TimespinnerLogic(LogicMixin):
 | 
			
		|||
        return self._timespinner_has_upwarddash(world, player) or (self.has('Timespinner Wheel', player) and self._timespinner_has_doublejump(world, player))
 | 
			
		||||
 | 
			
		||||
    def _timespinner_has_fastjump_on_npc(self, world: MultiWorld, player: int) -> bool:
 | 
			
		||||
        return self.has_all(['Timespinner Wheel', 'Talaria Attachment'], player)
 | 
			
		||||
        return self.has_all({'Timespinner Wheel', 'Talaria Attachment'}, player)
 | 
			
		||||
 | 
			
		||||
    def _timespinner_has_multiple_small_jumps_of_npc(self, world: MultiWorld, player: int) -> bool:
 | 
			
		||||
        return self.has('Timespinner Wheel', player) or self._timespinner_has_upwarddash(world, player)
 | 
			
		||||
 | 
			
		||||
    def _timespinner_has_upwarddash(self, world: MultiWorld, player: int) -> bool:
 | 
			
		||||
        return self.has_any(['Lightwall', 'Celestial Sash'], player)
 | 
			
		||||
        return self.has_any({'Lightwall', 'Celestial Sash'}, player)
 | 
			
		||||
    
 | 
			
		||||
    def _timespinner_has_fire(self, world: MultiWorld, player: int) -> bool:
 | 
			
		||||
        return self.has_any(['Fire Orb', 'Infernal Flames', 'Pyro Ring', 'Djinn Inferno'], player)
 | 
			
		||||
        return self.has_any({'Fire Orb', 'Infernal Flames', 'Pyro Ring', 'Djinn Inferno'}, player)
 | 
			
		||||
 | 
			
		||||
    def _timespinner_has_pink(self, world: MultiWorld, player: int) -> bool:
 | 
			
		||||
        return self.has_any(['Plasma Orb', 'Plasma Geyser', 'Royal Ring'], player)
 | 
			
		||||
        return self.has_any({'Plasma Orb', 'Plasma Geyser', 'Royal Ring'}, player)
 | 
			
		||||
 | 
			
		||||
    def _timespinner_has_keycard_A(self, world: MultiWorld, player: int) -> bool:
 | 
			
		||||
        return self.has('Security Keycard A', player)
 | 
			
		||||
| 
						 | 
				
			
			@ -37,19 +37,19 @@ class TimespinnerLogic(LogicMixin):
 | 
			
		|||
        if is_option_enabled(world, player, "SpecificKeycards"):
 | 
			
		||||
            return self.has('Security Keycard B', player)
 | 
			
		||||
        else:
 | 
			
		||||
            return self.has_any(['Security Keycard A', 'Security Keycard B'], player)
 | 
			
		||||
            return self.has_any({'Security Keycard A', 'Security Keycard B'}, player)
 | 
			
		||||
 | 
			
		||||
    def _timespinner_has_keycard_C(self, world: MultiWorld, player: int) -> bool:
 | 
			
		||||
        if is_option_enabled(world, player, "SpecificKeycards"):
 | 
			
		||||
            return self.has('Security Keycard C', player)
 | 
			
		||||
        else:
 | 
			
		||||
            return self.has_any(['Security Keycard A', 'Security Keycard B', 'Security Keycard C'], player)
 | 
			
		||||
            return self.has_any({'Security Keycard A', 'Security Keycard B', 'Security Keycard C'}, player)
 | 
			
		||||
 | 
			
		||||
    def _timespinner_has_keycard_D(self, world: MultiWorld, player: int) -> bool:
 | 
			
		||||
        if is_option_enabled(world, player, "SpecificKeycards"):
 | 
			
		||||
            return self.has('Security Keycard D', player)
 | 
			
		||||
        else:
 | 
			
		||||
            return self.has_any(['Security Keycard A', 'Security Keycard B', 'Security Keycard C', 'Security Keycard D'], player)
 | 
			
		||||
            return self.has_any({'Security Keycard A', 'Security Keycard B', 'Security Keycard C', 'Security Keycard D'}, player)
 | 
			
		||||
 | 
			
		||||
    def _timespinner_can_break_walls(self, world: MultiWorld, player: int) -> bool:
 | 
			
		||||
        if is_option_enabled(world, player, "FacebookMode"):
 | 
			
		||||
| 
						 | 
				
			
			@ -58,4 +58,4 @@ class TimespinnerLogic(LogicMixin):
 | 
			
		|||
            return True
 | 
			
		||||
 | 
			
		||||
    def _timespinner_can_kill_all_3_bosses(self, world: MultiWorld, player: int) -> bool:
 | 
			
		||||
        return self.has_all(['Killed Maw', 'Killed Twins', 'Killed Aelana'], player)
 | 
			
		||||
        return self.has_all({'Killed Maw', 'Killed Twins', 'Killed Aelana'}, player)
 | 
			
		||||
| 
						 | 
				
			
			@ -42,6 +42,14 @@ class Inverted(Toggle):
 | 
			
		|||
#    "Require gasmask for Maw"
 | 
			
		||||
#    display_name = "Stinky Maw"
 | 
			
		||||
 | 
			
		||||
class GyreArchives(Toggle):
 | 
			
		||||
    "Gyre locations are in logic. New warps are gated by Merchant Crow and Kobo"
 | 
			
		||||
    display_name = "Gyre Archives"
 | 
			
		||||
 | 
			
		||||
class Cantoran(Toggle):
 | 
			
		||||
    "Cantoran's fight and check are available upon revisiting his room"
 | 
			
		||||
    display_name = "Cantoran"
 | 
			
		||||
 | 
			
		||||
# Some options that are available in the timespinner randomizer arent currently implemented
 | 
			
		||||
timespinner_options: Dict[str, Toggle] = {
 | 
			
		||||
    "StartWithJewelryBox": StartWithJewelryBox,
 | 
			
		||||
| 
						 | 
				
			
			@ -54,6 +62,8 @@ timespinner_options: Dict[str, Toggle] = {
 | 
			
		|||
    "SpecificKeycards": SpecificKeycards,
 | 
			
		||||
    "Inverted": Inverted,
 | 
			
		||||
    #"StinkyMaw": StinkyMaw,
 | 
			
		||||
    "GyreArchives": GyreArchives,
 | 
			
		||||
    "Cantoran": Cantoran,
 | 
			
		||||
    "DeathLink": DeathLink,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -88,7 +88,7 @@ def create_regions(world: MultiWorld, player: int, locations: Tuple[LocationData
 | 
			
		|||
    connect(world, player, names, 'The lab (power off)', 'The lab (upper)', lambda state: state._timespinner_has_forwarddash_doublejump(world, player))
 | 
			
		||||
    connect(world, player, names, 'The lab (upper)', 'The lab (power off)')
 | 
			
		||||
    connect(world, player, names, 'The lab (upper)', 'Emperors tower', lambda state: state._timespinner_has_forwarddash_doublejump(world, player))
 | 
			
		||||
    connect(world, player, names, 'The lab (upper)', 'Ancient Pyramid (left)', lambda state: state.has_all(['Timespinner Wheel', 'Timespinner Spindle', 'Timespinner Gear 1', 'Timespinner Gear 2', 'Timespinner Gear 3'], player))
 | 
			
		||||
    connect(world, player, names, 'The lab (upper)', 'Ancient Pyramid (left)', 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, names, 'Skeleton Shaft', 'Lake desolation')
 | 
			
		||||
    connect(world, player, names, 'Skeleton Shaft', 'Sealed Caves (upper)', lambda state: state._timespinner_has_keycard_A(world, player))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,7 +18,7 @@ class TimespinnerWorld(World):
 | 
			
		|||
    game = "Timespinner"
 | 
			
		||||
    topology_present = True
 | 
			
		||||
    remote_items = False
 | 
			
		||||
    data_version = 3
 | 
			
		||||
    data_version = 4
 | 
			
		||||
 | 
			
		||||
    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)}
 | 
			
		||||
| 
						 | 
				
			
			@ -92,7 +92,7 @@ def get_excluded_items_based_on_options(world: MultiWorld, player: int) -> Set[s
 | 
			
		|||
        excluded_items.add('Meyef')
 | 
			
		||||
    if is_option_enabled(world, player, "QuickSeed"):
 | 
			
		||||
        excluded_items.add('Talaria Attachment')
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    return excluded_items
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -155,7 +155,9 @@ def create_item_with_correct_settings(world: MultiWorld, player: int, name: str)
 | 
			
		|||
 | 
			
		||||
    if (name == 'Tablet' or name == 'Library Keycard V') and not is_option_enabled(world, player, "DownloadableItems"):
 | 
			
		||||
        item.advancement = False
 | 
			
		||||
    if name == 'Oculus Ring' and not is_option_enabled(world, player, "FacebookMode"):
 | 
			
		||||
    elif name == 'Oculus Ring' and not is_option_enabled(world, player, "FacebookMode"):
 | 
			
		||||
        item.advancement = False
 | 
			
		||||
    elif (name == 'Kobo' or name == 'Merchant Crow') and not is_option_enabled(world, player, "GyreArchives"):
 | 
			
		||||
        item.advancement = False
 | 
			
		||||
 | 
			
		||||
    return item
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue