diff --git a/WebHostLib/static/styles/timespinnerTracker.css b/WebHostLib/static/styles/timespinnerTracker.css
index 007c6a19..640b5846 100644
--- a/WebHostLib/static/styles/timespinnerTracker.css
+++ b/WebHostLib/static/styles/timespinnerTracker.css
@@ -75,6 +75,27 @@
#inventory-table img.acquired.green{ /*32CD32*/
filter: hue-rotate(84deg) saturate(10) brightness(0.7);
}
+#inventory-table img.acquired.hotpink{ /*FF69B4*/
+ filter: sepia(100%) hue-rotate(300deg) saturate(10);
+}
+#inventory-table img.acquired.lightsalmon{ /*FFA07A*/
+ filter: sepia(100%) hue-rotate(347deg) saturate(10);
+}
+#inventory-table img.acquired.crimson{ /*DB143B*/
+ filter: sepia(100%) hue-rotate(318deg) saturate(10) brightness(0.86);
+}
+
+#inventory-table span{
+ color: #B4B4A0;
+ font-size: 40px;
+ max-width: 40px;
+ max-height: 40px;
+ filter: grayscale(100%) contrast(75%) brightness(30%);
+}
+
+#inventory-table span.acquired{
+ filter: none;
+}
#inventory-table div.image-stack{
display: grid;
diff --git a/WebHostLib/templates/tracker__Timespinner.html b/WebHostLib/templates/tracker__Timespinner.html
index b118c338..aa856765 100644
--- a/WebHostLib/templates/tracker__Timespinner.html
+++ b/WebHostLib/templates/tracker__Timespinner.html
@@ -99,6 +99,52 @@
{% endif %}
+ {% if 'PrismBreak' in options or 'LockKeyAmadeus' in options or 'GateKeep' in options %}
+
+ {% if 'PrismBreak' in options %}
+
+ {% endif %}
+ {% if 'LockKeyAmadeus' in options %}
+
+
+
+
+

+
+
+

+
+
+

+
+
+

+
+
+
+
+ {% endif %}
+ {% if 'GateKeep' in options %}
+
+ ❖
+
+ {% endif %}
+
+ {% endif %}
diff --git a/WebHostLib/tracker.py b/WebHostLib/tracker.py
index 043764a5..3748de97 100644
--- a/WebHostLib/tracker.py
+++ b/WebHostLib/tracker.py
@@ -1071,6 +1071,11 @@ if "Timespinner" in network_data_package["games"]:
"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",
+ "Laser Access": "https://timespinnerwiki.com/mediawiki/images/9/99/Historical_Documents.png",
+ "Lab Glasses": "https://timespinnerwiki.com/mediawiki/images/4/4a/Lab_Glasses.png",
+ "Eye Orb": "https://timespinnerwiki.com/mediawiki/images/a/a4/Eye_Orb.png",
+ "Lab Coat": "https://timespinnerwiki.com/mediawiki/images/5/51/Lab_Coat.png",
+ "Demon": "https://timespinnerwiki.com/mediawiki/images/f/f8/Familiar_Demon.png",
}
timespinner_location_ids = {
@@ -1118,6 +1123,9 @@ if "Timespinner" in network_data_package["games"]:
timespinner_location_ids["Ancient Pyramid"] += [
1337237, 1337238, 1337239,
1337240, 1337241, 1337242, 1337243, 1337244, 1337245]
+ if (slot_data["PyramidStart"]):
+ timespinner_location_ids["Ancient Pyramid"] += [
+ 1337233, 1337234, 1337235]
display_data = {}
diff --git a/worlds/timespinner/Items.py b/worlds/timespinner/Items.py
index 3beead95..a00fca7e 100644
--- a/worlds/timespinner/Items.py
+++ b/worlds/timespinner/Items.py
@@ -199,11 +199,16 @@ item_table: Dict[str, ItemData] = {
'Chaos Trap': ItemData('Trap', 1337186, 0, trap=True),
'Neurotoxin Trap': ItemData('Trap', 1337187, 0, trap=True),
'Bee Trap': ItemData('Trap', 1337188, 0, trap=True),
- 'Laser Access A': ItemData('Relic', 1337189, progression=True),
- 'Laser Access I': ItemData('Relic', 1337191, progression=True),
- 'Laser Access M': ItemData('Relic', 1337192, progression=True),
+ 'Laser Access A': ItemData('Laser Access', 1337189, progression=True),
+ 'Laser Access I': ItemData('Laser Access', 1337191, progression=True),
+ 'Laser Access M': ItemData('Laser Access', 1337192, progression=True),
'Throw Stun Trap': ItemData('Trap', 1337193, 0, trap=True),
- # 1337194 - 1337248 Reserved
+ 'Lab Access Genza': ItemData('Lab Access', 1337194, progression=True),
+ 'Lab Access Experiment': ItemData('Lab Access', 1337195, progression=True),
+ 'Lab Access Research': ItemData('Lab Access', 1337196, progression=True),
+ 'Lab Access Dynamo': ItemData('Lab Access', 1337197, progression=True),
+ 'Drawbridge Key': ItemData('Key', 1337198, progression=True),
+ # 1337199 - 1337248 Reserved
'Max Sand': ItemData('Stat', 1337249, 14)
}
@@ -259,6 +264,17 @@ starter_progression_items: Tuple[str, ...] = (
'Mysterious Warp Beacon'
)
+pyramid_start_starter_progression_items: Tuple[str, ...] = (
+ 'Succubus Hairpin',
+ 'Succubus Hairpin',
+ 'Twin Pyramid Key',
+ 'Celestial Sash',
+ 'Lightwall',
+ 'Modern Warp Beacon',
+ 'Timeworn Warp Beacon',
+ 'Mysterious Warp Beacon'
+)
+
filler_items: Tuple[str, ...] = (
'Potion',
'Ether',
@@ -280,4 +296,4 @@ def get_item_names_per_category() -> Dict[str, Set[str]]:
for name, data in item_table.items():
categories.setdefault(data.category, set()).add(name)
- return categories
\ No newline at end of file
+ return categories
diff --git a/worlds/timespinner/Locations.py b/worlds/timespinner/Locations.py
index 93ac6ccb..64430473 100644
--- a/worlds/timespinner/Locations.py
+++ b/worlds/timespinner/Locations.py
@@ -92,15 +92,15 @@ def get_location_datas(player: Optional[int], options: Optional[TimespinnerOptio
LocationData('Military Fortress (hangar)', 'Military Fortress: Pedestal', 1337065, lambda state: state.has('Water Mask', player) if flooded.flood_lab else (logic.has_doublejump_of_npc(state) or logic.has_forwarddash_doublejump(state))),
LocationData('The lab', 'Lab: Coffee break', 1337066),
LocationData('The lab', 'Lab: Lower trash right', 1337067, logic.has_doublejump),
- LocationData('The lab', 'Lab: Lower trash left', 1337068, logic.has_upwarddash),
+ LocationData('The lab', 'Lab: Lower trash left', 1337068, lambda state: logic.has_doublejump_of_npc(state) if options.lock_key_amadeus else logic.has_upwarddash ),
LocationData('The lab', 'Lab: Below lab entrance', 1337069, logic.has_doublejump),
- LocationData('The lab (power off)', 'Lab: Trash jump room', 1337070),
- LocationData('The lab (power off)', 'Lab: Dynamo Works', 1337071),
+ LocationData('The lab (power off)', 'Lab: Trash jump room', 1337070, lambda state: not options.lock_key_amadeus or logic.has_doublejump_of_npc(state) ),
+ LocationData('The lab (power off)', 'Lab: Dynamo Works', 1337071, lambda state: not options.lock_key_amadeus or (state.has_all(('Lab Access Research', 'Lab Access Dynamo'), player)) ),
LocationData('The lab (upper)', 'Lab: Genza (Blob Mom)', 1337072),
- LocationData('The lab (power off)', 'Lab: Experiment #13', 1337073),
+ LocationData('The lab (power off)', 'Lab: Experiment #13', 1337073, lambda state: not options.lock_key_amadeus or state.has('Lab Access Experiment', player) ),
LocationData('The lab (upper)', 'Lab: Download and chest room chest', 1337074),
LocationData('The lab (upper)', 'Lab: Lab secret', 1337075, logic.can_break_walls),
- LocationData('The lab (power off)', 'Lab: Spider Hell', 1337076, logic.has_keycard_A),
+ LocationData('The lab (power off)', 'Lab: Spider Hell', 1337076, lambda state: logic.has_keycard_A and not options.lock_key_amadeus or state.has('Lab Access Research', player)),
LocationData('Emperors tower', 'Emperor\'s Tower: Courtyard bottom chest', 1337077),
LocationData('Emperors tower', 'Emperor\'s Tower: Courtyard floor secret', 1337078, lambda state: logic.has_upwarddash(state) and logic.can_break_walls(state)),
LocationData('Emperors tower', 'Emperor\'s Tower: Courtyard upper chest', 1337079, lambda state: logic.has_upwarddash(state)),
@@ -214,11 +214,11 @@ def get_location_datas(player: Optional[int], options: Optional[TimespinnerOptio
LocationData('Library top', 'Library: Backer room terminal (Vandagray Metropolis Map)', 1337163, lambda state: state.has('Tablet', player)),
LocationData('Varndagroth tower right (elevator)', 'Varndagroth Towers (Right): Medbay terminal (Bleakness Research)', 1337164, lambda state: state.has('Tablet', player) and logic.has_keycard_B(state)),
LocationData('The lab (upper)', 'Lab: Download and chest room terminal (Experiment #13)', 1337165, lambda state: state.has('Tablet', player)),
- LocationData('The lab (power off)', 'Lab: Middle terminal (Amadeus Laboratory Map)', 1337166, lambda state: state.has('Tablet', player)),
- LocationData('The lab (power off)', 'Lab: Sentry platform terminal (Origins)', 1337167, lambda state: state.has('Tablet', player)),
+ LocationData('The lab (power off)', 'Lab: Middle terminal (Amadeus Laboratory Map)', 1337166, lambda state: state.has('Tablet', player) and (not options.lock_key_amadeus or state.has('Lab Access Research', player))),
+ LocationData('The lab (power off)', 'Lab: Sentry platform terminal (Origins)', 1337167, lambda state: state.has('Tablet', player) and (not options.lock_key_amadeus or state.has('Lab Access Genza', player) or logic.can_teleport_to(state, "Time", "GateDadsTower"))),
LocationData('The lab', 'Lab: Experiment 13 terminal (W.R.E.C Farewell)', 1337168, lambda state: state.has('Tablet', player)),
LocationData('The lab', 'Lab: Left terminal (Biotechnology)', 1337169, lambda state: state.has('Tablet', player)),
- LocationData('The lab (power off)', 'Lab: Right terminal (Experiment #11)', 1337170, lambda state: state.has('Tablet', player))
+ LocationData('The lab (power off)', 'Lab: Right terminal (Experiment #11)', 1337170, lambda state: state.has('Tablet', player) and (not options.lock_key_amadeus or state.has('Lab Access Research', player)))
)
# 1337176 - 1337176 Cantoran
@@ -254,7 +254,17 @@ def get_location_datas(player: Optional[int], options: Optional[TimespinnerOptio
LocationData('Caves of Banishment (Maw)', 'Caves of Banishment (Maw): Journal - Lower Left Caves (Naivety)', 1337198, lambda state: not flooded.flood_maw or state.has('Water Mask', player))
)
- # 1337199 - 1337236 Reserved for future use
+ # 1337199 - 1337232 Reserved for future use
+
+ # 1337233 - 1337235 Pyramid Start checks
+ if not options or options.pyramid_start:
+ location_table += (
+ LocationData('Ancient Pyramid (entrance)', 'Dark Forest: Training Dummy', 1337233),
+ LocationData('Ancient Pyramid (entrance)', 'Temporal Gyre: Forest Entrance', 1337234, lambda state: logic.has_upwarddash(state) or logic.can_teleport_to(state, "Time", "GateGyre")),
+ LocationData('Ancient Pyramid (entrance)', 'Ancient Pyramid: Rubble', 1337235),
+ )
+
+ # 1337236 Nightmare door
# 1337237 - 1337245 GyreArchives
if not options or options.gyre_archives:
diff --git a/worlds/timespinner/LogicExtensions.py b/worlds/timespinner/LogicExtensions.py
index 2a0a3587..878b69ae 100644
--- a/worlds/timespinner/LogicExtensions.py
+++ b/worlds/timespinner/LogicExtensions.py
@@ -10,6 +10,7 @@ class TimespinnerLogic:
flag_unchained_keys: bool
flag_eye_spy: bool
flag_specific_keycards: bool
+ flag_prism_break: bool
pyramid_keys_unlock: Optional[str]
present_keys_unlock: Optional[str]
past_keys_unlock: Optional[str]
diff --git a/worlds/timespinner/Options.py b/worlds/timespinner/Options.py
index 72f2d8b3..4cb7fbbc 100644
--- a/worlds/timespinner/Options.py
+++ b/worlds/timespinner/Options.py
@@ -60,6 +60,7 @@ class EnemyRando(Choice):
option_scaled = 1
option_unscaled = 2
option_ryshia = 3
+ option_no_hell_spiders = 4
alias_true = 1
class DamageRando(Choice):
@@ -377,6 +378,26 @@ class PrismBreak(Toggle):
"""Adds 3 Laser Access items to the item pool to remove the lasers blocking the military hangar area
instead of needing to beat the Golden Idol, Aelana, and The Maw."""
display_name = "Prism Break"
+
+class LockKeyAmadeus(Toggle):
+ """Lasers in Amadeus' Laboratory are disabled via items, rather than by de-powering the lab. Experiments will spawn in the lab."""
+ display_name = "Lock Key Amadeus"
+
+class RiskyWarps(Toggle):
+ """Expanded free-warp eligible locations, including Azure Queen, Xarion, Amadeus' Laboratory, and Emperor's Tower."""
+ display_name = "Risky Warps"
+
+class PyramidStart(Toggle):
+ """Start in ???. Takes priority over Inverted. Additional chests in Dark Forest and Pyramid. Sandman door behaves as it does in Enter Sandman."""
+ display_name = "Pyramid Start"
+
+class GateKeep(Toggle):
+ """The castle drawbridge starts raised, and can be lowered via item."""
+ display_name = "Gate Keep"
+
+class RoyalRoadblock(Toggle):
+ """The Royal Towers entrance door requires a royal orb (Plasma Orb, Plasma Geyser, or Royal Ring) to enter."""
+ display_name = "Royal Roadblock"
@dataclass
class TimespinnerOptions(PerGameCommonOptions, DeathLinkMixin):
@@ -415,6 +436,11 @@ class TimespinnerOptions(PerGameCommonOptions, DeathLinkMixin):
unchained_keys: UnchainedKeys
back_to_the_future: PresentAccessWithWheelAndSpindle
prism_break: PrismBreak
+ lock_key_amadeus: LockKeyAmadeus
+ risky_warps: RiskyWarps
+ pyramid_start: PyramidStart
+ gate_keep: GateKeep
+ royal_roadblock: RoyalRoadblock
trap_chance: TrapChance
traps: Traps
diff --git a/worlds/timespinner/PreCalculatedWeights.py b/worlds/timespinner/PreCalculatedWeights.py
index c9d80d7a..3ad7c2c7 100644
--- a/worlds/timespinner/PreCalculatedWeights.py
+++ b/worlds/timespinner/PreCalculatedWeights.py
@@ -52,11 +52,12 @@ class PreCalculatedWeights:
self.flood_lab = False
self.pyramid_keys_unlock, self.present_key_unlock, self.past_key_unlock, self.time_key_unlock = \
- self.get_pyramid_keys_unlocks(options, random, self.flood_maw, self.flood_xarion)
+ self.get_pyramid_keys_unlocks(options, random, self.flood_maw, self.flood_xarion, self.flood_lab)
@staticmethod
def get_pyramid_keys_unlocks(options: TimespinnerOptions, random: Random,
- is_maw_flooded: bool, is_xarion_flooded: bool) -> Tuple[str, str, str, str]:
+ is_maw_flooded: bool, is_xarion_flooded: bool,
+ is_lab_flooded: bool) -> Tuple[str, str, str, str]:
present_teleportation_gates: List[str] = [
"GateKittyBoss",
@@ -85,10 +86,15 @@ class PreCalculatedWeights:
if not is_maw_flooded:
past_teleportation_gates.append("GateMaw")
- if not is_xarion_flooded:
- present_teleportation_gates.append("GateXarion")
+ if options.risky_warps:
+ past_teleportation_gates.append("GateLakeSereneLeft")
+ present_teleportation_gates.append("GateDadsTower")
+ if not is_xarion_flooded:
+ present_teleportation_gates.append("GateXarion")
+ if not is_lab_flooded:
+ present_teleportation_gates.append("GateLabEntrance")
- if options.inverted:
+ if options.inverted or (options.pyramid_start and not options.back_to_the_future):
all_gates: Tuple[str, ...] = present_teleportation_gates
else:
all_gates: Tuple[str, ...] = past_teleportation_gates + present_teleportation_gates
diff --git a/worlds/timespinner/Regions.py b/worlds/timespinner/Regions.py
index f737b461..51b1688f 100644
--- a/worlds/timespinner/Regions.py
+++ b/worlds/timespinner/Regions.py
@@ -106,15 +106,15 @@ def create_regions_and_locations(world: MultiWorld, player: int, options: Timesp
connect(world, player, 'Sealed Caves (Sirens)', 'Varndagroth tower right (lower)', lambda state: state.has('Elevator Keycard', player))
connect(world, player, 'Sealed Caves (Sirens)', 'Space time continuum', logic.has_teleport)
connect(world, player, 'Military Fortress', 'Varndagroth tower right (lower)', logic.can_kill_all_3_bosses)
- connect(world, player, '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) and logic.can_kill_all_3_bosses(state))
connect(world, player, 'Military Fortress', 'Military Fortress (hangar)', logic.has_doublejump)
connect(world, player, 'Military Fortress (hangar)', 'Military Fortress')
connect(world, player, 'Military Fortress (hangar)', 'The lab', lambda state: logic.has_keycard_B(state) and (state.has('Water Mask', player) if flooded.flood_lab else logic.has_doublejump(state)))
connect(world, player, 'Temporal Gyre', 'Military Fortress')
connect(world, player, 'The lab', 'Military Fortress')
- connect(world, player, 'The lab', 'The lab (power off)', logic.has_doublejump_of_npc)
+ connect(world, player, 'The lab', 'The lab (power off)', lambda state: options.lock_key_amadeus or logic.has_doublejump_of_npc(state))
connect(world, player, 'The lab (power off)', 'The lab', lambda state: not flooded.flood_lab or state.has('Water Mask', player))
- connect(world, player, 'The lab (power off)', 'The lab (upper)', logic.has_forwarddash_doublejump)
+ connect(world, player, 'The lab (power off)', 'The lab (upper)', lambda state: logic.has_forwarddash_doublejump(state) and ((not options.lock_key_amadeus) or state.has('Lab Access Genza', player)))
connect(world, player, 'The lab (upper)', 'The lab (power off)')
connect(world, player, 'The lab (upper)', 'Emperors tower', logic.has_forwarddash_doublejump)
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))
@@ -125,12 +125,12 @@ def create_regions_and_locations(world: MultiWorld, player: int, options: Timesp
connect(world, player, 'Sealed Caves (Xarion)', 'Skeleton Shaft')
connect(world, player, 'Sealed Caves (Xarion)', 'Space time continuum', logic.has_teleport)
connect(world, player, 'Refugee Camp', 'Forest')
- connect(world, player, 'Refugee Camp', 'Library', lambda state: options.inverted and options.back_to_the_future and state.has_all({'Timespinner Wheel', 'Timespinner Spindle'}, player))
+ connect(world, player, 'Refugee Camp', 'Library', lambda state: (options.pyramid_start or options.inverted) and options.back_to_the_future and state.has_all({'Timespinner Wheel', 'Timespinner Spindle'}, player))
connect(world, player, 'Refugee Camp', 'Space time continuum', logic.has_teleport)
connect(world, player, 'Forest', 'Refugee Camp')
connect(world, player, 'Forest', 'Left Side forest Caves', lambda state: flooded.flood_lake_serene_bridge or state.has('Talaria Attachment', player) or logic.has_timestop(state))
connect(world, player, 'Forest', 'Caves of Banishment (Sirens)')
- connect(world, player, 'Forest', 'Castle Ramparts')
+ connect(world, player, 'Forest', 'Castle Ramparts', lambda state: not options.gate_keep or state.has('Drawbridge Key', player) or logic.has_upwarddash(state))
connect(world, player, 'Left Side forest Caves', 'Forest')
connect(world, player, 'Left Side forest Caves', 'Upper Lake Serene', logic.has_timestop)
connect(world, player, 'Left Side forest Caves', 'Lower Lake Serene', lambda state: not flooded.flood_lake_serene or state.has('Water Mask', player))
@@ -152,7 +152,7 @@ def create_regions_and_locations(world: MultiWorld, player: int, options: Timesp
connect(world, player, 'Castle Ramparts', 'Space time continuum', logic.has_teleport)
connect(world, player, 'Castle Keep', 'Castle Ramparts')
connect(world, player, 'Castle Keep', 'Castle Basement', lambda state: not flooded.flood_basement or state.has('Water Mask', player))
- connect(world, player, 'Castle Keep', 'Royal towers (lower)', logic.has_doublejump)
+ connect(world, player, 'Castle Keep', 'Royal towers (lower)', lambda state: logic.has_doublejump(state) and (not options.royal_roadblock or logic.has_pink(state)))
connect(world, player, 'Castle Keep', 'Space time continuum', logic.has_teleport)
connect(world, player, 'Royal towers (lower)', 'Castle Keep')
connect(world, player, 'Royal towers (lower)', 'Royal towers', lambda state: state.has('Timespinner Wheel', player) or logic.has_forwarddash_doublejump(state))
@@ -162,9 +162,12 @@ def create_regions_and_locations(world: MultiWorld, player: int, options: Timesp
connect(world, player, 'Royal towers (upper)', 'Royal towers')
#connect(world, player, 'Ancient Pyramid (entrance)', 'The lab (upper)', lambda state: not is_option_enabled(world, player, "EnterSandman"))
connect(world, player, 'Ancient Pyramid (entrance)', 'Ancient Pyramid (left)', logic.has_doublejump)
+ connect(world, player, 'Ancient Pyramid (entrance)', 'Space time continuum', logic.has_teleport)
connect(world, player, 'Ancient Pyramid (left)', 'Ancient Pyramid (entrance)')
connect(world, player, 'Ancient Pyramid (left)', 'Ancient Pyramid (right)', lambda state: flooded.flood_pyramid_shaft or logic.has_upwarddash(state))
+ connect(world, player, 'Ancient Pyramid (left)', 'Space time continuum', logic.has_teleport)
connect(world, player, 'Ancient Pyramid (right)', 'Ancient Pyramid (left)', lambda state: flooded.flood_pyramid_shaft or logic.has_upwarddash(state))
+ connect(world, player, 'Ancient Pyramid (right)', 'Space time continuum', logic.has_teleport)
connect(world, player, 'Space time continuum', 'Lake desolation', lambda state: logic.can_teleport_to(state, "Present", "GateLakeDesolation"))
connect(world, player, 'Space time continuum', 'Lower lake desolation', lambda state: logic.can_teleport_to(state, "Present", "GateKittyBoss"))
connect(world, player, 'Space time continuum', 'Library', lambda state: logic.can_teleport_to(state, "Present", "GateLeftLibrary"))
@@ -180,8 +183,9 @@ def create_regions_and_locations(world: MultiWorld, player: int, options: Timesp
connect(world, player, 'Space time continuum', 'Royal towers (lower)', lambda state: logic.can_teleport_to(state, "Past", "GateRoyalTowers"))
connect(world, player, '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 (upper)', lambda state: logic.can_teleport_to(state, "Past", "GateCavesOfBanishment"))
- connect(world, player, 'Space time continuum', 'Ancient Pyramid (entrance)', lambda state: logic.can_teleport_to(state, "Time", "GateGyre") or (not options.unchained_keys and options.enter_sandman))
- connect(world, player, 'Space time continuum', 'Ancient Pyramid (left)', lambda state: logic.can_teleport_to(state, "Time", "GateLeftPyramid"))
+ connect(world, player, 'Space time continuum', 'Military Fortress (hangar)', lambda state: logic.can_teleport_to(state, "Present", "GateLabEntrance"))
+ connect(world, player, 'Space time continuum', 'The lab (upper)', lambda state: logic.can_teleport_to(state, "Present", "GateDadsTower"))
+ connect(world, player, 'Space time continuum', 'Ancient Pyramid (entrance)', lambda state: logic.can_teleport_to(state, "Time", "GateGyre") or logic.can_teleport_to(state, "Time", "GateLeftPyramid") or (not options.unchained_keys and options.enter_sandman))
connect(world, player, 'Space time continuum', 'Ancient Pyramid (right)', lambda state: logic.can_teleport_to(state, "Time", "GateRightPyramid"))
if options.gyre_archives:
@@ -227,7 +231,9 @@ def connectStartingRegion(world: MultiWorld, player: int, options: TimespinnerOp
tutorial = world.get_region('Tutorial', player)
space_time_continuum = world.get_region('Space time continuum', player)
- if options.inverted:
+ if options.pyramid_start:
+ starting_region = world.get_region('Ancient Pyramid (entrance)', player)
+ elif options.inverted:
starting_region = world.get_region('Refugee Camp', player)
else:
starting_region = world.get_region('Lake desolation', player)
@@ -264,4 +270,4 @@ def split_location_datas_per_region(locations: List[LocationData]) -> Dict[str,
for location in locations:
per_region.setdefault(location.region, []).append(location)
- return per_region
\ No newline at end of file
+ return per_region
diff --git a/worlds/timespinner/__init__.py b/worlds/timespinner/__init__.py
index ca31d083..4d1efc41 100644
--- a/worlds/timespinner/__init__.py
+++ b/worlds/timespinner/__init__.py
@@ -1,7 +1,7 @@
from typing import Dict, List, Set, Tuple, TextIO, Any, Optional
from BaseClasses import Item, Tutorial, ItemClassification
from .Items import get_item_names_per_category
-from .Items import item_table, starter_melee_weapons, starter_spells, filler_items, starter_progression_items
+from .Items import item_table, starter_melee_weapons, starter_spells, filler_items, starter_progression_items, pyramid_start_starter_progression_items
from .Locations import get_location_datas, EventId
from .Options import BackwardsCompatiableTimespinnerOptions, Toggle
from .PreCalculatedWeights import PreCalculatedWeights
@@ -126,6 +126,11 @@ class TimespinnerWorld(World):
"UnchainedKeys": self.options.unchained_keys.value,
"PresentAccessWithWheelAndSpindle": self.options.back_to_the_future.value,
"PrismBreak": self.options.prism_break.value,
+ "LockKeyAmadeus": self.options.lock_key_amadeus.value,
+ "RiskyWarps": self.options.risky_warps.value,
+ "PyramidStart": self.options.pyramid_start.value,
+ "GateKeep": self.options.gate_keep.value,
+ "RoyalRoadblock": self.options.royal_roadblock.value,
"Traps": self.options.traps.value,
"DeathLink": self.options.death_link.value,
"StinkyMaw": True,
@@ -203,7 +208,7 @@ class TimespinnerWorld(World):
self.precalculated_weights.past_key_unlock = slot_data["PastGate"]
self.precalculated_weights.time_key_unlock = slot_data["TimeGate"]
# rising tides
- if (slot_data["Basement"] > 1):
+ if (slot_data["Basement"] > 0):
self.precalculated_weights.flood_basement = True
if (slot_data["Basement"] == 2):
self.precalculated_weights.flood_basement_high = True
@@ -304,6 +309,11 @@ class TimespinnerWorld(World):
elif name in {"Laser Access A", "Laser Access I", "Laser Access M"} \
and not self.options.prism_break:
item.classification = ItemClassification.filler
+ elif name in {"Lab Access Genza", "Lab Access Experiment", "Lab Access Research", "Lab Access Dynamo"} \
+ and not self.options.lock_key_amadeus:
+ item.classification = ItemClassification.filler
+ elif name == "Drawbridge Key" and not self.options.gate_keep:
+ item.classification = ItemClassification.filler
return item
@@ -341,6 +351,15 @@ class TimespinnerWorld(World):
excluded_items.add('Laser Access I')
excluded_items.add('Laser Access M')
+ if not self.options.lock_key_amadeus:
+ excluded_items.add('Lab Access Genza')
+ excluded_items.add('Lab Access Experiment')
+ excluded_items.add('Lab Access Research')
+ excluded_items.add('Lab Access Dynamo')
+
+ if not self.options.gate_keep:
+ excluded_items.add('Drawbridge Key')
+
for item in self.multiworld.precollected_items[self.player]:
if item.name not in self.item_name_groups['UseItem']:
excluded_items.add(item.name)
@@ -376,15 +395,18 @@ class TimespinnerWorld(World):
self.place_locked_item(excluded_items, location, item_name)
def place_first_progression_item(self, excluded_items: Set[str]) -> None:
- if self.options.quick_seed or self.options.inverted or self.precalculated_weights.flood_lake_desolation:
+ if (self.options.quick_seed or self.options.inverted or self.precalculated_weights.flood_lake_desolation) \
+ and not self.options.pyramid_start:
return
+ enabled_starter_progression_items = pyramid_start_starter_progression_items if self.options.pyramid_start else starter_progression_items
+
for item_name in self.options.start_inventory.value.keys():
- if item_name in starter_progression_items:
+ if item_name in enabled_starter_progression_items:
return
local_starter_progression_items = tuple(
- item for item in starter_progression_items
+ item for item in enabled_starter_progression_items
if item not in excluded_items and item not in self.options.non_local_items.value)
if not local_starter_progression_items: