mirror of
https://github.com/ArchipelagoMW/Archipelago.git
synced 2026-05-27 00:59:57 -07:00
change act shuffle starting acts + logic updates
This commit is contained in:
@@ -45,30 +45,30 @@ def adjust_options(world: "HatInTimeWorld"):
|
|||||||
if world.is_dlc1() and world.options.ShipShapeCustomTaskGoal <= 0:
|
if world.is_dlc1() and world.options.ShipShapeCustomTaskGoal <= 0:
|
||||||
# automatically determine task count based on Tasksanity settings
|
# automatically determine task count based on Tasksanity settings
|
||||||
if world.options.Tasksanity:
|
if world.options.Tasksanity:
|
||||||
world.options.ShipShapeCustomTaskGoal = world.options.TasksanityCheckCount * world.options.TasksanityTaskStep
|
world.options.ShipShapeCustomTaskGoal.value = world.options.TasksanityCheckCount * world.options.TasksanityTaskStep
|
||||||
else:
|
else:
|
||||||
world.options.ShipShapeCustomTaskGoal.value = 18
|
world.options.ShipShapeCustomTaskGoal.value = 18
|
||||||
|
|
||||||
# Don't allow Rush Hour goal if DLC2 content is disabled
|
# Don't allow Rush Hour goal if DLC2 content is disabled
|
||||||
if world.options.EndGoal == EndGoal.option_rush_hour and not world.options.EnableDLC2:
|
if world.options.EndGoal == EndGoal.option_rush_hour and not world.options.EnableDLC2:
|
||||||
world.options.EndGoal.value = 1
|
world.options.EndGoal.value = EndGoal.option_finale
|
||||||
|
|
||||||
# Don't allow Seal the Deal goal if Death Wish content is disabled
|
# Don't allow Seal the Deal goal if Death Wish content is disabled
|
||||||
if world.options.EndGoal == EndGoal.option_seal_the_deal and not world.is_dw():
|
if world.options.EndGoal == EndGoal.option_seal_the_deal and not world.is_dw():
|
||||||
world.options.EndGoal.value = 1
|
world.options.EndGoal.value = EndGoal.option_finale
|
||||||
|
|
||||||
if world.options.DWEnableBonus:
|
if world.options.DWEnableBonus:
|
||||||
world.options.DWAutoCompleteBonuses.value = 0
|
world.options.DWAutoCompleteBonuses.value = 0
|
||||||
|
|
||||||
if world.is_dw_only():
|
if world.is_dw_only():
|
||||||
world.options.EndGoal.value = 3
|
world.options.EndGoal.value = EndGoal.option_seal_the_deal
|
||||||
world.options.ActRandomizer.value = 0
|
world.options.ActRandomizer.value = 0
|
||||||
world.options.ShuffleAlpineZiplines.value = 0
|
world.options.ShuffleAlpineZiplines.value = 0
|
||||||
world.options.ShuffleSubconPaintings.value = 0
|
world.options.ShuffleSubconPaintings.value = 0
|
||||||
world.options.ShuffleStorybookPages.value = 0
|
world.options.ShuffleStorybookPages.value = 0
|
||||||
world.options.ShuffleActContracts.value = 0
|
world.options.ShuffleActContracts.value = 0
|
||||||
world.options.EnableDLC1.value = 0
|
world.options.EnableDLC1.value = 0
|
||||||
world.options.LogicDifficulty.value = -1
|
world.options.LogicDifficulty.value = LogicDifficulty.option_normal
|
||||||
world.options.DWTimePieceRequirement.value = 0
|
world.options.DWTimePieceRequirement.value = 0
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+139
-45
@@ -1,4 +1,4 @@
|
|||||||
from BaseClasses import Region, Entrance, ItemClassification, Location
|
from BaseClasses import Region, Entrance, ItemClassification, Location, LocationProgressType
|
||||||
from .Types import ChapterIndex, Difficulty, HatInTimeLocation, HatInTimeItem
|
from .Types import ChapterIndex, Difficulty, HatInTimeLocation, HatInTimeItem
|
||||||
from .Locations import location_table, storybook_pages, event_locs, is_location_valid, \
|
from .Locations import location_table, storybook_pages, event_locs, is_location_valid, \
|
||||||
shop_locations, TASKSANITY_START_ID, snatcher_coins, zero_jumps, zero_jumps_expert, zero_jumps_hard
|
shop_locations, TASKSANITY_START_ID, snatcher_coins, zero_jumps, zero_jumps_expert, zero_jumps_hard
|
||||||
@@ -10,6 +10,9 @@ if TYPE_CHECKING:
|
|||||||
from . import HatInTimeWorld
|
from . import HatInTimeWorld
|
||||||
|
|
||||||
|
|
||||||
|
MIN_FIRST_SPHERE_LOCATIONS = 30
|
||||||
|
|
||||||
|
|
||||||
# ChapterIndex: region
|
# ChapterIndex: region
|
||||||
chapter_regions = {
|
chapter_regions = {
|
||||||
ChapterIndex.SPACESHIP: "Spaceship",
|
ChapterIndex.SPACESHIP: "Spaceship",
|
||||||
@@ -217,17 +220,32 @@ chapter_act_info = {
|
|||||||
"Time Rift - Rumbi Factory": "Metro_CaveRift_RumbiFactory"
|
"Time Rift - Rumbi Factory": "Metro_CaveRift_RumbiFactory"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Guarantee that the first level a player can access is a location dense area beatable with no items
|
# Some of these may vary depending on options. See is_valid_first_act()
|
||||||
guaranteed_first_acts = [
|
guaranteed_first_acts = [
|
||||||
"Welcome to Mafia Town",
|
"Welcome to Mafia Town",
|
||||||
"Barrel Battle",
|
"Barrel Battle",
|
||||||
"She Came from Outer Space",
|
"She Came from Outer Space",
|
||||||
"Down with the Mafia!",
|
"Down with the Mafia!",
|
||||||
"Heating Up Mafia Town", # Removed in umbrella logic
|
"Heating Up Mafia Town",
|
||||||
"The Golden Vault",
|
"The Golden Vault",
|
||||||
|
|
||||||
"Contractual Obligations", # Removed in painting logic
|
"Dead Bird Studio",
|
||||||
"Queen Vanessa's Manor", # Removed in umbrella/painting logic
|
"Murder on the Owl Express",
|
||||||
|
"Dead Bird Studio Basement",
|
||||||
|
|
||||||
|
"Contractual Obligations",
|
||||||
|
"The Subcon Well",
|
||||||
|
"Queen Vanessa's Manor",
|
||||||
|
"Your Contract has Expired",
|
||||||
|
|
||||||
|
"Rock the Boat",
|
||||||
|
|
||||||
|
"Time Rift - Mafia of Cooks",
|
||||||
|
"Time Rift - Dead Bird Studio",
|
||||||
|
"Time Rift - Sleepy Subcon",
|
||||||
|
"Time Rift - Alpine Skyline"
|
||||||
|
"Time Rift - Tour",
|
||||||
|
"Time Rift - Rumbi Factory",
|
||||||
]
|
]
|
||||||
|
|
||||||
purple_time_rifts = [
|
purple_time_rifts = [
|
||||||
@@ -482,29 +500,61 @@ def randomize_act_entrances(world: "HatInTimeWorld"):
|
|||||||
f"\"{name1}: {name2}\" "
|
f"\"{name1}: {name2}\" "
|
||||||
f"is an invalid or disallowed act plando combination!")
|
f"is an invalid or disallowed act plando combination!")
|
||||||
|
|
||||||
first_act_mapped: bool = False
|
# Decide what should be on the first few levels before randomizing the rest
|
||||||
|
first_acts: List[Region] = []
|
||||||
|
first_chapter_name = chapter_regions[ChapterIndex(world.options.StartingChapter)]
|
||||||
|
first_acts.append(get_act_by_number(world, first_chapter_name, 1))
|
||||||
|
# Chapter 3 and 4 only have one level accessible at the start
|
||||||
|
if first_chapter_name == "Mafia Town" or first_chapter_name == "Battle of the Birds":
|
||||||
|
first_acts.append(get_act_by_number(world, first_chapter_name, 2))
|
||||||
|
first_acts.append(get_act_by_number(world, first_chapter_name, 3))
|
||||||
|
|
||||||
|
valid_first_acts: List[Region] = []
|
||||||
|
for candidate in candidate_list:
|
||||||
|
if is_valid_first_act(world, candidate):
|
||||||
|
valid_first_acts.append(candidate)
|
||||||
|
|
||||||
|
total_locations = 0
|
||||||
|
for level in first_acts:
|
||||||
|
if level not in region_list: # make sure it hasn't been plando'd
|
||||||
|
continue
|
||||||
|
|
||||||
|
candidate = valid_first_acts[world.random.randint(0, len(valid_first_acts)-1)]
|
||||||
|
region_list.remove(level)
|
||||||
|
candidate_list.remove(candidate)
|
||||||
|
valid_first_acts.remove(candidate)
|
||||||
|
connect_acts(world, level, candidate, rift_dict)
|
||||||
|
|
||||||
|
# Only allow one purple rift
|
||||||
|
if candidate.name in purple_time_rifts:
|
||||||
|
for act in reversed(valid_first_acts):
|
||||||
|
if act.name in purple_time_rifts:
|
||||||
|
valid_first_acts.remove(act)
|
||||||
|
|
||||||
|
total_locations += get_region_location_count(world, candidate.name)
|
||||||
|
if "Time Rift" not in candidate.name:
|
||||||
|
chapter = act_chapters.get(candidate.name)
|
||||||
|
if chapter == "Mafia Town":
|
||||||
|
total_locations += get_region_location_count(world, "Mafia Town Area (HUMT)")
|
||||||
|
if candidate.name != "Heating Up Mafia Town":
|
||||||
|
total_locations += get_region_location_count(world, "Mafia Town Area")
|
||||||
|
elif chapter == "Subcon Forest":
|
||||||
|
total_locations += get_region_location_count(world, "Subcon Forest Area")
|
||||||
|
elif chapter == "The Arctic Cruise":
|
||||||
|
total_locations += get_region_location_count(world, "Cruise Ship")
|
||||||
|
|
||||||
|
# If we have enough Sphere 1 locations, we can allow the rest to be randomized
|
||||||
|
if total_locations >= MIN_FIRST_SPHERE_LOCATIONS:
|
||||||
|
break
|
||||||
|
|
||||||
ignore_certain_rules: bool = False
|
ignore_certain_rules: bool = False
|
||||||
while len(region_list) > 0:
|
while len(region_list) > 0:
|
||||||
region: Region
|
region = region_list[0]
|
||||||
if not first_act_mapped:
|
|
||||||
region = get_first_act(world)
|
|
||||||
else:
|
|
||||||
region = region_list[0]
|
|
||||||
|
|
||||||
candidate: Region
|
candidate: Region
|
||||||
valid_candidates: List[Region] = []
|
valid_candidates: List[Region] = []
|
||||||
|
|
||||||
# Look for candidates to map this act to
|
# Look for candidates to map this act to
|
||||||
for c in candidate_list:
|
for c in candidate_list:
|
||||||
# Map the first act before anything
|
|
||||||
if not first_act_mapped:
|
|
||||||
if not is_valid_first_act(world, c):
|
|
||||||
continue
|
|
||||||
|
|
||||||
valid_candidates.append(c)
|
|
||||||
first_act_mapped = True
|
|
||||||
break # we can stop here, as we only need one
|
|
||||||
|
|
||||||
if is_valid_act_combo(world, region, c, ignore_certain_rules):
|
if is_valid_act_combo(world, region, c, ignore_certain_rules):
|
||||||
valid_candidates.append(c)
|
valid_candidates.append(c)
|
||||||
|
|
||||||
@@ -545,7 +595,7 @@ def sort_acts(act: Region) -> int:
|
|||||||
and "Time Rift" not in act.name:
|
and "Time Rift" not in act.name:
|
||||||
return -3
|
return -3
|
||||||
|
|
||||||
if act.name == "Contractual Obligations":
|
if act.name == "Contractual Obligations" or act.name == "The Subcon Well":
|
||||||
return -2
|
return -2
|
||||||
|
|
||||||
world = act.multiworld.worlds[act.player]
|
world = act.multiworld.worlds[act.player]
|
||||||
@@ -558,17 +608,6 @@ def sort_acts(act: Region) -> int:
|
|||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
def get_first_act(world: "HatInTimeWorld") -> Region:
|
|
||||||
first_chapter = get_first_chapter_region(world)
|
|
||||||
act: Optional[Region] = None
|
|
||||||
for e in first_chapter.exits:
|
|
||||||
if "Act 1" in e.name or "Free Roam" in e.name:
|
|
||||||
act = e.connected_region
|
|
||||||
break
|
|
||||||
|
|
||||||
return act
|
|
||||||
|
|
||||||
|
|
||||||
def connect_acts(world: "HatInTimeWorld", entrance_act: Region, exit_act: Region, rift_dict: Dict[str, Region]):
|
def connect_acts(world: "HatInTimeWorld", entrance_act: Region, exit_act: Region, rift_dict: Dict[str, Region]):
|
||||||
# Vanilla
|
# Vanilla
|
||||||
if exit_act.name == entrance_act.name:
|
if exit_act.name == entrance_act.name:
|
||||||
@@ -642,32 +681,66 @@ def is_valid_first_act(world: "HatInTimeWorld", act: Region) -> bool:
|
|||||||
if act.name not in guaranteed_first_acts:
|
if act.name not in guaranteed_first_acts:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Not completable without Umbrella
|
# If there's only a single level in the starting chapter, only allow Mafia Town or Subcon Forest levels
|
||||||
if world.options.UmbrellaLogic and (act.name == "Heating Up Mafia Town" or act.name == "Queen Vanessa's Manor"):
|
start_chapter = world.options.StartingChapter
|
||||||
|
if start_chapter is ChapterIndex.ALPINE or start_chapter is ChapterIndex.SUBCON:
|
||||||
|
if "Time Rift" in act.name:
|
||||||
|
return False
|
||||||
|
|
||||||
|
if act_chapters[act.name] != "Mafia Town" and act_chapters[act.name] != "Subcon Forest":
|
||||||
|
return False
|
||||||
|
|
||||||
|
if act.name in purple_time_rifts and not world.options.ShuffleStorybookPages:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Subcon sphere 1 is too small without painting unlocks, and no acts are completable either
|
diff = get_difficulty(world)
|
||||||
if world.options.ShuffleSubconPaintings and "Subcon Forest" in act_entrances[act.name]:
|
# Not completable without Umbrella?
|
||||||
|
if world.options.UmbrellaLogic:
|
||||||
|
# Needs to be at least moderate to cross the big dweller wall
|
||||||
|
if act.name == "Queen Vanessa's Manor" and diff < Difficulty.MODERATE:
|
||||||
|
return False
|
||||||
|
elif act.name == "Your Contract has Expired" and diff < Difficulty.EXPERT: # Snatcher Hover
|
||||||
|
return False
|
||||||
|
elif act.name == "Heating Up Mafia Town": # Straight up impossible
|
||||||
|
return False
|
||||||
|
|
||||||
|
if act.name == "Dead Bird Studio":
|
||||||
|
# No umbrella logic = moderate, umbrella logic = expert.
|
||||||
|
if diff < Difficulty.MODERATE or world.options.UmbrellaLogic and diff < Difficulty.EXPERT:
|
||||||
|
return False
|
||||||
|
elif act.name == "Dead Bird Studio Basement" and (diff < Difficulty.EXPERT or world.options.FinaleShuffle):
|
||||||
return False
|
return False
|
||||||
|
elif act.name == "Rock the Boat" and (diff < Difficulty.MODERATE or world.options.FinaleShuffle):
|
||||||
|
return False
|
||||||
|
elif act.name == "The Subcon Well" and diff < Difficulty.MODERATE:
|
||||||
|
return False
|
||||||
|
elif act.name == "Contractual Obligations" and world.options.ShuffleSubconPaintings:
|
||||||
|
return False
|
||||||
|
|
||||||
|
if world.options.ShuffleSubconPaintings and "Time Rift" not in act.name and act_chapters[act.name] == "Subcon Forest":
|
||||||
|
# This requires a cherry hover to enter Subcon
|
||||||
|
if act.name == "Your Contract has Expired":
|
||||||
|
if diff < Difficulty.EXPERT or world.options.NoPaintingSkips:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
# Only allow Subcon levels if paintings can be skipped
|
||||||
|
if diff < Difficulty.MODERATE or world.options.NoPaintingSkips:
|
||||||
|
return False
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def connect_time_rift(world: "HatInTimeWorld", time_rift: Region, exit_region: Region):
|
def connect_time_rift(world: "HatInTimeWorld", time_rift: Region, exit_region: Region):
|
||||||
count: int = len(rift_access_regions[time_rift.name])
|
i = 1
|
||||||
i: int = 1
|
while i <= len(rift_access_regions[time_rift.name]):
|
||||||
while i <= count:
|
|
||||||
name = f"{time_rift.name} Portal - Entrance {i}"
|
name = f"{time_rift.name} Portal - Entrance {i}"
|
||||||
entrance: Entrance
|
entrance: Entrance
|
||||||
try:
|
try:
|
||||||
entrance = world.multiworld.get_entrance(name, world.player)
|
entrance = world.multiworld.get_entrance(name, world.player)
|
||||||
|
reconnect_regions(entrance, entrance.parent_region, exit_region)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
if len(time_rift.entrances) > 0:
|
time_rift.connect(exit_region, name)
|
||||||
entrance = time_rift.entrances[i-1]
|
|
||||||
else:
|
|
||||||
entrance = time_rift.connect(exit_region, name)
|
|
||||||
|
|
||||||
reconnect_regions(entrance, entrance.parent_region, exit_region)
|
|
||||||
i += 1
|
i += 1
|
||||||
|
|
||||||
|
|
||||||
@@ -862,6 +935,27 @@ def get_shuffled_region(world: "HatInTimeWorld", region: str) -> str:
|
|||||||
return name
|
return name
|
||||||
|
|
||||||
|
|
||||||
|
def get_region_location_count(world: "HatInTimeWorld", region_name: str, included_only: bool = True) -> int:
|
||||||
|
count = 0
|
||||||
|
region = world.multiworld.get_region(region_name, world.player)
|
||||||
|
for loc in region.locations:
|
||||||
|
if loc.address is not None and (not included_only or loc.progress_type is not LocationProgressType.EXCLUDED):
|
||||||
|
count += 1
|
||||||
|
|
||||||
|
return count
|
||||||
|
|
||||||
|
|
||||||
|
def get_act_by_number(world: "HatInTimeWorld", chapter_name: str, num: int) -> Region:
|
||||||
|
chapter = world.multiworld.get_region(chapter_name, world.player)
|
||||||
|
act: Optional[Region] = None
|
||||||
|
for e in chapter.exits:
|
||||||
|
if f"Act {num}" in e.name or num == 1 and "Free Roam" in e.name:
|
||||||
|
act = e.connected_region
|
||||||
|
break
|
||||||
|
|
||||||
|
return act
|
||||||
|
|
||||||
|
|
||||||
def create_thug_shops(world: "HatInTimeWorld"):
|
def create_thug_shops(world: "HatInTimeWorld"):
|
||||||
min_items: int = world.options.NyakuzaThugMinShopItems.value
|
min_items: int = world.options.NyakuzaThugMinShopItems.value
|
||||||
max_items: int = world.options.NyakuzaThugMaxShopItems.value
|
max_items: int = world.options.NyakuzaThugMaxShopItems.value
|
||||||
|
|||||||
+12
-5
@@ -399,6 +399,10 @@ def set_moderate_rules(world: "HatInTimeWorld"):
|
|||||||
set_rule(world.multiworld.get_location("Subcon Forest - Manor Rooftop", world.player),
|
set_rule(world.multiworld.get_location("Subcon Forest - Manor Rooftop", world.player),
|
||||||
lambda state: has_paintings(state, world, 1))
|
lambda state: has_paintings(state, world, 1))
|
||||||
|
|
||||||
|
# Moderate: Village Time Rift with nothing IF umbrella logic is off
|
||||||
|
if not world.options.UmbrellaLogic:
|
||||||
|
set_rule(world.multiworld.get_location("Act Completion (Time Rift - Village)", world.player), lambda state: True)
|
||||||
|
|
||||||
# Moderate: get to Birdhouse/Yellow Band Hills without Brewing Hat
|
# Moderate: get to Birdhouse/Yellow Band Hills without Brewing Hat
|
||||||
set_rule(world.multiworld.get_entrance("-> The Birdhouse", world.player),
|
set_rule(world.multiworld.get_entrance("-> The Birdhouse", world.player),
|
||||||
lambda state: can_use_hookshot(state, world))
|
lambda state: can_use_hookshot(state, world))
|
||||||
@@ -478,6 +482,8 @@ def set_hard_rules(world: "HatInTimeWorld"):
|
|||||||
# No Dweller Mask required
|
# No Dweller Mask required
|
||||||
set_rule(world.multiworld.get_location("Subcon Forest - Dweller Floating Rocks", world.player),
|
set_rule(world.multiworld.get_location("Subcon Forest - Dweller Floating Rocks", world.player),
|
||||||
lambda state: has_paintings(state, world, 3))
|
lambda state: has_paintings(state, world, 3))
|
||||||
|
set_rule(world.multiworld.get_location("Subcon Forest - Dweller Platforming Tree B", world.player),
|
||||||
|
lambda state: has_paintings(state, world, 3))
|
||||||
|
|
||||||
# Cherry bridge over boss arena gap (painting still expected)
|
# Cherry bridge over boss arena gap (painting still expected)
|
||||||
set_rule(world.multiworld.get_location("Subcon Forest - Boss Arena Chest", world.player),
|
set_rule(world.multiworld.get_location("Subcon Forest - Boss Arena Chest", world.player),
|
||||||
@@ -494,9 +500,6 @@ def set_hard_rules(world: "HatInTimeWorld"):
|
|||||||
add_rule(world.multiworld.get_location("Subcon Forest - Long Tree Climb Chest", world.player),
|
add_rule(world.multiworld.get_location("Subcon Forest - Long Tree Climb Chest", world.player),
|
||||||
lambda state: can_use_hat(state, world, HatType.SPRINT) and has_paintings(state, world, 2), "or")
|
lambda state: can_use_hat(state, world, HatType.SPRINT) and has_paintings(state, world, 2), "or")
|
||||||
|
|
||||||
add_rule(world.multiworld.get_location("Subcon Forest - Dweller Platforming Tree B", world.player),
|
|
||||||
lambda state: has_paintings(state, world, 3) and can_use_hat(state, world, HatType.SPRINT), "or")
|
|
||||||
|
|
||||||
add_rule(world.multiworld.get_location("Act Completion (Time Rift - Curly Tail Trail)", world.player),
|
add_rule(world.multiworld.get_location("Act Completion (Time Rift - Curly Tail Trail)", world.player),
|
||||||
lambda state: can_use_hat(state, world, HatType.SPRINT), "or")
|
lambda state: can_use_hat(state, world, HatType.SPRINT), "or")
|
||||||
|
|
||||||
@@ -581,8 +584,6 @@ def set_expert_rules(world: "HatInTimeWorld"):
|
|||||||
# Set painting rules only. Skipping paintings is determined in has_paintings
|
# Set painting rules only. Skipping paintings is determined in has_paintings
|
||||||
set_rule(world.multiworld.get_location("Subcon Forest - Boss Arena Chest", world.player),
|
set_rule(world.multiworld.get_location("Subcon Forest - Boss Arena Chest", world.player),
|
||||||
lambda state: has_paintings(state, world, 1, True))
|
lambda state: has_paintings(state, world, 1, True))
|
||||||
set_rule(world.multiworld.get_location("Subcon Forest - Dweller Platforming Tree B", world.player),
|
|
||||||
lambda state: has_paintings(state, world, 3, True))
|
|
||||||
set_rule(world.multiworld.get_location("Subcon Forest - Magnet Badge Bush", world.player),
|
set_rule(world.multiworld.get_location("Subcon Forest - Magnet Badge Bush", world.player),
|
||||||
lambda state: has_paintings(state, world, 3, True))
|
lambda state: has_paintings(state, world, 3, True))
|
||||||
|
|
||||||
@@ -601,6 +602,12 @@ def set_expert_rules(world: "HatInTimeWorld"):
|
|||||||
and state.has("Metro Ticket - Blue", world.player)
|
and state.has("Metro Ticket - Blue", world.player)
|
||||||
and state.has("Metro Ticket - Pink", world.player))
|
and state.has("Metro Ticket - Pink", world.player))
|
||||||
|
|
||||||
|
# Expert: Yellow/Green Manhole with nothing using a Boop Clip
|
||||||
|
set_rule(world.multiworld.get_location("Act Completion (Yellow Overpass Manhole)", world.player),
|
||||||
|
lambda state: True)
|
||||||
|
set_rule(world.multiworld.get_location("Act Completion (Green Clean Manhole)", world.player),
|
||||||
|
lambda state: True)
|
||||||
|
|
||||||
|
|
||||||
def set_mafia_town_rules(world: "HatInTimeWorld"):
|
def set_mafia_town_rules(world: "HatInTimeWorld"):
|
||||||
add_rule(world.multiworld.get_location("Mafia Town - Behind HQ Chest", world.player),
|
add_rule(world.multiworld.get_location("Mafia Town - Behind HQ Chest", world.player),
|
||||||
|
|||||||
Reference in New Issue
Block a user