Just to be safe

This commit is contained in:
CookieCat
2023-08-29 14:30:59 -04:00
parent 6d9bfbcf36
commit 149a42b175
4 changed files with 359 additions and 468 deletions

View File

@@ -11,6 +11,7 @@ class LocData(NamedTuple):
required_hats: Optional[List[HatType]] = [HatType.NONE]
hookshot: Optional[bool] = False
dlc_flags: Optional[HatDLC] = HatDLC.none
paintings: Optional[int] = 0 # Paintings required for Subcon painting shuffle
# For UmbrellaLogic setting
umbrella: Optional[bool] = False # Umbrella required for this check
@@ -69,13 +70,17 @@ def is_location_valid(world: World, location: str) -> bool:
def get_location_names() -> Dict[str, int]:
names = {name: data.id for name, data in location_table.items()}
id_start: int = 300204
id_start: int = get_tasksanity_start_id()
for i in range(TasksanityCheckCount.range_end):
names.setdefault(format("Tasksanity Check %i") % (i+1), id_start+i)
return names
def get_tasksanity_start_id() -> int:
return 300204
ahit_locations = {
"Spaceship - Rumbi Abuse": LocData(301000, "Spaceship", dweller_bell=1),
@@ -166,66 +171,75 @@ ahit_locations = {
"Subcon Village - Graveyard Ice Cube": LocData(325077, "Subcon Forest Area"),
"Subcon Village - House Top": LocData(325471, "Subcon Forest Area"),
"Subcon Village - Ice Cube House": LocData(325469, "Subcon Forest Area"),
"Subcon Village - Snatcher Statue Chest": LocData(323730, "Subcon Forest Area"),
"Subcon Village - Snatcher Statue Chest": LocData(323730, "Subcon Forest Area", paintings=1),
"Subcon Village - Stump Platform Chest": LocData(323729, "Subcon Forest Area"),
"Subcon Forest - Giant Tree Climb": LocData(325470, "Subcon Forest Area"),
"Subcon Forest - Swamp Gravestone": LocData(326296, "Subcon Forest Area", required_hats=[HatType.BREWING],),
"Subcon Forest - Swamp Gravestone": LocData(326296, "Subcon Forest Area",
required_hats=[HatType.BREWING], paintings=1),
"Subcon Forest - Swamp Near Well": LocData(324762, "Subcon Forest Area"),
"Subcon Forest - Swamp Tree A": LocData(324763, "Subcon Forest Area"),
"Subcon Forest - Swamp Tree B": LocData(324764, "Subcon Forest Area"),
"Subcon Forest - Swamp Ice Wall": LocData(324706, "Subcon Forest Area"),
"Subcon Forest - Swamp Treehouse": LocData(325468, "Subcon Forest Area"),
"Subcon Forest - Swamp Tree Chest": LocData(323728, "Subcon Forest Area"),
"Subcon Forest - Swamp Near Well": LocData(324762, "Subcon Forest Area", paintings=1),
"Subcon Forest - Swamp Tree A": LocData(324763, "Subcon Forest Area", paintings=1),
"Subcon Forest - Swamp Tree B": LocData(324764, "Subcon Forest Area", paintings=1),
"Subcon Forest - Swamp Ice Wall": LocData(324706, "Subcon Forest Area", paintings=1),
"Subcon Forest - Swamp Treehouse": LocData(325468, "Subcon Forest Area", paintings=1),
"Subcon Forest - Swamp Tree Chest": LocData(323728, "Subcon Forest Area", paintings=1),
"Subcon Forest - Dweller Stump": LocData(324767, "Subcon Forest Area", required_hats=[HatType.DWELLER]),
"Subcon Forest - Dweller Stump": LocData(324767, "Subcon Forest Area",
required_hats=[HatType.DWELLER], paintings=3),
"Subcon Forest - Dweller Floating Rocks": LocData(324464, "Subcon Forest Area", required_hats=[HatType.DWELLER]),
"Subcon Forest - Dweller Floating Rocks": LocData(324464, "Subcon Forest Area",
required_hats=[HatType.DWELLER], paintings=3),
"Subcon Forest - Dweller Platforming Tree A": LocData(324709, "Subcon Forest Area"),
"Subcon Forest - Dweller Platforming Tree A": LocData(324709, "Subcon Forest Area", paintings=3),
"Subcon Forest - Dweller Platforming Tree B": LocData(324855, "Subcon Forest Area", required_hats=[HatType.DWELLER]),
"Subcon Forest - Dweller Platforming Tree B": LocData(324855, "Subcon Forest Area",
required_hats=[HatType.DWELLER], paintings=3),
"Subcon Forest - Giant Time Piece": LocData(325473, "Subcon Forest Area"),
"Subcon Forest - Gallows": LocData(325472, "Subcon Forest Area"),
"Subcon Forest - Giant Time Piece": LocData(325473, "Subcon Forest Area", paintings=3),
"Subcon Forest - Gallows": LocData(325472, "Subcon Forest Area", paintings=3),
"Subcon Forest - Green and Purple Dweller Rocks": LocData(325082, "Subcon Forest Area"),
"Subcon Forest - Green and Purple Dweller Rocks": LocData(325082, "Subcon Forest Area", paintings=3),
"Subcon Forest - Dweller Shack": LocData(324463, "Subcon Forest Area", required_hats=[HatType.DWELLER]),
"Subcon Forest - Dweller Shack": LocData(324463, "Subcon Forest Area",
required_hats=[HatType.DWELLER], paintings=3),
"Subcon Forest - Tall Tree Hookshot Swing": LocData(324766, "Subcon Forest Area",
required_hats=[HatType.DWELLER],
hookshot=True),
hookshot=True,
paintings=3),
"Subcon Forest - Burning House": LocData(324710, "Subcon Forest Area"),
"Subcon Forest - Burning Tree Climb": LocData(325079, "Subcon Forest Area"),
"Subcon Forest - Burning Stump Chest": LocData(323731, "Subcon Forest Area"),
"Subcon Forest - Burning Forest Treehouse": LocData(325467, "Subcon Forest Area"),
"Subcon Forest - Spider Bone Cage A": LocData(324462, "Subcon Forest Area"),
"Subcon Forest - Spider Bone Cage B": LocData(325080, "Subcon Forest Area"),
"Subcon Forest - Triple Spider Bounce": LocData(324765, "Subcon Forest Area"),
"Subcon Forest - Noose Treehouse": LocData(324856, "Subcon Forest Area", hookshot=True),
"Subcon Forest - Ice Cube Shack": LocData(324465, "Subcon Forest Area"),
"Subcon Forest - Burning House": LocData(324710, "Subcon Forest Area", paintings=2),
"Subcon Forest - Burning Tree Climb": LocData(325079, "Subcon Forest Area", paintings=2),
"Subcon Forest - Burning Stump Chest": LocData(323731, "Subcon Forest Area", paintings=2),
"Subcon Forest - Burning Forest Treehouse": LocData(325467, "Subcon Forest Area", paintings=2),
"Subcon Forest - Spider Bone Cage A": LocData(324462, "Subcon Forest Area", paintings=2),
"Subcon Forest - Spider Bone Cage B": LocData(325080, "Subcon Forest Area", paintings=2),
"Subcon Forest - Triple Spider Bounce": LocData(324765, "Subcon Forest Area", paintings=2),
"Subcon Forest - Noose Treehouse": LocData(324856, "Subcon Forest Area", hookshot=True, paintings=2),
"Subcon Forest - Ice Cube Shack": LocData(324465, "Subcon Forest Area", paintings=1),
"Subcon Forest - Long Tree Climb Chest": LocData(323734, "Subcon Forest Area", required_hats=[HatType.DWELLER]),
"Subcon Forest - Long Tree Climb Chest": LocData(323734, "Subcon Forest Area",
required_hats=[HatType.DWELLER], paintings=2),
"Subcon Forest - Boss Arena Chest": LocData(323735, "Subcon Forest Area"),
"Subcon Forest - Manor Rooftop": LocData(325466, "Subcon Forest Area", dweller_bell=2),
"Subcon Forest - Manor Rooftop": LocData(325466, "Subcon Forest Area", dweller_bell=2, paintings=1),
"Subcon Forest - Infinite Yarn Bush": LocData(325478, "Subcon Forest Area", required_hats=[HatType.BREWING]),
"Subcon Forest - Infinite Yarn Bush": LocData(325478, "Subcon Forest Area",
required_hats=[HatType.BREWING], paintings=2),
"Subcon Forest - Magnet Badge Bush": LocData(325479, "Subcon Forest Area", required_hats=[HatType.BREWING]),
"Subcon Forest - Magnet Badge Bush": LocData(325479, "Subcon Forest Area",
required_hats=[HatType.BREWING], paintings=3),
"Subcon Well - Hookshot Badge Chest": LocData(324114, "The Subcon Well", dweller_bell=1),
"Subcon Well - Above Chest": LocData(324612, "The Subcon Well", dweller_bell=1),
"Subcon Well - On Pipe": LocData(324311, "The Subcon Well", hookshot=True, dweller_bell=1),
"Subcon Well - Mushroom": LocData(325318, "The Subcon Well", dweller_bell=1),
"Subcon Well - Hookshot Badge Chest": LocData(324114, "The Subcon Well", dweller_bell=1, paintings=1),
"Subcon Well - Above Chest": LocData(324612, "The Subcon Well", dweller_bell=1, paintings=1),
"Subcon Well - On Pipe": LocData(324311, "The Subcon Well", hookshot=True, dweller_bell=1, paintings=1),
"Subcon Well - Mushroom": LocData(325318, "The Subcon Well", dweller_bell=1, paintings=1),
"Queen Vanessa's Manor - Cellar": LocData(324841, "Queen Vanessa's Manor", dweller_bell=2),
"Queen Vanessa's Manor - Bedroom Chest": LocData(323808, "Queen Vanessa's Manor", dweller_bell=2),
"Queen Vanessa's Manor - Hall Chest": LocData(323896, "Queen Vanessa's Manor", dweller_bell=2),
"Queen Vanessa's Manor - Chandelier": LocData(325546, "Queen Vanessa's Manor", dweller_bell=2),
"Queen Vanessa's Manor - Cellar": LocData(324841, "Queen Vanessa's Manor", dweller_bell=2, paintings=1),
"Queen Vanessa's Manor - Bedroom Chest": LocData(323808, "Queen Vanessa's Manor", dweller_bell=2, paintings=1),
"Queen Vanessa's Manor - Hall Chest": LocData(323896, "Queen Vanessa's Manor", dweller_bell=2, paintings=1),
"Queen Vanessa's Manor - Chandelier": LocData(325546, "Queen Vanessa's Manor", dweller_bell=2, paintings=1),
# 330000 range - Alpine Skyline
"Alpine Skyline - Goat Village: Below Hookpoint": LocData(334856, "Goat Village"),
@@ -328,10 +342,10 @@ act_completions = {
"Act Completion (Time Rift - The Moon)": LocData(312785, "Time Rift - The Moon"),
"Act Completion (Time Rift - Dead Bird Studio)": LocData(312577, "Time Rift - Dead Bird Studio"),
"Act Completion (Contractual Obligations)": LocData(312317, "Contractual Obligations"),
"Act Completion (The Subcon Well)": LocData(311160, "The Subcon Well", hookshot=True, umbrella=True),
"Act Completion (Toilet of Doom)": LocData(311984, "Toilet of Doom", hookshot=True),
"Act Completion (Queen Vanessa's Manor)": LocData(312017, "Queen Vanessa's Manor", umbrella=True),
"Act Completion (Contractual Obligations)": LocData(312317, "Contractual Obligations", paintings=1),
"Act Completion (The Subcon Well)": LocData(311160, "The Subcon Well", hookshot=True, umbrella=True, paintings=1),
"Act Completion (Toilet of Doom)": LocData(311984, "Toilet of Doom", hookshot=True, paintings=1),
"Act Completion (Queen Vanessa's Manor)": LocData(312017, "Queen Vanessa's Manor", umbrella=True, paintings=1),
"Act Completion (Mail Delivery Service)": LocData(312032, "Mail Delivery Service", required_hats=[HatType.SPRINT]),
"Act Completion (Your Contract has Expired)": LocData(311390, "Your Contract has Expired", umbrella=True),
"Act Completion (Time Rift - Pipe)": LocData(313069, "Time Rift - Pipe", hookshot=True),

View File

@@ -1,6 +1,7 @@
from worlds.AutoWorld import World
from BaseClasses import Region, Entrance, ItemClassification, Location
from .Locations import HatInTimeLocation, location_table, storybook_pages, event_locs, is_location_valid, shop_locations
from .Locations import HatInTimeLocation, location_table, storybook_pages, event_locs, is_location_valid, \
shop_locations, get_tasksanity_start_id
from .Items import HatInTimeItem
from .Types import ChapterIndex
import typing
@@ -413,11 +414,10 @@ def create_rift_connections(world: World, region: Region):
def create_tasksanity_locations(world: World):
ship_shape: Region = world.multiworld.get_region("Ship Shape", world.player)
id_start: int = 300204
id_start: int = get_tasksanity_start_id()
for i in range(world.multiworld.TasksanityCheckCount[world.player].value):
location = HatInTimeLocation(world.player, format("Tasksanity Check %i" % (i+1)), id_start+i, ship_shape)
ship_shape.locations.append(location)
# world.location_name_to_id.setdefault(location.name, location.address)
def randomize_act_entrances(world: World):

View File

@@ -32,17 +32,7 @@ act_connections = {
def can_use_hat(state: CollectionState, world: World, hat: HatType) -> bool:
return state.count("Yarn", world.player) >= get_hat_cost(world, hat)
def get_hat_cost(world: World, hat: HatType) -> int:
cost: int = 0
for h in world.get_hat_craft_order():
cost += world.get_hat_yarn_costs().get(h)
if h == hat:
break
return cost
return state.has("Yarn", world.player, world.get_hat_yarn_costs().get(hat))
def can_sdj(state: CollectionState, world: World):
@@ -98,23 +88,19 @@ def can_clear_metro(state: CollectionState, world: World) -> bool:
def set_rules(world: World):
w = world
mw = world.multiworld
p = world.player
dlc1: bool = bool(mw.EnableDLC1[p].value > 0)
dlc2: bool = bool(mw.EnableDLC2[p].value > 0)
dlc1: bool = bool(world.multiworld.EnableDLC1[world.player].value > 0)
dlc2: bool = bool(world.multiworld.EnableDLC2[world.player].value > 0)
# First, chapter access
starting_chapter = ChapterIndex(mw.StartingChapter[p].value)
w.set_chapter_cost(starting_chapter, 0)
starting_chapter = ChapterIndex(world.multiworld.StartingChapter[world.player].value)
world.set_chapter_cost(starting_chapter, 0)
# Chapter costs increase progressively. Randomly decide the chapter order, except for Finale
chapter_list: typing.List[ChapterIndex] = [ChapterIndex.MAFIA, ChapterIndex.BIRDS,
ChapterIndex.SUBCON, ChapterIndex.ALPINE]
final_chapter = ChapterIndex.FINALE
if mw.EndGoal[p].value == 2:
if world.multiworld.EndGoal[world.player].value == 2:
final_chapter = ChapterIndex.METRO
chapter_list.append(ChapterIndex.FINALE)
@@ -125,7 +111,7 @@ def set_rules(world: World):
chapter_list.append(ChapterIndex.METRO)
chapter_list.remove(starting_chapter)
mw.random.shuffle(chapter_list)
world.multiworld.random.shuffle(chapter_list)
if starting_chapter is not ChapterIndex.ALPINE and dlc1 or dlc2:
index1: int = 69
@@ -143,15 +129,15 @@ def set_rules(world: World):
if lowest_index == 0:
pos = 0
else:
pos = mw.random.randint(0, lowest_index)
pos = world.multiworld.random.randint(0, lowest_index)
chapter_list.insert(pos, ChapterIndex.ALPINE)
lowest_cost: int = mw.LowestChapterCost[p].value
highest_cost: int = mw.HighestChapterCost[p].value
lowest_cost: int = world.multiworld.LowestChapterCost[world.player].value
highest_cost: int = world.multiworld.HighestChapterCost[world.player].value
cost_increment: int = mw.ChapterCostIncrement[p].value
min_difference: int = mw.ChapterCostMinDifference[p].value
cost_increment: int = world.multiworld.ChapterCostIncrement[world.player].value
min_difference: int = world.multiworld.ChapterCostMinDifference[world.player].value
last_cost: int = 0
cost: int
loop_count: int = 0
@@ -161,109 +147,112 @@ def set_rules(world: World):
if min_range >= highest_cost:
min_range = highest_cost-1
value: int = mw.random.randint(min_range, min(highest_cost, max(lowest_cost, last_cost + cost_increment)))
value: int = world.multiworld.random.randint(min_range, min(highest_cost,
max(lowest_cost, last_cost + cost_increment)))
cost = mw.random.randint(value, min(value + cost_increment, highest_cost))
cost = world.multiworld.random.randint(value, min(value + cost_increment, highest_cost))
if loop_count >= 1:
if last_cost + min_difference > cost:
cost = last_cost + min_difference
cost = min(cost, highest_cost)
w.set_chapter_cost(chapter, cost)
world.set_chapter_cost(chapter, cost)
last_cost = cost
loop_count += 1
w.set_chapter_cost(final_chapter, mw.random.randint(mw.FinalChapterMinCost[p].value,
mw.FinalChapterMaxCost[p].value))
world.set_chapter_cost(final_chapter, world.multiworld.random.randint(
world.multiworld.FinalChapterMinCost[world.player].value,
world.multiworld.FinalChapterMaxCost[world.player].value))
add_rule(mw.get_entrance("Telescope -> Mafia Town", p),
lambda state: state.has("Time Piece", p, w.get_chapter_cost(ChapterIndex.MAFIA)))
add_rule(world.multiworld.get_entrance("Telescope -> Mafia Town", world.player),
lambda state: state.has("Time Piece", world.player, world.get_chapter_cost(ChapterIndex.MAFIA)))
add_rule(mw.get_entrance("Telescope -> Battle of the Birds", p),
lambda state: state.has("Time Piece", p, w.get_chapter_cost(ChapterIndex.BIRDS)))
add_rule(world.multiworld.get_entrance("Telescope -> Battle of the Birds", world.player),
lambda state: state.has("Time Piece", world.player, world.get_chapter_cost(ChapterIndex.BIRDS)))
add_rule(mw.get_entrance("Telescope -> Subcon Forest", p),
lambda state: state.has("Time Piece", p, w.get_chapter_cost(ChapterIndex.SUBCON)))
add_rule(world.multiworld.get_entrance("Telescope -> Subcon Forest", world.player),
lambda state: state.has("Time Piece", world.player, world.get_chapter_cost(ChapterIndex.SUBCON)))
add_rule(mw.get_entrance("Telescope -> Alpine Skyline", p),
lambda state: state.has("Time Piece", p, w.get_chapter_cost(ChapterIndex.ALPINE)))
add_rule(world.multiworld.get_entrance("Telescope -> Alpine Skyline", world.player),
lambda state: state.has("Time Piece", world.player, world.get_chapter_cost(ChapterIndex.ALPINE)))
add_rule(mw.get_entrance("Telescope -> Time's End", p),
lambda state: state.has("Time Piece", p, w.get_chapter_cost(ChapterIndex.FINALE))
and can_use_hat(state, w, HatType.BREWING) and can_use_hat(state, w, HatType.DWELLER))
add_rule(world.multiworld.get_entrance("Telescope -> Time's End", world.player),
lambda state: state.has("Time Piece", world.player, world.get_chapter_cost(ChapterIndex.FINALE))
and can_use_hat(state, world, HatType.BREWING) and can_use_hat(state, world, HatType.DWELLER))
if dlc1:
add_rule(mw.get_entrance("Telescope -> The Arctic Cruise", p),
lambda state: state.has("Time Piece", p, w.get_chapter_cost(ChapterIndex.ALPINE))
and state.has("Time Piece", p, w.get_chapter_cost(ChapterIndex.CRUISE)))
add_rule(world.multiworld.get_entrance("Telescope -> The Arctic Cruise", world.player),
lambda state: state.has("Time Piece", world.player, world.get_chapter_cost(ChapterIndex.ALPINE))
and state.has("Time Piece", world.player, world.get_chapter_cost(ChapterIndex.CRUISE)))
if dlc2:
add_rule(mw.get_entrance("Telescope -> Nyakuza Metro", p),
lambda state: state.has("Time Piece", p, w.get_chapter_cost(ChapterIndex.ALPINE))
and state.has("Time Piece", p, w.get_chapter_cost(ChapterIndex.METRO))
and can_use_hat(state, w, HatType.DWELLER) and can_use_hat(state, w, HatType.ICE))
add_rule(world.multiworld.get_entrance("Telescope -> Nyakuza Metro", world.player),
lambda state: state.has("Time Piece", world.player, world.get_chapter_cost(ChapterIndex.ALPINE))
and state.has("Time Piece", world.player, world.get_chapter_cost(ChapterIndex.METRO))
and can_use_hat(state, world, HatType.DWELLER) and can_use_hat(state, world, HatType.ICE))
if mw.ActRandomizer[p].value == 0:
set_default_rift_rules(w)
if world.multiworld.ActRandomizer[world.player].value == 0:
set_default_rift_rules(world)
location: Location
for (key, data) in location_table.items():
if not is_location_valid(w, key):
if not is_location_valid(world, key):
continue
if key in contract_locations.keys():
continue
location = mw.get_location(key, p)
location = world.multiworld.get_location(key, world.player)
# Not all locations in Alpine can be reached from The Illness has Spread
# as many of the ziplines are blocked off
if data.region == "Alpine Skyline Area":
if key not in tihs_locations:
add_rule(location, lambda state: state.can_reach("Alpine Free Roam", "Region", p), "and")
add_rule(location, lambda state: state.can_reach("Alpine Free Roam", "Region", world.player), "and")
else:
add_rule(location, lambda state: can_use_hookshot(state, w))
add_rule(location, lambda state: can_use_hookshot(state, world))
if data.region == "The Birdhouse" or data.region == "The Lava Cake" \
or data.region == "The Windmill" or data.region == "The Twilight Bell":
add_rule(location, lambda state: state.can_reach("Alpine Free Roam", "Region", p), "and")
add_rule(location, lambda state: state.can_reach("Alpine Free Roam", "Region", world.player), "and")
for hat in data.required_hats:
if hat is not HatType.NONE:
add_rule(location, lambda state, hat=hat: can_use_hat(state, w, hat))
add_rule(location, lambda state, required_hat=hat: can_use_hat(state, world, required_hat))
if data.hookshot:
add_rule(location, lambda state: can_use_hookshot(state, w))
add_rule(location, lambda state: can_use_hookshot(state, world))
if data.umbrella and mw.UmbrellaLogic[p].value > 0:
add_rule(location, lambda state: state.has("Umbrella", p))
if data.umbrella and world.multiworld.UmbrellaLogic[world.player].value > 0:
add_rule(location, lambda state: state.has("Umbrella", world.player))
if data.paintings > 0 and world.multiworld.ShuffleSubconPaintings[world.player].value > 0:
add_rule(location, lambda state, paintings=data.paintings:
state.count("Progressive Painting Unlock", world.player) >= paintings)
if data.dweller_bell > 0:
if data.dweller_bell == 1: # Required to be hit regardless of Dweller Mask
add_rule(location, lambda state: can_hit_bells(state, w))
add_rule(location, lambda state: can_hit_bells(state, world))
else: # Can bypass with Dweller Mask
add_rule(location, lambda state: can_hit_bells(state, w) or can_use_hat(state, w, HatType.DWELLER))
add_rule(location, lambda state: can_hit_bells(state, world) or can_use_hat(state, world, HatType.DWELLER))
set_specific_rules(w)
set_specific_rules(world)
if mw.LogicDifficulty[p].value >= 1:
mw.SDJLogic[p].value = 1
if world.multiworld.LogicDifficulty[world.player].value >= 1:
world.multiworld.SDJLogic[world.player].value = 1
if mw.SDJLogic[p].value > 0:
if world.multiworld.SDJLogic[world.player].value > 0:
set_sdj_rules(world)
if mw.ShuffleAlpineZiplines[p].value > 0:
set_alps_zipline_rules(w)
if mw.ShuffleSubconPaintings[p].value > 0:
set_painting_rules(w)
if world.multiworld.ShuffleAlpineZiplines[world.player].value > 0:
set_alps_zipline_rules(world)
for (key, acts) in act_connections.items():
if "Arctic Cruise" in key and not dlc1:
continue
i: int = 1
entrance: Entrance = mw.get_entrance(key, p)
entrance: Entrance = world.multiworld.get_entrance(key, world.player)
region: Region = entrance.connected_region
access_rules: typing.List[typing.Callable[[CollectionState], bool]] = []
entrance.parent_region.exits.remove(entrance)
@@ -273,18 +262,18 @@ def set_rules(world: World):
entrances: typing.List[Entrance] = []
for act in acts:
act_entrance: Entrance = mw.get_entrance(act, p)
act_entrance: Entrance = world.multiworld.get_entrance(act, world.player)
access_rules.append(act_entrance.access_rule)
required_region = act_entrance.connected_region
name: str = format("%s: Connection %i" % (key, i))
new_entrance: Entrance = connect_regions(required_region, region, name, p)
new_entrance: Entrance = connect_regions(required_region, region, name, world.player)
entrances.append(new_entrance)
# Copy access rules from act completions
if "Free Roam" not in required_region.name:
rule: typing.Callable[[CollectionState], bool]
name = format("Act Completion (%s)" % required_region.name)
rule = mw.get_location(name, p).access_rule
rule = world.multiworld.get_location(name, world.player).access_rule
access_rules.append(rule)
i += 1
@@ -293,186 +282,193 @@ def set_rules(world: World):
for rules in access_rules:
add_rule(e, rules)
for entrance in mw.get_region("Alpine Free Roam", p).entrances:
add_rule(entrance, lambda state: can_use_hookshot(state, w))
if mw.UmbrellaLogic[p].value > 0:
add_rule(entrance, lambda state: state.has("Umbrella", p))
for entrance in world.multiworld.get_region("Alpine Free Roam", world.player).entrances:
add_rule(entrance, lambda state: can_use_hookshot(state, world))
if world.multiworld.UmbrellaLogic[world.player].value > 0:
add_rule(entrance, lambda state: state.has("Umbrella", world.player))
if mw.EndGoal[p].value == 1:
mw.completion_condition[p] = lambda state: state.has("Time Piece Cluster", p)
elif mw.EndGoal[p].value == 2:
mw.completion_condition[p] = lambda state: state.has("Rush Hour Cleared", p)
if world.multiworld.EndGoal[world.player].value == 1:
world.multiworld.completion_condition[world.player] = lambda state: state.has("Time Piece Cluster", world.player)
elif world.multiworld.EndGoal[world.player].value == 2:
world.multiworld.completion_condition[world.player] = lambda state: state.has("Rush Hour Cleared", world.player)
def set_specific_rules(world: World):
mw = world.multiworld
w = world
p = world.player
dlc1: bool = bool(mw.EnableDLC1[p].value > 0)
dlc1: bool = bool(world.multiworld.EnableDLC1[world.player].value > 0)
add_rule(mw.get_entrance("Alpine Skyline - Finale", p),
lambda state: can_clear_alpine(state, w))
add_rule(world.multiworld.get_entrance("Alpine Skyline - Finale", world.player),
lambda state: can_clear_alpine(state, world))
add_rule(mw.get_location("Mafia Boss Shop Item", p),
lambda state: state.has("Time Piece", p, 12)
and state.has("Time Piece", p, w.get_chapter_cost(ChapterIndex.BIRDS)))
add_rule(world.multiworld.get_location("Mafia Boss Shop Item", world.player),
lambda state: state.has("Time Piece", world.player, 12)
and state.has("Time Piece", world.player, world.get_chapter_cost(ChapterIndex.BIRDS)))
add_rule(mw.get_location("Spaceship - Rumbi Abuse", p),
lambda state: state.has("Time Piece", p, 4))
add_rule(world.multiworld.get_location("Spaceship - Rumbi Abuse", world.player),
lambda state: state.has("Time Piece", world.player, 4))
# Normal logic
if mw.LogicDifficulty[p].value == 0:
add_rule(mw.get_entrance("-> The Birdhouse", p),
lambda state: can_use_hat(state, w, HatType.BREWING))
if world.multiworld.LogicDifficulty[world.player].value == 0:
add_rule(world.multiworld.get_entrance("-> The Birdhouse", world.player),
lambda state: can_use_hat(state, world, HatType.BREWING))
add_rule(mw.get_location("Alpine Skyline - Yellow Band Hills", p),
lambda state: can_use_hat(state, w, HatType.BREWING))
add_rule(world.multiworld.get_location("Alpine Skyline - Yellow Band Hills", world.player),
lambda state: can_use_hat(state, world, HatType.BREWING))
if dlc1:
add_rule(mw.get_location("Act Completion (Time Rift - Deep Sea)", p),
lambda state: can_use_hat(state, w, HatType.DWELLER))
add_rule(world.multiworld.get_location("Act Completion (Time Rift - Deep Sea)", world.player),
lambda state: can_use_hat(state, world, HatType.DWELLER))
add_rule(mw.get_location("Rock the Boat - Post Captain Rescue", p),
lambda state: can_use_hat(state, w, HatType.ICE))
add_rule(world.multiworld.get_location("Rock the Boat - Post Captain Rescue", world.player),
lambda state: can_use_hat(state, world, HatType.ICE))
add_rule(mw.get_location("Act Completion (Rock the Boat)", p),
lambda state: can_use_hat(state, w, HatType.ICE))
add_rule(world.multiworld.get_location("Act Completion (Rock the Boat)", world.player),
lambda state: can_use_hat(state, world, HatType.ICE))
# Hard logic, includes SDJ stuff
if mw.LogicDifficulty[p].value >= 1:
add_rule(mw.get_location("Act Completion (Time Rift - The Twilight Bell)", p),
lambda state: can_use_hat(state, w, HatType.SPRINT) and state.has("Scooter Badge", p), "or")
if world.multiworld.LogicDifficulty[world.player].value >= 1:
add_rule(world.multiworld.get_location("Act Completion (Time Rift - The Twilight Bell)", world.player),
lambda state: can_use_hat(state, world, HatType.SPRINT)
and state.has("Scooter Badge", world.player), "or")
# Expert logic
if mw.LogicDifficulty[p].value >= 2:
set_rule(mw.get_location("Alpine Skyline - The Twilight Path", p), lambda state: True)
if world.multiworld.LogicDifficulty[world.player].value >= 2:
set_rule(world.multiworld.get_location("Alpine Skyline - The Twilight Path", world.player), lambda state: True)
else:
add_rule(mw.get_entrance("-> The Twilight Bell", p),
lambda state: can_use_hat(state, w, HatType.DWELLER))
add_rule(world.multiworld.get_entrance("-> The Twilight Bell", world.player),
lambda state: can_use_hat(state, world, HatType.DWELLER))
add_rule(mw.get_location("Mafia Town - Behind HQ Chest", p),
lambda state: state.can_reach("Act Completion (Heating Up Mafia Town)", "Location", p)
or state.can_reach("Down with the Mafia!", "Region", p)
or state.can_reach("Cheating the Race", "Region", p)
or state.can_reach("The Golden Vault", "Region", p))
add_rule(world.multiworld.get_location("Mafia Town - Behind HQ Chest", world.player),
lambda state: state.can_reach("Act Completion (Heating Up Mafia Town)", "Location", world.player)
or state.can_reach("Down with the Mafia!", "Region", world.player)
or state.can_reach("Cheating the Race", "Region", world.player)
or state.can_reach("The Golden Vault", "Region", world.player))
# Old guys don't appear in SCFOS
add_rule(mw.get_location("Mafia Town - Old Man (Steel Beams)", p),
lambda state: state.can_reach("Welcome to Mafia Town", "Region", p)
or state.can_reach("Barrel Battle", "Region", p)
or state.can_reach("Cheating the Race", "Region", p)
or state.can_reach("The Golden Vault", "Region", p)
or state.can_reach("Down with the Mafia!", "Region", p))
add_rule(world.multiworld.get_location("Mafia Town - Old Man (Steel Beams)", world.player),
lambda state: state.can_reach("Welcome to Mafia Town", "Region", world.player)
or state.can_reach("Barrel Battle", "Region", world.player)
or state.can_reach("Cheating the Race", "Region", world.player)
or state.can_reach("The Golden Vault", "Region", world.player)
or state.can_reach("Down with the Mafia!", "Region", world.player))
add_rule(mw.get_location("Mafia Town - Old Man (Seaside Spaghetti)", p),
lambda state: state.can_reach("Welcome to Mafia Town", "Region", p)
or state.can_reach("Barrel Battle", "Region", p)
or state.can_reach("Cheating the Race", "Region", p)
or state.can_reach("The Golden Vault", "Region", p)
or state.can_reach("Down with the Mafia!", "Region", p))
add_rule(world.multiworld.get_location("Mafia Town - Old Man (Seaside Spaghetti)", world.player),
lambda state: state.can_reach("Welcome to Mafia Town", "Region", world.player)
or state.can_reach("Barrel Battle", "Region", world.player)
or state.can_reach("Cheating the Race", "Region", world.player)
or state.can_reach("The Golden Vault", "Region", world.player)
or state.can_reach("Down with the Mafia!", "Region", world.player))
# Only available outside She Came from Outer Space
add_rule(mw.get_location("Mafia Town - Mafia Geek Platform", p),
lambda state: state.can_reach("Welcome to Mafia Town", "Region", p)
or state.can_reach("Barrel Battle", "Region", p)
or state.can_reach("Down with the Mafia!", "Region", p)
or state.can_reach("Cheating the Race", "Region", p)
or state.can_reach("Heating Up Mafia Town", "Region", p)
or state.can_reach("The Golden Vault", "Region", p))
add_rule(world.multiworld.get_location("Mafia Town - Mafia Geek Platform", world.player),
lambda state: state.can_reach("Welcome to Mafia Town", "Region", world.player)
or state.can_reach("Barrel Battle", "Region", world.player)
or state.can_reach("Down with the Mafia!", "Region", world.player)
or state.can_reach("Cheating the Race", "Region", world.player)
or state.can_reach("Heating Up Mafia Town", "Region", world.player)
or state.can_reach("The Golden Vault", "Region", world.player))
# Only available outside Down with the Mafia! (for some reason)
add_rule(mw.get_location("Mafia Town - On Scaffolding", p),
lambda state: state.can_reach("Welcome to Mafia Town", "Region", p)
or state.can_reach("Barrel Battle", "Region", p)
or state.can_reach("She Came from Outer Space", "Region", p)
or state.can_reach("Cheating the Race", "Region", p)
or state.can_reach("Heating Up Mafia Town", "Region", p)
or state.can_reach("The Golden Vault", "Region", p))
add_rule(world.multiworld.get_location("Mafia Town - On Scaffolding", world.player),
lambda state: state.can_reach("Welcome to Mafia Town", "Region", world.player)
or state.can_reach("Barrel Battle", "Region", world.player)
or state.can_reach("She Came from Outer Space", "Region", world.player)
or state.can_reach("Cheating the Race", "Region", world.player)
or state.can_reach("Heating Up Mafia Town", "Region", world.player)
or state.can_reach("The Golden Vault", "Region", world.player))
# For some reason, the brewing crate is removed in HUMT
set_rule(mw.get_location("Mafia Town - Secret Cave", p),
lambda state: state.can_reach("Heating Up Mafia Town", "Region", p)
or can_use_hat(state, w, HatType.BREWING))
set_rule(world.multiworld.get_location("Mafia Town - Secret Cave", world.player),
lambda state: state.can_reach("Heating Up Mafia Town", "Region", world.player)
or can_use_hat(state, world, HatType.BREWING))
# Can bounce across the lava to get this without Hookshot (need to die though :P)
set_rule(mw.get_location("Mafia Town - Above Boats", p),
lambda state: state.can_reach("Heating Up Mafia Town", "Region", p)
or can_use_hookshot(state, w))
# Can bounce across the lava to get this without Hookshot (need to die though :world.player)
set_rule(world.multiworld.get_location("Mafia Town - Above Boats", world.player),
lambda state: state.can_reach("Heating Up Mafia Town", "Region", world.player)
or can_use_hookshot(state, world))
set_rule(mw.get_location("Act Completion (Cheating the Race)", p),
lambda state: can_use_hat(state, w, HatType.TIME_STOP)
or mw.CTRWithSprint[p].value > 0 and can_use_hat(state, w, HatType.SPRINT))
set_rule(world.multiworld.get_location("Act Completion (Cheating the Race)", world.player),
lambda state: can_use_hat(state, world, HatType.TIME_STOP)
or world.multiworld.CTRWithSprint[world.player].value > 0 and can_use_hat(state, world, HatType.SPRINT))
set_rule(mw.get_location("Subcon Forest - Boss Arena Chest", p),
lambda state: state.can_reach("Toilet of Doom", "Region", p)
and (mw.ShuffleSubconPaintings[p].value == 0 or state.has("Progressive Painting Unlock", p, 1))
or state.can_reach("Your Contract has Expired", "Region", p))
set_rule(world.multiworld.get_location("Subcon Forest - Boss Arena Chest", world.player),
lambda state: state.can_reach("Toilet of Doom", "Region", world.player)
and (world.multiworld.ShuffleSubconPaintings[world.player].value == 0
or state.has("Progressive Painting Unlock", world.player, 1))
or state.can_reach("Your Contract has Expired", "Region", world.player))
if mw.UmbrellaLogic[p].value > 0:
add_rule(mw.get_location("Act Completion (Toilet of Doom)", p),
lambda state: state.has("Umbrella", p) or can_use_hat(state, w, HatType.BREWING))
if world.multiworld.UmbrellaLogic[world.player].value > 0:
add_rule(world.multiworld.get_location("Act Completion (Toilet of Doom)", world.player),
lambda state: state.has("Umbrella", world.player) or can_use_hat(state, world, HatType.BREWING))
set_rule(mw.get_location("Act Completion (Time Rift - Village)", p),
lambda state: can_use_hat(state, w, HatType.BREWING) or state.has("Umbrella", p)
or can_use_hat(state, w, HatType.DWELLER))
set_rule(world.multiworld.get_location("Act Completion (Time Rift - Village)", world.player),
lambda state: can_use_hat(state, world, HatType.BREWING) or state.has("Umbrella", world.player)
or can_use_hat(state, world, HatType.DWELLER))
add_rule(mw.get_entrance("Subcon Forest - Act 2", p),
lambda state: state.has("Snatcher's Contract - The Subcon Well", p))
add_rule(world.multiworld.get_entrance("Subcon Forest - Act 2", world.player),
lambda state: state.has("Snatcher's Contract - The Subcon Well", world.player))
add_rule(mw.get_entrance("Subcon Forest - Act 3", p),
lambda state: state.has("Snatcher's Contract - Toilet of Doom", p))
add_rule(world.multiworld.get_entrance("Subcon Forest - Act 3", world.player),
lambda state: state.has("Snatcher's Contract - Toilet of Doom", world.player))
add_rule(mw.get_entrance("Subcon Forest - Act 4", p),
lambda state: state.has("Snatcher's Contract - Queen Vanessa's Manor", p))
add_rule(world.multiworld.get_entrance("Subcon Forest - Act 4", world.player),
lambda state: state.has("Snatcher's Contract - Queen Vanessa's Manor", world.player))
add_rule(mw.get_entrance("Subcon Forest - Act 5", p),
lambda state: state.has("Snatcher's Contract - Mail Delivery Service", p))
add_rule(world.multiworld.get_entrance("Subcon Forest - Act 5", world.player),
lambda state: state.has("Snatcher's Contract - Mail Delivery Service", world.player))
if mw.ShuffleSubconPaintings[p].value > 0:
if world.multiworld.ShuffleSubconPaintings[world.player].value > 0:
for key in contract_locations:
if key == "Snatcher's Contract - The Subcon Well":
continue
add_rule(mw.get_location(key, p),
lambda state: state.has("Progressive Painting Unlock", p, 1))
add_rule(world.multiworld.get_location(key, world.player),
lambda state: state.has("Progressive Painting Unlock", world.player, 1))
add_rule(mw.get_location("Alpine Skyline - Mystifying Time Mesa: Zipline", p),
lambda state: can_use_hat(state, w, HatType.SPRINT) or can_use_hat(state, w, HatType.TIME_STOP))
add_rule(world.multiworld.get_location("Alpine Skyline - Mystifying Time Mesa: Zipline", world.player),
lambda state: can_use_hat(state, world, HatType.SPRINT) or can_use_hat(state, world, HatType.TIME_STOP))
if mw.EnableDLC1[p].value > 0:
add_rule(mw.get_entrance("Cruise Ship Entrance BV", p), lambda state: can_use_hookshot(state, w))
if world.multiworld.EnableDLC1[world.player].value > 0:
add_rule(world.multiworld.get_entrance("Cruise Ship Entrance BV", world.player),
lambda state: can_use_hookshot(state, world))
# This particular item isn't present in Act 3 for some reason, yes in vanilla too
add_rule(mw.get_location("The Arctic Cruise - Toilet", p),
lambda state: state.can_reach("Bon Voyage!", "Region", p)
or state.can_reach("Ship Shape", "Region", p))
add_rule(world.multiworld.get_location("The Arctic Cruise - Toilet", world.player),
lambda state: state.can_reach("Bon Voyage!", "Region", world.player)
or state.can_reach("Ship Shape", "Region", world.player))
if mw.EnableDLC2[p].value > 0:
add_rule(mw.get_entrance("-> Bluefin Tunnel", p),
lambda state: state.has("Metro Ticket - Green", p) or state.has("Metro Ticket - Blue", p))
if world.multiworld.EnableDLC2[world.player].value > 0:
add_rule(world.multiworld.get_entrance("-> Bluefin Tunnel", world.player),
lambda state: state.has("Metro Ticket - Green", world.player)
or state.has("Metro Ticket - Blue", world.player))
add_rule(mw.get_entrance("-> Pink Paw Station", p),
lambda state: state.has("Metro Ticket - Pink", p)
or state.has("Metro Ticket - Yellow", p) and state.has("Metro Ticket - Blue", p))
add_rule(world.multiworld.get_entrance("-> Pink Paw Station", world.player),
lambda state: state.has("Metro Ticket - Pink", world.player)
or state.has("Metro Ticket - Yellow", world.player) and state.has("Metro Ticket - Blue", world.player))
add_rule(mw.get_entrance("Nyakuza Metro - Finale", p),
lambda state: can_clear_metro(state, w))
add_rule(world.multiworld.get_entrance("Nyakuza Metro - Finale", world.player),
lambda state: can_clear_metro(state, world))
add_rule(mw.get_location("Act Completion (Rush Hour)", p),
lambda state: state.has("Metro Ticket - Yellow", p) and state.has("Metro Ticket - Blue", p)
and state.has("Metro Ticket - Pink", p))
add_rule(world.multiworld.get_location("Act Completion (Rush Hour)", world.player),
lambda state: state.has("Metro Ticket - Yellow", world.player)
and state.has("Metro Ticket - Blue", world.player)
and state.has("Metro Ticket - Pink", world.player))
for key in shop_locations.keys():
if "Green Clean Station Thug B" in key and is_location_valid(w, key):
add_rule(mw.get_location(key, p), lambda state: state.has("Metro Ticket - Yellow", p), "or")
if "Green Clean Station Thug B" in key and is_location_valid(world, key):
add_rule(world.multiworld.get_location(key, world.player),
lambda state: state.has("Metro Ticket - Yellow", world.player), "or")
def set_sdj_rules(world: World):
add_rule(world.multiworld.get_location("Subcon Forest - Long Tree Climb Chest", world.player),
lambda state: can_sdj(state, world), "or")
lambda state: can_sdj(state, world)
and (world.multiworld.ShuffleSubconPaintings[world.player].value == 0
or state.count("Progressive Painting Unlock", world.player) >= 2), "or")
add_rule(world.multiworld.get_location("Subcon Forest - Green and Purple Dweller Rocks", world.player),
lambda state: can_sdj(state, world), "or")
lambda state: can_sdj(state, world)
and (world.multiworld.ShuffleSubconPaintings[world.player].value == 0
or state.count("Progressive Painting Unlock", world.player) >= 3), "or")
add_rule(world.multiworld.get_location("Alpine Skyline - The Birdhouse: Dweller Platforms Relic", world.player),
lambda state: can_sdj(state, world), "or")
@@ -525,160 +521,164 @@ def reg_act_connection(world: World, region: typing.Union[str, Region], unlocked
# See randomize_act_entrances in Regions.py
# Called BEFORE set_rules!
def set_rift_rules(world: World, regions: typing.Dict[str, Region]):
w = world
mw = world.multiworld
p = world.player
# This is accessing the regions in place of these time rifts, so we can set the rules on all the entrances.
for entrance in regions["Time Rift - Gallery"].entrances:
add_rule(entrance, lambda state: can_use_hat(state, w, HatType.BREWING)
and state.has("Time Piece", p, w.get_chapter_cost(ChapterIndex.BIRDS)))
add_rule(entrance, lambda state: can_use_hat(state, world, HatType.BREWING)
and state.has("Time Piece", world.player, world.get_chapter_cost(ChapterIndex.BIRDS)))
for entrance in regions["Time Rift - The Lab"].entrances:
add_rule(entrance, lambda state: can_use_hat(state, w, HatType.DWELLER)
and state.has("Time Piece", p, w.get_chapter_cost(ChapterIndex.ALPINE)))
add_rule(entrance, lambda state: can_use_hat(state, world, HatType.DWELLER)
and state.has("Time Piece", world.player, world.get_chapter_cost(ChapterIndex.ALPINE)))
for entrance in regions["Time Rift - Sewers"].entrances:
add_rule(entrance, lambda state: can_clear_act(state, w, "Mafia Town - Act 4"))
reg_act_connection(w, mw.get_entrance("Mafia Town - Act 4", p).connected_region, entrance)
add_rule(entrance, lambda state: can_clear_act(state, world, "Mafia Town - Act 4"))
reg_act_connection(world, world.multiworld.get_entrance("Mafia Town - Act 4",
world.player).connected_region, entrance)
for entrance in regions["Time Rift - Bazaar"].entrances:
add_rule(entrance, lambda state: can_clear_act(state, w, "Mafia Town - Act 6"))
reg_act_connection(w, mw.get_entrance("Mafia Town - Act 6", p).connected_region, entrance)
add_rule(entrance, lambda state: can_clear_act(state, world, "Mafia Town - Act 6"))
reg_act_connection(world, world.multiworld.get_entrance("Mafia Town - Act 6",
world.player).connected_region, entrance)
for entrance in regions["Time Rift - Mafia of Cooks"].entrances:
add_rule(entrance, lambda state: has_relic_combo(state, w, "Burger"))
add_rule(entrance, lambda state: has_relic_combo(state, world, "Burger"))
for entrance in regions["Time Rift - The Owl Express"].entrances:
add_rule(entrance, lambda state: can_clear_act(state, w, "Battle of the Birds - Act 2"))
add_rule(entrance, lambda state: can_clear_act(state, w, "Battle of the Birds - Act 3"))
reg_act_connection(w, mw.get_entrance("Battle of the Birds - Act 2", p).connected_region, entrance)
reg_act_connection(w, mw.get_entrance("Battle of the Birds - Act 3", p).connected_region, entrance)
add_rule(entrance, lambda state: can_clear_act(state, world, "Battle of the Birds - Act 2"))
add_rule(entrance, lambda state: can_clear_act(state, world, "Battle of the Birds - Act 3"))
reg_act_connection(world, world.multiworld.get_entrance("Battle of the Birds - Act 2",
world.player).connected_region, entrance)
reg_act_connection(world, world.multiworld.get_entrance("Battle of the Birds - Act 3",
world.player).connected_region, entrance)
for entrance in regions["Time Rift - The Moon"].entrances:
add_rule(entrance, lambda state: can_clear_act(state, w, "Battle of the Birds - Act 4"))
add_rule(entrance, lambda state: can_clear_act(state, w, "Battle of the Birds - Act 5"))
reg_act_connection(w, mw.get_entrance("Battle of the Birds - Act 4", p).connected_region, entrance)
reg_act_connection(w, mw.get_entrance("Battle of the Birds - Act 5", p).connected_region, entrance)
add_rule(entrance, lambda state: can_clear_act(state, world, "Battle of the Birds - Act 4"))
add_rule(entrance, lambda state: can_clear_act(state, world, "Battle of the Birds - Act 5"))
reg_act_connection(world, world.multiworld.get_entrance("Battle of the Birds - Act 4",
world.player).connected_region, entrance)
reg_act_connection(world, world.multiworld.get_entrance("Battle of the Birds - Act 5",
world.player).connected_region, entrance)
for entrance in regions["Time Rift - Dead Bird Studio"].entrances:
add_rule(entrance, lambda state: has_relic_combo(state, w, "Train"))
add_rule(entrance, lambda state: has_relic_combo(state, world, "Train"))
for entrance in regions["Time Rift - Pipe"].entrances:
add_rule(entrance, lambda state: can_clear_act(state, w, "Subcon Forest - Act 2"))
reg_act_connection(w, mw.get_entrance("Subcon Forest - Act 2", p).connected_region, entrance)
if mw.ShuffleSubconPaintings[p].value > 0:
add_rule(entrance, lambda state: state.has("Progressive Painting Unlock", p, 2))
add_rule(entrance, lambda state: can_clear_act(state, world, "Subcon Forest - Act 2"))
reg_act_connection(world, world.multiworld.get_entrance("Subcon Forest - Act 2",
world.player).connected_region, entrance)
if world.multiworld.ShuffleSubconPaintings[world.player].value > 0:
add_rule(entrance, lambda state: state.has("Progressive Painting Unlock", world.player, 2))
for entrance in regions["Time Rift - Village"].entrances:
add_rule(entrance, lambda state: can_clear_act(state, w, "Subcon Forest - Act 4"))
reg_act_connection(w, mw.get_entrance("Subcon Forest - Act 4", p).connected_region, entrance)
if mw.ShuffleSubconPaintings[p].value > 0:
add_rule(entrance, lambda state: state.has("Progressive Painting Unlock", p, 2))
add_rule(entrance, lambda state: can_clear_act(state, world, "Subcon Forest - Act 4"))
reg_act_connection(world, world.multiworld.get_entrance("Subcon Forest - Act 4",
world.player).connected_region, entrance)
if world.multiworld.ShuffleSubconPaintings[world.player].value > 0:
add_rule(entrance, lambda state: state.has("Progressive Painting Unlock", world.player, 2))
for entrance in regions["Time Rift - Sleepy Subcon"].entrances:
add_rule(entrance, lambda state: has_relic_combo(state, w, "UFO"))
if mw.ShuffleSubconPaintings[p].value > 0:
add_rule(entrance, lambda state: state.has("Progressive Painting Unlock", p, 3))
add_rule(entrance, lambda state: has_relic_combo(state, world, "UFO"))
if world.multiworld.ShuffleSubconPaintings[world.player].value > 0:
add_rule(entrance, lambda state: state.has("Progressive Painting Unlock", world.player, 3))
for entrance in regions["Time Rift - Curly Tail Trail"].entrances:
add_rule(entrance, lambda state: state.has("Windmill Cleared", p))
add_rule(entrance, lambda state: state.has("Windmill Cleared", world.player))
for entrance in regions["Time Rift - The Twilight Bell"].entrances:
add_rule(entrance, lambda state: state.has("Twilight Bell Cleared", p))
add_rule(entrance, lambda state: state.has("Twilight Bell Cleared", world.player))
for entrance in regions["Time Rift - Alpine Skyline"].entrances:
add_rule(entrance, lambda state: has_relic_combo(state, w, "Crayon"))
add_rule(entrance, lambda state: has_relic_combo(state, world, "Crayon"))
if mw.EnableDLC1[p].value > 0:
if world.multiworld.EnableDLC1[world.player].value > 0:
for entrance in regions["Time Rift - Balcony"].entrances:
add_rule(entrance, lambda state: can_clear_act(state, w, "The Arctic Cruise - Finale"))
add_rule(entrance, lambda state: can_clear_act(state, world, "The Arctic Cruise - Finale"))
for entrance in regions["Time Rift - Deep Sea"].entrances:
add_rule(entrance, lambda state: has_relic_combo(state, w, "Cake"))
add_rule(entrance, lambda state: has_relic_combo(state, world, "Cake"))
if mw.EnableDLC2[p].value > 0:
if world.multiworld.EnableDLC2[world.player].value > 0:
for entrance in regions["Time Rift - Rumbi Factory"].entrances:
add_rule(entrance, lambda state: has_relic_combo(state, w, "Necklace"))
add_rule(entrance, lambda state: has_relic_combo(state, world, "Necklace"))
# Basically the same as above, but without the need of the dict since we are just setting defaults
# Called if Act Rando is disabled
def set_default_rift_rules(world: World):
w = world
mw = world.multiworld
p = world.player
for entrance in mw.get_region("Time Rift - Gallery", p).entrances:
add_rule(entrance, lambda state: can_use_hat(state, w, HatType.BREWING)
and state.has("Time Piece", p, w.get_chapter_cost(ChapterIndex.BIRDS)))
for entrance in world.multiworld.get_region("Time Rift - Gallery", world.player).entrances:
add_rule(entrance, lambda state: can_use_hat(state, world, HatType.BREWING)
and state.has("Time Piece", world.player, world.get_chapter_cost(ChapterIndex.BIRDS)))
for entrance in mw.get_region("Time Rift - The Lab", p).entrances:
add_rule(entrance, lambda state: can_use_hat(state, w, HatType.DWELLER)
and state.has("Time Piece", p, w.get_chapter_cost(ChapterIndex.ALPINE)))
for entrance in world.multiworld.get_region("Time Rift - The Lab", world.player).entrances:
add_rule(entrance, lambda state: can_use_hat(state, world, HatType.DWELLER)
and state.has("Time Piece", world.player, world.get_chapter_cost(ChapterIndex.ALPINE)))
for entrance in mw.get_region("Time Rift - Sewers", p).entrances:
for entrance in world.multiworld.get_region("Time Rift - Sewers", world.player).entrances:
add_rule(entrance, lambda state: can_clear_act(state, world, "Mafia Town - Act 4"))
reg_act_connection(w, "Down with the Mafia!", entrance.name)
reg_act_connection(world, "Down with the Mafia!", entrance.name)
for entrance in mw.get_region("Time Rift - Bazaar", p).entrances:
for entrance in world.multiworld.get_region("Time Rift - Bazaar", world.player).entrances:
add_rule(entrance, lambda state: can_clear_act(state, world, "Mafia Town - Act 6"))
reg_act_connection(w, "Heating Up Mafia Town", entrance.name)
reg_act_connection(world, "Heating Up Mafia Town", entrance.name)
for entrance in mw.get_region("Time Rift - Mafia of Cooks", p).entrances:
add_rule(entrance, lambda state: has_relic_combo(state, w, "Burger"))
for entrance in world.multiworld.get_region("Time Rift - Mafia of Cooks", world.player).entrances:
add_rule(entrance, lambda state: has_relic_combo(state, world, "Burger"))
for entrance in mw.get_region("Time Rift - The Owl Express", p).entrances:
for entrance in world.multiworld.get_region("Time Rift - The Owl Express", world.player).entrances:
add_rule(entrance, lambda state: can_clear_act(state, world, "Battle of the Birds - Act 2"))
add_rule(entrance, lambda state: can_clear_act(state, world, "Battle of the Birds - Act 3"))
reg_act_connection(w, "Murder on the Owl Express", entrance.name)
reg_act_connection(w, "Picture Perfect", entrance.name)
reg_act_connection(world, "Murder on the Owl Express", entrance.name)
reg_act_connection(world, "Picture Perfect", entrance.name)
for entrance in mw.get_region("Time Rift - The Moon", p).entrances:
for entrance in world.multiworld.get_region("Time Rift - The Moon", world.player).entrances:
add_rule(entrance, lambda state: can_clear_act(state, world, "Battle of the Birds - Act 4"))
add_rule(entrance, lambda state: can_clear_act(state, world, "Battle of the Birds - Act 5"))
reg_act_connection(w, "Train Rush", entrance.name)
reg_act_connection(w, "The Big Parade", entrance.name)
reg_act_connection(world, "Train Rush", entrance.name)
reg_act_connection(world, "The Big Parade", entrance.name)
for entrance in mw.get_region("Time Rift - Dead Bird Studio", p).entrances:
add_rule(entrance, lambda state: has_relic_combo(state, w, "Train"))
for entrance in world.multiworld.get_region("Time Rift - Dead Bird Studio", world.player).entrances:
add_rule(entrance, lambda state: has_relic_combo(state, world, "Train"))
for entrance in mw.get_region("Time Rift - Pipe", p).entrances:
for entrance in world.multiworld.get_region("Time Rift - Pipe", world.player).entrances:
add_rule(entrance, lambda state: can_clear_act(state, world, "Subcon Forest - Act 2"))
reg_act_connection(w, "The Subcon Well", entrance.name)
if mw.ShuffleSubconPaintings[p].value > 0:
add_rule(entrance, lambda state: state.has("Progressive Painting Unlock", p, 2))
reg_act_connection(world, "The Subcon Well", entrance.name)
if world.multiworld.ShuffleSubconPaintings[world.player].value > 0:
add_rule(entrance, lambda state: state.has("Progressive Painting Unlock", world.player, 2))
for entrance in mw.get_region("Time Rift - Village", p).entrances:
for entrance in world.multiworld.get_region("Time Rift - Village", world.player).entrances:
add_rule(entrance, lambda state: can_clear_act(state, world, "Subcon Forest - Act 4"))
reg_act_connection(w, "Queen Vanessa's Manor", entrance.name)
if mw.ShuffleSubconPaintings[p].value > 0:
add_rule(entrance, lambda state: state.has("Progressive Painting Unlock", p, 2))
reg_act_connection(world, "Queen Vanessa's Manor", entrance.name)
if world.multiworld.ShuffleSubconPaintings[world.player].value > 0:
add_rule(entrance, lambda state: state.has("Progressive Painting Unlock", world.player, 2))
for entrance in mw.get_region("Time Rift - Sleepy Subcon", p).entrances:
add_rule(entrance, lambda state: has_relic_combo(state, w, "UFO"))
if mw.ShuffleSubconPaintings[p].value > 0:
add_rule(entrance, lambda state: state.has("Progressive Painting Unlock", p, 3))
for entrance in world.multiworld.get_region("Time Rift - Sleepy Subcon", world.player).entrances:
add_rule(entrance, lambda state: has_relic_combo(state, world, "UFO"))
if world.multiworld.ShuffleSubconPaintings[world.player].value > 0:
add_rule(entrance, lambda state: state.has("Progressive Painting Unlock", world.player, 3))
for entrance in mw.get_region("Time Rift - Curly Tail Trail", p).entrances:
add_rule(entrance, lambda state: state.has("Windmill Cleared", p))
for entrance in world.multiworld.get_region("Time Rift - Curly Tail Trail", world.player).entrances:
add_rule(entrance, lambda state: state.has("Windmill Cleared", world.player))
for entrance in mw.get_region("Time Rift - The Twilight Bell", p).entrances:
add_rule(entrance, lambda state: state.has("Twilight Bell Cleared", p))
for entrance in world.multiworld.get_region("Time Rift - The Twilight Bell", world.player).entrances:
add_rule(entrance, lambda state: state.has("Twilight Bell Cleared", world.player))
for entrance in mw.get_region("Time Rift - Alpine Skyline", p).entrances:
add_rule(entrance, lambda state: has_relic_combo(state, w, "Crayon"))
for entrance in world.multiworld.get_region("Time Rift - Alpine Skyline", world.player).entrances:
add_rule(entrance, lambda state: has_relic_combo(state, world, "Crayon"))
if mw.EnableDLC1[p].value > 0:
for entrance in mw.get_region("Time Rift - Balcony", p).entrances:
add_rule(entrance, lambda state: can_clear_act(state, w, "The Arctic Cruise - Finale"))
if world.multiworld.EnableDLC1[world.player].value > 0:
for entrance in world.multiworld.get_region("Time Rift - Balcony", world.player).entrances:
add_rule(entrance, lambda state: can_clear_act(state, world, "The Arctic Cruise - Finale"))
for entrance in mw.get_region("Time Rift - Deep Sea", p).entrances:
add_rule(entrance, lambda state: has_relic_combo(state, w, "Cake"))
for entrance in world.multiworld.get_region("Time Rift - Deep Sea", world.player).entrances:
add_rule(entrance, lambda state: has_relic_combo(state, world, "Cake"))
if mw.EnableDLC2[p].value > 0:
for entrance in mw.get_region("Time Rift - Rumbi Factory", p).entrances:
add_rule(entrance, lambda state: has_relic_combo(state, w, "Necklace"))
if world.multiworld.EnableDLC2[world.player].value > 0:
for entrance in world.multiworld.get_region("Time Rift - Rumbi Factory", world.player).entrances:
add_rule(entrance, lambda state: has_relic_combo(state, world, "Necklace"))
def connect_regions(start_region: Region, exit_region: Region, entrancename: str, player: int) -> Entrance:
@@ -686,131 +686,3 @@ def connect_regions(start_region: Region, exit_region: Region, entrancename: str
start_region.exits.append(entrance)
entrance.connect(exit_region)
return entrance
def set_painting_rules(world: World):
add_rule(world.multiworld.get_location("Subcon Village - Snatcher Statue Chest", world.player),
lambda state: state.has("Progressive Painting Unlock", world.player, 1))
add_rule(world.multiworld.get_location("Subcon Forest - Swamp Gravestone", world.player),
lambda state: state.has("Progressive Painting Unlock", world.player, 1))
add_rule(world.multiworld.get_location("Subcon Forest - Swamp Near Well", world.player),
lambda state: state.has("Progressive Painting Unlock", world.player, 1))
add_rule(world.multiworld.get_location("Subcon Forest - Swamp Tree A", world.player),
lambda state: state.has("Progressive Painting Unlock", world.player, 1))
add_rule(world.multiworld.get_location("Subcon Forest - Swamp Tree B", world.player),
lambda state: state.has("Progressive Painting Unlock", world.player, 1))
add_rule(world.multiworld.get_location("Subcon Forest - Swamp Ice Wall", world.player),
lambda state: state.has("Progressive Painting Unlock", world.player, 1))
add_rule(world.multiworld.get_location("Subcon Forest - Swamp Treehouse", world.player),
lambda state: state.has("Progressive Painting Unlock", world.player, 1))
add_rule(world.multiworld.get_location("Subcon Forest - Swamp Tree Chest", world.player),
lambda state: state.has("Progressive Painting Unlock", world.player, 1))
add_rule(world.multiworld.get_location("Subcon Forest - Ice Cube Shack", world.player),
lambda state: state.has("Progressive Painting Unlock", world.player, 1))
add_rule(world.multiworld.get_location("Subcon Forest - Manor Rooftop", world.player),
lambda state: state.has("Progressive Painting Unlock", world.player, 1))
add_rule(world.multiworld.get_location("Subcon Well - Hookshot Badge Chest", world.player),
lambda state: state.has("Progressive Painting Unlock", world.player, 1))
add_rule(world.multiworld.get_location("Subcon Well - Above Chest", world.player),
lambda state: state.has("Progressive Painting Unlock", world.player, 1))
add_rule(world.multiworld.get_location("Subcon Well - On Pipe", world.player),
lambda state: state.has("Progressive Painting Unlock", world.player, 1))
add_rule(world.multiworld.get_location("Subcon Well - Mushroom", world.player),
lambda state: state.has("Progressive Painting Unlock", world.player, 1))
add_rule(world.multiworld.get_location("Queen Vanessa's Manor - Cellar", world.player),
lambda state: state.has("Progressive Painting Unlock", world.player, 1))
add_rule(world.multiworld.get_location("Queen Vanessa's Manor - Bedroom Chest", world.player),
lambda state: state.has("Progressive Painting Unlock", world.player, 1))
add_rule(world.multiworld.get_location("Queen Vanessa's Manor - Hall Chest", world.player),
lambda state: state.has("Progressive Painting Unlock", world.player, 1))
add_rule(world.multiworld.get_location("Queen Vanessa's Manor - Chandelier", world.player),
lambda state: state.has("Progressive Painting Unlock", world.player, 1))
add_rule(world.multiworld.get_location("Subcon Forest - Burning House", world.player),
lambda state: state.has("Progressive Painting Unlock", world.player, 2))
add_rule(world.multiworld.get_location("Subcon Forest - Burning Tree Climb", world.player),
lambda state: state.has("Progressive Painting Unlock", world.player, 2))
add_rule(world.multiworld.get_location("Subcon Forest - Burning Stump Chest", world.player),
lambda state: state.has("Progressive Painting Unlock", world.player, 2))
add_rule(world.multiworld.get_location("Subcon Forest - Burning Forest Treehouse", world.player),
lambda state: state.has("Progressive Painting Unlock", world.player, 2))
add_rule(world.multiworld.get_location("Subcon Forest - Spider Bone Cage A", world.player),
lambda state: state.has("Progressive Painting Unlock", world.player, 2))
add_rule(world.multiworld.get_location("Subcon Forest - Spider Bone Cage B", world.player),
lambda state: state.has("Progressive Painting Unlock", world.player, 2))
add_rule(world.multiworld.get_location("Subcon Forest - Triple Spider Bounce", world.player),
lambda state: state.has("Progressive Painting Unlock", world.player, 2))
add_rule(world.multiworld.get_location("Subcon Forest - Noose Treehouse", world.player),
lambda state: state.has("Progressive Painting Unlock", world.player, 2))
add_rule(world.multiworld.get_location("Subcon Forest - Long Tree Climb Chest", world.player),
lambda state: state.has("Progressive Painting Unlock", world.player, 2))
add_rule(world.multiworld.get_location("Subcon Forest - Infinite Yarn Bush", world.player),
lambda state: state.has("Progressive Painting Unlock", world.player, 2))
add_rule(world.multiworld.get_location("Subcon Forest - Dweller Stump", world.player),
lambda state: state.has("Progressive Painting Unlock", world.player, 3))
add_rule(world.multiworld.get_location("Subcon Forest - Dweller Floating Rocks", world.player),
lambda state: state.has("Progressive Painting Unlock", world.player, 3))
add_rule(world.multiworld.get_location("Subcon Forest - Dweller Platforming Tree A", world.player),
lambda state: state.has("Progressive Painting Unlock", world.player, 3))
add_rule(world.multiworld.get_location("Subcon Forest - Dweller Platforming Tree B", world.player),
lambda state: state.has("Progressive Painting Unlock", world.player, 3))
add_rule(world.multiworld.get_location("Subcon Forest - Giant Time Piece", world.player),
lambda state: state.has("Progressive Painting Unlock", world.player, 3))
add_rule(world.multiworld.get_location("Subcon Forest - Gallows", world.player),
lambda state: state.has("Progressive Painting Unlock", world.player, 3))
add_rule(world.multiworld.get_location("Subcon Forest - Green and Purple Dweller Rocks", world.player),
lambda state: state.has("Progressive Painting Unlock", world.player, 3))
add_rule(world.multiworld.get_location("Subcon Forest - Dweller Shack", world.player),
lambda state: state.has("Progressive Painting Unlock", world.player, 3))
add_rule(world.multiworld.get_location("Subcon Forest - Tall Tree Hookshot Swing", world.player),
lambda state: state.has("Progressive Painting Unlock", world.player, 3))
add_rule(world.multiworld.get_location("Subcon Forest - Magnet Badge Bush", world.player),
lambda state: state.has("Progressive Painting Unlock", world.player, 3))
add_rule(world.multiworld.get_location("Act Completion (Contractual Obligations)", world.player),
lambda state: state.has("Progressive Painting Unlock", world.player, 1))
add_rule(world.multiworld.get_location("Act Completion (The Subcon Well)", world.player),
lambda state: state.has("Progressive Painting Unlock", world.player, 1))
add_rule(world.multiworld.get_location("Act Completion (Toilet of Doom)", world.player),
lambda state: state.has("Progressive Painting Unlock", world.player, 1))
add_rule(world.multiworld.get_location("Act Completion (Queen Vanessa's Manor)", world.player),
lambda state: state.has("Progressive Painting Unlock", world.player, 1))

View File

@@ -8,7 +8,7 @@ from .Regions import create_region, create_regions, connect_regions, randomize_a
create_events, chapter_regions, act_chapters
from .Locations import HatInTimeLocation, location_table, get_total_locations, contract_locations, is_location_valid, \
get_location_names
get_location_names, get_tasksanity_start_id
from .Types import HatDLC, HatType, ChapterIndex
from .Options import ahit_options, slot_data_options, adjust_options
@@ -18,6 +18,7 @@ import typing
hat_craft_order: typing.Dict[int, typing.List[HatType]] = {}
hat_yarn_costs: typing.Dict[int, typing.Dict[HatType, int]] = {}
slot_data_yarn_costs: typing.Dict[int, typing.Dict[HatType, int]] = {}
chapter_timepiece_costs: typing.Dict[int, typing.Dict[ChapterIndex, int]] = {}
@@ -79,6 +80,9 @@ class HatInTimeWorld(World):
hat_yarn_costs[self.player] = {HatType.SPRINT: -1, HatType.BREWING: -1, HatType.ICE: -1,
HatType.DWELLER: -1, HatType.TIME_STOP: -1}
slot_data_yarn_costs[self.player] = {HatType.SPRINT: -1, HatType.BREWING: -1, HatType.ICE: -1,
HatType.DWELLER: -1, HatType.TIME_STOP: -1}
hat_craft_order[self.player] = [HatType.SPRINT, HatType.BREWING, HatType.ICE,
HatType.DWELLER, HatType.TIME_STOP]
@@ -167,11 +171,11 @@ class HatInTimeWorld(World):
return create_item(self, name)
def fill_slot_data(self) -> dict:
slot_data: dict = {"SprintYarnCost": hat_yarn_costs[self.player][HatType.SPRINT],
"BrewingYarnCost": hat_yarn_costs[self.player][HatType.BREWING],
"IceYarnCost": hat_yarn_costs[self.player][HatType.ICE],
"DwellerYarnCost": hat_yarn_costs[self.player][HatType.DWELLER],
"TimeStopYarnCost": hat_yarn_costs[self.player][HatType.TIME_STOP],
slot_data: dict = {"SprintYarnCost": slot_data_yarn_costs[self.player][HatType.SPRINT],
"BrewingYarnCost": slot_data_yarn_costs[self.player][HatType.BREWING],
"IceYarnCost": slot_data_yarn_costs[self.player][HatType.ICE],
"DwellerYarnCost": slot_data_yarn_costs[self.player][HatType.DWELLER],
"TimeStopYarnCost": slot_data_yarn_costs[self.player][HatType.TIME_STOP],
"Chapter1Cost": chapter_timepiece_costs[self.player][ChapterIndex.MAFIA],
"Chapter2Cost": chapter_timepiece_costs[self.player][ChapterIndex.BIRDS],
"Chapter3Cost": chapter_timepiece_costs[self.player][ChapterIndex.SUBCON],
@@ -203,7 +207,7 @@ class HatInTimeWorld(World):
def extend_hint_information(self, hint_data: typing.Dict[int, typing.Dict[int, str]]):
new_hint_data = {}
alpine_regions = ["The Birdhouse", "The Lava Cake", "The Windmill", "The Twilight Bell"]
alpine_regions = ["The Birdhouse", "The Lava Cake", "The Windmill", "The Twilight Bell", "Alpine Skyline Area"]
metro_regions = ["Yellow Overpass Station", "Green Clean Station", "Bluefin Tunnel", "Pink Paw Station"]
for key, data in location_table.items():
@@ -226,7 +230,7 @@ class HatInTimeWorld(World):
if self.multiworld.EnableDLC1[self.player].value > 0 and self.multiworld.Tasksanity[self.player].value > 0:
ship_shape_region = self.get_shuffled_region("Ship Shape")
id_start: int = 300204
id_start: int = get_tasksanity_start_id()
for i in range(self.multiworld.TasksanityCheckCount[self.player].value):
new_hint_data[id_start+i] = ship_shape_region
@@ -248,7 +252,8 @@ class HatInTimeWorld(World):
max_cost: int = 0
for i in range(5):
cost = mw.random.randint(min(min_yarn_cost, max_yarn_cost), max(max_yarn_cost, min_yarn_cost))
hat_yarn_costs[self.player][HatType(i)] = cost
hat_yarn_costs[self.player][HatType(i)] = cost + max_cost
slot_data_yarn_costs[self.player][HatType(i)] = cost
max_cost += cost
available_yarn = mw.YarnAvailable[p].value