Timespinner: New options from TS Rando v1.25 + Logic fix (#2090)
Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>
This commit is contained in:
parent
3b357315ee
commit
d1b22935b4
|
@ -1,4 +1,4 @@
|
||||||
from typing import List, Tuple, Optional, Callable, NamedTuple
|
from typing import List, Optional, Callable, NamedTuple
|
||||||
from BaseClasses import MultiWorld, CollectionState
|
from BaseClasses import MultiWorld, CollectionState
|
||||||
from .Options import is_option_enabled
|
from .Options import is_option_enabled
|
||||||
from .PreCalculatedWeights import PreCalculatedWeights
|
from .PreCalculatedWeights import PreCalculatedWeights
|
||||||
|
@ -11,11 +11,11 @@ class LocationData(NamedTuple):
|
||||||
region: str
|
region: str
|
||||||
name: str
|
name: str
|
||||||
code: Optional[int]
|
code: Optional[int]
|
||||||
rule: Callable[[CollectionState], bool] = lambda state: True
|
rule: Optional[Callable[[CollectionState], bool]] = None
|
||||||
|
|
||||||
|
|
||||||
def get_location_datas(world: Optional[MultiWorld], player: Optional[int],
|
def get_location_datas(world: Optional[MultiWorld], player: Optional[int],
|
||||||
precalculated_weights: PreCalculatedWeights) -> Tuple[LocationData, ...]:
|
precalculated_weights: PreCalculatedWeights) -> List[LocationData]:
|
||||||
|
|
||||||
flooded: PreCalculatedWeights = precalculated_weights
|
flooded: PreCalculatedWeights = precalculated_weights
|
||||||
logic = TimespinnerLogic(world, player, precalculated_weights)
|
logic = TimespinnerLogic(world, player, precalculated_weights)
|
||||||
|
@ -88,9 +88,9 @@ def get_location_datas(world: Optional[MultiWorld], player: Optional[int],
|
||||||
LocationData('Military Fortress (hangar)', 'Military Fortress: Soldiers bridge', 1337060),
|
LocationData('Military Fortress (hangar)', 'Military Fortress: Soldiers bridge', 1337060),
|
||||||
LocationData('Military Fortress (hangar)', 'Military Fortress: Giantess room', 1337061),
|
LocationData('Military Fortress (hangar)', 'Military Fortress: Giantess room', 1337061),
|
||||||
LocationData('Military Fortress (hangar)', 'Military Fortress: Giantess bridge', 1337062),
|
LocationData('Military Fortress (hangar)', 'Military Fortress: Giantess bridge', 1337062),
|
||||||
LocationData('Military Fortress (hangar)', 'Military Fortress: B door chest 2', 1337063, lambda state: logic.has_doublejump(state) and logic.has_keycard_B(state)),
|
LocationData('Military Fortress (hangar)', 'Military Fortress: B door chest 2', 1337063, lambda state: logic.has_keycard_B(state) and (state.has('Water Mask', player) if flooded.flood_lab else logic.has_doublejump(state))),
|
||||||
LocationData('Military Fortress (hangar)', 'Military Fortress: B door chest 1', 1337064, lambda state: logic.has_doublejump(state) and logic.has_keycard_B(state)),
|
LocationData('Military Fortress (hangar)', 'Military Fortress: B door chest 1', 1337064, lambda state: logic.has_keycard_B(state) and (state.has('Water Mask', player) if flooded.flood_lab else logic.has_doublejump(state))),
|
||||||
LocationData('Military Fortress (hangar)', 'Military Fortress: Pedestal', 1337065, lambda state: logic.has_doublejump_of_npc(state) or logic.has_forwarddash_doublejump(state)),
|
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: Coffee break', 1337066),
|
||||||
LocationData('The lab', 'Lab: Lower trash right', 1337067, logic.has_doublejump),
|
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, logic.has_upwarddash),
|
||||||
|
@ -139,17 +139,17 @@ def get_location_datas(world: Optional[MultiWorld], player: Optional[int],
|
||||||
LocationData('Lower Lake Serene', 'Lake Serene (Lower): Under the eels', 1337106),
|
LocationData('Lower Lake Serene', 'Lake Serene (Lower): Under the eels', 1337106),
|
||||||
LocationData('Lower Lake Serene', 'Lake Serene (Lower): Water spikes room', 1337107),
|
LocationData('Lower Lake Serene', 'Lake Serene (Lower): Water spikes room', 1337107),
|
||||||
LocationData('Lower Lake Serene', 'Lake Serene (Lower): Underwater secret', 1337108, logic.can_break_walls),
|
LocationData('Lower Lake Serene', 'Lake Serene (Lower): Underwater secret', 1337108, logic.can_break_walls),
|
||||||
LocationData('Lower Lake Serene', 'Lake Serene (Lower): T chest', 1337109, lambda state: not flooded.dry_lake_serene or logic.has_doublejump_of_npc(state)),
|
LocationData('Lower Lake Serene', 'Lake Serene (Lower): T chest', 1337109, lambda state: flooded.flood_lake_serene or logic.has_doublejump_of_npc(state)),
|
||||||
LocationData('Lower Lake Serene', 'Lake Serene (Lower): Past the eels', 1337110),
|
LocationData('Lower Lake Serene', 'Lake Serene (Lower): Past the eels', 1337110),
|
||||||
LocationData('Lower Lake Serene', 'Lake Serene (Lower): Underwater pedestal', 1337111, lambda state: not flooded.dry_lake_serene or logic.has_doublejump(state)),
|
LocationData('Lower Lake Serene', 'Lake Serene (Lower): Underwater pedestal', 1337111, lambda state: flooded.flood_lake_serene or logic.has_doublejump(state)),
|
||||||
LocationData('Caves of Banishment (upper)', 'Caves of Banishment (Maw): Shroom jump room', 1337112, lambda state: not flooded.flood_maw or logic.has_doublejump(state)),
|
LocationData('Caves of Banishment (upper)', 'Caves of Banishment (Maw): Shroom jump room', 1337112, lambda state: flooded.flood_maw or logic.has_doublejump(state)),
|
||||||
LocationData('Caves of Banishment (upper)', 'Caves of Banishment (Maw): Secret room', 1337113, lambda state: logic.can_break_walls(state) and (not flooded.flood_maw or state.has('Water Mask', player))),
|
LocationData('Caves of Banishment (upper)', 'Caves of Banishment (Maw): Secret room', 1337113, lambda state: logic.can_break_walls(state) and (not flooded.flood_maw or state.has('Water Mask', player))),
|
||||||
LocationData('Caves of Banishment (upper)', 'Caves of Banishment (Maw): Bottom left room', 1337114, lambda state: not flooded.flood_maw or state.has('Water Mask', player)),
|
LocationData('Caves of Banishment (upper)', 'Caves of Banishment (Maw): Bottom left room', 1337114, lambda state: not flooded.flood_maw or state.has('Water Mask', player)),
|
||||||
LocationData('Caves of Banishment (upper)', 'Caves of Banishment (Maw): Single shroom room', 1337115),
|
LocationData('Caves of Banishment (upper)', 'Caves of Banishment (Maw): Single shroom room', 1337115),
|
||||||
LocationData('Caves of Banishment (upper)', 'Caves of Banishment (Maw): Jackpot room chest 1', 1337116, lambda state: logic.has_forwarddash_doublejump(state) or flooded.flood_maw),
|
LocationData('Caves of Banishment (upper)', 'Caves of Banishment (Maw): Jackpot room chest 1', 1337116, lambda state: flooded.flood_maw or logic.has_forwarddash_doublejump(state)),
|
||||||
LocationData('Caves of Banishment (upper)', 'Caves of Banishment (Maw): Jackpot room chest 2', 1337117, lambda state: logic.has_forwarddash_doublejump(state) or flooded.flood_maw),
|
LocationData('Caves of Banishment (upper)', 'Caves of Banishment (Maw): Jackpot room chest 2', 1337117, lambda state: flooded.flood_maw or logic.has_forwarddash_doublejump(state)),
|
||||||
LocationData('Caves of Banishment (upper)', 'Caves of Banishment (Maw): Jackpot room chest 3', 1337118, lambda state: logic.has_forwarddash_doublejump(state) or flooded.flood_maw),
|
LocationData('Caves of Banishment (upper)', 'Caves of Banishment (Maw): Jackpot room chest 3', 1337118, lambda state: flooded.flood_maw or logic.has_forwarddash_doublejump(state)),
|
||||||
LocationData('Caves of Banishment (upper)', 'Caves of Banishment (Maw): Jackpot room chest 4', 1337119, lambda state: logic.has_forwarddash_doublejump(state) or flooded.flood_maw),
|
LocationData('Caves of Banishment (upper)', 'Caves of Banishment (Maw): Jackpot room chest 4', 1337119, lambda state: flooded.flood_maw or logic.has_forwarddash_doublejump(state)),
|
||||||
LocationData('Caves of Banishment (upper)', 'Caves of Banishment (Maw): Pedestal', 1337120, lambda state: not flooded.flood_maw or state.has('Water Mask', player)),
|
LocationData('Caves of Banishment (upper)', 'Caves of Banishment (Maw): Pedestal', 1337120, lambda state: not flooded.flood_maw or state.has('Water Mask', player)),
|
||||||
LocationData('Caves of Banishment (Maw)', 'Caves of Banishment (Maw): Last chance before Maw', 1337121, lambda state: state.has('Water Mask', player) if flooded.flood_maw else logic.has_doublejump(state)),
|
LocationData('Caves of Banishment (Maw)', 'Caves of Banishment (Maw): Last chance before Maw', 1337121, lambda state: state.has('Water Mask', player) if flooded.flood_maw else logic.has_doublejump(state)),
|
||||||
LocationData('Caves of Banishment (Maw)', 'Caves of Banishment (Maw): Plasma Crystal', 1337173, lambda state: state.has_any({'Gas Mask', 'Talaria Attachment'}, player) and (not flooded.flood_maw or state.has('Water Mask', player))),
|
LocationData('Caves of Banishment (Maw)', 'Caves of Banishment (Maw): Plasma Crystal', 1337173, lambda state: state.has_any({'Gas Mask', 'Talaria Attachment'}, player) and (not flooded.flood_maw or state.has('Water Mask', player))),
|
||||||
|
@ -197,7 +197,7 @@ def get_location_datas(world: Optional[MultiWorld], player: Optional[int],
|
||||||
LocationData('Ancient Pyramid (entrance)', 'Ancient Pyramid: Why not it\'s right there', 1337246),
|
LocationData('Ancient Pyramid (entrance)', 'Ancient Pyramid: Why not it\'s right there', 1337246),
|
||||||
LocationData('Ancient Pyramid (left)', 'Ancient Pyramid: Conviction guarded room', 1337247),
|
LocationData('Ancient Pyramid (left)', 'Ancient Pyramid: Conviction guarded room', 1337247),
|
||||||
LocationData('Ancient Pyramid (left)', 'Ancient Pyramid: Pit secret room', 1337248, lambda state: logic.can_break_walls(state) and (not flooded.flood_pyramid_shaft or state.has('Water Mask', player))),
|
LocationData('Ancient Pyramid (left)', 'Ancient Pyramid: Pit secret room', 1337248, lambda state: logic.can_break_walls(state) and (not flooded.flood_pyramid_shaft or state.has('Water Mask', player))),
|
||||||
LocationData('Ancient Pyramid (left)', 'Ancient Pyramid: Regret chest', 1337249, lambda state: logic.can_break_walls(state) and (not flooded.flood_pyramid_shaft or state.has('Water Mask', player))),
|
LocationData('Ancient Pyramid (left)', 'Ancient Pyramid: Regret chest', 1337249, lambda state: logic.can_break_walls(state) and (state.has('Water Mask', player) if flooded.flood_pyramid_shaft else logic.has_doublejump(state))),
|
||||||
LocationData('Ancient Pyramid (right)', 'Ancient Pyramid: Nightmare Door chest', 1337236, lambda state: not flooded.flood_pyramid_back or state.has('Water Mask', player)),
|
LocationData('Ancient Pyramid (right)', 'Ancient Pyramid: Nightmare Door chest', 1337236, lambda state: not flooded.flood_pyramid_back or state.has('Water Mask', player)),
|
||||||
LocationData('Ancient Pyramid (right)', 'Killed Nightmare', EventId, lambda state: state.has_all({'Timespinner Wheel', 'Timespinner Spindle', 'Timespinner Gear 1', 'Timespinner Gear 2', 'Timespinner Gear 3'}, player) and (not flooded.flood_pyramid_back or state.has('Water Mask', player)))
|
LocationData('Ancient Pyramid (right)', 'Killed Nightmare', EventId, lambda state: state.has_all({'Timespinner Wheel', 'Timespinner Spindle', 'Timespinner Gear 1', 'Timespinner Gear 2', 'Timespinner Gear 3'}, player) and (not flooded.flood_pyramid_back or state.has('Water Mask', player)))
|
||||||
]
|
]
|
||||||
|
@ -271,4 +271,4 @@ def get_location_datas(world: Optional[MultiWorld], player: Optional[int],
|
||||||
LocationData('Ifrit\'s Lair', 'Ifrit: Post fight (chest)', 1337245),
|
LocationData('Ifrit\'s Lair', 'Ifrit: Post fight (chest)', 1337245),
|
||||||
)
|
)
|
||||||
|
|
||||||
return tuple(location_table)
|
return location_table
|
||||||
|
|
|
@ -54,14 +54,23 @@ class LoreChecks(Toggle):
|
||||||
display_name = "Lore Checks"
|
display_name = "Lore Checks"
|
||||||
|
|
||||||
|
|
||||||
class BossRando(Toggle):
|
class BossRando(Choice):
|
||||||
"Shuffles the positions of all bosses."
|
"Wheter all boss locations are shuffled, and if their damage/hp should be scaled."
|
||||||
display_name = "Boss Randomization"
|
display_name = "Boss Randomization"
|
||||||
|
option_off = 0
|
||||||
|
option_scaled = 1
|
||||||
|
option_unscaled = 2
|
||||||
|
alias_true = 1
|
||||||
|
|
||||||
|
|
||||||
class BossScaling(DefaultOnToggle):
|
class EnemyRando(Choice):
|
||||||
"When Boss Rando is enabled, scales the bosses' HP, XP, and ATK to the stats of the location they replace (Recommended)"
|
"Wheter enemies will be randomized, and if their damage/hp should be scaled."
|
||||||
display_name = "Scale Random Boss Stats"
|
display_name = "Enemy Randomization"
|
||||||
|
option_off = 0
|
||||||
|
option_scaled = 1
|
||||||
|
option_unscaled = 2
|
||||||
|
option_ryshia = 3
|
||||||
|
alias_true = 1
|
||||||
|
|
||||||
|
|
||||||
class DamageRando(Choice):
|
class DamageRando(Choice):
|
||||||
|
@ -336,6 +345,7 @@ def rising_tide_option(location: str, with_save_point_option: bool = False) -> D
|
||||||
class RisingTidesOverrides(OptionDict):
|
class RisingTidesOverrides(OptionDict):
|
||||||
"""Odds for specific areas to be flooded or drained, only has effect when RisingTides is on.
|
"""Odds for specific areas to be flooded or drained, only has effect when RisingTides is on.
|
||||||
Areas that are not specified will roll with the default 33% chance of getting flooded or drained"""
|
Areas that are not specified will roll with the default 33% chance of getting flooded or drained"""
|
||||||
|
display_name = "Rising Tides Overrides"
|
||||||
schema = Schema({
|
schema = Schema({
|
||||||
**rising_tide_option("Xarion"),
|
**rising_tide_option("Xarion"),
|
||||||
**rising_tide_option("Maw"),
|
**rising_tide_option("Maw"),
|
||||||
|
@ -345,9 +355,10 @@ class RisingTidesOverrides(OptionDict):
|
||||||
**rising_tide_option("CastleBasement", with_save_point_option=True),
|
**rising_tide_option("CastleBasement", with_save_point_option=True),
|
||||||
**rising_tide_option("CastleCourtyard"),
|
**rising_tide_option("CastleCourtyard"),
|
||||||
**rising_tide_option("LakeDesolation"),
|
**rising_tide_option("LakeDesolation"),
|
||||||
**rising_tide_option("LakeSerene")
|
**rising_tide_option("LakeSerene"),
|
||||||
|
**rising_tide_option("LakeSereneBridge"),
|
||||||
|
**rising_tide_option("Lab"),
|
||||||
})
|
})
|
||||||
display_name = "Rising Tides Overrides"
|
|
||||||
default = {
|
default = {
|
||||||
"Xarion": { "Dry": 67, "Flooded": 33 },
|
"Xarion": { "Dry": 67, "Flooded": 33 },
|
||||||
"Maw": { "Dry": 67, "Flooded": 33 },
|
"Maw": { "Dry": 67, "Flooded": 33 },
|
||||||
|
@ -358,6 +369,8 @@ class RisingTidesOverrides(OptionDict):
|
||||||
"CastleCourtyard": { "Dry": 67, "Flooded": 33 },
|
"CastleCourtyard": { "Dry": 67, "Flooded": 33 },
|
||||||
"LakeDesolation": { "Dry": 67, "Flooded": 33 },
|
"LakeDesolation": { "Dry": 67, "Flooded": 33 },
|
||||||
"LakeSerene": { "Dry": 33, "Flooded": 67 },
|
"LakeSerene": { "Dry": 33, "Flooded": 67 },
|
||||||
|
"LakeSereneBridge": { "Dry": 67, "Flooded": 33 },
|
||||||
|
"Lab": { "Dry": 67, "Flooded": 33 },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -383,6 +396,11 @@ class Traps(OptionList):
|
||||||
default = [ "Meteor Sparrow Trap", "Poison Trap", "Chaos Trap", "Neurotoxin Trap", "Bee Trap" ]
|
default = [ "Meteor Sparrow Trap", "Poison Trap", "Chaos Trap", "Neurotoxin Trap", "Bee Trap" ]
|
||||||
|
|
||||||
|
|
||||||
|
class PresentAccessWithWheelAndSpindle(Toggle):
|
||||||
|
"""When inverted, allows using the refugee camp warp when both the Timespinner Wheel and Spindle is acquired."""
|
||||||
|
display_name = "Past Wheel & Spindle Warp"
|
||||||
|
|
||||||
|
|
||||||
# Some options that are available in the timespinner randomizer arent currently implemented
|
# Some options that are available in the timespinner randomizer arent currently implemented
|
||||||
timespinner_options: Dict[str, Option] = {
|
timespinner_options: Dict[str, Option] = {
|
||||||
"StartWithJewelryBox": StartWithJewelryBox,
|
"StartWithJewelryBox": StartWithJewelryBox,
|
||||||
|
@ -396,7 +414,7 @@ timespinner_options: Dict[str, Option] = {
|
||||||
"Cantoran": Cantoran,
|
"Cantoran": Cantoran,
|
||||||
"LoreChecks": LoreChecks,
|
"LoreChecks": LoreChecks,
|
||||||
"BossRando": BossRando,
|
"BossRando": BossRando,
|
||||||
"BossScaling": BossScaling,
|
"EnemyRando": EnemyRando,
|
||||||
"DamageRando": DamageRando,
|
"DamageRando": DamageRando,
|
||||||
"DamageRandoOverrides": DamageRandoOverrides,
|
"DamageRandoOverrides": DamageRandoOverrides,
|
||||||
"HpCap": HpCap,
|
"HpCap": HpCap,
|
||||||
|
@ -419,6 +437,7 @@ timespinner_options: Dict[str, Option] = {
|
||||||
"UnchainedKeys": UnchainedKeys,
|
"UnchainedKeys": UnchainedKeys,
|
||||||
"TrapChance": TrapChance,
|
"TrapChance": TrapChance,
|
||||||
"Traps": Traps,
|
"Traps": Traps,
|
||||||
|
"PresentAccessWithWheelAndSpindle": PresentAccessWithWheelAndSpindle,
|
||||||
"DeathLink": DeathLink,
|
"DeathLink": DeathLink,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from typing import Tuple, Dict, Union
|
from typing import Tuple, Dict, Union, List
|
||||||
from BaseClasses import MultiWorld
|
from BaseClasses import MultiWorld
|
||||||
from .Options import timespinner_options, is_option_enabled, get_option_value
|
from .Options import timespinner_options, is_option_enabled, get_option_value
|
||||||
|
|
||||||
|
@ -17,7 +17,9 @@ class PreCalculatedWeights:
|
||||||
flood_moat: bool
|
flood_moat: bool
|
||||||
flood_courtyard: bool
|
flood_courtyard: bool
|
||||||
flood_lake_desolation: bool
|
flood_lake_desolation: bool
|
||||||
dry_lake_serene: bool
|
flood_lake_serene: bool
|
||||||
|
flood_lake_serene_bridge: bool
|
||||||
|
flood_lab: bool
|
||||||
|
|
||||||
def __init__(self, world: MultiWorld, player: int):
|
def __init__(self, world: MultiWorld, player: int):
|
||||||
if world and is_option_enabled(world, player, "RisingTides"):
|
if world and is_option_enabled(world, player, "RisingTides"):
|
||||||
|
@ -32,8 +34,9 @@ class PreCalculatedWeights:
|
||||||
self.flood_moat, _ = self.roll_flood_setting(world, player, weights_overrrides, "CastleMoat")
|
self.flood_moat, _ = self.roll_flood_setting(world, player, weights_overrrides, "CastleMoat")
|
||||||
self.flood_courtyard, _ = self.roll_flood_setting(world, player, weights_overrrides, "CastleCourtyard")
|
self.flood_courtyard, _ = self.roll_flood_setting(world, player, weights_overrrides, "CastleCourtyard")
|
||||||
self.flood_lake_desolation, _ = self.roll_flood_setting(world, player, weights_overrrides, "LakeDesolation")
|
self.flood_lake_desolation, _ = self.roll_flood_setting(world, player, weights_overrrides, "LakeDesolation")
|
||||||
flood_lake_serene, _ = self.roll_flood_setting(world, player, weights_overrrides, "LakeSerene")
|
self.flood_lake_serene, _ = self.roll_flood_setting(world, player, weights_overrrides, "LakeSerene")
|
||||||
self.dry_lake_serene = not flood_lake_serene
|
self.flood_lake_serene_bridge, _ = self.roll_flood_setting(world, player, weights_overrrides, "LakeSereneBridge")
|
||||||
|
self.flood_lab, _ = self.roll_flood_setting(world, player, weights_overrrides, "Lab")
|
||||||
else:
|
else:
|
||||||
self.flood_basement = False
|
self.flood_basement = False
|
||||||
self.flood_basement_high = False
|
self.flood_basement_high = False
|
||||||
|
@ -44,30 +47,32 @@ class PreCalculatedWeights:
|
||||||
self.flood_moat = False
|
self.flood_moat = False
|
||||||
self.flood_courtyard = False
|
self.flood_courtyard = False
|
||||||
self.flood_lake_desolation = False
|
self.flood_lake_desolation = False
|
||||||
self.dry_lake_serene = False
|
self.flood_lake_serene = True
|
||||||
|
self.flood_lake_serene_bridge = False
|
||||||
|
self.flood_lab = False
|
||||||
|
|
||||||
self.pyramid_keys_unlock, self.present_key_unlock, self.past_key_unlock, self.time_key_unlock = \
|
self.pyramid_keys_unlock, self.present_key_unlock, self.past_key_unlock, self.time_key_unlock = \
|
||||||
self.get_pyramid_keys_unlocks(world, player, self.flood_maw)
|
self.get_pyramid_keys_unlocks(world, player, self.flood_maw, self.flood_xarion)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_pyramid_keys_unlocks(world: MultiWorld, player: int, is_maw_flooded: bool) -> Tuple[str, str, str, str]:
|
def get_pyramid_keys_unlocks(world: MultiWorld, player: int, is_maw_flooded: bool, is_xarion_flooded: bool) -> Tuple[str, str, str, str]:
|
||||||
present_teleportation_gates: Tuple[str, ...] = (
|
present_teleportation_gates: List[str] = [
|
||||||
"GateKittyBoss",
|
"GateKittyBoss",
|
||||||
"GateLeftLibrary",
|
"GateLeftLibrary",
|
||||||
"GateMilitaryGate",
|
"GateMilitaryGate",
|
||||||
"GateSealedCaves",
|
"GateSealedCaves",
|
||||||
"GateSealedSirensCave",
|
"GateSealedSirensCave",
|
||||||
"GateLakeDesolation"
|
"GateLakeDesolation"
|
||||||
)
|
]
|
||||||
|
|
||||||
past_teleportation_gates: Tuple[str, ...] = (
|
past_teleportation_gates: List[str] = [
|
||||||
"GateLakeSereneRight",
|
"GateLakeSereneRight",
|
||||||
"GateAccessToPast",
|
"GateAccessToPast",
|
||||||
"GateCastleRamparts",
|
"GateCastleRamparts",
|
||||||
"GateCastleKeep",
|
"GateCastleKeep",
|
||||||
"GateRoyalTowers",
|
"GateRoyalTowers",
|
||||||
"GateCavesOfBanishment"
|
"GateCavesOfBanishment"
|
||||||
)
|
]
|
||||||
|
|
||||||
ancient_pyramid_teleportation_gates: Tuple[str, ...] = (
|
ancient_pyramid_teleportation_gates: Tuple[str, ...] = (
|
||||||
"GateGyre",
|
"GateGyre",
|
||||||
|
@ -84,7 +89,10 @@ class PreCalculatedWeights:
|
||||||
)
|
)
|
||||||
|
|
||||||
if not is_maw_flooded:
|
if not is_maw_flooded:
|
||||||
past_teleportation_gates += ("GateMaw", )
|
past_teleportation_gates.append("GateMaw")
|
||||||
|
|
||||||
|
if not is_xarion_flooded:
|
||||||
|
present_teleportation_gates.append("GateXarion")
|
||||||
|
|
||||||
if is_option_enabled(world, player, "Inverted"):
|
if is_option_enabled(world, player, "Inverted"):
|
||||||
all_gates: Tuple[str, ...] = present_teleportation_gates
|
all_gates: Tuple[str, ...] = present_teleportation_gates
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from typing import List, Set, Dict, Tuple, Optional, Callable
|
from typing import List, Set, Dict, 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, get_location_datas
|
from .Locations import LocationData, get_location_datas
|
||||||
|
@ -7,9 +7,8 @@ from .LogicExtensions import TimespinnerLogic
|
||||||
|
|
||||||
|
|
||||||
def create_regions_and_locations(world: MultiWorld, player: int, precalculated_weights: PreCalculatedWeights):
|
def create_regions_and_locations(world: MultiWorld, player: int, precalculated_weights: PreCalculatedWeights):
|
||||||
locationn_datas: Tuple[LocationData] = get_location_datas(world, player, precalculated_weights)
|
locations_per_region: Dict[str, List[LocationData]] = split_location_datas_per_region(
|
||||||
|
get_location_datas(world, player, precalculated_weights))
|
||||||
locations_per_region: Dict[str, List[LocationData]] = split_location_datas_per_region(locationn_datas)
|
|
||||||
|
|
||||||
regions = [
|
regions = [
|
||||||
create_region(world, player, locations_per_region, 'Menu'),
|
create_region(world, player, locations_per_region, 'Menu'),
|
||||||
|
@ -32,7 +31,6 @@ def create_regions_and_locations(world: MultiWorld, player: int, precalculated_w
|
||||||
create_region(world, player, locations_per_region, 'The lab (upper)'),
|
create_region(world, player, locations_per_region, 'The lab (upper)'),
|
||||||
create_region(world, player, locations_per_region, 'Emperors tower'),
|
create_region(world, player, locations_per_region, 'Emperors tower'),
|
||||||
create_region(world, player, locations_per_region, 'Skeleton Shaft'),
|
create_region(world, player, locations_per_region, 'Skeleton Shaft'),
|
||||||
create_region(world, player, locations_per_region, 'Sealed Caves (upper)'),
|
|
||||||
create_region(world, player, locations_per_region, 'Sealed Caves (Xarion)'),
|
create_region(world, player, locations_per_region, 'Sealed Caves (Xarion)'),
|
||||||
create_region(world, player, locations_per_region, 'Refugee Camp'),
|
create_region(world, player, locations_per_region, 'Refugee Camp'),
|
||||||
create_region(world, player, locations_per_region, 'Forest'),
|
create_region(world, player, locations_per_region, 'Forest'),
|
||||||
|
@ -63,7 +61,7 @@ def create_regions_and_locations(world: MultiWorld, player: int, precalculated_w
|
||||||
|
|
||||||
if __debug__:
|
if __debug__:
|
||||||
throwIfAnyLocationIsNotAssignedToARegion(regions, locations_per_region.keys())
|
throwIfAnyLocationIsNotAssignedToARegion(regions, locations_per_region.keys())
|
||||||
|
|
||||||
world.regions += regions
|
world.regions += regions
|
||||||
|
|
||||||
connectStartingRegion(world, player)
|
connectStartingRegion(world, player)
|
||||||
|
@ -71,9 +69,9 @@ def create_regions_and_locations(world: MultiWorld, player: int, precalculated_w
|
||||||
flooded: PreCalculatedWeights = precalculated_weights
|
flooded: PreCalculatedWeights = precalculated_weights
|
||||||
logic = TimespinnerLogic(world, player, precalculated_weights)
|
logic = TimespinnerLogic(world, player, precalculated_weights)
|
||||||
|
|
||||||
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, 'Lake desolation', 'Lower lake desolation', lambda state: flooded.flood_lake_desolation or logic.has_timestop(state) or state.has('Talaria Attachment', 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, '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', 'Skeleton Shaft', lambda state: logic.has_doublejump(state) or flooded.flood_lake_desolation)
|
connect(world, player, 'Lake desolation', 'Skeleton Shaft', lambda state: flooded.flood_lake_desolation or logic.has_doublejump(state))
|
||||||
connect(world, player, 'Lake desolation', 'Space time continuum', logic.has_teleport)
|
connect(world, player, 'Lake desolation', 'Space time continuum', logic.has_teleport)
|
||||||
connect(world, player, 'Upper lake desolation', 'Lake desolation')
|
connect(world, player, 'Upper lake desolation', 'Lake desolation')
|
||||||
connect(world, player, 'Upper lake desolation', 'Eastern lake desolation')
|
connect(world, player, 'Upper lake desolation', 'Eastern lake desolation')
|
||||||
|
@ -109,40 +107,38 @@ def create_regions_and_locations(world: MultiWorld, player: int, precalculated_w
|
||||||
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))
|
||||||
connect(world, player, 'Military Fortress', 'Military Fortress (hangar)', logic.has_doublejump)
|
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)', 'Military Fortress')
|
||||||
connect(world, player, '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 (state.has('Water Mask', player) if flooded.flood_lab else logic.has_doublejump(state)))
|
||||||
connect(world, player, 'Temporal Gyre', 'Military Fortress')
|
connect(world, player, 'Temporal Gyre', 'Military Fortress')
|
||||||
connect(world, player, 'The lab', '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)', logic.has_doublejump_of_npc)
|
||||||
connect(world, player, 'The lab (power off)', 'The lab')
|
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)', logic.has_forwarddash_doublejump)
|
||||||
connect(world, player, 'The lab (upper)', 'The lab (power off)')
|
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)', '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))
|
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, 'Emperors tower', 'The lab (upper)')
|
connect(world, player, 'Emperors tower', 'The lab (upper)')
|
||||||
connect(world, player, 'Skeleton Shaft', 'Lake desolation')
|
connect(world, player, 'Skeleton Shaft', 'Lake desolation')
|
||||||
connect(world, player, 'Skeleton Shaft', 'Sealed Caves (upper)', logic.has_keycard_A)
|
connect(world, player, 'Skeleton Shaft', 'Sealed Caves (Xarion)', logic.has_keycard_A)
|
||||||
connect(world, player, 'Skeleton Shaft', 'Space time continuum', logic.has_teleport)
|
connect(world, player, 'Skeleton Shaft', 'Space time continuum', logic.has_teleport)
|
||||||
connect(world, player, 'Sealed Caves (upper)', 'Skeleton Shaft')
|
connect(world, player, 'Sealed Caves (Xarion)', 'Skeleton Shaft')
|
||||||
connect(world, player, 'Sealed Caves (upper)', 'Sealed Caves (Xarion)', lambda state: logic.has_teleport(state) or logic.has_doublejump(state))
|
|
||||||
connect(world, player, 'Sealed Caves (Xarion)', 'Sealed Caves (upper)', logic.has_doublejump)
|
|
||||||
connect(world, player, 'Sealed Caves (Xarion)', 'Space time continuum', logic.has_teleport)
|
connect(world, player, 'Sealed Caves (Xarion)', 'Space time continuum', logic.has_teleport)
|
||||||
connect(world, player, 'Refugee Camp', 'Forest')
|
connect(world, player, 'Refugee Camp', 'Forest')
|
||||||
#connect(world, player, 'Refugee Camp', 'Library', lambda state: not is_option_enabled(world, player, "Inverted"))
|
connect(world, player, 'Refugee Camp', 'Library', lambda state: is_option_enabled(world, player, "Inverted") and is_option_enabled(world, player, "PresentAccessWithWheelAndSpindle") and state.has_all({'Timespinner Wheel', 'Timespinner Spindle'}, player))
|
||||||
connect(world, player, 'Refugee Camp', 'Space time continuum', logic.has_teleport)
|
connect(world, player, 'Refugee Camp', 'Space time continuum', logic.has_teleport)
|
||||||
connect(world, player, 'Forest', 'Refugee Camp')
|
connect(world, player, 'Forest', 'Refugee Camp')
|
||||||
connect(world, player, '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: 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', 'Caves of Banishment (Sirens)')
|
||||||
connect(world, player, 'Forest', 'Castle Ramparts')
|
connect(world, player, 'Forest', 'Castle Ramparts')
|
||||||
connect(world, player, 'Left Side forest Caves', 'Forest')
|
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', 'Upper Lake Serene', logic.has_timestop)
|
||||||
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, 'Left Side forest Caves', 'Lower Lake Serene', lambda state: not flooded.flood_lake_serene or state.has('Water Mask', player))
|
||||||
connect(world, player, '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, 'Upper Lake Serene', 'Left Side forest Caves')
|
connect(world, player, 'Upper Lake Serene', 'Left Side forest Caves')
|
||||||
connect(world, player, 'Upper Lake Serene', 'Lower Lake Serene', lambda state: state.has('Water Mask', player) or flooded.dry_lake_serene)
|
connect(world, player, 'Upper Lake Serene', 'Lower Lake Serene', lambda state: not flooded.flood_lake_serene or state.has('Water Mask', player))
|
||||||
connect(world, player, 'Lower Lake Serene', 'Upper Lake Serene')
|
connect(world, player, 'Lower Lake Serene', 'Upper Lake Serene')
|
||||||
connect(world, player, 'Lower Lake Serene', 'Left Side forest Caves')
|
connect(world, player, 'Lower Lake Serene', 'Left Side forest Caves')
|
||||||
connect(world, player, 'Lower Lake Serene', 'Caves of Banishment (upper)', lambda state: not flooded.dry_lake_serene or logic.has_doublejump(state))
|
connect(world, player, 'Lower Lake Serene', 'Caves of Banishment (upper)', lambda state: flooded.flood_lake_serene or logic.has_doublejump(state))
|
||||||
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, 'Caves of Banishment (upper)', 'Lower Lake Serene', lambda state: not flooded.flood_lake_serene or state.has('Water Mask', player))
|
||||||
connect(world, player, 'Caves of Banishment (upper)', 'Caves of Banishment (Maw)', lambda state: logic.has_doublejump(state) or state.has_any({'Gas Mask', 'Talaria Attachment'} or logic.has_teleport(state), player))
|
connect(world, player, 'Caves of Banishment (upper)', 'Caves of Banishment (Maw)', lambda state: logic.has_doublejump(state) or state.has_any({'Gas Mask', 'Talaria Attachment'} or logic.has_teleport(state), player))
|
||||||
connect(world, player, '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, '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))
|
||||||
|
@ -153,7 +149,7 @@ def create_regions_and_locations(world: MultiWorld, player: int, precalculated_w
|
||||||
connect(world, player, 'Castle Ramparts', 'Castle Keep')
|
connect(world, player, 'Castle Ramparts', 'Castle Keep')
|
||||||
connect(world, player, 'Castle Ramparts', 'Space time continuum', logic.has_teleport)
|
connect(world, player, 'Castle Ramparts', 'Space time continuum', logic.has_teleport)
|
||||||
connect(world, player, 'Castle Keep', 'Castle Ramparts')
|
connect(world, player, 'Castle Keep', 'Castle Ramparts')
|
||||||
connect(world, player, '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: 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)', logic.has_doublejump)
|
||||||
connect(world, player, 'Castle Keep', 'Space time continuum', logic.has_teleport)
|
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)', 'Castle Keep')
|
||||||
|
@ -165,14 +161,15 @@ def create_regions_and_locations(world: MultiWorld, player: int, precalculated_w
|
||||||
#connect(world, player, '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, 'Ancient Pyramid (entrance)', 'Ancient Pyramid (left)', logic.has_doublejump)
|
connect(world, player, 'Ancient Pyramid (entrance)', 'Ancient Pyramid (left)', logic.has_doublejump)
|
||||||
connect(world, player, 'Ancient Pyramid (left)', 'Ancient Pyramid (entrance)')
|
connect(world, player, 'Ancient Pyramid (left)', 'Ancient Pyramid (entrance)')
|
||||||
connect(world, player, '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: flooded.flood_pyramid_shaft or logic.has_upwarddash(state))
|
||||||
connect(world, player, '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: flooded.flood_pyramid_shaft or logic.has_upwarddash(state))
|
||||||
connect(world, player, '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, '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, '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, '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, '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, '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, 'Space time continuum', 'Sealed Caves (Xarion)', lambda state: logic.can_teleport_to(state, "Present", "GateXarion"))
|
||||||
connect(world, player, '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, '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, '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"))
|
||||||
|
@ -204,12 +201,13 @@ def throwIfAnyLocationIsNotAssignedToARegion(regions: List[Region], regionNames:
|
||||||
|
|
||||||
def create_location(player: int, location_data: LocationData, region: Region) -> 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
|
|
||||||
|
if location_data.rule:
|
||||||
|
location.access_rule = location_data.rule
|
||||||
|
|
||||||
if id is None:
|
if id is None:
|
||||||
location.event = True
|
location.event = True
|
||||||
location.locked = True
|
location.locked = True
|
||||||
|
|
||||||
return location
|
return location
|
||||||
|
|
||||||
|
|
||||||
|
@ -220,7 +218,6 @@ def create_region(world: MultiWorld, player: int, locations_per_region: Dict[str
|
||||||
for location_data in locations_per_region[name]:
|
for location_data in locations_per_region[name]:
|
||||||
location = create_location(player, location_data, region)
|
location = create_location(player, location_data, region)
|
||||||
region.locations.append(location)
|
region.locations.append(location)
|
||||||
|
|
||||||
return region
|
return region
|
||||||
|
|
||||||
|
|
||||||
|
@ -237,11 +234,9 @@ def connectStartingRegion(world: MultiWorld, player: int):
|
||||||
menu_to_tutorial = Entrance(player, 'Tutorial', menu)
|
menu_to_tutorial = Entrance(player, 'Tutorial', menu)
|
||||||
menu_to_tutorial.connect(tutorial)
|
menu_to_tutorial.connect(tutorial)
|
||||||
menu.exits.append(menu_to_tutorial)
|
menu.exits.append(menu_to_tutorial)
|
||||||
|
|
||||||
tutorial_to_start = Entrance(player, 'Start Game', tutorial)
|
tutorial_to_start = Entrance(player, 'Start Game', tutorial)
|
||||||
tutorial_to_start.connect(starting_region)
|
tutorial_to_start.connect(starting_region)
|
||||||
tutorial.exits.append(tutorial_to_start)
|
tutorial.exits.append(tutorial_to_start)
|
||||||
|
|
||||||
teleport_back_to_start = Entrance(player, 'Teleport back to start', space_time_continuum)
|
teleport_back_to_start = Entrance(player, 'Teleport back to start', space_time_continuum)
|
||||||
teleport_back_to_start.connect(starting_region)
|
teleport_back_to_start.connect(starting_region)
|
||||||
space_time_continuum.exits.append(teleport_back_to_start)
|
space_time_continuum.exits.append(teleport_back_to_start)
|
||||||
|
@ -249,7 +244,7 @@ def connectStartingRegion(world: MultiWorld, player: int):
|
||||||
|
|
||||||
def connect(world: MultiWorld, player: 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)
|
||||||
|
|
||||||
|
@ -257,15 +252,13 @@ def connect(world: MultiWorld, player: int, source: str, target: str,
|
||||||
|
|
||||||
if rule:
|
if rule:
|
||||||
connection.access_rule = rule
|
connection.access_rule = rule
|
||||||
|
|
||||||
sourceRegion.exits.append(connection)
|
sourceRegion.exits.append(connection)
|
||||||
connection.connect(targetRegion)
|
connection.connect(targetRegion)
|
||||||
|
|
||||||
|
|
||||||
def split_location_datas_per_region(locations: Tuple[LocationData, ...]) -> Dict[str, List[LocationData]]:
|
def split_location_datas_per_region(locations: List[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:
|
||||||
per_region.setdefault(location.region, []).append(location)
|
per_region.setdefault(location.region, []).append(location)
|
||||||
|
return per_region
|
||||||
return per_region
|
|
|
@ -39,9 +39,9 @@ class TimespinnerWorld(World):
|
||||||
option_definitions = timespinner_options
|
option_definitions = timespinner_options
|
||||||
game = "Timespinner"
|
game = "Timespinner"
|
||||||
topology_present = True
|
topology_present = True
|
||||||
data_version = 11
|
data_version = 12
|
||||||
web = TimespinnerWebWorld()
|
web = TimespinnerWebWorld()
|
||||||
required_client_version = (0, 3, 7)
|
required_client_version = (0, 4, 2)
|
||||||
|
|
||||||
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_location_datas(None, None, None)}
|
location_name_to_id = {location.name: location.code for location in get_location_datas(None, None, None)}
|
||||||
|
@ -108,7 +108,9 @@ class TimespinnerWorld(World):
|
||||||
slot_data["CastleMoat"] = self.precalculated_weights.flood_moat
|
slot_data["CastleMoat"] = self.precalculated_weights.flood_moat
|
||||||
slot_data["CastleCourtyard"] = self.precalculated_weights.flood_courtyard
|
slot_data["CastleCourtyard"] = self.precalculated_weights.flood_courtyard
|
||||||
slot_data["LakeDesolation"] = self.precalculated_weights.flood_lake_desolation
|
slot_data["LakeDesolation"] = self.precalculated_weights.flood_lake_desolation
|
||||||
slot_data["DryLakeSerene"] = self.precalculated_weights.dry_lake_serene
|
slot_data["DryLakeSerene"] = not self.precalculated_weights.flood_lake_serene
|
||||||
|
slot_data["LakeSereneBridge"] = self.precalculated_weights.flood_lake_serene_bridge
|
||||||
|
slot_data["Lab"] = self.precalculated_weights.flood_lab
|
||||||
|
|
||||||
return slot_data
|
return slot_data
|
||||||
|
|
||||||
|
@ -144,8 +146,12 @@ class TimespinnerWorld(World):
|
||||||
flooded_areas.append("Castle Courtyard")
|
flooded_areas.append("Castle Courtyard")
|
||||||
if self.precalculated_weights.flood_lake_desolation:
|
if self.precalculated_weights.flood_lake_desolation:
|
||||||
flooded_areas.append("Lake Desolation")
|
flooded_areas.append("Lake Desolation")
|
||||||
if not self.precalculated_weights.dry_lake_serene:
|
if self.precalculated_weights.flood_lake_serene:
|
||||||
flooded_areas.append("Lake Serene")
|
flooded_areas.append("Lake Serene")
|
||||||
|
if self.precalculated_weights.flood_lake_serene_bridge:
|
||||||
|
flooded_areas.append("Lake Serene Bridge")
|
||||||
|
if self.precalculated_weights.flood_lab:
|
||||||
|
flooded_areas.append("Lab")
|
||||||
|
|
||||||
if len(flooded_areas) == 0:
|
if len(flooded_areas) == 0:
|
||||||
flooded_areas_string: str = "None"
|
flooded_areas_string: str = "None"
|
||||||
|
@ -220,15 +226,18 @@ class TimespinnerWorld(World):
|
||||||
|
|
||||||
def assign_starter_items(self, excluded_items: Set[str]) -> None:
|
def assign_starter_items(self, excluded_items: Set[str]) -> None:
|
||||||
non_local_items: Set[str] = self.multiworld.non_local_items[self.player].value
|
non_local_items: Set[str] = self.multiworld.non_local_items[self.player].value
|
||||||
|
local_items: Set[str] = self.multiworld.local_items[self.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 in local_items or not item in non_local_items)
|
||||||
if not local_starter_melee_weapons:
|
if not local_starter_melee_weapons:
|
||||||
if 'Plasma Orb' in non_local_items:
|
if 'Plasma Orb' in non_local_items:
|
||||||
raise Exception("Atleast one melee orb must be local")
|
raise Exception("Atleast one melee orb must be local")
|
||||||
else:
|
else:
|
||||||
local_starter_melee_weapons = ('Plasma Orb',)
|
local_starter_melee_weapons = ('Plasma Orb',)
|
||||||
|
|
||||||
local_starter_spells = tuple(item for item in starter_spells if item not in non_local_items)
|
local_starter_spells = tuple(item for item in starter_spells if
|
||||||
|
item in local_items or not item in non_local_items)
|
||||||
if not local_starter_spells:
|
if not local_starter_spells:
|
||||||
if 'Lightwall' in non_local_items:
|
if 'Lightwall' in non_local_items:
|
||||||
raise Exception("Atleast one spell must be local")
|
raise Exception("Atleast one spell must be local")
|
||||||
|
|
Loading…
Reference in New Issue