Skip to content

Timespinner: New options from TS Rando v1.25 + Logic fix #2090

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 49 commits into from
Nov 22, 2023
Merged
Show file tree
Hide file tree
Changes from 32 commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
6f74ca6
Flooded logic fixes
Jarno458 Jun 28, 2023
fb34202
Fixed some flood logic + added spindle+wheel wrap option from past to…
Jarno458 Jun 28, 2023
aef8def
Lots of things
Jarno458 Jun 29, 2023
34a2973
Added new options + logic
Jarno458 Jul 13, 2023
573c51a
Updated minimal version
Jarno458 Jul 16, 2023
b99c3ca
Fixed some lake serene flooding
Jarno458 Jul 22, 2023
b76b8ff
Merge branch 'ArchipelagoMW:main' into ts_updates_mid_2023
Jarno458 Aug 7, 2023
91bdad7
Merge branch 'main' into ts_updates_mid_2023
Jarno458 Aug 14, 2023
6d0f502
Merge branch 'main' into ts_updates_mid_2023
Jarno458 Aug 17, 2023
7d4e547
Merge branch 'main' into ts_updates_mid_2023
Jarno458 Sep 3, 2023
f3d14f4
Merge branch 'main' into ts_updates_mid_2023
Jarno458 Sep 15, 2023
1286553
Merge branch 'main' into ts_updates_mid_2023
Jarno458 Sep 20, 2023
592c608
Slightly optimized lambda methods
Jarno458 Sep 24, 2023
4d6d20d
Merge branch 'main' into ts_updates_mid_2023
Jarno458 Sep 24, 2023
e892928
Merge branch 'main' into ts_updates_mid_2023
Jarno458 Oct 1, 2023
0a6bae6
Merge branch 'main' into ts_updates_mid_2023
Jarno458 Oct 2, 2023
758585f
Merge branch 'main' into ts_updates_mid_2023
Jarno458 Oct 2, 2023
a879700
Merge branch 'main' into ts_updates_mid_2023
Jarno458 Oct 7, 2023
3755930
Merge branch 'main' into ts_updates_mid_2023
Jarno458 Oct 8, 2023
1ea5ba4
Merge branch 'main' into ts_updates_mid_2023
Jarno458 Oct 10, 2023
8468c08
Merge branch 'main' into ts_updates_mid_2023
Jarno458 Oct 11, 2023
4277ac1
Merge branch 'main' into ts_updates_mid_2023
Jarno458 Oct 14, 2023
863f218
Merge branch 'main' into ts_updates_mid_2023
Jarno458 Oct 20, 2023
783cb37
Merge branch 'main' into ts_updates_mid_2023
Jarno458 Oct 23, 2023
4cff31f
Improve performance of Timespinner create_regions
Jarno458 Oct 25, 2023
c0292d7
perf_gen_fails
Jarno458 Oct 26, 2023
5408b62
Removed hardcoded seed
Jarno458 Oct 26, 2023
437a99e
Fixed generation error caused by new options system
Jarno458 Oct 26, 2023
6024441
Reverted unintentional change
Jarno458 Oct 26, 2023
31580d2
Merge remote-tracking branch 'remotes/origin/ts_perf' into ts_updates…
Jarno458 Oct 26, 2023
30bd182
Reapplied correct regions after merge
Jarno458 Oct 26, 2023
7af9d23
Merge branch 'ts_new_options_fix' into ts_updates_mid_2023
Jarno458 Oct 26, 2023
7aa1b52
Merge branch 'main' into ts_perf
Jarno458 Oct 31, 2023
048604f
Update worlds/timespinner/Regions.py
Jarno458 Oct 31, 2023
d903f51
Merge branch 'main' into ts_updates_mid_2023
Jarno458 Oct 31, 2023
74f2377
Merge branch 'main' into ts_perf
Jarno458 Oct 31, 2023
a0f5912
Merge branch 'main' into ts_updates_mid_2023
Jarno458 Nov 1, 2023
13b2a39
Fixed logic error
Jarno458 Nov 1, 2023
e179e75
Merge remote-tracking branch 'remotes/origin/ts_perf' into ts_updates…
Jarno458 Nov 1, 2023
4968a52
Reverted back to world region lookups as it seems to make to god dann…
Jarno458 Nov 1, 2023
8eed3c8
Merge remote-tracking branch 'remotes/origin/ts_perf' into ts_updates…
Jarno458 Nov 1, 2023
c2c1756
Merge branch 'main' into ts_updates_mid_2023
Jarno458 Nov 2, 2023
c0b436b
Fixed logic bug
Jarno458 Nov 2, 2023
65b141e
Merge branch 'main' into ts_updates_mid_2023
Jarno458 Nov 2, 2023
16fedf6
Merge branch 'main' into ts_updates_mid_2023
Jarno458 Nov 5, 2023
2283a60
Merge branch 'main' into ts_updates_mid_2023
Jarno458 Nov 7, 2023
100b741
Merge branch 'main' into ts_updates_mid_2023
Jarno458 Nov 17, 2023
ea92c03
Allow local_items items to take precedence non_local_items
Jarno458 Nov 18, 2023
6de083c
Merge branch 'main' into ts_updates_mid_2023
Jarno458 Nov 22, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 11 additions & 11 deletions worlds/timespinner/Locations.py
Original file line number Diff line number Diff line change
@@ -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 .Options import is_option_enabled
from .PreCalculatedWeights import PreCalculatedWeights
Expand All @@ -11,11 +11,11 @@ class LocationData(NamedTuple):
region: str
name: str
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],
precalculated_weights: PreCalculatedWeights) -> Tuple[LocationData, ...]:
precalculated_weights: PreCalculatedWeights) -> List[LocationData]:

flooded: PreCalculatedWeights = precalculated_weights
logic = TimespinnerLogic(world, player, precalculated_weights)
Expand Down Expand Up @@ -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: Giantess room', 1337061),
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 1', 1337064, lambda state: logic.has_doublejump(state) and logic.has_keycard_B(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: 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_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: 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),
Expand Down Expand Up @@ -139,10 +139,10 @@ 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): 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): 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): Underwater pedestal', 1337111, lambda state: not flooded.dry_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('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: 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): 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),
Expand Down Expand Up @@ -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 (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: 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)', '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)))
]
Expand Down Expand Up @@ -271,4 +271,4 @@ def get_location_datas(world: Optional[MultiWorld], player: Optional[int],
LocationData('Ifrit\'s Lair', 'Ifrit: Post fight (chest)', 1337245),
)

return tuple(location_table)
return location_table
35 changes: 27 additions & 8 deletions worlds/timespinner/Options.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,23 @@ class LoreChecks(Toggle):
display_name = "Lore Checks"


class BossRando(Toggle):
"Shuffles the positions of all bosses."
class BossRando(Choice):
"Wheter all boss locations are shuffled, and if their damage/hp should be scaled."
display_name = "Boss Randomization"
option_off = 0
option_scaled = 1
option_unscaled = 2
alias_true = 1


class BossScaling(DefaultOnToggle):
"When Boss Rando is enabled, scales the bosses' HP, XP, and ATK to the stats of the location they replace (Recommended)"
display_name = "Scale Random Boss Stats"
class EnemyRando(Choice):
"Wheter enemies will be randomized, and if their damage/hp should be scaled."
display_name = "Enemy Randomization"
option_off = 0
option_scaled = 1
option_unscaled = 2
option_ryshia = 3
alias_true = 1


class DamageRando(Choice):
Expand Down Expand Up @@ -336,6 +345,7 @@ def rising_tide_option(location: str, with_save_point_option: bool = False) -> D
class RisingTidesOverrides(OptionDict):
"""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"""
display_name = "Rising Tides Overrides"
schema = Schema({
**rising_tide_option("Xarion"),
**rising_tide_option("Maw"),
Expand All @@ -345,9 +355,10 @@ class RisingTidesOverrides(OptionDict):
**rising_tide_option("CastleBasement", with_save_point_option=True),
**rising_tide_option("CastleCourtyard"),
**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 = {
"Xarion": { "Dry": 67, "Flooded": 33 },
"Maw": { "Dry": 67, "Flooded": 33 },
Expand All @@ -358,6 +369,8 @@ class RisingTidesOverrides(OptionDict):
"CastleCourtyard": { "Dry": 67, "Flooded": 33 },
"LakeDesolation": { "Dry": 67, "Flooded": 33 },
"LakeSerene": { "Dry": 33, "Flooded": 67 },
"LakeSereneBridge": { "Dry": 67, "Flooded": 33 },
"Lab": { "Dry": 67, "Flooded": 33 },
}


Expand All @@ -383,6 +396,11 @@ class Traps(OptionList):
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
timespinner_options: Dict[str, Option] = {
"StartWithJewelryBox": StartWithJewelryBox,
Expand All @@ -396,7 +414,7 @@ class Traps(OptionList):
"Cantoran": Cantoran,
"LoreChecks": LoreChecks,
"BossRando": BossRando,
"BossScaling": BossScaling,
"EnemyRando": EnemyRando,
"DamageRando": DamageRando,
"DamageRandoOverrides": DamageRandoOverrides,
"HpCap": HpCap,
Expand All @@ -419,6 +437,7 @@ class Traps(OptionList):
"UnchainedKeys": UnchainedKeys,
"TrapChance": TrapChance,
"Traps": Traps,
"PresentAccessWithWheelAndSpindle": PresentAccessWithWheelAndSpindle,
"DeathLink": DeathLink,
}

Expand Down
32 changes: 20 additions & 12 deletions worlds/timespinner/PreCalculatedWeights.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Tuple, Dict, Union
from typing import Tuple, Dict, Union, List
from BaseClasses import MultiWorld
from .Options import timespinner_options, is_option_enabled, get_option_value

Expand All @@ -17,7 +17,9 @@ class PreCalculatedWeights:
flood_moat: bool
flood_courtyard: 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):
if world and is_option_enabled(world, player, "RisingTides"):
Expand All @@ -32,8 +34,9 @@ def __init__(self, world: MultiWorld, player: int):
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_lake_desolation, _ = self.roll_flood_setting(world, player, weights_overrrides, "LakeDesolation")
flood_lake_serene, _ = self.roll_flood_setting(world, player, weights_overrrides, "LakeSerene")
self.dry_lake_serene = not flood_lake_serene
self.flood_lake_serene, _ = self.roll_flood_setting(world, player, weights_overrrides, "LakeSerene")
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:
self.flood_basement = False
self.flood_basement_high = False
Expand All @@ -44,30 +47,32 @@ def __init__(self, world: MultiWorld, player: int):
self.flood_moat = False
self.flood_courtyard = 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.get_pyramid_keys_unlocks(world, player, self.flood_maw)
self.get_pyramid_keys_unlocks(world, player, self.flood_maw, self.flood_xarion)

@staticmethod
def get_pyramid_keys_unlocks(world: MultiWorld, player: int, is_maw_flooded: bool) -> Tuple[str, str, str, str]:
present_teleportation_gates: Tuple[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: List[str] = [
"GateKittyBoss",
"GateLeftLibrary",
"GateMilitaryGate",
"GateSealedCaves",
"GateSealedSirensCave",
"GateLakeDesolation"
)
]

past_teleportation_gates: Tuple[str, ...] = (
past_teleportation_gates: List[str] = [
"GateLakeSereneRight",
"GateAccessToPast",
"GateCastleRamparts",
"GateCastleKeep",
"GateRoyalTowers",
"GateCavesOfBanishment"
)
]

ancient_pyramid_teleportation_gates: Tuple[str, ...] = (
"GateGyre",
Expand All @@ -84,7 +89,10 @@ def get_pyramid_keys_unlocks(world: MultiWorld, player: int, is_maw_flooded: boo
)

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"):
all_gates: Tuple[str, ...] = present_teleportation_gates
Expand Down
Loading