mirror of
https://github.com/ArchipelagoMW/Archipelago.git
synced 2026-03-23 20:33:22 -07:00
0.9b - cleanup + expanded logic difficulty
This commit is contained in:
@@ -19,11 +19,11 @@ def item_dlc_enabled(world: World, name: str) -> bool:
|
||||
|
||||
if data.dlc_flags == HatDLC.none:
|
||||
return True
|
||||
elif data.dlc_flags == HatDLC.dlc1 and world.multiworld.EnableDLC1[world.player].value > 0:
|
||||
elif data.dlc_flags == HatDLC.dlc1 and world.is_dlc1():
|
||||
return True
|
||||
elif data.dlc_flags == HatDLC.dlc2 and world.multiworld.EnableDLC2[world.player].value > 0:
|
||||
elif data.dlc_flags == HatDLC.dlc2 and world.is_dlc2():
|
||||
return True
|
||||
elif data.dlc_flags == HatDLC.death_wish and world.multiworld.EnableDeathWish[world.player].value > 0:
|
||||
elif data.dlc_flags == HatDLC.death_wish and world.is_dw():
|
||||
return True
|
||||
|
||||
return False
|
||||
@@ -31,10 +31,10 @@ def item_dlc_enabled(world: World, name: str) -> bool:
|
||||
|
||||
def get_total_time_pieces(world: World) -> int:
|
||||
count: int = 40
|
||||
if world.multiworld.EnableDLC1[world.player].value > 0:
|
||||
if world.is_dlc1():
|
||||
count += 6
|
||||
|
||||
if world.multiworld.EnableDLC2[world.player].value > 0:
|
||||
if world.is_dlc2():
|
||||
count += 10
|
||||
|
||||
return min(40+world.multiworld.MaxExtraTimePieces[world.player].value, count)
|
||||
@@ -110,7 +110,7 @@ ahit_items = {
|
||||
"Hover Badge": ItemData(300026, ItemClassification.useful),
|
||||
"Hookshot Badge": ItemData(300027, ItemClassification.progression),
|
||||
"Item Magnet Badge": ItemData(300028, ItemClassification.useful),
|
||||
"No Bonk Badge": ItemData(300029, ItemClassification.useful),
|
||||
"No Bonk Badge": ItemData(300029, ItemClassification.progression),
|
||||
"Compass Badge": ItemData(300030, ItemClassification.useful),
|
||||
"Scooter Badge": ItemData(300031, ItemClassification.progression),
|
||||
"Badge Pin": ItemData(300043, ItemClassification.useful),
|
||||
|
||||
@@ -15,7 +15,7 @@ class LocData(NamedTuple):
|
||||
|
||||
# For UmbrellaLogic setting
|
||||
umbrella: Optional[bool] = False # Umbrella required for this check
|
||||
dweller_bell: Optional[int] = 0 # Dweller bell hit required, 1 means must hit bell, 2 means can bypass w/mask
|
||||
hit_requirement: Optional[int] = 0 # Hit required. 1 = Umbrella/Brewing only, 2 = bypass w/Dweller Mask (bells)
|
||||
|
||||
# Other
|
||||
act_complete_event: Optional[bool] = True # Only used for event locations. Copy access rule from act completion
|
||||
@@ -33,7 +33,7 @@ def get_total_locations(world: World) -> int:
|
||||
if is_location_valid(world, name):
|
||||
total += 1
|
||||
|
||||
if world.multiworld.EnableDLC1[world.player].value > 0 and world.multiworld.Tasksanity[world.player].value > 0:
|
||||
if world.is_dlc1() and world.multiworld.Tasksanity[world.player].value > 0:
|
||||
total += world.multiworld.TasksanityCheckCount[world.player].value
|
||||
|
||||
return total
|
||||
@@ -44,11 +44,11 @@ def location_dlc_enabled(world: World, location: str) -> bool:
|
||||
|
||||
if data.dlc_flags == HatDLC.none:
|
||||
return True
|
||||
elif data.dlc_flags == HatDLC.dlc1 and world.multiworld.EnableDLC1[world.player].value > 0:
|
||||
elif data.dlc_flags == HatDLC.dlc1 and world.is_dlc1():
|
||||
return True
|
||||
elif data.dlc_flags == HatDLC.dlc2 and world.multiworld.EnableDLC2[world.player].value > 0:
|
||||
elif data.dlc_flags == HatDLC.dlc2 and world.is_dlc2():
|
||||
return True
|
||||
elif data.dlc_flags == HatDLC.death_wish and world.multiworld.EnableDeathWish[world.player].value > 0:
|
||||
elif data.dlc_flags == HatDLC.death_wish and world.is_dw():
|
||||
return True
|
||||
|
||||
return False
|
||||
@@ -82,7 +82,7 @@ def get_tasksanity_start_id() -> int:
|
||||
|
||||
|
||||
ahit_locations = {
|
||||
"Spaceship - Rumbi Abuse": LocData(301000, "Spaceship", dweller_bell=1),
|
||||
"Spaceship - Rumbi Abuse": LocData(301000, "Spaceship", hit_requirement=1),
|
||||
|
||||
# 300000 range - Mafia Town/Batle of the Birds
|
||||
"Welcome to Mafia Town - Umbrella": LocData(301002, "Welcome to Mafia Town"),
|
||||
@@ -136,10 +136,10 @@ ahit_locations = {
|
||||
"Dead Bird Studio - Red Building Top": LocData(305024, "Dead Bird Studio - Elevator Area"),
|
||||
"Dead Bird Studio - Behind Water Tower": LocData(305248, "Dead Bird Studio - Elevator Area"),
|
||||
"Dead Bird Studio - Side of House": LocData(305247, "Dead Bird Studio - Elevator Area"),
|
||||
"Dead Bird Studio - DJ Grooves Sign Chest": LocData(303901, "Dead Bird Studio", umbrella=True),
|
||||
"Dead Bird Studio - Tightrope Chest": LocData(303898, "Dead Bird Studio", umbrella=True),
|
||||
"Dead Bird Studio - Tepee Chest": LocData(303899, "Dead Bird Studio", umbrella=True),
|
||||
"Dead Bird Studio - Conductor Chest": LocData(303900, "Dead Bird Studio", umbrella=True),
|
||||
"Dead Bird Studio - DJ Grooves Sign Chest": LocData(303901, "Dead Bird Studio", hit_requirement=1),
|
||||
"Dead Bird Studio - Tightrope Chest": LocData(303898, "Dead Bird Studio", hit_requirement=1),
|
||||
"Dead Bird Studio - Tepee Chest": LocData(303899, "Dead Bird Studio", hit_requirement=1),
|
||||
"Dead Bird Studio - Conductor Chest": LocData(303900, "Dead Bird Studio", hit_requirement=1),
|
||||
|
||||
"Murder on the Owl Express - Cafeteria": LocData(305313, "Murder on the Owl Express"),
|
||||
"Murder on the Owl Express - Luggage Room Top": LocData(305090, "Murder on the Owl Express"),
|
||||
@@ -223,7 +223,7 @@ ahit_locations = {
|
||||
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, paintings=1),
|
||||
"Subcon Forest - Manor Rooftop": LocData(325466, "Subcon Forest Area", hit_requirement=2, paintings=1),
|
||||
|
||||
"Subcon Forest - Infinite Yarn Bush": LocData(325478, "Subcon Forest Area",
|
||||
required_hats=[HatType.BREWING], paintings=2),
|
||||
@@ -231,15 +231,15 @@ ahit_locations = {
|
||||
"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, 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),
|
||||
"Subcon Well - Hookshot Badge Chest": LocData(324114, "The Subcon Well", hit_requirement=1, paintings=1),
|
||||
"Subcon Well - Above Chest": LocData(324612, "The Subcon Well", hit_requirement=1, paintings=1),
|
||||
"Subcon Well - On Pipe": LocData(324311, "The Subcon Well", hookshot=True, hit_requirement=1, paintings=1),
|
||||
"Subcon Well - Mushroom": LocData(325318, "The Subcon Well", hit_requirement=1, paintings=1),
|
||||
|
||||
"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),
|
||||
"Queen Vanessa's Manor - Cellar": LocData(324841, "Queen Vanessa's Manor", hit_requirement=2, paintings=1),
|
||||
"Queen Vanessa's Manor - Bedroom Chest": LocData(323808, "Queen Vanessa's Manor", hit_requirement=2, paintings=1),
|
||||
"Queen Vanessa's Manor - Hall Chest": LocData(323896, "Queen Vanessa's Manor", hit_requirement=2, paintings=1),
|
||||
"Queen Vanessa's Manor - Chandelier": LocData(325546, "Queen Vanessa's Manor", hit_requirement=2, paintings=1),
|
||||
|
||||
# 330000 range - Alpine Skyline
|
||||
"Alpine Skyline - Goat Village: Below Hookpoint": LocData(334856, "Goat Village"),
|
||||
@@ -298,26 +298,26 @@ ahit_locations = {
|
||||
"Nyakuza Metro - Main Station Dining Area": LocData(304105, "Nyakuza Free Roam", dlc_flags=HatDLC.dlc2),
|
||||
"Nyakuza Metro - Top of Ramen Shop": LocData(304104, "Nyakuza Free Roam", dlc_flags=HatDLC.dlc2),
|
||||
|
||||
"Nyakuza Metro - Yellow Overpass Station Crate": LocData(305413, "Yellow Overpass Station",
|
||||
dlc_flags=HatDLC.dlc2,
|
||||
required_hats=[HatType.BREWING]),
|
||||
"Yellow Overpass Station - Brewing Crate": LocData(305413, "Yellow Overpass Station",
|
||||
dlc_flags=HatDLC.dlc2,
|
||||
required_hats=[HatType.BREWING]),
|
||||
|
||||
"Nyakuza Metro - Bluefin Tunnel Cat Vacuum": LocData(305111, "Bluefin Tunnel", dlc_flags=HatDLC.dlc2),
|
||||
"Bluefin Tunnel - Cat Vacuum": LocData(305111, "Bluefin Tunnel", dlc_flags=HatDLC.dlc2),
|
||||
|
||||
"Nyakuza Metro - Pink Paw Station Cat Vacuum": LocData(305110, "Pink Paw Station",
|
||||
dlc_flags=HatDLC.dlc2,
|
||||
hookshot=True,
|
||||
required_hats=[HatType.DWELLER]),
|
||||
"Pink Paw Station - Cat Vacuum": LocData(305110, "Pink Paw Station",
|
||||
dlc_flags=HatDLC.dlc2,
|
||||
hookshot=True,
|
||||
required_hats=[HatType.DWELLER]),
|
||||
|
||||
"Nyakuza Metro - Pink Paw Station Behind Fan": LocData(304106, "Pink Paw Station",
|
||||
dlc_flags=HatDLC.dlc2,
|
||||
hookshot=True,
|
||||
required_hats=[HatType.TIME_STOP, HatType.DWELLER]),
|
||||
"Pink Paw Station - Behind Fan": LocData(304106, "Pink Paw Station",
|
||||
dlc_flags=HatDLC.dlc2,
|
||||
hookshot=True,
|
||||
required_hats=[HatType.TIME_STOP, HatType.DWELLER]),
|
||||
}
|
||||
|
||||
act_completions = {
|
||||
# 310000 range - Act Completions
|
||||
"Act Completion (Time Rift - Gallery)": LocData(312758, "Time Rift - Gallery", required_hats=[HatType.BREWING]),
|
||||
"Act Completion (Time Rift - Gallery)": LocData(312758, "Time Rift - Gallery"),
|
||||
"Act Completion (Time Rift - The Lab)": LocData(312838, "Time Rift - The Lab"),
|
||||
|
||||
"Act Completion (Welcome to Mafia Town)": LocData(311771, "Welcome to Mafia Town"),
|
||||
@@ -331,7 +331,7 @@ act_completions = {
|
||||
"Act Completion (Time Rift - Sewers)": LocData(312484, "Time Rift - Sewers"),
|
||||
"Act Completion (Time Rift - Mafia of Cooks)": LocData(311855, "Time Rift - Mafia of Cooks"),
|
||||
|
||||
"Act Completion (Dead Bird Studio)": LocData(311383, "Dead Bird Studio", umbrella=True),
|
||||
"Act Completion (Dead Bird Studio)": LocData(311383, "Dead Bird Studio", hit_requirement=1),
|
||||
"Act Completion (Murder on the Owl Express)": LocData(311544, "Murder on the Owl Express"),
|
||||
"Act Completion (Picture Perfect)": LocData(311587, "Picture Perfect"),
|
||||
"Act Completion (Train Rush)": LocData(312481, "Train Rush", hookshot=True),
|
||||
@@ -389,7 +389,7 @@ act_completions = {
|
||||
|
||||
"Act Completion (Green Clean Manhole)": LocData(311388, "Green Clean Manhole",
|
||||
dlc_flags=HatDLC.dlc2,
|
||||
required_hats=[HatType.ICE, HatType.DWELLER]),
|
||||
required_hats=[HatType.ICE]),
|
||||
|
||||
"Act Completion (Bluefin Tunnel)": LocData(311208, "Bluefin Tunnel", dlc_flags=HatDLC.dlc2),
|
||||
|
||||
@@ -498,7 +498,8 @@ shop_locations = {
|
||||
"Yellow Overpass Station - Yellow Ticket Booth": LocData(301014, "Yellow Overpass Station", dlc_flags=HatDLC.dlc2),
|
||||
"Green Clean Station - Green Ticket Booth": LocData(301015, "Green Clean Station", dlc_flags=HatDLC.dlc2),
|
||||
"Bluefin Tunnel - Blue Ticket Booth": LocData(301016, "Bluefin Tunnel", dlc_flags=HatDLC.dlc2),
|
||||
"Pink Paw Station - Pink Ticket Booth": LocData(301017, "Pink Paw Station", dlc_flags=HatDLC.dlc2),
|
||||
"Pink Paw Station - Pink Ticket Booth": LocData(301017, "Pink Paw Station", dlc_flags=HatDLC.dlc2,
|
||||
hookshot=True, required_hats=[HatType.DWELLER]),
|
||||
|
||||
"Main Station Thug A - Item 1": LocData(301048, "Nyakuza Free Roam", dlc_flags=HatDLC.dlc2,
|
||||
nyakuza_thug="Hat_NPC_NyakuzaShop_0"),
|
||||
@@ -647,6 +648,7 @@ tihs_locations = [
|
||||
|
||||
event_locs = {
|
||||
"HUMT Access": LocData(0, "Heating Up Mafia Town", act_complete_event=False),
|
||||
"Subcon Forest Access": LocData(0, "Subcon Forest Area", act_complete_event=False),
|
||||
"Birdhouse Cleared": LocData(0, "The Birdhouse"),
|
||||
"Lava Cake Cleared": LocData(0, "The Lava Cake"),
|
||||
"Windmill Cleared": LocData(0, "The Windmill"),
|
||||
|
||||
@@ -93,7 +93,7 @@ class NoFreeRoamFinale(Toggle):
|
||||
|
||||
|
||||
class LogicDifficulty(Choice):
|
||||
"""Choose the difficulty setting for logic. Note that Hard or above will force SDJ logic on."""
|
||||
"""Choose the difficulty setting for logic."""
|
||||
display_name = "Logic Difficulty"
|
||||
option_normal = 0
|
||||
option_hard = 1
|
||||
@@ -101,12 +101,36 @@ class LogicDifficulty(Choice):
|
||||
default = 0
|
||||
|
||||
|
||||
class KnowledgeChecks(Toggle):
|
||||
"""Put tricks into logic that are not necessarily difficult,
|
||||
but require knowledge that is not obvious or commonly known. Can include glitches such as No Bonk Surfing.
|
||||
This option will be forced on if logic difficulty is at least hard."""
|
||||
display_name = "Knowledge Checks"
|
||||
default = 0
|
||||
|
||||
|
||||
class RandomizeHatOrder(Toggle):
|
||||
"""Randomize the order that hats are stitched in."""
|
||||
display_name = "Randomize Hat Order"
|
||||
default = 1
|
||||
|
||||
|
||||
class YarnBalancePercent(Range):
|
||||
"""How much (in percentage) of the yarn in the pool that will be progression balanced."""
|
||||
display_name = "Yarn Balance Percentage"
|
||||
default = 20
|
||||
range_start = 0
|
||||
range_end = 100
|
||||
|
||||
|
||||
class TimePieceBalancePercent(Range):
|
||||
"""How much (in percentage) of time pieces in the pool that will be progression balanced."""
|
||||
display_name = "Time Piece Balance Percentage"
|
||||
default = 35
|
||||
range_start = 0
|
||||
range_end = 100
|
||||
|
||||
|
||||
class UmbrellaLogic(Toggle):
|
||||
"""Makes Hat Kid's default punch attack do absolutely nothing, making the Umbrella much more relevant and useful"""
|
||||
display_name = "Umbrella Logic"
|
||||
@@ -161,12 +185,6 @@ class StartingChapter(Choice):
|
||||
default = 1
|
||||
|
||||
|
||||
class SDJLogic(Toggle):
|
||||
"""Allow the SDJ (Sprint Double Jump) technique to be considered in logic."""
|
||||
display_name = "SDJ Logic"
|
||||
default = 0
|
||||
|
||||
|
||||
class CTRWithSprint(Toggle):
|
||||
"""If enabled, clearing Cheating the Race with just Sprint Hat can be in logic."""
|
||||
display_name = "Cheating the Race with Sprint Hat"
|
||||
@@ -445,6 +463,9 @@ ahit_options: typing.Dict[str, type(Option)] = {
|
||||
"VanillaAlpine": VanillaAlpine,
|
||||
"NoFreeRoamFinale": NoFreeRoamFinale,
|
||||
"LogicDifficulty": LogicDifficulty,
|
||||
"KnowledgeChecks": KnowledgeChecks,
|
||||
"YarnBalancePercent": YarnBalancePercent,
|
||||
"TimePieceBalancePercent": TimePieceBalancePercent,
|
||||
"RandomizeHatOrder": RandomizeHatOrder,
|
||||
"UmbrellaLogic": UmbrellaLogic,
|
||||
"StartWithCompassBadge": StartWithCompassBadge,
|
||||
@@ -453,7 +474,6 @@ ahit_options: typing.Dict[str, type(Option)] = {
|
||||
"ShuffleActContracts": ShuffleActContracts,
|
||||
"ShuffleSubconPaintings": ShuffleSubconPaintings,
|
||||
"StartingChapter": StartingChapter,
|
||||
"SDJLogic": SDJLogic,
|
||||
"CTRWithSprint": CTRWithSprint,
|
||||
|
||||
"EnableDLC1": EnableDLC1,
|
||||
@@ -502,13 +522,13 @@ slot_data_options: typing.Dict[str, type(Option)] = {
|
||||
"ActRandomizer": ActRandomizer,
|
||||
"ShuffleAlpineZiplines": ShuffleAlpineZiplines,
|
||||
"LogicDifficulty": LogicDifficulty,
|
||||
"KnowledgeChecks": KnowledgeChecks,
|
||||
"RandomizeHatOrder": RandomizeHatOrder,
|
||||
"UmbrellaLogic": UmbrellaLogic,
|
||||
"CompassBadgeMode": CompassBadgeMode,
|
||||
"ShuffleStorybookPages": ShuffleStorybookPages,
|
||||
"ShuffleActContracts": ShuffleActContracts,
|
||||
"ShuffleSubconPaintings": ShuffleSubconPaintings,
|
||||
"SDJLogic": SDJLogic,
|
||||
|
||||
"EnableDLC1": EnableDLC1,
|
||||
"Tasksanity": Tasksanity,
|
||||
|
||||
@@ -250,7 +250,6 @@ chapter_finales = [
|
||||
# entrance: region
|
||||
blacklisted_acts = {
|
||||
"Battle of the Birds - Finale A": "Award Ceremony",
|
||||
"Time's End - Act 1": "The Finale",
|
||||
}
|
||||
|
||||
|
||||
@@ -359,7 +358,7 @@ def create_regions(world: World):
|
||||
create_region_and_connect(w, "The Finale", "Time's End - Act 1", times_end)
|
||||
|
||||
# ------------------------------------------- DLC1 ------------------------------------------------- #
|
||||
if mw.EnableDLC1[p].value > 0:
|
||||
if w.is_dlc1():
|
||||
arctic_cruise = create_region_and_connect(w, "The Arctic Cruise", "Telescope -> The Arctic Cruise", spaceship)
|
||||
cruise_ship = create_region(w, "Cruise Ship")
|
||||
|
||||
@@ -382,7 +381,7 @@ def create_regions(world: World):
|
||||
|
||||
connect_regions(mw.get_region("Cruise Ship", p), badge_seller, "CS -> Badge Seller", p)
|
||||
|
||||
if mw.EnableDLC2[p].value > 0:
|
||||
if w.is_dlc2():
|
||||
nyakuza_metro = create_region_and_connect(w, "Nyakuza Metro", "Telescope -> Nyakuza Metro", spaceship)
|
||||
metro_freeroam = create_region_and_connect(w, "Nyakuza Free Roam", "Nyakuza Metro - Free Roam", nyakuza_metro)
|
||||
create_region_and_connect(w, "Rush Hour", "Nyakuza Metro - Finale", nyakuza_metro)
|
||||
@@ -471,36 +470,6 @@ def randomize_act_entrances(world: World):
|
||||
# Look for candidates to map this act to
|
||||
candidate_list: typing.List[Region] = []
|
||||
for candidate in region_list:
|
||||
|
||||
if world.multiworld.VanillaAlpine[world.player].value > 0 and region.name == "Alpine Free Roam" \
|
||||
or world.multiworld.VanillaAlpine[world.player].value == 2 and region.name == "The Illness has Spread":
|
||||
candidate_list.clear()
|
||||
candidate_list.append(region)
|
||||
break
|
||||
|
||||
if world.multiworld.VanillaAlpine[world.player].value > 0 and candidate.name == "Alpine Free Roam" \
|
||||
or world.multiworld.VanillaAlpine[world.player].value == 2 and candidate.name == "The Illness has Spread":
|
||||
continue
|
||||
|
||||
if world.multiworld.VanillaMetro[world.player].value > 0 and region.name == "Nyakuza Free Roam":
|
||||
candidate_list.clear()
|
||||
candidate_list.append(region)
|
||||
break
|
||||
|
||||
if world.multiworld.VanillaMetro[world.player].value > 0 and candidate.name == "Nyakuza Free Roam":
|
||||
continue
|
||||
|
||||
if candidate.name == "Rush Hour" and world.multiworld.EndGoal[world.player].value == 2 or \
|
||||
world.multiworld.VanillaMetro[world.player].value == 2:
|
||||
continue
|
||||
|
||||
if region.name == "Rush Hour":
|
||||
if world.multiworld.EndGoal[world.player].value == 2 or \
|
||||
world.multiworld.VanillaMetro[world.player].value == 2:
|
||||
candidate_list.clear()
|
||||
candidate_list.append(region)
|
||||
break
|
||||
|
||||
# We're mapping something to the first act, make sure it is valid
|
||||
if not has_guaranteed:
|
||||
if candidate.name not in guaranteed_first_acts:
|
||||
@@ -618,6 +587,19 @@ def is_act_blacklisted(world: World, name: str) -> bool:
|
||||
if name == "The Finale":
|
||||
return world.multiworld.EndGoal[world.player].value == 1
|
||||
|
||||
if name == "Alpine Free Roam":
|
||||
return world.multiworld.VanillaAlpine[world.player].value > 0
|
||||
|
||||
if name == "The Illness has Spread":
|
||||
return world.multiworld.VanillaAlpine[world.player].value == 2
|
||||
|
||||
if name == "Nyakuza Free Roam":
|
||||
return world.multiworld.VanillaMetro[world.player].value > 0
|
||||
|
||||
if name == "Rush Hour":
|
||||
return world.multiworld.EndGoal[world.player].value == 2 \
|
||||
or world.multiworld.VanillaMetro[world.player].value == 2
|
||||
|
||||
return name in blacklisted_acts.values()
|
||||
|
||||
|
||||
|
||||
@@ -49,10 +49,60 @@ def can_sdj(state: CollectionState, world: World):
|
||||
return can_use_hat(state, world, HatType.SPRINT)
|
||||
|
||||
|
||||
def painting_logic(world: World) -> bool:
|
||||
return world.multiworld.ShuffleSubconPaintings[world.player].value > 0
|
||||
|
||||
|
||||
def is_player_knowledgeable(world: World) -> bool:
|
||||
return world.multiworld.KnowledgeChecks[world.player].value > 0
|
||||
|
||||
|
||||
# 0 = Normal, 1 = Hard, 2 = Expert
|
||||
def get_difficulty(world: World) -> int:
|
||||
return world.multiworld.LogicDifficulty[world.player].value
|
||||
|
||||
|
||||
def has_paintings(state: CollectionState, world: World, count: int) -> bool:
|
||||
if not painting_logic(world):
|
||||
return True
|
||||
|
||||
# Cherry Hover
|
||||
if get_difficulty(world) == 2:
|
||||
return True
|
||||
|
||||
# All paintings can be skipped with No Bonk, very easily, if the player knows
|
||||
if is_player_knowledgeable(world) and can_surf(state, world):
|
||||
return True
|
||||
|
||||
paintings: int = state.count("Progressive Painting Unlock", world.player)
|
||||
|
||||
if is_player_knowledgeable(world):
|
||||
# Green paintings can also be skipped very easily without No Bonk
|
||||
if paintings >= 1 and count == 3:
|
||||
return True
|
||||
|
||||
return paintings >= count
|
||||
|
||||
|
||||
def zipline_logic(world: World) -> bool:
|
||||
return world.multiworld.ShuffleAlpineZiplines[world.player].value > 0
|
||||
|
||||
|
||||
def can_use_hookshot(state: CollectionState, world: World):
|
||||
return state.has("Hookshot Badge", world.player)
|
||||
|
||||
|
||||
def can_hit(state: CollectionState, world: World):
|
||||
if world.multiworld.UmbrellaLogic[world.player].value == 0:
|
||||
return True
|
||||
|
||||
return state.has("Umbrella", world.player) or can_use_hat(state, world, HatType.BREWING)
|
||||
|
||||
|
||||
def can_surf(state: CollectionState, world: World):
|
||||
return state.has("No Bonk Badge", world.player)
|
||||
|
||||
|
||||
def has_relic_combo(state: CollectionState, world: World, relic: str) -> bool:
|
||||
return state.has_group(relic, world.player, len(world.item_name_groups[relic]))
|
||||
|
||||
@@ -61,13 +111,6 @@ def get_relic_count(state: CollectionState, world: World, relic: str) -> int:
|
||||
return state.count_group(relic, world.player)
|
||||
|
||||
|
||||
def can_hit_bells(state: CollectionState, world: World):
|
||||
if world.multiworld.UmbrellaLogic[world.player].value == 0:
|
||||
return True
|
||||
|
||||
return state.has("Umbrella", world.player) or can_use_hat(state, world, HatType.BREWING)
|
||||
|
||||
|
||||
# Only use for rifts
|
||||
def can_clear_act(state: CollectionState, world: World, act_entrance: str) -> bool:
|
||||
entrance: Entrance = world.multiworld.get_entrance(act_entrance, world.player)
|
||||
@@ -98,9 +141,6 @@ def can_clear_metro(state: CollectionState, world: World) -> bool:
|
||||
|
||||
|
||||
def set_rules(world: World):
|
||||
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(world.multiworld.StartingChapter[world.player].value)
|
||||
world.set_chapter_cost(starting_chapter, 0)
|
||||
@@ -114,25 +154,26 @@ def set_rules(world: World):
|
||||
final_chapter = ChapterIndex.METRO
|
||||
chapter_list.append(ChapterIndex.FINALE)
|
||||
|
||||
if dlc1:
|
||||
if world.is_dlc1():
|
||||
chapter_list.append(ChapterIndex.CRUISE)
|
||||
|
||||
if dlc2 and final_chapter is not ChapterIndex.METRO:
|
||||
if world.is_dlc2() and final_chapter is not ChapterIndex.METRO:
|
||||
chapter_list.append(ChapterIndex.METRO)
|
||||
|
||||
chapter_list.remove(starting_chapter)
|
||||
world.multiworld.random.shuffle(chapter_list)
|
||||
|
||||
if starting_chapter is not ChapterIndex.ALPINE and (dlc1 or dlc2):
|
||||
if starting_chapter is not ChapterIndex.ALPINE and (world.is_dlc1() or world.is_dlc2()):
|
||||
index1: int = 69
|
||||
index2: int = 69
|
||||
pos: int
|
||||
lowest_index: int
|
||||
chapter_list.remove(ChapterIndex.ALPINE)
|
||||
|
||||
if dlc1:
|
||||
if world.is_dlc1():
|
||||
index1 = chapter_list.index(ChapterIndex.CRUISE)
|
||||
|
||||
if dlc2 and final_chapter is not ChapterIndex.METRO:
|
||||
if world.is_dlc2() and final_chapter is not ChapterIndex.METRO:
|
||||
index2 = chapter_list.index(ChapterIndex.METRO)
|
||||
|
||||
lowest_index = min(index1, index2)
|
||||
@@ -143,6 +184,14 @@ def set_rules(world: World):
|
||||
|
||||
chapter_list.insert(pos, ChapterIndex.ALPINE)
|
||||
|
||||
if world.is_dlc1() and world.is_dlc2() and final_chapter is not ChapterIndex.METRO:
|
||||
chapter_list.remove(ChapterIndex.METRO)
|
||||
index = chapter_list.index(ChapterIndex.CRUISE)
|
||||
if index >= len(chapter_list):
|
||||
chapter_list.append(ChapterIndex.METRO)
|
||||
else:
|
||||
chapter_list.insert(world.multiworld.random.randint(index+1, len(chapter_list)), ChapterIndex.METRO)
|
||||
|
||||
lowest_cost: int = world.multiworld.LowestChapterCost[world.player].value
|
||||
highest_cost: int = world.multiworld.HighestChapterCost[world.player].value
|
||||
|
||||
@@ -190,12 +239,12 @@ def set_rules(world: World):
|
||||
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:
|
||||
if world.is_dlc1():
|
||||
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:
|
||||
if world.is_dlc2():
|
||||
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))
|
||||
@@ -237,28 +286,21 @@ def set_rules(world: World):
|
||||
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)
|
||||
add_rule(location, lambda state, paintings=data.paintings: has_paintings(state, world, 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, world))
|
||||
else: # Can bypass with Dweller Mask
|
||||
add_rule(location, lambda state: can_hit_bells(state, world) or can_use_hat(state, world, HatType.DWELLER))
|
||||
if data.hit_requirement > 0:
|
||||
if data.hit_requirement == 1:
|
||||
add_rule(location, lambda state: can_hit(state, world))
|
||||
else: # Can bypass with Dweller Mask (dweller bells)
|
||||
add_rule(location, lambda state: can_hit(state, world) or can_use_hat(state, world, HatType.DWELLER))
|
||||
|
||||
if get_difficulty(world) >= 1:
|
||||
world.multiworld.KnowledgeChecks[world.player].value = 1
|
||||
|
||||
set_specific_rules(world)
|
||||
|
||||
if world.multiworld.LogicDifficulty[world.player].value >= 1:
|
||||
world.multiworld.SDJLogic[world.player].value = 1
|
||||
|
||||
if world.multiworld.SDJLogic[world.player].value > 0:
|
||||
set_sdj_rules(world)
|
||||
|
||||
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:
|
||||
if "Arctic Cruise" in key and not world.is_dlc1():
|
||||
continue
|
||||
|
||||
i: int = 1
|
||||
@@ -304,11 +346,6 @@ def set_rules(world: World):
|
||||
|
||||
|
||||
def set_specific_rules(world: World):
|
||||
dlc1: bool = bool(world.multiworld.EnableDLC1[world.player].value > 0)
|
||||
|
||||
add_rule(world.multiworld.get_entrance("Alpine Skyline - Finale", world.player),
|
||||
lambda state: can_clear_alpine(state, world))
|
||||
|
||||
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)))
|
||||
@@ -316,37 +353,158 @@ def set_specific_rules(world: World):
|
||||
add_rule(world.multiworld.get_location("Spaceship - Rumbi Abuse", world.player),
|
||||
lambda state: state.has("Time Piece", world.player, 4))
|
||||
|
||||
# Normal logic
|
||||
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))
|
||||
set_mafia_town_rules(world)
|
||||
set_subcon_rules(world)
|
||||
set_alps_rules(world)
|
||||
|
||||
add_rule(world.multiworld.get_location("Alpine Skyline - Yellow Band Hills", world.player),
|
||||
lambda state: can_use_hat(state, world, HatType.BREWING))
|
||||
if world.is_dlc1():
|
||||
set_dlc1_rules(world)
|
||||
|
||||
if dlc1:
|
||||
add_rule(world.multiworld.get_location("Act Completion (Time Rift - Deep Sea)", world.player),
|
||||
lambda state: can_use_hat(state, world, HatType.DWELLER))
|
||||
if world.is_dlc2():
|
||||
set_dlc2_rules(world)
|
||||
|
||||
add_rule(world.multiworld.get_location("Rock the Boat - Post Captain Rescue", world.player),
|
||||
lambda state: can_use_hat(state, world, HatType.ICE))
|
||||
difficulty: int = get_difficulty(world)
|
||||
if is_player_knowledgeable(world) or difficulty >= 1:
|
||||
set_knowledge_rules(world)
|
||||
|
||||
add_rule(world.multiworld.get_location("Act Completion (Rock the Boat)", world.player),
|
||||
lambda state: can_use_hat(state, world, HatType.ICE))
|
||||
if difficulty == 0:
|
||||
set_normal_rules(world)
|
||||
|
||||
# Hard logic, includes SDJ stuff
|
||||
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")
|
||||
if difficulty >= 1:
|
||||
set_hard_rules(world)
|
||||
|
||||
# Expert logic
|
||||
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(world.multiworld.get_entrance("-> The Twilight Bell", world.player),
|
||||
if difficulty >= 2:
|
||||
set_expert_rules(world)
|
||||
|
||||
|
||||
def set_normal_rules(world: World):
|
||||
# Hard: get to Birdhouse without Brewing Hat
|
||||
add_rule(world.multiworld.get_entrance("-> The Birdhouse", world.player),
|
||||
lambda state: can_use_hat(state, world, HatType.BREWING))
|
||||
|
||||
add_rule(world.multiworld.get_location("Alpine Skyline - Yellow Band Hills", world.player),
|
||||
lambda state: can_use_hat(state, world, HatType.BREWING))
|
||||
|
||||
# Hard: gallery without Brewing Hat
|
||||
add_rule(world.multiworld.get_location("Act Completion (Time Rift - Gallery)", world.player),
|
||||
lambda state: can_use_hat(state, world, HatType.BREWING))
|
||||
|
||||
if world.is_dlc1():
|
||||
# Hard: clear Deep Sea without Dweller Mask
|
||||
add_rule(world.multiworld.get_location("Act Completion (Time Rift - Deep Sea)", world.player),
|
||||
lambda state: can_use_hat(state, world, HatType.DWELLER))
|
||||
|
||||
# Hard: clear Rock the Boat without Ice Hat
|
||||
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(world.multiworld.get_location("Act Completion (Rock the Boat)", world.player),
|
||||
lambda state: can_use_hat(state, world, HatType.ICE))
|
||||
|
||||
if world.is_dlc2():
|
||||
# Hard: clear Green Clean Manhole without Dweller Mask
|
||||
add_rule(world.multiworld.get_location("Act Completion (Green Clean Manhole)", world.player),
|
||||
lambda state: can_use_hat(state, world, HatType.DWELLER))
|
||||
|
||||
|
||||
def set_hard_rules(world: World):
|
||||
# Hard: clear Time Rift - The Twilight Bell with Sprint+Scooter only
|
||||
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")
|
||||
|
||||
# Hard: Cross Subcon boss arena gap with No Bonk + SDJ,
|
||||
# allowing access to the boss arena chest, and Toilet of Doom without Hookshot
|
||||
# Doing this in reverse from YCHE is expert logic, which expects you to cherry hover
|
||||
add_rule(world.multiworld.get_location("Act Completion (Toilet of Doom)", world.player),
|
||||
lambda state: can_surf(state, world) and can_sdj(state, world) and can_hit(state, world), "or")
|
||||
|
||||
add_rule(world.multiworld.get_location("Subcon Forest - Boss Arena Chest", world.player),
|
||||
lambda state: can_surf(state, world) and can_sdj(state, world), "or")
|
||||
|
||||
add_rule(world.multiworld.get_location("Subcon Forest - Long Tree Climb Chest", world.player),
|
||||
lambda state: can_sdj(state, world)
|
||||
and has_paintings(state, world, 2), "or")
|
||||
|
||||
add_rule(world.multiworld.get_location("Alpine Skyline - The Birdhouse: Dweller Platforms Relic", world.player),
|
||||
lambda state: can_sdj(state, world), "or")
|
||||
|
||||
add_rule(world.multiworld.get_location("Act Completion (Time Rift - Curly Tail Trail)", world.player),
|
||||
lambda state: can_sdj(state, world), "or")
|
||||
|
||||
|
||||
def set_expert_rules(world: World):
|
||||
# Expert: get to and clear Twilight Bell without Dweller Mask using SDJ. Brewing Hat required to complete act.
|
||||
add_rule(world.multiworld.get_location("Alpine Skyline - The Twilight Path", world.player),
|
||||
lambda state: can_sdj(state, world)
|
||||
and (not zipline_logic(world) or state.has("Zipline Unlock - The Twilight Bell Path", world.player)), "or")
|
||||
|
||||
add_rule(world.multiworld.get_entrance("-> The Twilight Bell", world.player),
|
||||
lambda state: can_sdj(state, world) and can_use_hookshot(state, world)
|
||||
and (not zipline_logic(world) or state.has("Zipline Unlock - The Twilight Bell Path", world.player)), "or")
|
||||
|
||||
add_rule(world.multiworld.get_location("Act Completion (The Twilight Bell)", world.player),
|
||||
lambda state: can_sdj(state, world) and can_use_hat(state, world, HatType.BREWING), "or")
|
||||
|
||||
# Expert: enter and clear The Subcon Well with No Bonk Badge only
|
||||
for loc in world.multiworld.get_region("The Subcon Well", world.player).locations:
|
||||
add_rule(loc, lambda state: can_surf(state, world) and has_paintings(state, world, 1), "or")
|
||||
|
||||
# Expert: Cherry Hovering
|
||||
connect_regions(world.multiworld.get_region("Your Contract has Expired", world.player),
|
||||
world.multiworld.get_region("Subcon Forest Area", world.player),
|
||||
"Subcon Forest Entrance YCHE", world.player)
|
||||
|
||||
set_rule(world.multiworld.get_location("Act Completion (Toilet of Doom)", world.player),
|
||||
lambda state: can_hit(state, world))
|
||||
|
||||
set_rule(world.multiworld.get_location("Subcon Forest - Boss Arena Chest", world.player), lambda state: True)
|
||||
|
||||
# Manor hover with 1 painting unlock
|
||||
for loc in world.multiworld.get_region("Queen Vanessa's Manor", world.player).locations:
|
||||
set_rule(loc, lambda state: not painting_logic(world)
|
||||
or state.count("Progressive Painting Unlock", world.player) >= 1)
|
||||
|
||||
set_rule(world.multiworld.get_location("Subcon Forest - Manor Rooftop", world.player),
|
||||
lambda state: not painting_logic(world)
|
||||
or state.count("Progressive Painting Unlock", world.player) >= 1)
|
||||
|
||||
|
||||
def set_knowledge_rules(world: World):
|
||||
# Can jump down from HQ to get these
|
||||
add_rule(world.multiworld.get_location("Mafia Town - Clock Tower Chest", world.player),
|
||||
lambda state: state.can_reach("Act Completion (Heating Up Mafia Town)", "Location", world.player)
|
||||
or state.can_reach("Cheating the Race", "Region", world.player)
|
||||
or state.can_reach("The Golden Vault", "Region", world.player), "or")
|
||||
|
||||
add_rule(world.multiworld.get_location("Mafia Town - Top of Ruined Tower", world.player),
|
||||
lambda state: state.can_reach("Act Completion (Heating Up Mafia Town)", "Location", world.player)
|
||||
or state.can_reach("Cheating the Race", "Region", world.player)
|
||||
or state.can_reach("The Golden Vault", "Region", world.player), "or")
|
||||
|
||||
# Dweller Mask requirement in Pink Paw can also be skipped by jumping on lamp post.
|
||||
# The item behind the Time Stop fan can be walked past without Time Stop hat as well.
|
||||
# (just set hookshot rule, because dweller requirement is skipped, but hookshot is still necessary)
|
||||
if world.is_dlc2():
|
||||
# There is a glitched fall damage volume near the Yellow Overpass time piece that warps the player to Pink Paw
|
||||
add_rule(world.multiworld.get_entrance("-> Pink Paw Station", world.player),
|
||||
lambda state: can_use_hookshot(state, world), "or")
|
||||
|
||||
for loc in world.multiworld.get_region("Pink Paw Station", world.player).locations:
|
||||
|
||||
# Can't jump back down to the manhole due to a fall damage trigger.
|
||||
if loc.name == "Act Completion (Pink Paw Manhole)":
|
||||
set_rule(loc, 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))
|
||||
and can_use_hat(state, world, HatType.ICE))
|
||||
|
||||
continue
|
||||
|
||||
set_rule(loc, lambda state: can_use_hookshot(state, world))
|
||||
|
||||
|
||||
def set_mafia_town_rules(world: World):
|
||||
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)
|
||||
@@ -398,15 +556,16 @@ def set_specific_rules(world: World):
|
||||
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))
|
||||
|
||||
|
||||
def set_subcon_rules(world: World):
|
||||
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))
|
||||
and (not painting_logic(world) or has_paintings(state, world, 1))
|
||||
or state.can_reach("Your Contract has Expired", "Region", world.player))
|
||||
|
||||
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))
|
||||
lambda state: can_hit(state, world))
|
||||
|
||||
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)
|
||||
@@ -424,90 +583,84 @@ def set_specific_rules(world: World):
|
||||
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 world.multiworld.ShuffleSubconPaintings[world.player].value > 0:
|
||||
if painting_logic(world):
|
||||
for key in contract_locations:
|
||||
if key == "Snatcher's Contract - The Subcon Well":
|
||||
continue
|
||||
|
||||
add_rule(world.multiworld.get_location(key, world.player),
|
||||
lambda state: state.has("Progressive Painting Unlock", world.player, 1))
|
||||
|
||||
add_rule(world.multiworld.get_location(key, world.player), lambda state: has_paintings(state, world, 1))
|
||||
|
||||
|
||||
def set_alps_rules(world: World):
|
||||
add_rule(world.multiworld.get_entrance("-> The Birdhouse", world.player),
|
||||
lambda state: can_use_hookshot(state, world))
|
||||
add_rule(world.multiworld.get_entrance("-> The Lava Cake", world.player),
|
||||
lambda state: can_use_hookshot(state, world))
|
||||
add_rule(world.multiworld.get_entrance("-> The Windmill", world.player),
|
||||
lambda state: can_use_hookshot(state, world))
|
||||
|
||||
add_rule(world.multiworld.get_entrance("-> The Twilight Bell", world.player),
|
||||
lambda state: can_use_hat(state, world, HatType.DWELLER) and can_use_hookshot(state, world))
|
||||
|
||||
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 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))
|
||||
add_rule(world.multiworld.get_entrance("Alpine Skyline - Finale", world.player),
|
||||
lambda state: can_clear_alpine(state, world))
|
||||
|
||||
# This particular item isn't present in Act 3 for some reason, yes in vanilla too
|
||||
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 zipline_logic(world):
|
||||
add_rule(world.multiworld.get_entrance("-> The Birdhouse", world.player),
|
||||
lambda state: state.has("Zipline Unlock - The Birdhouse Path", world.player))
|
||||
|
||||
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(world.multiworld.get_entrance("-> The Lava Cake", world.player),
|
||||
lambda state: state.has("Zipline Unlock - The Lava Cake Path", world.player))
|
||||
|
||||
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(world.multiworld.get_entrance("-> The Windmill", world.player),
|
||||
lambda state: state.has("Zipline Unlock - The Windmill Path", world.player))
|
||||
|
||||
add_rule(world.multiworld.get_entrance("Nyakuza Metro - Finale", world.player),
|
||||
lambda state: can_clear_metro(state, world))
|
||||
add_rule(world.multiworld.get_entrance("-> The Twilight Bell", world.player),
|
||||
lambda state: state.has("Zipline Unlock - The Twilight Bell Path", world.player))
|
||||
|
||||
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))
|
||||
add_rule(world.multiworld.get_location("Act Completion (The Illness has Spread)", world.player),
|
||||
lambda state: state.has("Zipline Unlock - The Birdhouse Path", world.player)
|
||||
and state.has("Zipline Unlock - The Lava Cake Path", world.player)
|
||||
and state.has("Zipline Unlock - The Windmill Path", world.player))
|
||||
|
||||
for key in shop_locations.keys():
|
||||
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")
|
||||
for (loc, zipline) in zipline_unlocks.items():
|
||||
add_rule(world.multiworld.get_location(loc, world.player), lambda state: state.has(zipline, world.player))
|
||||
|
||||
|
||||
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)
|
||||
and (world.multiworld.ShuffleSubconPaintings[world.player].value == 0
|
||||
or state.count("Progressive Painting Unlock", world.player) >= 2), "or")
|
||||
def set_dlc1_rules(world: World):
|
||||
add_rule(world.multiworld.get_entrance("Cruise Ship Entrance BV", world.player),
|
||||
lambda state: can_use_hookshot(state, world))
|
||||
|
||||
add_rule(world.multiworld.get_location("Subcon Forest - Green and Purple Dweller Rocks", world.player),
|
||||
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")
|
||||
|
||||
add_rule(world.multiworld.get_location("Act Completion (Time Rift - Gallery)", world.player),
|
||||
lambda state: can_sdj(state, world), "or")
|
||||
|
||||
add_rule(world.multiworld.get_location("Act Completion (Time Rift - Curly Tail Trail)", world.player),
|
||||
lambda state: can_sdj(state, world), "or")
|
||||
# This particular item isn't present in Act 3 for some reason, yes in vanilla too
|
||||
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))
|
||||
|
||||
|
||||
def set_alps_zipline_rules(world: World):
|
||||
add_rule(world.multiworld.get_entrance("-> The Birdhouse", world.player),
|
||||
lambda state: state.has("Zipline Unlock - The Birdhouse Path", world.player))
|
||||
def set_dlc2_rules(world: World):
|
||||
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(world.multiworld.get_entrance("-> The Lava Cake", world.player),
|
||||
lambda state: state.has("Zipline Unlock - The Lava Cake Path", world.player))
|
||||
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(world.multiworld.get_entrance("-> The Windmill", world.player),
|
||||
lambda state: state.has("Zipline Unlock - The Windmill Path", world.player))
|
||||
add_rule(world.multiworld.get_entrance("Nyakuza Metro - Finale", world.player),
|
||||
lambda state: can_clear_metro(state, world))
|
||||
|
||||
add_rule(world.multiworld.get_entrance("-> The Twilight Bell", world.player),
|
||||
lambda state: state.has("Zipline Unlock - The Twilight Bell Path", world.player))
|
||||
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))
|
||||
|
||||
add_rule(world.multiworld.get_location("Act Completion (The Illness has Spread)", world.player),
|
||||
lambda state: state.has("Zipline Unlock - The Birdhouse Path", world.player)
|
||||
and state.has("Zipline Unlock - The Lava Cake Path", world.player)
|
||||
and state.has("Zipline Unlock - The Windmill Path", world.player))
|
||||
|
||||
for (loc, zipline) in zipline_unlocks.items():
|
||||
add_rule(world.multiworld.get_location(loc, world.player), lambda state: state.has(zipline, world.player))
|
||||
for key in shop_locations.keys():
|
||||
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 reg_act_connection(world: World, region: typing.Union[str, Region], unlocked_entrance: typing.Union[str, Entrance]):
|
||||
@@ -575,22 +728,21 @@ def set_rift_rules(world: World, regions: typing.Dict[str, Region]):
|
||||
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))
|
||||
if painting_logic(world):
|
||||
add_rule(entrance, lambda state: has_paintings(state, world, 2))
|
||||
|
||||
for entrance in regions["Time Rift - Village"].entrances:
|
||||
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))
|
||||
if painting_logic(world):
|
||||
add_rule(entrance, lambda state: has_paintings(state, world, 2))
|
||||
|
||||
for entrance in regions["Time Rift - Sleepy Subcon"].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))
|
||||
if painting_logic(world):
|
||||
add_rule(entrance, lambda state: has_paintings(state, world, 3))
|
||||
|
||||
for entrance in regions["Time Rift - Curly Tail Trail"].entrances:
|
||||
add_rule(entrance, lambda state: state.has("Windmill Cleared", world.player))
|
||||
@@ -601,14 +753,14 @@ def set_rift_rules(world: World, regions: typing.Dict[str, Region]):
|
||||
for entrance in regions["Time Rift - Alpine Skyline"].entrances:
|
||||
add_rule(entrance, lambda state: has_relic_combo(state, world, "Crayon"))
|
||||
|
||||
if world.multiworld.EnableDLC1[world.player].value > 0:
|
||||
if world.is_dlc1() > 0:
|
||||
for entrance in regions["Time Rift - Balcony"].entrances:
|
||||
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, world, "Cake"))
|
||||
|
||||
if world.multiworld.EnableDLC2[world.player].value > 0:
|
||||
if world.is_dlc2() > 0:
|
||||
for entrance in regions["Time Rift - Rumbi Factory"].entrances:
|
||||
add_rule(entrance, lambda state: has_relic_combo(state, world, "Necklace"))
|
||||
|
||||
@@ -654,19 +806,19 @@ def set_default_rift_rules(world: World):
|
||||
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(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))
|
||||
if painting_logic(world):
|
||||
add_rule(entrance, lambda state: has_paintings(state, world, 2))
|
||||
|
||||
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(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))
|
||||
if painting_logic(world):
|
||||
add_rule(entrance, lambda state: has_paintings(state, world, 2))
|
||||
|
||||
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))
|
||||
if painting_logic(world):
|
||||
add_rule(entrance, lambda state: has_paintings(state, world, 3))
|
||||
|
||||
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))
|
||||
@@ -677,14 +829,14 @@ def set_default_rift_rules(world: World):
|
||||
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 world.multiworld.EnableDLC1[world.player].value > 0:
|
||||
if world.is_dlc1():
|
||||
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 world.multiworld.get_region("Time Rift - Deep Sea", world.player).entrances:
|
||||
add_rule(entrance, lambda state: has_relic_combo(state, world, "Cake"))
|
||||
|
||||
if world.multiworld.EnableDLC2[world.player].value > 0:
|
||||
if world.is_dlc2():
|
||||
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"))
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ class HatInTimeWorld(World):
|
||||
yarn_pool: typing.List[Item] = create_multiple_items(self, "Yarn", self.multiworld.YarnAvailable[self.player].value)
|
||||
|
||||
# 1/5 is progression balanced
|
||||
for i in range(len(yarn_pool) // 5):
|
||||
for i in range(int(len(yarn_pool) * (0.01 * self.multiworld.YarnBalancePercent[self.player].value))):
|
||||
yarn_pool[i].classification = ItemClassification.progression
|
||||
|
||||
itempool += yarn_pool
|
||||
@@ -125,17 +125,16 @@ class HatInTimeWorld(World):
|
||||
if name == "Time Piece":
|
||||
tp_count: int = 40
|
||||
max_extra: int = 0
|
||||
if self.multiworld.EnableDLC1[self.player].value > 0:
|
||||
if self.is_dlc1():
|
||||
max_extra += 6
|
||||
|
||||
if self.multiworld.EnableDLC2[self.player].value > 0:
|
||||
if self.is_dlc2():
|
||||
max_extra += 10
|
||||
|
||||
tp_count += min(max_extra, self.multiworld.MaxExtraTimePieces[self.player].value)
|
||||
tp_list: typing.List[Item] = create_multiple_items(self, name, tp_count)
|
||||
|
||||
# 1/5 is progression balanced
|
||||
for i in range(len(tp_list) // 5):
|
||||
for i in range(int(len(tp_list) * (0.01 * self.multiworld.TimePieceBalancePercent[self.player].value))):
|
||||
tp_list[i].classification = ItemClassification.progression
|
||||
|
||||
itempool += tp_list
|
||||
@@ -191,7 +190,7 @@ class HatInTimeWorld(World):
|
||||
for name in self.act_connections.keys():
|
||||
slot_data[name] = self.act_connections[name]
|
||||
|
||||
if self.multiworld.EnableDLC2[self.player].value > 0:
|
||||
if self.is_dlc2():
|
||||
for name in self.nyakuza_thug_items.keys():
|
||||
slot_data[name] = self.nyakuza_thug_items[name]
|
||||
|
||||
@@ -224,7 +223,7 @@ class HatInTimeWorld(World):
|
||||
|
||||
new_hint_data[location.address] = self.get_shuffled_region(region_name)
|
||||
|
||||
if self.multiworld.EnableDLC1[self.player].value > 0 and self.multiworld.Tasksanity[self.player].value > 0:
|
||||
if self.is_dlc1() and self.multiworld.Tasksanity[self.player].value > 0:
|
||||
ship_shape_region = self.get_shuffled_region("Ship Shape")
|
||||
id_start: int = get_tasksanity_start_id()
|
||||
for i in range(self.multiworld.TasksanityCheckCount[self.player].value):
|
||||
@@ -288,3 +287,12 @@ class HatInTimeWorld(World):
|
||||
|
||||
def get_chapter_costs(self):
|
||||
return chapter_timepiece_costs[self.player]
|
||||
|
||||
def is_dlc1(self) -> bool:
|
||||
return self.multiworld.EnableDLC1[self.player].value > 0
|
||||
|
||||
def is_dlc2(self) -> bool:
|
||||
return self.multiworld.EnableDLC2[self.player].value > 0
|
||||
|
||||
def is_dw(self) -> bool:
|
||||
return self.multiworld.EnableDeathWish[self.player].value > 0
|
||||
|
||||
Reference in New Issue
Block a user