mirror of
https://github.com/ArchipelagoMW/Archipelago.git
synced 2026-03-24 23:03:23 -07:00
duh
This commit is contained in:
190
worlds/ahit/Items.py
Normal file
190
worlds/ahit/Items.py
Normal file
@@ -0,0 +1,190 @@
|
||||
from BaseClasses import Item, ItemClassification
|
||||
from worlds.AutoWorld import World
|
||||
from .Types import HatDLC
|
||||
import typing
|
||||
|
||||
|
||||
class ItemData(typing.NamedTuple):
|
||||
code: typing.Optional[int]
|
||||
classification: ItemClassification
|
||||
dlc_flags: typing.Optional[HatDLC] = HatDLC.none
|
||||
|
||||
|
||||
class HatInTimeItem(Item):
|
||||
game: str = "A Hat in Time"
|
||||
|
||||
|
||||
def item_dlc_enabled(world: World, name: str) -> bool:
|
||||
data = item_table[name]
|
||||
|
||||
if data.dlc_flags == HatDLC.none:
|
||||
return True
|
||||
elif data.dlc_flags == HatDLC.dlc1 and world.multiworld.EnableDLC1[world.player].value > 0:
|
||||
return True
|
||||
elif data.dlc_flags == HatDLC.dlc2 and world.multiworld.EnableDLC2[world.player].value > 0:
|
||||
return True
|
||||
elif data.dlc_flags == HatDLC.death_wish and world.multiworld.EnableDeathWish[world.player].value > 0:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def get_total_time_pieces(world: World) -> int:
|
||||
count: int = 40
|
||||
if world.multiworld.EnableDLC1[world.player].value > 0:
|
||||
count += 6
|
||||
|
||||
return min(40+world.multiworld.MaxExtraTimePieces[world.player].value, count)
|
||||
|
||||
|
||||
def create_item(world: World, name: str) -> Item:
|
||||
data = item_table[name]
|
||||
return HatInTimeItem(name, data.classification, data.code, world.player)
|
||||
|
||||
|
||||
def create_multiple_items(world: World, name: str, count: int = 1) -> typing.List[Item]:
|
||||
data = item_table[name]
|
||||
itemlist: typing.List[Item] = []
|
||||
|
||||
for i in range(count):
|
||||
itemlist += [HatInTimeItem(name, data.classification, data.code, world.player)]
|
||||
|
||||
return itemlist
|
||||
|
||||
|
||||
def create_junk_items(world: World, count: int) -> typing.List[Item]:
|
||||
trap_chance = world.multiworld.TrapChance[world.player].value
|
||||
junk_pool: typing.List[Item] = []
|
||||
junk_list: typing.Dict[str, int] = {}
|
||||
trap_list: typing.Dict[str, int] = {}
|
||||
ic: ItemClassification
|
||||
|
||||
for name in item_table.keys():
|
||||
ic = item_table[name].classification
|
||||
if ic == ItemClassification.filler:
|
||||
junk_list[name] = junk_weights.get(name)
|
||||
elif trap_chance > 0 and ic == ItemClassification.trap:
|
||||
if name == "Baby Trap":
|
||||
trap_list[name] = world.multiworld.BabyTrapWeight[world.player].value
|
||||
elif name == "Laser Trap":
|
||||
trap_list[name] = world.multiworld.LaserTrapWeight[world.player].value
|
||||
elif name == "Parade Trap":
|
||||
trap_list[name] = world.multiworld.ParadeTrapWeight[world.player].value
|
||||
|
||||
for i in range(count):
|
||||
if trap_chance > 0 and world.multiworld.random.randint(1, 100) <= trap_chance:
|
||||
junk_pool += [world.create_item(
|
||||
world.multiworld.random.choices(list(trap_list.keys()), weights=list(trap_list.values()), k=1)[0])]
|
||||
else:
|
||||
junk_pool += [world.create_item(
|
||||
world.multiworld.random.choices(list(junk_list.keys()), weights=list(junk_list.values()), k=1)[0])]
|
||||
|
||||
return junk_pool
|
||||
|
||||
|
||||
ahit_items = {
|
||||
"Yarn": ItemData(300001, ItemClassification.progression_skip_balancing),
|
||||
"Time Piece": ItemData(300002, ItemClassification.progression_skip_balancing),
|
||||
"Progressive Painting Unlock": ItemData(300003, ItemClassification.progression),
|
||||
|
||||
# Relics
|
||||
"Relic (Burger Patty)": ItemData(300006, ItemClassification.progression),
|
||||
"Relic (Burger Cushion)": ItemData(300007, ItemClassification.progression),
|
||||
"Relic (Mountain Set)": ItemData(300008, ItemClassification.progression),
|
||||
"Relic (Train)": ItemData(300009, ItemClassification.progression),
|
||||
"Relic (UFO)": ItemData(300010, ItemClassification.progression),
|
||||
"Relic (Cow)": ItemData(300011, ItemClassification.progression),
|
||||
"Relic (Cool Cow)": ItemData(300012, ItemClassification.progression),
|
||||
"Relic (Tin-foil Hat Cow)": ItemData(300013, ItemClassification.progression),
|
||||
"Relic (Crayon Box)": ItemData(300014, ItemClassification.progression),
|
||||
"Relic (Red Crayon)": ItemData(300015, ItemClassification.progression),
|
||||
"Relic (Blue Crayon)": ItemData(300016, ItemClassification.progression),
|
||||
"Relic (Green Crayon)": ItemData(300017, ItemClassification.progression),
|
||||
|
||||
# Badges
|
||||
"Projectile Badge": ItemData(300024, ItemClassification.useful),
|
||||
"Fast Hatter Badge": ItemData(300025, ItemClassification.useful),
|
||||
"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),
|
||||
"Compass Badge": ItemData(300030, ItemClassification.useful),
|
||||
"Scooter Badge": ItemData(300031, ItemClassification.progression),
|
||||
"Badge Pin": ItemData(300043, ItemClassification.useful),
|
||||
|
||||
# Other
|
||||
# "Rift Token": ItemData(300032, ItemClassification.filler),
|
||||
"Random Cosmetic": ItemData(300044, ItemClassification.filler),
|
||||
"Umbrella": ItemData(300033, ItemClassification.progression),
|
||||
|
||||
# Garbage items
|
||||
"25 Pons": ItemData(300034, ItemClassification.filler),
|
||||
"50 Pons": ItemData(300035, ItemClassification.filler),
|
||||
"100 Pons": ItemData(300036, ItemClassification.filler),
|
||||
"Health Pon": ItemData(300037, ItemClassification.filler),
|
||||
|
||||
# Traps
|
||||
"Baby Trap": ItemData(300039, ItemClassification.trap),
|
||||
"Laser Trap": ItemData(300040, ItemClassification.trap),
|
||||
"Parade Trap": ItemData(300041, ItemClassification.trap),
|
||||
|
||||
# DLC1 items
|
||||
"Relic (Cake Stand)": ItemData(300018, ItemClassification.progression, HatDLC.dlc1),
|
||||
"Relic (Cake)": ItemData(300019, ItemClassification.progression, HatDLC.dlc1),
|
||||
"Relic (Cake Slice)": ItemData(300020, ItemClassification.progression, HatDLC.dlc1),
|
||||
"Relic (Shortcake)": ItemData(300021, ItemClassification.progression, HatDLC.dlc1),
|
||||
|
||||
# DLC2 items
|
||||
"Relic (Necklace Bust)": ItemData(300022, ItemClassification.progression, HatDLC.dlc2),
|
||||
"Relic (Necklace)": ItemData(300023, ItemClassification.progression, HatDLC.dlc2),
|
||||
"Metro Ticket - Yellow": ItemData(300045, ItemClassification.progression, HatDLC.dlc2),
|
||||
"Metro Ticket - Green": ItemData(300046, ItemClassification.progression, HatDLC.dlc2),
|
||||
"Metro Ticket - Blue": ItemData(300047, ItemClassification.progression, HatDLC.dlc2),
|
||||
"Metro Ticket - Pink": ItemData(300048, ItemClassification.progression, HatDLC.dlc2),
|
||||
|
||||
# Death Wish items
|
||||
"One-Hit Hero Badge": ItemData(300038, ItemClassification.progression, HatDLC.death_wish),
|
||||
"Camera Badge": ItemData(300042, ItemClassification.progression, HatDLC.death_wish),
|
||||
}
|
||||
|
||||
act_contracts = {
|
||||
"Snatcher's Contract - The Subcon Well": ItemData(300200, ItemClassification.progression),
|
||||
"Snatcher's Contract - Toilet of Doom": ItemData(300201, ItemClassification.progression),
|
||||
"Snatcher's Contract - Queen Vanessa's Manor": ItemData(300202, ItemClassification.progression),
|
||||
"Snatcher's Contract - Mail Delivery Service": ItemData(300203, ItemClassification.progression),
|
||||
}
|
||||
|
||||
alps_hooks = {
|
||||
"Zipline Unlock - The Birdhouse Path": ItemData(300204, ItemClassification.progression),
|
||||
"Zipline Unlock - The Lava Cake Path": ItemData(300205, ItemClassification.progression),
|
||||
"Zipline Unlock - The Windmill Path": ItemData(300206, ItemClassification.progression),
|
||||
"Zipline Unlock - The Twilight Bell Path": ItemData(300207, ItemClassification.progression),
|
||||
}
|
||||
|
||||
relic_groups = {
|
||||
"Burger": {"Relic (Burger Patty)", "Relic (Burger Cushion)"},
|
||||
"Train": {"Relic (Mountain Set)", "Relic (Train)"},
|
||||
"UFO": {"Relic (UFO)", "Relic (Cow)", "Relic (Cool Cow)", "Relic (Tin-foil Hat Cow)"},
|
||||
"Crayon": {"Relic (Crayon Box)", "Relic (Red Crayon)", "Relic (Blue Crayon)", "Relic (Green Crayon)"},
|
||||
"Cake": {"Relic (Cake Stand)", "Relic (Cake)", "Relic (Cake Slice)", "Relic (Shortcake)"},
|
||||
"Necklace": {"Relic (Necklace Bust)", "Relic (Necklace)"},
|
||||
}
|
||||
|
||||
item_frequencies = {
|
||||
"Badge Pin": 2,
|
||||
"Progressive Painting Unlock": 3,
|
||||
}
|
||||
|
||||
junk_weights = {
|
||||
"25 Pons": 50,
|
||||
"50 Pons": 10,
|
||||
"Health Pon": 35,
|
||||
"100 Pons": 5,
|
||||
"Random Cosmetic": 25,
|
||||
}
|
||||
|
||||
item_table = {
|
||||
**ahit_items,
|
||||
**act_contracts,
|
||||
**alps_hooks,
|
||||
}
|
||||
682
worlds/ahit/Locations.py
Normal file
682
worlds/ahit/Locations.py
Normal file
@@ -0,0 +1,682 @@
|
||||
from BaseClasses import Location
|
||||
from worlds.AutoWorld import World
|
||||
from .Types import HatDLC, HatType
|
||||
from typing import Optional, NamedTuple, List, Dict
|
||||
from .Options import TasksanityCheckCount
|
||||
|
||||
|
||||
class LocData(NamedTuple):
|
||||
id: int
|
||||
region: str
|
||||
required_hats: Optional[List[HatType]] = [HatType.NONE]
|
||||
required_tps: Optional[int] = 0
|
||||
hookshot: Optional[bool] = False
|
||||
dlc_flags: Optional[HatDLC] = HatDLC.none
|
||||
paintings: Optional[int] = 0 # Progressive paintings required for Subcon painting shuffle
|
||||
|
||||
# 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
|
||||
|
||||
# Other
|
||||
act_complete_event: Optional[bool] = True # Only used for event locations. Copy access rule from act completion
|
||||
nyakuza_thug: Optional[str] = "" # Name of Nyakuza thug NPC (for metro shops)
|
||||
|
||||
|
||||
class HatInTimeLocation(Location):
|
||||
game: str = "A Hat in Time"
|
||||
|
||||
|
||||
def get_total_locations(world: World) -> int:
|
||||
total: int = 0
|
||||
|
||||
for (name) in location_table.keys():
|
||||
if is_location_valid(world, name):
|
||||
total += 1
|
||||
|
||||
if world.multiworld.EnableDLC1[world.player].value > 0 and world.multiworld.Tasksanity[world.player].value > 0:
|
||||
total += world.multiworld.TasksanityCheckCount[world.player].value
|
||||
|
||||
return total
|
||||
|
||||
|
||||
def location_dlc_enabled(world: World, location: str) -> bool:
|
||||
data = location_table.get(location) or event_locs.get(location)
|
||||
|
||||
if data.dlc_flags == HatDLC.none:
|
||||
return True
|
||||
elif data.dlc_flags == HatDLC.dlc1 and world.multiworld.EnableDLC1[world.player].value > 0:
|
||||
return True
|
||||
elif data.dlc_flags == HatDLC.dlc2 and world.multiworld.EnableDLC2[world.player].value > 0:
|
||||
return True
|
||||
elif data.dlc_flags == HatDLC.death_wish and world.multiworld.EnableDeathWish[world.player].value > 0:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def is_location_valid(world: World, location: str) -> bool:
|
||||
if not location_dlc_enabled(world, location):
|
||||
return False
|
||||
|
||||
if location in storybook_pages.keys() \
|
||||
and world.multiworld.ShuffleStorybookPages[world.player].value == 0:
|
||||
return False
|
||||
|
||||
if location in shop_locations and location not in world.shop_locs:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def get_location_names() -> Dict[str, int]:
|
||||
names = {name: data.id for name, data in location_table.items()}
|
||||
id_start: int = 300204
|
||||
for i in range(TasksanityCheckCount.range_end):
|
||||
names.setdefault(format("Tasksanity Check %i") % (i+1), id_start+i)
|
||||
|
||||
return names
|
||||
|
||||
|
||||
ahit_locations = {
|
||||
"Spaceship - Rumbi Abuse": LocData(301000, "Spaceship", required_tps=4, dweller_bell=1),
|
||||
# "Spaceship - Cooking Cat": LocData(301001, "Spaceship", required_tps=5),
|
||||
|
||||
# 300000 range - Mafia Town/Batle of the Birds
|
||||
"Welcome to Mafia Town - Umbrella": LocData(301002, "Welcome to Mafia Town"),
|
||||
"Mafia Town - Old Man (Seaside Spaghetti)": LocData(303833, "Mafia Town Area"),
|
||||
"Mafia Town - Old Man (Steel Beams)": LocData(303832, "Mafia Town Area"),
|
||||
"Mafia Town - Blue Vault": LocData(302850, "Mafia Town Area"),
|
||||
"Mafia Town - Green Vault": LocData(302851, "Mafia Town Area"),
|
||||
"Mafia Town - Red Vault": LocData(302848, "Mafia Town Area"),
|
||||
"Mafia Town - Blue Vault Brewing Crate": LocData(305572, "Mafia Town Area", required_hats=[HatType.BREWING]),
|
||||
"Mafia Town - Plaza Under Boxes": LocData(304458, "Mafia Town Area"),
|
||||
"Mafia Town - Small Boat": LocData(304460, "Mafia Town Area"),
|
||||
"Mafia Town - Staircase Pon Cluster": LocData(304611, "Mafia Town Area"),
|
||||
"Mafia Town - Palm Tree": LocData(304609, "Mafia Town Area"),
|
||||
"Mafia Town - Port": LocData(305219, "Mafia Town Area"),
|
||||
"Mafia Town - Docks Chest": LocData(303534, "Mafia Town Area"),
|
||||
"Mafia Town - Ice Hat Cage": LocData(304831, "Mafia Town Area", required_hats=[HatType.ICE]),
|
||||
"Mafia Town - Hidden Buttons Chest": LocData(303483, "Mafia Town Area"),
|
||||
|
||||
# These can be accessed from HUMT, the above locations can't be
|
||||
"Mafia Town - Dweller Boxes": LocData(304462, "Mafia Town Area (HUMT)"),
|
||||
"Mafia Town - Ledge Chest": LocData(303530, "Mafia Town Area (HUMT)"),
|
||||
"Mafia Town - Yellow Sphere Building Chest": LocData(303535, "Mafia Town Area (HUMT)"),
|
||||
"Mafia Town - Beneath Scaffolding": LocData(304456, "Mafia Town Area (HUMT)"),
|
||||
"Mafia Town - On Scaffolding": LocData(304457, "Mafia Town Area (HUMT)"),
|
||||
"Mafia Town - Cargo Ship": LocData(304459, "Mafia Town Area (HUMT)"),
|
||||
"Mafia Town - Beach Alcove": LocData(304463, "Mafia Town Area (HUMT)"),
|
||||
"Mafia Town - Wood Cage": LocData(304606, "Mafia Town Area (HUMT)"),
|
||||
"Mafia Town - Beach Patio": LocData(304610, "Mafia Town Area (HUMT)"),
|
||||
"Mafia Town - Steel Beam Nest": LocData(304608, "Mafia Town Area (HUMT)"),
|
||||
"Mafia Town - Top of Ruined Tower": LocData(304607, "Mafia Town Area (HUMT)", required_hats=[HatType.ICE]),
|
||||
"Mafia Town - Hot Air Balloon": LocData(304829, "Mafia Town Area (HUMT)", required_hats=[HatType.ICE]),
|
||||
"Mafia Town - Camera Badge 1": LocData(302003, "Mafia Town Area (HUMT)"),
|
||||
"Mafia Town - Camera Badge 2": LocData(302004, "Mafia Town Area (HUMT)"),
|
||||
"Mafia Town - Chest Beneath Aqueduct": LocData(303489, "Mafia Town Area (HUMT)"),
|
||||
"Mafia Town - Secret Cave": LocData(305220, "Mafia Town Area (HUMT)", required_hats=[HatType.BREWING]),
|
||||
"Mafia Town - Crow Chest": LocData(303532, "Mafia Town Area (HUMT)"),
|
||||
"Mafia Town - Above Boats": LocData(305218, "Mafia Town Area (HUMT)", hookshot=True),
|
||||
"Mafia Town - Slip Slide Chest": LocData(303529, "Mafia Town Area (HUMT)"),
|
||||
"Mafia Town - Behind Faucet": LocData(304214, "Mafia Town Area (HUMT)"),
|
||||
"Mafia Town - Clock Tower Chest": LocData(303481, "Mafia Town Area (HUMT)", hookshot=True),
|
||||
"Mafia Town - Top of Lighthouse": LocData(304213, "Mafia Town Area (HUMT)", hookshot=True),
|
||||
"Mafia Town - Mafia Geek Platform": LocData(304212, "Mafia Town Area (HUMT)"),
|
||||
"Mafia Town - Behind HQ Chest": LocData(303486, "Mafia Town Area (HUMT)"),
|
||||
|
||||
"Mafia HQ - Hallway Brewing Crate": LocData(305387, "Down with the Mafia!", required_hats=[HatType.BREWING]),
|
||||
"Mafia HQ - Freezer Chest": LocData(303241, "Down with the Mafia!"),
|
||||
"Mafia HQ - Secret Room": LocData(304979, "Down with the Mafia!", required_hats=[HatType.ICE]),
|
||||
"Mafia HQ - Bathroom Stall Chest": LocData(303243, "Down with the Mafia!"),
|
||||
|
||||
"Dead Bird Studio - Up the Ladder": LocData(304874, "Dead Bird Studio - Elevator Area"),
|
||||
"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),
|
||||
|
||||
"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"),
|
||||
"Murder on the Owl Express - Luggage Room Bottom": LocData(305091, "Murder on the Owl Express"),
|
||||
|
||||
"Murder on the Owl Express - Raven Suite Room": LocData(305701, "Murder on the Owl Express",
|
||||
required_hats=[HatType.BREWING]),
|
||||
|
||||
"Murder on the Owl Express - Raven Suite Top": LocData(305312, "Murder on the Owl Express"),
|
||||
"Murder on the Owl Express - Lounge Chest": LocData(303963, "Murder on the Owl Express"),
|
||||
|
||||
"Picture Perfect - Behind Badge Seller": LocData(304307, "Picture Perfect"),
|
||||
"Picture Perfect - Hats Buy Building": LocData(304530, "Picture Perfect"),
|
||||
|
||||
"Dead Bird Studio Basement - Window Platform": LocData(305432, "Dead Bird Studio Basement", hookshot=True),
|
||||
"Dead Bird Studio Basement - Cardboard Conductor": LocData(305059, "Dead Bird Studio Basement", hookshot=True),
|
||||
"Dead Bird Studio Basement - Above Conductor Sign": LocData(305057, "Dead Bird Studio Basement", hookshot=True),
|
||||
"Dead Bird Studio Basement - Logo Wall": LocData(305207, "Dead Bird Studio Basement"),
|
||||
"Dead Bird Studio Basement - Disco Room": LocData(305061, "Dead Bird Studio Basement", hookshot=True),
|
||||
"Dead Bird Studio Basement - Small Room": LocData(304813, "Dead Bird Studio Basement", hookshot=True),
|
||||
"Dead Bird Studio Basement - Vent Pipe": LocData(305430, "Dead Bird Studio Basement"),
|
||||
"Dead Bird Studio Basement - Tightrope": LocData(305058, "Dead Bird Studio Basement", hookshot=True),
|
||||
"Dead Bird Studio Basement - Cameras": LocData(305431, "Dead Bird Studio Basement", hookshot=True),
|
||||
"Dead Bird Studio Basement - Locked Room": LocData(305819, "Dead Bird Studio Basement", hookshot=True),
|
||||
|
||||
# 320000 range - Subcon Forest
|
||||
"Contractual Obligations - Cherry Bomb Bone Cage": LocData(324761, "Contractual Obligations"),
|
||||
"Subcon Village - Tree Top Ice Cube": LocData(325078, "Subcon Forest Area"),
|
||||
"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", 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],
|
||||
paintings=1),
|
||||
|
||||
"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],
|
||||
paintings=3),
|
||||
|
||||
"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", paintings=3),
|
||||
|
||||
"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", paintings=1),
|
||||
"Subcon Forest - Gallows": LocData(325472, "Subcon Forest Area", paintings=1),
|
||||
|
||||
"Subcon Forest - Green and Purple Dweller Rocks": LocData(325082, "Subcon Forest Area",
|
||||
required_hats=[HatType.DWELLER],
|
||||
paintings=3),
|
||||
|
||||
"Subcon Forest - Dweller Shack": LocData(324463, "Subcon Forest Area",
|
||||
required_hats=[HatType.DWELLER],
|
||||
paintings=1),
|
||||
|
||||
"Subcon Forest - Tall Tree Hookshot Swing": LocData(324766, "Subcon Forest Area",
|
||||
paintings=3,
|
||||
required_hats=[HatType.DWELLER],
|
||||
hookshot=True),
|
||||
|
||||
"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],
|
||||
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 - 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],
|
||||
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),
|
||||
|
||||
"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"),
|
||||
"Alpine Skyline - Goat Village: Hidden Branch": LocData(334855, "Goat Village"),
|
||||
"Alpine Skyline - Goat Refinery": LocData(333635, "Alpine Skyline Area"),
|
||||
"Alpine Skyline - Bird Pass Fork": LocData(335911, "Alpine Skyline Area"),
|
||||
"Alpine Skyline - Yellow Band Hills": LocData(335756, "Alpine Skyline Area", required_hats=[HatType.BREWING]),
|
||||
"Alpine Skyline - The Purrloined Village: Horned Stone": LocData(335561, "Alpine Skyline Area"),
|
||||
"Alpine Skyline - The Purrloined Village: Chest Reward": LocData(334831, "Alpine Skyline Area"),
|
||||
"Alpine Skyline - The Birdhouse: Triple Crow Chest": LocData(334758, "The Birdhouse"),
|
||||
|
||||
"Alpine Skyline - The Birdhouse: Dweller Platforms Relic": LocData(336497, "The Birdhouse",
|
||||
required_hats=[HatType.DWELLER]),
|
||||
|
||||
"Alpine Skyline - The Birdhouse: Brewing Crate House": LocData(336496, "The Birdhouse"),
|
||||
"Alpine Skyline - The Birdhouse: Hay Bale": LocData(335885, "The Birdhouse"),
|
||||
"Alpine Skyline - The Birdhouse: Alpine Crow Mini-Gauntlet": LocData(335886, "The Birdhouse"),
|
||||
"Alpine Skyline - The Birdhouse: Outer Edge": LocData(335492, "The Birdhouse"),
|
||||
|
||||
"Alpine Skyline - Mystifying Time Mesa: Zipline": LocData(337058, "Alpine Skyline Area"),
|
||||
"Alpine Skyline - Mystifying Time Mesa: Gate Puzzle": LocData(336052, "Alpine Skyline Area"),
|
||||
"Alpine Skyline - Ember Summit": LocData(336311, "Alpine Skyline Area"),
|
||||
"Alpine Skyline - The Lava Cake: Center Fence Cage": LocData(335448, "The Lava Cake"),
|
||||
"Alpine Skyline - The Lava Cake: Outer Island Chest": LocData(334291, "The Lava Cake"),
|
||||
"Alpine Skyline - The Lava Cake: Dweller Pillars": LocData(335417, "The Lava Cake"),
|
||||
"Alpine Skyline - The Lava Cake: Top Cake": LocData(335418, "The Lava Cake"),
|
||||
"Alpine Skyline - The Twilight Path": LocData(334434, "Alpine Skyline Area", required_hats=[HatType.DWELLER]),
|
||||
"Alpine Skyline - The Twilight Bell: Wide Purple Platform": LocData(336478, "The Twilight Bell"),
|
||||
"Alpine Skyline - The Twilight Bell: Ice Platform": LocData(335826, "The Twilight Bell"),
|
||||
"Alpine Skyline - Goat Outpost Horn": LocData(334760, "Alpine Skyline Area"),
|
||||
"Alpine Skyline - Windy Passage": LocData(334776, "Alpine Skyline Area"),
|
||||
"Alpine Skyline - The Windmill: Inside Pon Cluster": LocData(336395, "The Windmill"),
|
||||
"Alpine Skyline - The Windmill: Entrance": LocData(335783, "The Windmill"),
|
||||
"Alpine Skyline - The Windmill: Dropdown": LocData(335815, "The Windmill"),
|
||||
"Alpine Skyline - The Windmill: House Window": LocData(335389, "The Windmill"),
|
||||
|
||||
"The Finale - Frozen Item": LocData(304108, "The Finale"),
|
||||
|
||||
"Bon Voyage! - Lamp Post Top": LocData(305321, "Bon Voyage!", dlc_flags=HatDLC.dlc1),
|
||||
"Bon Voyage! - Mafia Cargo Ship": LocData(304313, "Bon Voyage!", dlc_flags=HatDLC.dlc1),
|
||||
"The Arctic Cruise - Toilet": LocData(305109, "Cruise Ship", dlc_flags=HatDLC.dlc1),
|
||||
"The Arctic Cruise - Bar": LocData(304251, "Cruise Ship", dlc_flags=HatDLC.dlc1),
|
||||
"The Arctic Cruise - Dive Board Ledge": LocData(304254, "Cruise Ship", dlc_flags=HatDLC.dlc1),
|
||||
"The Arctic Cruise - Top Balcony": LocData(304255, "Cruise Ship", dlc_flags=HatDLC.dlc1),
|
||||
"The Arctic Cruise - Octopus Room": LocData(305253, "Cruise Ship", dlc_flags=HatDLC.dlc1),
|
||||
"The Arctic Cruise - Octopus Room Top": LocData(304249, "Cruise Ship", dlc_flags=HatDLC.dlc1),
|
||||
"The Arctic Cruise - Laundry Room": LocData(304250, "Cruise Ship", dlc_flags=HatDLC.dlc1),
|
||||
"The Arctic Cruise - Ship Side": LocData(304247, "Cruise Ship", dlc_flags=HatDLC.dlc1),
|
||||
"The Arctic Cruise - Silver Ring": LocData(305252, "Cruise Ship", dlc_flags=HatDLC.dlc1),
|
||||
"Rock the Boat - Reception Room - Suitcase": LocData(304045, "Rock the Boat", dlc_flags=HatDLC.dlc1),
|
||||
"Rock the Boat - Reception Room - Under Desk": LocData(304047, "Rock the Boat", dlc_flags=HatDLC.dlc1),
|
||||
"Rock the Boat - Lamp Post": LocData(304048, "Rock the Boat", dlc_flags=HatDLC.dlc1),
|
||||
"Rock the Boat - Iceberg Top": LocData(304046, "Rock the Boat", dlc_flags=HatDLC.dlc1),
|
||||
"Rock the Boat - Post Captain Rescue": LocData(304049, "Rock the Boat", dlc_flags=HatDLC.dlc1),
|
||||
|
||||
"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]),
|
||||
|
||||
"Nyakuza Metro - 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]),
|
||||
|
||||
"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]),
|
||||
}
|
||||
|
||||
act_completions = {
|
||||
# 310000 range - Act Completions
|
||||
"Act Completion (Time Rift - Gallery)": LocData(312758, "Time Rift - Gallery", required_hats=[HatType.BREWING]),
|
||||
"Act Completion (Time Rift - The Lab)": LocData(312838, "Time Rift - The Lab"),
|
||||
|
||||
"Act Completion (Welcome to Mafia Town)": LocData(311771, "Welcome to Mafia Town"),
|
||||
"Act Completion (Barrel Battle)": LocData(311958, "Barrel Battle"),
|
||||
"Act Completion (She Came from Outer Space)": LocData(312262, "She Came from Outer Space"),
|
||||
"Act Completion (Down with the Mafia!)": LocData(311326, "Down with the Mafia!"),
|
||||
"Act Completion (Cheating the Race)": LocData(312318, "Cheating the Race"),
|
||||
"Act Completion (Heating Up Mafia Town)": LocData(311481, "Heating Up Mafia Town", umbrella=True),
|
||||
"Act Completion (The Golden Vault)": LocData(312250, "The Golden Vault"),
|
||||
"Act Completion (Time Rift - Bazaar)": LocData(312465, "Time Rift - Bazaar"),
|
||||
"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 (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),
|
||||
"Act Completion (The Big Parade)": LocData(311157, "The Big Parade", umbrella=True),
|
||||
"Act Completion (Award Ceremony)": LocData(311488, "Award Ceremony"),
|
||||
"Act Completion (Dead Bird Studio Basement)": LocData(312253, "Dead Bird Studio Basement", hookshot=True),
|
||||
"Act Completion (Time Rift - The Owl Express)": LocData(312807, "Time Rift - The Owl Express"),
|
||||
"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", 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),
|
||||
"Act Completion (Time Rift - Village)": LocData(313056, "Time Rift - Village"),
|
||||
"Act Completion (Time Rift - Sleepy Subcon)": LocData(312086, "Time Rift - Sleepy Subcon"),
|
||||
|
||||
"Act Completion (The Birdhouse)": LocData(311428, "The Birdhouse"),
|
||||
"Act Completion (The Lava Cake)": LocData(312509, "The Lava Cake"),
|
||||
"Act Completion (The Twilight Bell)": LocData(311540, "The Twilight Bell"),
|
||||
"Act Completion (The Windmill)": LocData(312263, "The Windmill"),
|
||||
"Act Completion (The Illness has Spread)": LocData(312022, "The Illness has Spread", hookshot=True),
|
||||
|
||||
"Act Completion (Time Rift - The Twilight Bell)": LocData(312399, "Time Rift - The Twilight Bell",
|
||||
required_hats=[HatType.DWELLER]),
|
||||
|
||||
"Act Completion (Time Rift - Curly Tail Trail)": LocData(313335, "Time Rift - Curly Tail Trail",
|
||||
required_hats=[HatType.ICE]),
|
||||
|
||||
"Act Completion (Time Rift - Alpine Skyline)": LocData(311777, "Time Rift - Alpine Skyline"),
|
||||
|
||||
"Act Completion (The Finale)": LocData(311872, "The Finale", hookshot=True, required_hats=[HatType.DWELLER]),
|
||||
"Act Completion (Time Rift - Tour)": LocData(311803, "Time Rift - Tour", dlc_flags=HatDLC.dlc1),
|
||||
|
||||
"Act Completion (Bon Voyage!)": LocData(311520, "Bon Voyage!", dlc_flags=HatDLC.dlc1, hookshot=True),
|
||||
"Act Completion (Ship Shape)": LocData(311451, "Ship Shape", dlc_flags=HatDLC.dlc1),
|
||||
"Act Completion (Rock the Boat)": LocData(311437, "Rock the Boat", dlc_flags=HatDLC.dlc1),
|
||||
"Act Completion (Time Rift - Balcony)": LocData(312226, "Time Rift - Balcony", dlc_flags=HatDLC.dlc1, hookshot=True),
|
||||
"Act Completion (Time Rift - Deep Sea)": LocData(312434, "Time Rift - Deep Sea", dlc_flags=HatDLC.dlc1, hookshot=True),
|
||||
|
||||
"Act Completion (Nyakuza Metro Intro)": LocData(311138, "Nyakuza Free Roam", dlc_flags=HatDLC.dlc2),
|
||||
|
||||
"Act Completion (Yellow Overpass Station)": LocData(311206, "Yellow Overpass Station",
|
||||
dlc_flags=HatDLC.dlc2,
|
||||
hookshot=True),
|
||||
|
||||
"Act Completion (Yellow Overpass Manhole)": LocData(311387, "Yellow Overpass Manhole",
|
||||
dlc_flags=HatDLC.dlc2,
|
||||
required_hats=[HatType.ICE]),
|
||||
|
||||
"Act Completion (Green Clean Station)": LocData(311207, "Green Clean Station", dlc_flags=HatDLC.dlc2),
|
||||
|
||||
"Act Completion (Green Clean Manhole)": LocData(311388, "Green Clean Manhole",
|
||||
dlc_flags=HatDLC.dlc2,
|
||||
required_hats=[HatType.ICE, HatType.DWELLER]),
|
||||
|
||||
"Act Completion (Bluefin Tunnel)": LocData(311208, "Bluefin Tunnel", dlc_flags=HatDLC.dlc2),
|
||||
|
||||
"Act Completion (Pink Paw Station)": LocData(311209, "Pink Paw Station",
|
||||
dlc_flags=HatDLC.dlc2,
|
||||
hookshot=True,
|
||||
required_hats=[HatType.DWELLER]),
|
||||
|
||||
"Act Completion (Pink Paw Manhole)": LocData(311389, "Pink Paw Manhole",
|
||||
dlc_flags=HatDLC.dlc2,
|
||||
required_hats=[HatType.ICE]),
|
||||
|
||||
"Act Completion (Rush Hour)": LocData(311210, "Rush Hour",
|
||||
dlc_flags=HatDLC.dlc2,
|
||||
hookshot=True,
|
||||
required_hats=[HatType.ICE, HatType.BREWING]),
|
||||
|
||||
"Act Completion (Rumbi Factory)": LocData(312736, "Time Rift - Rumbi Factory", dlc_flags=HatDLC.dlc2),
|
||||
}
|
||||
|
||||
storybook_pages = {
|
||||
"Mafia of Cooks - Page: Fish Pile": LocData(345091, "Time Rift - Mafia of Cooks"),
|
||||
"Mafia of Cooks - Page: Trash Mound": LocData(345090, "Time Rift - Mafia of Cooks"),
|
||||
"Mafia of Cooks - Page: Beside Red Building": LocData(345092, "Time Rift - Mafia of Cooks"),
|
||||
"Mafia of Cooks - Page: Behind Shipping Containers": LocData(345095, "Time Rift - Mafia of Cooks"),
|
||||
"Mafia of Cooks - Page: Top of Boat": LocData(345093, "Time Rift - Mafia of Cooks"),
|
||||
"Mafia of Cooks - Page: Below Dock": LocData(345094, "Time Rift - Mafia of Cooks"),
|
||||
|
||||
"Dead Bird Studio (Rift) - Page: Behind Cardboard Planet": LocData(345449, "Time Rift - Dead Bird Studio"),
|
||||
"Dead Bird Studio (Rift) - Page: Near Time Rift Gate": LocData(345447, "Time Rift - Dead Bird Studio"),
|
||||
"Dead Bird Studio (Rift) - Page: Top of Metal Bar": LocData(345448, "Time Rift - Dead Bird Studio"),
|
||||
"Dead Bird Studio (Rift) - Page: Lava Lamp": LocData(345450, "Time Rift - Dead Bird Studio"),
|
||||
"Dead Bird Studio (Rift) - Page: Above Horse Picture": LocData(345451, "Time Rift - Dead Bird Studio"),
|
||||
"Dead Bird Studio (Rift) - Page: Green Screen": LocData(345452, "Time Rift - Dead Bird Studio"),
|
||||
"Dead Bird Studio (Rift) - Page: In The Corner": LocData(345453, "Time Rift - Dead Bird Studio"),
|
||||
"Dead Bird Studio (Rift) - Page: Above TV Room": LocData(345445, "Time Rift - Dead Bird Studio"),
|
||||
|
||||
"Sleepy Subcon - Page: Behind Entrance Area": LocData(345373, "Time Rift - Sleepy Subcon"),
|
||||
"Sleepy Subcon - Page: Near Wrecking Ball": LocData(345327, "Time Rift - Sleepy Subcon"),
|
||||
"Sleepy Subcon - Page: Behind Crane": LocData(345371, "Time Rift - Sleepy Subcon"),
|
||||
"Sleepy Subcon - Page: Wrecked Treehouse": LocData(345326, "Time Rift - Sleepy Subcon"),
|
||||
"Sleepy Subcon - Page: Behind 2nd Rift Gate": LocData(345372, "Time Rift - Sleepy Subcon"),
|
||||
"Sleepy Subcon - Page: Rotating Platform": LocData(345328, "Time Rift - Sleepy Subcon"),
|
||||
"Sleepy Subcon - Page: Behind 3rd Rift Gate": LocData(345329, "Time Rift - Sleepy Subcon"),
|
||||
"Sleepy Subcon - Page: Frozen Tree": LocData(345330, "Time Rift - Sleepy Subcon"),
|
||||
"Sleepy Subcon - Page: Secret Library": LocData(345370, "Time Rift - Sleepy Subcon"),
|
||||
|
||||
"Alpine Skyline (Rift) - Page: Entrance Area Hidden Ledge": LocData(345016, "Time Rift - Alpine Skyline"),
|
||||
"Alpine Skyline (Rift) - Page: Windmill Island Ledge": LocData(345012, "Time Rift - Alpine Skyline"),
|
||||
"Alpine Skyline (Rift) - Page: Waterfall Wooden Pillar": LocData(345015, "Time Rift - Alpine Skyline"),
|
||||
"Alpine Skyline (Rift) - Page: Lonely Birdhouse Top": LocData(345014, "Time Rift - Alpine Skyline"),
|
||||
"Alpine Skyline (Rift) - Page: Below Aqueduct": LocData(345013, "Time Rift - Alpine Skyline"),
|
||||
|
||||
"Deep Sea - Page: Starfish": LocData(346454, "Time Rift - Deep Sea", dlc_flags=HatDLC.dlc1),
|
||||
"Deep Sea - Page: Mini Castle": LocData(346452, "Time Rift - Deep Sea", dlc_flags=HatDLC.dlc1),
|
||||
"Deep Sea - Page: Urchins": LocData(346449, "Time Rift - Deep Sea", dlc_flags=HatDLC.dlc1),
|
||||
"Deep Sea - Page: Big Castle": LocData(346450, "Time Rift - Deep Sea", dlc_flags=HatDLC.dlc1, hookshot=True),
|
||||
"Deep Sea - Page: Castle Top Chest": LocData(304850, "Time Rift - Deep Sea", dlc_flags=HatDLC.dlc1, hookshot=True),
|
||||
"Deep Sea - Page: Urchin Ledge": LocData(346451, "Time Rift - Deep Sea", dlc_flags=HatDLC.dlc1, hookshot=True),
|
||||
"Deep Sea - Page: Hidden Castle Chest": LocData(304849, "Time Rift - Deep Sea", dlc_flags=HatDLC.dlc1, hookshot=True),
|
||||
"Deep Sea - Page: Falling Platform": LocData(346456, "Time Rift - Deep Sea", dlc_flags=HatDLC.dlc1, hookshot=True),
|
||||
"Deep Sea - Page: Lava Starfish": LocData(346453, "Time Rift - Deep Sea", dlc_flags=HatDLC.dlc1, hookshot=True),
|
||||
|
||||
"Tour - Page: Mafia Town - Ledge": LocData(345038, "Time Rift - Tour", dlc_flags=HatDLC.dlc1),
|
||||
"Tour - Page: Mafia Town - Beach": LocData(345039, "Time Rift - Tour", dlc_flags=HatDLC.dlc1),
|
||||
"Tour - Page: Dead Bird Studio - C.A.W. Agents": LocData(345040, "Time Rift - Tour", dlc_flags=HatDLC.dlc1),
|
||||
"Tour - Page: Dead Bird Studio - Fragile Box": LocData(345041, "Time Rift - Tour", dlc_flags=HatDLC.dlc1),
|
||||
"Tour - Page: Subcon Forest - Giant Frozen Tree": LocData(345042, "Time Rift - Tour", dlc_flags=HatDLC.dlc1),
|
||||
"Tour - Page: Subcon Forest - Top of Pillar": LocData(345043, "Time Rift - Tour", dlc_flags=HatDLC.dlc1),
|
||||
"Tour - Page: Alpine Skyline - Birdhouse": LocData(345044, "Time Rift - Tour", dlc_flags=HatDLC.dlc1),
|
||||
"Tour - Page: Alpine Skyline - Behind Lava Isle": LocData(345047, "Time Rift - Tour", dlc_flags=HatDLC.dlc1),
|
||||
"Tour - Page: The Finale - Near Entrance": LocData(345087, "Time Rift - Tour", dlc_flags=HatDLC.dlc1),
|
||||
|
||||
"Rumbi Factory - Page: Manhole": LocData(345891, "Time Rift - Rumbi Factory", dlc_flags=HatDLC.dlc2),
|
||||
"Rumbi Factory - Page: Shutter Doors": LocData(345888, "Time Rift - Rumbi Factory", dlc_flags=HatDLC.dlc2),
|
||||
"Rumbi Factory - Page: Toxic Waste Dispenser": LocData(345892, "Time Rift - Rumbi Factory", dlc_flags=HatDLC.dlc2),
|
||||
"Rumbi Factory - Page: 3rd Area Ledge": LocData(345889, "Time Rift - Rumbi Factory", dlc_flags=HatDLC.dlc2),
|
||||
"Rumbi Factory - Page: Green Box Assembly Line": LocData(345884, "Time Rift - Rumbi Factory", dlc_flags=HatDLC.dlc2),
|
||||
"Rumbi Factory - Page: Broken Window": LocData(345885, "Time Rift - Rumbi Factory", dlc_flags=HatDLC.dlc2),
|
||||
"Rumbi Factory - Page: Money Vault": LocData(345890, "Time Rift - Rumbi Factory", dlc_flags=HatDLC.dlc2),
|
||||
"Rumbi Factory - Page: Warehouse Boxes": LocData(345887, "Time Rift - Rumbi Factory", dlc_flags=HatDLC.dlc2),
|
||||
"Rumbi Factory - Page: Glass Shelf": LocData(345886, "Time Rift - Rumbi Factory", dlc_flags=HatDLC.dlc2),
|
||||
"Rumbi Factory - Page: Last Area": LocData(345883, "Time Rift - Rumbi Factory", dlc_flags=HatDLC.dlc2),
|
||||
}
|
||||
|
||||
contract_locations = {
|
||||
"Snatcher's Contract - The Subcon Well": LocData(300200, "Contractual Obligations"),
|
||||
"Snatcher's Contract - Toilet of Doom": LocData(300201, "Subcon Forest Area"),
|
||||
"Snatcher's Contract - Queen Vanessa's Manor": LocData(300202, "Subcon Forest Area"),
|
||||
"Snatcher's Contract - Mail Delivery Service": LocData(300203, "Subcon Forest Area"),
|
||||
}
|
||||
|
||||
shop_locations = {
|
||||
"Badge Seller - Item 1": LocData(301003, "Badge Seller"),
|
||||
"Badge Seller - Item 2": LocData(301004, "Badge Seller"),
|
||||
"Badge Seller - Item 3": LocData(301005, "Badge Seller"),
|
||||
"Badge Seller - Item 4": LocData(301006, "Badge Seller"),
|
||||
"Badge Seller - Item 5": LocData(301007, "Badge Seller"),
|
||||
"Badge Seller - Item 6": LocData(301008, "Badge Seller"),
|
||||
"Badge Seller - Item 7": LocData(301009, "Badge Seller"),
|
||||
"Badge Seller - Item 8": LocData(301010, "Badge Seller"),
|
||||
"Badge Seller - Item 9": LocData(301011, "Badge Seller"),
|
||||
"Badge Seller - Item 10": LocData(301012, "Badge Seller"),
|
||||
"Mafia Boss Shop Item": LocData(301013, "Spaceship", required_tps=12),
|
||||
|
||||
"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),
|
||||
|
||||
"Main Station Thug A - Item 1": LocData(301048, "Nyakuza Free Roam", dlc_flags=HatDLC.dlc2,
|
||||
nyakuza_thug="Hat_NPC_NyakuzaShop_0"),
|
||||
"Main Station Thug A - Item 2": LocData(301049, "Nyakuza Free Roam", dlc_flags=HatDLC.dlc2,
|
||||
nyakuza_thug="Hat_NPC_NyakuzaShop_0"),
|
||||
"Main Station Thug A - Item 3": LocData(301050, "Nyakuza Free Roam", dlc_flags=HatDLC.dlc2,
|
||||
nyakuza_thug="Hat_NPC_NyakuzaShop_0"),
|
||||
"Main Station Thug A - Item 4": LocData(301051, "Nyakuza Free Roam", dlc_flags=HatDLC.dlc2,
|
||||
nyakuza_thug="Hat_NPC_NyakuzaShop_0"),
|
||||
"Main Station Thug A - Item 5": LocData(301052, "Nyakuza Free Roam", dlc_flags=HatDLC.dlc2,
|
||||
nyakuza_thug="Hat_NPC_NyakuzaShop_0"),
|
||||
|
||||
"Main Station Thug B - Item 1": LocData(301053, "Nyakuza Free Roam", dlc_flags=HatDLC.dlc2,
|
||||
nyakuza_thug="Hat_NPC_NyakuzaShop_1"),
|
||||
"Main Station Thug B - Item 2": LocData(301054, "Nyakuza Free Roam", dlc_flags=HatDLC.dlc2,
|
||||
nyakuza_thug="Hat_NPC_NyakuzaShop_1"),
|
||||
"Main Station Thug B - Item 3": LocData(301055, "Nyakuza Free Roam", dlc_flags=HatDLC.dlc2,
|
||||
nyakuza_thug="Hat_NPC_NyakuzaShop_1"),
|
||||
"Main Station Thug B - Item 4": LocData(301056, "Nyakuza Free Roam", dlc_flags=HatDLC.dlc2,
|
||||
nyakuza_thug="Hat_NPC_NyakuzaShop_1"),
|
||||
"Main Station Thug B - Item 5": LocData(301057, "Nyakuza Free Roam", dlc_flags=HatDLC.dlc2,
|
||||
nyakuza_thug="Hat_NPC_NyakuzaShop_1"),
|
||||
|
||||
"Main Station Thug C - Item 1": LocData(301058, "Nyakuza Free Roam", dlc_flags=HatDLC.dlc2,
|
||||
nyakuza_thug="Hat_NPC_NyakuzaShop_2"),
|
||||
"Main Station Thug C - Item 2": LocData(301059, "Nyakuza Free Roam", dlc_flags=HatDLC.dlc2,
|
||||
nyakuza_thug="Hat_NPC_NyakuzaShop_2"),
|
||||
"Main Station Thug C - Item 3": LocData(301060, "Nyakuza Free Roam", dlc_flags=HatDLC.dlc2,
|
||||
nyakuza_thug="Hat_NPC_NyakuzaShop_2"),
|
||||
"Main Station Thug C - Item 4": LocData(301061, "Nyakuza Free Roam", dlc_flags=HatDLC.dlc2,
|
||||
nyakuza_thug="Hat_NPC_NyakuzaShop_2"),
|
||||
"Main Station Thug C - Item 5": LocData(301062, "Nyakuza Free Roam", dlc_flags=HatDLC.dlc2,
|
||||
nyakuza_thug="Hat_NPC_NyakuzaShop_2"),
|
||||
|
||||
"Yellow Overpass Thug A - Item 1": LocData(301018, "Yellow Overpass Station", dlc_flags=HatDLC.dlc2,
|
||||
nyakuza_thug="Hat_NPC_NyakuzaShop_13"),
|
||||
"Yellow Overpass Thug A - Item 2": LocData(301019, "Yellow Overpass Station", dlc_flags=HatDLC.dlc2,
|
||||
nyakuza_thug="Hat_NPC_NyakuzaShop_13"),
|
||||
"Yellow Overpass Thug A - Item 3": LocData(301020, "Yellow Overpass Station", dlc_flags=HatDLC.dlc2,
|
||||
nyakuza_thug="Hat_NPC_NyakuzaShop_13"),
|
||||
"Yellow Overpass Thug A - Item 4": LocData(301021, "Yellow Overpass Station", dlc_flags=HatDLC.dlc2,
|
||||
nyakuza_thug="Hat_NPC_NyakuzaShop_13"),
|
||||
"Yellow Overpass Thug A - Item 5": LocData(301022, "Yellow Overpass Station", dlc_flags=HatDLC.dlc2,
|
||||
nyakuza_thug="Hat_NPC_NyakuzaShop_13"),
|
||||
|
||||
"Yellow Overpass Thug B - Item 1": LocData(301043, "Yellow Overpass Station", dlc_flags=HatDLC.dlc2,
|
||||
nyakuza_thug="Hat_NPC_NyakuzaShop_5"),
|
||||
"Yellow Overpass Thug B - Item 2": LocData(301044, "Yellow Overpass Station", dlc_flags=HatDLC.dlc2,
|
||||
nyakuza_thug="Hat_NPC_NyakuzaShop_5"),
|
||||
"Yellow Overpass Thug B - Item 3": LocData(301045, "Yellow Overpass Station", dlc_flags=HatDLC.dlc2,
|
||||
nyakuza_thug="Hat_NPC_NyakuzaShop_5"),
|
||||
"Yellow Overpass Thug B - Item 4": LocData(301046, "Yellow Overpass Station", dlc_flags=HatDLC.dlc2,
|
||||
nyakuza_thug="Hat_NPC_NyakuzaShop_5"),
|
||||
"Yellow Overpass Thug B - Item 5": LocData(301047, "Yellow Overpass Station", dlc_flags=HatDLC.dlc2,
|
||||
nyakuza_thug="Hat_NPC_NyakuzaShop_5"),
|
||||
|
||||
"Yellow Overpass Thug C - Item 1": LocData(301063, "Yellow Overpass Station", dlc_flags=HatDLC.dlc2,
|
||||
nyakuza_thug="Hat_NPC_NyakuzaShop_14"),
|
||||
"Yellow Overpass Thug C - Item 2": LocData(301064, "Yellow Overpass Station", dlc_flags=HatDLC.dlc2,
|
||||
nyakuza_thug="Hat_NPC_NyakuzaShop_14"),
|
||||
"Yellow Overpass Thug C - Item 3": LocData(301065, "Yellow Overpass Station", dlc_flags=HatDLC.dlc2,
|
||||
nyakuza_thug="Hat_NPC_NyakuzaShop_14"),
|
||||
"Yellow Overpass Thug C - Item 4": LocData(301066, "Yellow Overpass Station", dlc_flags=HatDLC.dlc2,
|
||||
nyakuza_thug="Hat_NPC_NyakuzaShop_14"),
|
||||
"Yellow Overpass Thug C - Item 5": LocData(301067, "Yellow Overpass Station", dlc_flags=HatDLC.dlc2,
|
||||
nyakuza_thug="Hat_NPC_NyakuzaShop_14"),
|
||||
|
||||
"Green Clean Station Thug A - Item 1": LocData(301033, "Green Clean Station", dlc_flags=HatDLC.dlc2,
|
||||
nyakuza_thug="Hat_NPC_NyakuzaShop_4"),
|
||||
"Green Clean Station Thug A - Item 2": LocData(301034, "Green Clean Station", dlc_flags=HatDLC.dlc2,
|
||||
nyakuza_thug="Hat_NPC_NyakuzaShop_4"),
|
||||
"Green Clean Station Thug A - Item 3": LocData(301035, "Green Clean Station", dlc_flags=HatDLC.dlc2,
|
||||
nyakuza_thug="Hat_NPC_NyakuzaShop_4"),
|
||||
"Green Clean Station Thug A - Item 4": LocData(301036, "Green Clean Station", dlc_flags=HatDLC.dlc2,
|
||||
nyakuza_thug="Hat_NPC_NyakuzaShop_4"),
|
||||
"Green Clean Station Thug A - Item 5": LocData(301037, "Green Clean Station", dlc_flags=HatDLC.dlc2,
|
||||
nyakuza_thug="Hat_NPC_NyakuzaShop_4"),
|
||||
|
||||
# This guy requires either the yellow ticket or the Ice Hat
|
||||
"Green Clean Station Thug B - Item 1": LocData(301028, "Green Clean Station", dlc_flags=HatDLC.dlc2,
|
||||
required_hats=[HatType.ICE], nyakuza_thug="Hat_NPC_NyakuzaShop_6"),
|
||||
"Green Clean Station Thug B - Item 2": LocData(301029, "Green Clean Station", dlc_flags=HatDLC.dlc2,
|
||||
required_hats=[HatType.ICE], nyakuza_thug="Hat_NPC_NyakuzaShop_6"),
|
||||
"Green Clean Station Thug B - Item 3": LocData(301030, "Green Clean Station", dlc_flags=HatDLC.dlc2,
|
||||
required_hats=[HatType.ICE], nyakuza_thug="Hat_NPC_NyakuzaShop_6"),
|
||||
"Green Clean Station Thug B - Item 4": LocData(301031, "Green Clean Station", dlc_flags=HatDLC.dlc2,
|
||||
required_hats=[HatType.ICE], nyakuza_thug="Hat_NPC_NyakuzaShop_6"),
|
||||
"Green Clean Station Thug B - Item 5": LocData(301032, "Green Clean Station", dlc_flags=HatDLC.dlc2,
|
||||
required_hats=[HatType.ICE], nyakuza_thug="Hat_NPC_NyakuzaShop_6"),
|
||||
|
||||
"Bluefin Tunnel Thug - Item 1": LocData(301023, "Bluefin Tunnel", dlc_flags=HatDLC.dlc2,
|
||||
nyakuza_thug="Hat_NPC_NyakuzaShop_7"),
|
||||
"Bluefin Tunnel Thug - Item 2": LocData(301024, "Bluefin Tunnel", dlc_flags=HatDLC.dlc2,
|
||||
nyakuza_thug="Hat_NPC_NyakuzaShop_7"),
|
||||
"Bluefin Tunnel Thug - Item 3": LocData(301025, "Bluefin Tunnel", dlc_flags=HatDLC.dlc2,
|
||||
nyakuza_thug="Hat_NPC_NyakuzaShop_7"),
|
||||
"Bluefin Tunnel Thug - Item 4": LocData(301026, "Bluefin Tunnel", dlc_flags=HatDLC.dlc2,
|
||||
nyakuza_thug="Hat_NPC_NyakuzaShop_7"),
|
||||
"Bluefin Tunnel Thug - Item 5": LocData(301027, "Bluefin Tunnel", dlc_flags=HatDLC.dlc2,
|
||||
nyakuza_thug="Hat_NPC_NyakuzaShop_7"),
|
||||
|
||||
"Pink Paw Station Thug - Item 1": LocData(301038, "Pink Paw Station", dlc_flags=HatDLC.dlc2,
|
||||
required_hats=[HatType.DWELLER], hookshot=True,
|
||||
nyakuza_thug="Hat_NPC_NyakuzaShop_12"),
|
||||
"Pink Paw Station Thug - Item 2": LocData(301039, "Pink Paw Station", dlc_flags=HatDLC.dlc2,
|
||||
required_hats=[HatType.DWELLER], hookshot=True,
|
||||
nyakuza_thug="Hat_NPC_NyakuzaShop_12"),
|
||||
"Pink Paw Station Thug - Item 3": LocData(301040, "Pink Paw Station", dlc_flags=HatDLC.dlc2,
|
||||
required_hats=[HatType.DWELLER], hookshot=True,
|
||||
nyakuza_thug="Hat_NPC_NyakuzaShop_12"),
|
||||
"Pink Paw Station Thug - Item 4": LocData(301041, "Pink Paw Station", dlc_flags=HatDLC.dlc2,
|
||||
required_hats=[HatType.DWELLER], hookshot=True,
|
||||
nyakuza_thug="Hat_NPC_NyakuzaShop_12"),
|
||||
"Pink Paw Station Thug - Item 5": LocData(301042, "Pink Paw Station", dlc_flags=HatDLC.dlc2,
|
||||
required_hats=[HatType.DWELLER], hookshot=True,
|
||||
nyakuza_thug="Hat_NPC_NyakuzaShop_12"),
|
||||
|
||||
}
|
||||
|
||||
# Don't put any of the locations from peaks here, the rules for their entrances are set already
|
||||
zipline_unlocks = {
|
||||
"Alpine Skyline - Bird Pass Fork": "Zipline Unlock - The Birdhouse Path",
|
||||
"Alpine Skyline - Yellow Band Hills": "Zipline Unlock - The Birdhouse Path",
|
||||
"Alpine Skyline - The Purrloined Village: Horned Stone": "Zipline Unlock - The Birdhouse Path",
|
||||
"Alpine Skyline - The Purrloined Village: Chest Reward": "Zipline Unlock - The Birdhouse Path",
|
||||
|
||||
"Alpine Skyline - Mystifying Time Mesa: Zipline": "Zipline Unlock - The Lava Cake Path",
|
||||
"Alpine Skyline - Mystifying Time Mesa: Gate Puzzle": "Zipline Unlock - The Lava Cake Path",
|
||||
"Alpine Skyline - Ember Summit": "Zipline Unlock - The Lava Cake Path",
|
||||
|
||||
"Alpine Skyline - Goat Outpost Horn": "Zipline Unlock - The Windmill Path",
|
||||
"Alpine Skyline - Windy Passage": "Zipline Unlock - The Windmill Path",
|
||||
|
||||
"Alpine Skyline - The Twilight Path": "Zipline Unlock - The Twilight Bell Path",
|
||||
}
|
||||
|
||||
# Locations in Alpine that are available in The Illness has Spread
|
||||
# Goat Village locations don't need to be put here
|
||||
tihs_locations = [
|
||||
"Alpine Skyline - Bird Pass Fork",
|
||||
"Alpine Skyline - Yellow Band Hills",
|
||||
"Alpine Skyline - Ember Summit",
|
||||
"Alpine Skyline - Goat Outpost Horn",
|
||||
"Alpine Skyline - Windy Passage",
|
||||
]
|
||||
|
||||
event_locs = {
|
||||
"Birdhouse Cleared": LocData(0, "The Birdhouse"),
|
||||
"Lava Cake Cleared": LocData(0, "The Lava Cake"),
|
||||
"Windmill Cleared": LocData(0, "The Windmill"),
|
||||
"Twilight Bell Cleared": LocData(0, "The Twilight Bell"),
|
||||
"Time Piece Cluster": LocData(0, "The Finale"),
|
||||
|
||||
# not really an act
|
||||
"Nyakuza Intro Cleared": LocData(0, "Nyakuza Free Roam", dlc_flags=HatDLC.dlc2, act_complete_event=False),
|
||||
|
||||
"Yellow Overpass Station Cleared": LocData(0, "Yellow Overpass Station", dlc_flags=HatDLC.dlc2),
|
||||
"Green Clean Station Cleared": LocData(0, "Green Clean Station", dlc_flags=HatDLC.dlc2),
|
||||
"Bluefin Tunnel Cleared": LocData(0, "Bluefin Tunnel", dlc_flags=HatDLC.dlc2),
|
||||
"Pink Paw Station Cleared": LocData(0, "Pink Paw Station", dlc_flags=HatDLC.dlc2),
|
||||
"Yellow Overpass Manhole Cleared": LocData(0, "Yellow Overpass Manhole", dlc_flags=HatDLC.dlc2),
|
||||
"Green Clean Manhole Cleared": LocData(0, "Green Clean Manhole", dlc_flags=HatDLC.dlc2),
|
||||
"Pink Paw Manhole Cleared": LocData(0, "Pink Paw Manhole", dlc_flags=HatDLC.dlc2),
|
||||
"Rush Hour Cleared": LocData(0, "Rush Hour", dlc_flags=HatDLC.dlc2),
|
||||
}
|
||||
|
||||
location_table = {
|
||||
**ahit_locations,
|
||||
**act_completions,
|
||||
**storybook_pages,
|
||||
**contract_locations,
|
||||
**shop_locations,
|
||||
}
|
||||
517
worlds/ahit/Options.py
Normal file
517
worlds/ahit/Options.py
Normal file
@@ -0,0 +1,517 @@
|
||||
import typing
|
||||
from worlds.AutoWorld import World
|
||||
from Options import Option, Range, Toggle, DeathLink, Choice
|
||||
from .Items import get_total_time_pieces
|
||||
|
||||
|
||||
def adjust_options(world: World):
|
||||
world.multiworld.HighestChapterCost[world.player].value = max(
|
||||
world.multiworld.HighestChapterCost[world.player].value,
|
||||
world.multiworld.LowestChapterCost[world.player].value)
|
||||
|
||||
world.multiworld.LowestChapterCost[world.player].value = min(
|
||||
world.multiworld.LowestChapterCost[world.player].value,
|
||||
world.multiworld.HighestChapterCost[world.player].value)
|
||||
|
||||
world.multiworld.FinalChapterMinCost[world.player].value = min(
|
||||
world.multiworld.FinalChapterMinCost[world.player].value,
|
||||
world.multiworld.FinalChapterMaxCost[world.player].value)
|
||||
|
||||
world.multiworld.FinalChapterMaxCost[world.player].value = max(
|
||||
world.multiworld.FinalChapterMaxCost[world.player].value,
|
||||
world.multiworld.FinalChapterMinCost[world.player].value)
|
||||
|
||||
world.multiworld.BadgeSellerMinItems[world.player].value = min(
|
||||
world.multiworld.BadgeSellerMinItems[world.player].value,
|
||||
world.multiworld.BadgeSellerMaxItems[world.player].value)
|
||||
|
||||
world.multiworld.BadgeSellerMaxItems[world.player].value = max(
|
||||
world.multiworld.BadgeSellerMinItems[world.player].value,
|
||||
world.multiworld.BadgeSellerMaxItems[world.player].value)
|
||||
|
||||
total_tps: int = get_total_time_pieces(world)
|
||||
if world.multiworld.HighestChapterCost[world.player].value > total_tps-5:
|
||||
world.multiworld.HighestChapterCost[world.player].value = min(45, total_tps-5)
|
||||
|
||||
if world.multiworld.FinalChapterMaxCost[world.player].value > total_tps:
|
||||
world.multiworld.FinalChapterMaxCost[world.player].value = min(50, total_tps)
|
||||
|
||||
# Don't allow Rush Hour goal if DLC2 content is disabled
|
||||
if world.multiworld.EndGoal[world.player].value == 2 and world.multiworld.EnableDLC2[world.player].value == 0:
|
||||
world.multiworld.EndGoal[world.player].value = 1
|
||||
|
||||
|
||||
# General
|
||||
class EndGoal(Choice):
|
||||
"""The end goal required to beat the game.
|
||||
Finale: Reach Time's End and beat Mustache Girl. The Finale will be in its vanilla location.
|
||||
|
||||
Rush Hour: Reach and complete Rush Hour. The level will be in its vanilla location and Chapter 7
|
||||
will be the final chapter. You also must find Nyakuza Metro itself and complete all of its levels.
|
||||
Requires DLC2 content to be enabled."""
|
||||
display_name = "End Goal"
|
||||
option_finale = 1
|
||||
option_rush_hour = 2
|
||||
default = 1
|
||||
|
||||
|
||||
class ActRandomizer(Choice):
|
||||
"""If enabled, shuffle the game's Acts between each other.
|
||||
Light will cause Time Rifts to only be shuffled amongst each other,
|
||||
and Blue Time Rifts and Purple Time Rifts are shuffled separately."""
|
||||
display_name = "Shuffle Acts"
|
||||
option_false = 0
|
||||
option_light = 1
|
||||
option_insanity = 2
|
||||
default = 1
|
||||
|
||||
|
||||
class ShuffleAlpineZiplines(Toggle):
|
||||
"""If enabled, Alpine's zipline paths leading to the peaks will be locked behind items."""
|
||||
display_name = "Shuffle Alpine Ziplines"
|
||||
default = 0
|
||||
|
||||
|
||||
class VanillaAlpine(Choice):
|
||||
"""If enabled, force Alpine (and optionally its finale) onto their vanilla locations in act shuffle."""
|
||||
display_name = "Vanilla Alpine Skyline"
|
||||
option_false = 0
|
||||
option_true = 1
|
||||
option_finale = 2
|
||||
default = 0
|
||||
|
||||
|
||||
class LogicDifficulty(Choice):
|
||||
"""Choose the difficulty setting for logic. Note that Hard or above will force SDJ logic on."""
|
||||
display_name = "Logic Difficulty"
|
||||
option_normal = 0
|
||||
option_hard = 1
|
||||
option_expert = 2
|
||||
default = 0
|
||||
|
||||
|
||||
class RandomizeHatOrder(Toggle):
|
||||
"""Randomize the order that hats are stitched in."""
|
||||
display_name = "Randomize Hat Order"
|
||||
default = 1
|
||||
|
||||
|
||||
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"
|
||||
default = 0
|
||||
|
||||
|
||||
class StartWithCompassBadge(Toggle):
|
||||
"""If enabled, start with the Compass Badge. In Archipelago, the Compass Badge will track all items in the world
|
||||
(instead of just Relics). Recommended if you're not familiar with where item locations are."""
|
||||
display_name = "Start with Compass Badge"
|
||||
default = 1
|
||||
|
||||
|
||||
class CompassBadgeMode(Choice):
|
||||
"""closest - Compass Badge points to the closest item regardless of classification
|
||||
important_only - Compass Badge points to progression/useful items only
|
||||
important_first - Compass Badge points to progression/useful items first, then it will point to junk items"""
|
||||
display_name = "Compass Badge Mode"
|
||||
option_closest = 1
|
||||
option_important_only = 2
|
||||
option_important_first = 3
|
||||
default = 1
|
||||
|
||||
|
||||
class ShuffleStorybookPages(Toggle):
|
||||
"""If enabled, each storybook page in the purple Time Rifts is an item check.
|
||||
The Compass Badge can track these down for you."""
|
||||
display_name = "Shuffle Storybook Pages"
|
||||
default = 1
|
||||
|
||||
|
||||
class ShuffleActContracts(Toggle):
|
||||
"""If enabled, shuffle Snatcher's act contracts into the pool as items"""
|
||||
display_name = "Shuffle Contracts"
|
||||
default = 1
|
||||
|
||||
|
||||
class ShuffleSubconPaintings(Toggle):
|
||||
"""If enabled, shuffle items into the pool that unlock Subcon Forest fire spirit paintings.
|
||||
These items are progressive, with the order of Village-Swamp-Courtyard."""
|
||||
display_name = "Shuffle Subcon Paintings"
|
||||
default = 0
|
||||
|
||||
|
||||
class StartingChapter(Choice):
|
||||
"""Determines which chapter you will be guaranteed to be able to enter at the beginning of the game."""
|
||||
display_name = "Starting Chapter"
|
||||
option_1 = 1
|
||||
option_2 = 2
|
||||
option_3 = 3
|
||||
option_4 = 4
|
||||
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"
|
||||
default = 0
|
||||
|
||||
|
||||
# DLC
|
||||
class EnableDLC1(Toggle):
|
||||
"""Shuffle content from The Arctic Cruise (Chapter 6) into the game. This also includes the Tour time rift.
|
||||
DO NOT ENABLE THIS OPTION IF YOU DO NOT HAVE SEAL THE DEAL DLC INSTALLED!!!"""
|
||||
display_name = "Shuffle Chapter 6"
|
||||
default = 0
|
||||
|
||||
|
||||
class Tasksanity(Toggle):
|
||||
"""If enabled, Ship Shape tasks will become checks. Requires DLC1 content to be enabled."""
|
||||
display_name = "Tasksanity"
|
||||
default = 0
|
||||
|
||||
|
||||
class TasksanityTaskStep(Range):
|
||||
"""How many tasks the player must complete in Tasksanity to send a check."""
|
||||
display_name = "Tasksanity Task Step"
|
||||
range_start = 1
|
||||
range_end = 3
|
||||
default = 1
|
||||
|
||||
|
||||
class TasksanityCheckCount(Range):
|
||||
"""How many Tasksanity checks there will be in total."""
|
||||
display_name = "Tasksanity Check Count"
|
||||
range_start = 5
|
||||
range_end = 30
|
||||
default = 18
|
||||
|
||||
|
||||
class EnableDLC2(Toggle):
|
||||
"""Shuffle content from Nyakuza Metro (Chapter 7) into the game.
|
||||
DO NOT ENABLE THIS OPTION IF YOU DO NOT HAVE NYAKUZA METRO DLC INSTALLED!!!"""
|
||||
display_name = "Shuffle Chapter 7"
|
||||
default = 0
|
||||
|
||||
|
||||
class MetroMinPonCost(Range):
|
||||
"""The cheapest an item can be in any Nyakuza Metro shop. Includes ticket booths."""
|
||||
display_name = "Metro Shops Minimum Pon Cost"
|
||||
range_start = 10
|
||||
range_end = 800
|
||||
default = 50
|
||||
|
||||
|
||||
class MetroMaxPonCost(Range):
|
||||
"""The most expensive an item can be in any Nyakuza Metro shop. Includes ticket booths."""
|
||||
display_name = "Metro Shops Minimum Pon Cost"
|
||||
range_start = 10
|
||||
range_end = 800
|
||||
default = 200
|
||||
|
||||
|
||||
class NyakuzaThugMinShopItems(Range):
|
||||
"""The smallest amount of items that the thugs in Nyakuza Metro can have for sale."""
|
||||
display_name = "Nyakuza Thug Minimum Shop Items"
|
||||
range_start = 0
|
||||
range_end = 5
|
||||
default = 2
|
||||
|
||||
|
||||
class NyakuzaThugMaxShopItems(Range):
|
||||
"""The largest amount of items that the thugs in Nyakuza Metro can have for sale."""
|
||||
display_name = "Nyakuza Thug Maximum Shop Items"
|
||||
range_start = 0
|
||||
range_end = 5
|
||||
default = 4
|
||||
|
||||
|
||||
class BaseballBat(Toggle):
|
||||
"""Replace the Umbrella with the baseball bat from Nyakuza Metro.
|
||||
DLC2 content does not have to be shuffled for this option but Nyakuza Metro still needs to be installed."""
|
||||
display_name = "Baseball Bat"
|
||||
default = 0
|
||||
|
||||
|
||||
class VanillaMetro(Choice):
|
||||
"""Force Nyakuza Metro (and optionally its finale) onto their vanilla locations in act shuffle."""
|
||||
display_name = "Vanilla Metro"
|
||||
option_false = 0
|
||||
option_true = 1
|
||||
option_finale = 2
|
||||
|
||||
|
||||
class ChapterCostIncrement(Range):
|
||||
"""Lower values mean chapter costs increase slower. Higher values make the cost differences more steep."""
|
||||
display_name = "Chapter Cost Increment"
|
||||
range_start = 1
|
||||
range_end = 8
|
||||
default = 4
|
||||
|
||||
|
||||
class ChapterCostMinDifference(Range):
|
||||
"""The minimum difference between chapter costs."""
|
||||
display_name = "Minimum Chapter Cost Difference"
|
||||
range_start = 1
|
||||
range_end = 8
|
||||
default = 5
|
||||
|
||||
|
||||
class LowestChapterCost(Range):
|
||||
"""Value determining the lowest possible cost for a chapter.
|
||||
Chapter costs will, progressively, be calculated based on this value (except for Chapter 5)."""
|
||||
display_name = "Lowest Possible Chapter Cost"
|
||||
range_start = 0
|
||||
range_end = 10
|
||||
default = 5
|
||||
|
||||
|
||||
class HighestChapterCost(Range):
|
||||
"""Value determining the highest possible cost for a chapter.
|
||||
Chapter costs will, progressively, be calculated based on this value (except for Chapter 5)."""
|
||||
display_name = "Highest Possible Chapter Cost"
|
||||
range_start = 15
|
||||
range_end = 45
|
||||
default = 25
|
||||
|
||||
|
||||
class FinalChapterMinCost(Range):
|
||||
"""Minimum Time Pieces required to enter the final chapter. This is part of your goal."""
|
||||
display_name = "Final Chapter Minimum Time Piece Cost"
|
||||
range_start = 0
|
||||
range_end = 50
|
||||
default = 30
|
||||
|
||||
|
||||
class FinalChapterMaxCost(Range):
|
||||
"""Maximum Time Pieces required to enter the final chapter. This is part of your goal."""
|
||||
display_name = "Final Chapter Maximum Time Piece Cost"
|
||||
range_start = 0
|
||||
range_end = 50
|
||||
default = 35
|
||||
|
||||
|
||||
class MaxExtraTimePieces(Range):
|
||||
"""Maximum amount of extra Time Pieces from the DLCs.
|
||||
Arctic Cruise will add up to 6. Nyakuza Metro will add up to 10. The absolute maximum is 56."""
|
||||
display_name = "Max Extra Time Pieces"
|
||||
range_start = 0
|
||||
range_end = 16
|
||||
default = 16
|
||||
|
||||
|
||||
# Death Wish
|
||||
class EnableDeathWish(Toggle):
|
||||
"""NOT IMPLEMENTED Shuffle Death Wish contracts into the game.
|
||||
Each contract by default will have a single check granted upon completion.
|
||||
DO NOT ENABLE THIS OPTION IF YOU DO NOT HAVE SEAL THE DEAL DLC INSTALLED!!!"""
|
||||
display_name = "Enable Death Wish"
|
||||
default = 0
|
||||
|
||||
|
||||
class DWEnableBonus(Toggle):
|
||||
"""NOT IMPLEMENTED In Death Wish, allow the full completion of contracts to reward items."""
|
||||
display_name = "Shuffle Death Wish Full Completions"
|
||||
default = 0
|
||||
|
||||
|
||||
class DWExcludeAnnoyingContracts(Toggle):
|
||||
"""NOT IMPLEMENTED Exclude Death Wish contracts from the pool that are particularly tedious or take a long time to reach/clear."""
|
||||
display_name = "Exclude Annoying Death Wish Contracts"
|
||||
default = 1
|
||||
|
||||
|
||||
class DWExcludeAnnoyingBonuses(Toggle):
|
||||
"""NOT IMPLEMENTED If Death Wish full completions are shuffled in, exclude particularly tedious Death Wish full completions
|
||||
from the pool"""
|
||||
display_name = "Exclude Annoying Death Wish Full Completions"
|
||||
default = 1
|
||||
|
||||
|
||||
# Yarn
|
||||
class YarnCostMin(Range):
|
||||
"""The minimum possible yarn needed to stitch each hat."""
|
||||
display_name = "Minimum Yarn Cost"
|
||||
range_start = 1
|
||||
range_end = 12
|
||||
default = 4
|
||||
|
||||
|
||||
class YarnCostMax(Range):
|
||||
"""The maximum possible yarn needed to stitch each hat."""
|
||||
display_name = "Maximum Yarn Cost"
|
||||
range_start = 1
|
||||
range_end = 12
|
||||
default = 8
|
||||
|
||||
|
||||
class YarnAvailable(Range):
|
||||
"""How much yarn is available to collect in the item pool."""
|
||||
display_name = "Yarn Available"
|
||||
range_start = 30
|
||||
range_end = 75
|
||||
default = 45
|
||||
|
||||
|
||||
class MinPonCost(Range):
|
||||
"""The minimum amount of Pons that any shop item can cost."""
|
||||
display_name = "Minimum Shop Pon Cost"
|
||||
range_start = 10
|
||||
range_end = 800
|
||||
default = 75
|
||||
|
||||
|
||||
class MaxPonCost(Range):
|
||||
"""The maximum amount of Pons that any shop item can cost."""
|
||||
display_name = "Maximum Shop Pon Cost"
|
||||
range_start = 10
|
||||
range_end = 800
|
||||
default = 400
|
||||
|
||||
|
||||
class BadgeSellerMinItems(Range):
|
||||
"""The smallest amount of items that the Badge Seller can have for sale."""
|
||||
display_name = "Badge Seller Minimum Items"
|
||||
range_start = 0
|
||||
range_end = 10
|
||||
default = 4
|
||||
|
||||
|
||||
class BadgeSellerMaxItems(Range):
|
||||
"""The largest amount of items that the Badge Seller can have for sale."""
|
||||
display_name = "Badge Seller Maximum Items"
|
||||
range_start = 0
|
||||
range_end = 10
|
||||
default = 8
|
||||
|
||||
|
||||
# Traps
|
||||
class TrapChance(Range):
|
||||
"""The chance for any junk item in the pool to be replaced by a trap."""
|
||||
display_name = "Trap Chance"
|
||||
range_start = 0
|
||||
range_end = 100
|
||||
default = 0
|
||||
|
||||
|
||||
class BabyTrapWeight(Range):
|
||||
"""The weight of Baby Traps in the trap pool.
|
||||
Baby Traps place a multitude of the Conductor's grandkids into Hat Kid's hands, causing her to lose her balance."""
|
||||
display_name = "Baby Trap Weight"
|
||||
range_start = 0
|
||||
range_end = 100
|
||||
default = 40
|
||||
|
||||
|
||||
class LaserTrapWeight(Range):
|
||||
"""The weight of Laser Traps in the trap pool.
|
||||
Laser Traps will spawn multiple giant lasers (from Snatcher's boss fight) at Hat Kid's location."""
|
||||
display_name = "Laser Trap Weight"
|
||||
range_start = 0
|
||||
range_end = 100
|
||||
default = 40
|
||||
|
||||
|
||||
class ParadeTrapWeight(Range):
|
||||
"""The weight of Parade Traps in the trap pool.
|
||||
Parade Traps will summon multiple Express Band owls with knives that chase Hat Kid by mimicking her movement."""
|
||||
display_name = "Parade Trap Weight"
|
||||
range_start = 0
|
||||
range_end = 100
|
||||
default = 20
|
||||
|
||||
|
||||
ahit_options: typing.Dict[str, type(Option)] = {
|
||||
|
||||
"EndGoal": EndGoal,
|
||||
"ActRandomizer": ActRandomizer,
|
||||
"ShuffleAlpineZiplines": ShuffleAlpineZiplines,
|
||||
"VanillaAlpine": VanillaAlpine,
|
||||
"LogicDifficulty": LogicDifficulty,
|
||||
"RandomizeHatOrder": RandomizeHatOrder,
|
||||
"UmbrellaLogic": UmbrellaLogic,
|
||||
"StartWithCompassBadge": StartWithCompassBadge,
|
||||
"CompassBadgeMode": CompassBadgeMode,
|
||||
"ShuffleStorybookPages": ShuffleStorybookPages,
|
||||
"ShuffleActContracts": ShuffleActContracts,
|
||||
"ShuffleSubconPaintings": ShuffleSubconPaintings,
|
||||
"StartingChapter": StartingChapter,
|
||||
"SDJLogic": SDJLogic,
|
||||
"CTRWithSprint": CTRWithSprint,
|
||||
|
||||
"EnableDLC1": EnableDLC1,
|
||||
"Tasksanity": Tasksanity,
|
||||
"TasksanityTaskStep": TasksanityTaskStep,
|
||||
"TasksanityCheckCount": TasksanityCheckCount,
|
||||
|
||||
"EnableDeathWish": EnableDeathWish,
|
||||
"EnableDLC2": EnableDLC2,
|
||||
"BaseballBat": BaseballBat,
|
||||
"VanillaMetro": VanillaMetro,
|
||||
"MetroMinPonCost": MetroMinPonCost,
|
||||
"MetroMaxPonCost": MetroMaxPonCost,
|
||||
"NyakuzaThugMinShopItems": NyakuzaThugMinShopItems,
|
||||
"NyakuzaThugMaxShopItems": NyakuzaThugMaxShopItems,
|
||||
|
||||
"LowestChapterCost": LowestChapterCost,
|
||||
"HighestChapterCost": HighestChapterCost,
|
||||
"ChapterCostIncrement": ChapterCostIncrement,
|
||||
"ChapterCostMinDifference": ChapterCostMinDifference,
|
||||
"MaxExtraTimePieces": MaxExtraTimePieces,
|
||||
|
||||
"FinalChapterMinCost": FinalChapterMinCost,
|
||||
"FinalChapterMaxCost": FinalChapterMaxCost,
|
||||
|
||||
"YarnCostMin": YarnCostMin,
|
||||
"YarnCostMax": YarnCostMax,
|
||||
"YarnAvailable": YarnAvailable,
|
||||
|
||||
"MinPonCost": MinPonCost,
|
||||
"MaxPonCost": MaxPonCost,
|
||||
"BadgeSellerMinItems": BadgeSellerMinItems,
|
||||
"BadgeSellerMaxItems": BadgeSellerMaxItems,
|
||||
|
||||
"TrapChance": TrapChance,
|
||||
"BabyTrapWeight": BabyTrapWeight,
|
||||
"LaserTrapWeight": LaserTrapWeight,
|
||||
"ParadeTrapWeight": ParadeTrapWeight,
|
||||
|
||||
"death_link": DeathLink,
|
||||
}
|
||||
|
||||
slot_data_options: typing.Dict[str, type(Option)] = {
|
||||
|
||||
"EndGoal": EndGoal,
|
||||
"ActRandomizer": ActRandomizer,
|
||||
"ShuffleAlpineZiplines": ShuffleAlpineZiplines,
|
||||
"LogicDifficulty": LogicDifficulty,
|
||||
"RandomizeHatOrder": RandomizeHatOrder,
|
||||
"UmbrellaLogic": UmbrellaLogic,
|
||||
"CompassBadgeMode": CompassBadgeMode,
|
||||
"ShuffleStorybookPages": ShuffleStorybookPages,
|
||||
"ShuffleActContracts": ShuffleActContracts,
|
||||
"ShuffleSubconPaintings": ShuffleSubconPaintings,
|
||||
"SDJLogic": SDJLogic,
|
||||
|
||||
"EnableDLC1": EnableDLC1,
|
||||
"Tasksanity": Tasksanity,
|
||||
"TasksanityTaskStep": TasksanityTaskStep,
|
||||
"TasksanityCheckCount": TasksanityCheckCount,
|
||||
|
||||
"EnableDeathWish": EnableDeathWish,
|
||||
|
||||
"EnableDLC2": EnableDLC2,
|
||||
"MetroMinPonCost": MetroMinPonCost,
|
||||
"MetroMaxPonCost": MetroMaxPonCost,
|
||||
"BaseballBat": BaseballBat,
|
||||
|
||||
"MinPonCost": MinPonCost,
|
||||
"MaxPonCost": MaxPonCost,
|
||||
|
||||
"death_link": DeathLink,
|
||||
}
|
||||
760
worlds/ahit/Regions.py
Normal file
760
worlds/ahit/Regions.py
Normal file
@@ -0,0 +1,760 @@
|
||||
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 .Items import HatInTimeItem
|
||||
from .Types import ChapterIndex
|
||||
import typing
|
||||
from .Rules import set_rift_rules
|
||||
|
||||
|
||||
# ChapterIndex: region
|
||||
chapter_regions = {
|
||||
ChapterIndex.SPACESHIP: "Spaceship",
|
||||
ChapterIndex.MAFIA: "Mafia Town",
|
||||
ChapterIndex.BIRDS: "Battle of the Birds",
|
||||
ChapterIndex.SUBCON: "Subcon Forest",
|
||||
ChapterIndex.ALPINE: "Alpine Skyline",
|
||||
ChapterIndex.FINALE: "Time's End",
|
||||
ChapterIndex.CRUISE: "The Arctic Cruise",
|
||||
ChapterIndex.METRO: "Nyakuza Metro",
|
||||
}
|
||||
|
||||
# entrance: region
|
||||
act_entrances = {
|
||||
"Welcome to Mafia Town": "Mafia Town - Act 1",
|
||||
"Barrel Battle": "Mafia Town - Act 2",
|
||||
"She Came from Outer Space": "Mafia Town - Act 3",
|
||||
"Down with the Mafia!": "Mafia Town - Act 4",
|
||||
"Cheating the Race": "Mafia Town - Act 5",
|
||||
"Heating Up Mafia Town": "Mafia Town - Act 6",
|
||||
"The Golden Vault": "Mafia Town - Act 7",
|
||||
|
||||
"Dead Bird Studio": "Battle of the Birds - Act 1",
|
||||
"Murder on the Owl Express": "Battle of the Birds - Act 2",
|
||||
"Picture Perfect": "Battle of the Birds - Act 3",
|
||||
"Train Rush": "Battle of the Birds - Act 4",
|
||||
"The Big Parade": "Battle of the Birds - Act 5",
|
||||
"Award Ceremony": "Battle of the Birds - Finale A",
|
||||
"Dead Bird Studio Basement": "Battle of the Birds - Finale B",
|
||||
|
||||
"Contractual Obligations": "Subcon Forest - Act 1",
|
||||
"The Subcon Well": "Subcon Forest - Act 2",
|
||||
"Toilet of Doom": "Subcon Forest - Act 3",
|
||||
"Queen Vanessa's Manor": "Subcon Forest - Act 4",
|
||||
"Mail Delivery Service": "Subcon Forest - Act 5",
|
||||
"Your Contract has Expired": "Subcon Forest - Finale",
|
||||
|
||||
"Alpine Free Roam": "Alpine Skyline - Free Roam",
|
||||
"The Illness has Spread": "Alpine Skyline - Finale",
|
||||
|
||||
"The Finale": "Time's End - Act 1",
|
||||
|
||||
"Bon Voyage!": "The Arctic Cruise - Act 1",
|
||||
"Ship Shape": "The Arctic Cruise - Act 2",
|
||||
"Rock the Boat": "The Arctic Cruise - Finale",
|
||||
|
||||
"Nyakuza Free Roam": "Nyakuza Metro - Free Roam",
|
||||
"Rush Hour": "Nyakuza Metro - Finale",
|
||||
}
|
||||
|
||||
act_chapters = {
|
||||
"Time Rift - Gallery": "Spaceship",
|
||||
"Time Rift - The Lab": "Spaceship",
|
||||
|
||||
"Welcome to Mafia Town": "Mafia Town",
|
||||
"Barrel Battle": "Mafia Town",
|
||||
"She Came from Outer Space": "Mafia Town",
|
||||
"Down with the Mafia!": "Mafia Town",
|
||||
"Cheating the Race": "Mafia Town",
|
||||
"Heating Up Mafia Town": "Mafia Town",
|
||||
"The Golden Vault": "Mafia Town",
|
||||
"Time Rift - Mafia of Cooks": "Mafia Town",
|
||||
"Time Rift - Sewers": "Mafia Town",
|
||||
"Time Rift - Bazaar": "Mafia Town",
|
||||
|
||||
"Dead Bird Studio": "Battle of the Birds",
|
||||
"Murder on the Owl Express": "Battle of the Birds",
|
||||
"Picture Perfect": "Battle of the Birds",
|
||||
"Train Rush": "Battle of the Birds",
|
||||
"The Big Parade": "Battle of the Birds",
|
||||
"Award Ceremony": "Battle of the Birds",
|
||||
"Dead Bird Studio Basement": "Battle of the Birds",
|
||||
"Time Rift - Dead Bird Studio": "Battle of the Birds",
|
||||
"Time Rift - The Owl Express": "Battle of the Birds",
|
||||
"Time Rift - The Moon": "Battle of the Birds",
|
||||
|
||||
"Contractual Obligations": "Subcon Forest",
|
||||
"The Subcon Well": "Subcon Forest",
|
||||
"Toilet of Doom": "Subcon Forest",
|
||||
"Queen Vanessa's Manor": "Subcon Forest",
|
||||
"Mail Delivery Service": "Subcon Forest",
|
||||
"Your Contract has Expired": "Subcon Forest",
|
||||
"Time Rift - Sleepy Subcon": "Subcon Forest",
|
||||
"Time Rift - Pipe": "Subcon Forest",
|
||||
"Time Rift - Village": "Subcon Forest",
|
||||
|
||||
"Alpine Free Roam": "Alpine Skyline",
|
||||
"The Illness has Spread": "Alpine Skyline",
|
||||
"Time Rift - Alpine Skyline": "Alpine Skyline",
|
||||
"Time Rift - The Twilight Bell": "Alpine Skyline",
|
||||
"Time Rift - Curly Tail Trail": "Alpine Skyline",
|
||||
|
||||
"The Finale": "Time's End",
|
||||
"Time Rift - Tour": "Time's End",
|
||||
|
||||
"Bon Voyage!": "The Arctic Cruise",
|
||||
"Ship Shape": "The Arctic Cruise",
|
||||
"Rock the Boat": "The Arctic Cruise",
|
||||
"Time Rift - Balcony": "The Arctic Cruise",
|
||||
"Time Rift - Deep Sea": "The Arctic Cruise",
|
||||
|
||||
"Nyakuza Free Roam": "Nyakuza Metro",
|
||||
"Rush Hour": "Nyakuza Metro",
|
||||
"Time Rift - Rumbi Factory": "Nyakuza Metro",
|
||||
}
|
||||
|
||||
# region: list[Region]
|
||||
rift_access_regions = {
|
||||
"Time Rift - Gallery": ["Spaceship"],
|
||||
"Time Rift - The Lab": ["Spaceship"],
|
||||
|
||||
"Time Rift - Sewers": ["Welcome to Mafia Town", "Barrel Battle", "She Came from Outer Space",
|
||||
"Down with the Mafia!", "Cheating the Race", "Heating Up Mafia Town",
|
||||
"The Golden Vault"],
|
||||
|
||||
"Time Rift - Bazaar": ["Welcome to Mafia Town", "Barrel Battle", "She Came from Outer Space",
|
||||
"Down with the Mafia!", "Cheating the Race", "Heating Up Mafia Town",
|
||||
"The Golden Vault"],
|
||||
|
||||
"Time Rift - Mafia of Cooks": ["Welcome to Mafia Town", "Barrel Battle", "She Came from Outer Space",
|
||||
"Down with the Mafia!", "Cheating the Race", "The Golden Vault"],
|
||||
|
||||
"Time Rift - The Owl Express": ["Murder on the Owl Express"],
|
||||
"Time Rift - The Moon": ["Picture Perfect", "The Big Parade"],
|
||||
"Time Rift - Dead Bird Studio": ["Dead Bird Studio", "Dead Bird Studio Basement"],
|
||||
|
||||
"Time Rift - Pipe": ["Contractual Obligations", "The Subcon Well",
|
||||
"Toilet of Doom", "Queen Vanessa's Manor",
|
||||
"Mail Delivery Service"],
|
||||
|
||||
"Time Rift - Village": ["Contractual Obligations", "The Subcon Well",
|
||||
"Toilet of Doom", "Queen Vanessa's Manor",
|
||||
"Mail Delivery Service"],
|
||||
|
||||
"Time Rift - Sleepy Subcon": ["Contractual Obligations", "The Subcon Well",
|
||||
"Toilet of Doom", "Queen Vanessa's Manor",
|
||||
"Mail Delivery Service"],
|
||||
|
||||
"Time Rift - The Twilight Bell": ["Alpine Free Roam"],
|
||||
"Time Rift - Curly Tail Trail": ["Alpine Free Roam"],
|
||||
"Time Rift - Alpine Skyline": ["Alpine Free Roam", "The Illness has Spread"],
|
||||
|
||||
"Time Rift - Tour": ["Time's End"],
|
||||
|
||||
"Time Rift - Balcony": ["Cruise Ship"],
|
||||
"Time Rift - Deep Sea": ["Cruise Ship"],
|
||||
|
||||
"Time Rift - Rumbi Factory": ["Nyakuza Free Roam"],
|
||||
}
|
||||
|
||||
# Hat_ChapterActInfo, from the game files to be used in act shuffle
|
||||
chapter_act_info = {
|
||||
"Time Rift - Gallery": "hatintime_chapterinfo.spaceship.Spaceship_WaterRift_Gallery",
|
||||
"Time Rift - The Lab": "hatintime_chapterinfo.spaceship.Spaceship_WaterRift_MailRoom",
|
||||
|
||||
"Welcome to Mafia Town": "hatintime_chapterinfo.MafiaTown.MafiaTown_Welcome",
|
||||
"Barrel Battle": "hatintime_chapterinfo.MafiaTown.MafiaTown_BarrelBattle",
|
||||
"She Came from Outer Space": "hatintime_chapterinfo.MafiaTown.MafiaTown_AlienChase",
|
||||
"Down with the Mafia!": "hatintime_chapterinfo.MafiaTown.MafiaTown_MafiaBoss",
|
||||
"Cheating the Race": "hatintime_chapterinfo.MafiaTown.MafiaTown_Race",
|
||||
"Heating Up Mafia Town": "hatintime_chapterinfo.MafiaTown.MafiaTown_Lava",
|
||||
"The Golden Vault": "hatintime_chapterinfo.MafiaTown.MafiaTown_GoldenVault",
|
||||
"Time Rift - Mafia of Cooks": "hatintime_chapterinfo.MafiaTown.MafiaTown_CaveRift_Mafia",
|
||||
"Time Rift - Sewers": "hatintime_chapterinfo.MafiaTown.MafiaTown_WaterRift_Easy",
|
||||
"Time Rift - Bazaar": "hatintime_chapterinfo.MafiaTown.MafiaTown_WaterRift_Hard",
|
||||
|
||||
"Dead Bird Studio": "hatintime_chapterinfo.BattleOfTheBirds.BattleOfTheBirds_DeadBirdStudio",
|
||||
"Murder on the Owl Express": "hatintime_chapterinfo.BattleOfTheBirds.BattleOfTheBirds_Murder",
|
||||
"Picture Perfect": "hatintime_chapterinfo.BattleOfTheBirds.BattleOfTheBirds_PicturePerfect",
|
||||
"Train Rush": "hatintime_chapterinfo.BattleOfTheBirds.BattleOfTheBirds_TrainRush",
|
||||
"The Big Parade": "hatintime_chapterinfo.BattleOfTheBirds.BattleOfTheBirds_Parade",
|
||||
"Award Ceremony": "hatintime_chapterinfo.BattleOfTheBirds.BattleOfTheBirds_AwardCeremony",
|
||||
"Dead Bird Studio Basement": "DeadBirdBasement", # Dead Bird Studio Basement has no ChapterActInfo
|
||||
"Time Rift - Dead Bird Studio": "hatintime_chapterinfo.BattleOfTheBirds.BattleOfTheBirds_CaveRift_Basement",
|
||||
"Time Rift - The Owl Express": "hatintime_chapterinfo.BattleOfTheBirds.BattleOfTheBirds_WaterRift_Panels",
|
||||
"Time Rift - The Moon": "hatintime_chapterinfo.BattleOfTheBirds.BattleOfTheBirds_WaterRift_Parade",
|
||||
|
||||
"Contractual Obligations": "hatintime_chapterinfo.subconforest.SubconForest_IceWall",
|
||||
"The Subcon Well": "hatintime_chapterinfo.subconforest.SubconForest_Cave",
|
||||
"Toilet of Doom": "hatintime_chapterinfo.subconforest.SubconForest_Toilet",
|
||||
"Queen Vanessa's Manor": "hatintime_chapterinfo.subconforest.SubconForest_Manor",
|
||||
"Mail Delivery Service": "hatintime_chapterinfo.subconforest.SubconForest_MailDelivery",
|
||||
"Your Contract has Expired": "hatintime_chapterinfo.subconforest.SubconForest_SnatcherBoss",
|
||||
"Time Rift - Sleepy Subcon": "hatintime_chapterinfo.subconforest.SubconForest_CaveRift_Raccoon",
|
||||
"Time Rift - Pipe": "hatintime_chapterinfo.subconforest.SubconForest_WaterRift_Hookshot",
|
||||
"Time Rift - Village": "hatintime_chapterinfo.subconforest.SubconForest_WaterRift_Dwellers",
|
||||
|
||||
"Alpine Free Roam": "hatintime_chapterinfo.AlpineSkyline.AlpineSkyline_IntroMountain",
|
||||
"The Illness has Spread": "hatintime_chapterinfo.AlpineSkyline.AlpineSkyline_Finale",
|
||||
"Time Rift - Alpine Skyline": "hatintime_chapterinfo.AlpineSkyline.AlpineSkyline_CaveRift_Alpine",
|
||||
"Time Rift - The Twilight Bell": "hatintime_chapterinfo.AlpineSkyline.AlpineSkyline_WaterRift_Goats",
|
||||
"Time Rift - Curly Tail Trail": "hatintime_chapterinfo.AlpineSkyline.AlpineSkyline_WaterRift_Cats",
|
||||
|
||||
"The Finale": "hatintime_chapterinfo.TheFinale.TheFinale_FinalBoss",
|
||||
"Time Rift - Tour": "hatintime_chapterinfo_dlc1.spaceship.CaveRift_Tour",
|
||||
|
||||
"Bon Voyage!": "hatintime_chapterinfo_dlc1.Cruise.Cruise_Boarding",
|
||||
"Ship Shape": "hatintime_chapterinfo_dlc1.Cruise.Cruise_Working",
|
||||
"Rock the Boat": "hatintime_chapterinfo_dlc1.Cruise.Cruise_Sinking",
|
||||
"Time Rift - Balcony": "hatintime_chapterinfo_dlc1.Cruise.Cruise_WaterRift_Slide",
|
||||
"Time Rift - Deep Sea": "hatintime_chapterinfo_dlc1.Cruise.Cruise_CaveRift",
|
||||
|
||||
"Nyakuza Free Roam": "hatintime_chapterinfo_dlc2.metro.Metro_FreeRoam",
|
||||
"Rush Hour": "hatintime_chapterinfo_dlc2.metro.Metro_Escape",
|
||||
"Time Rift - Rumbi Factory": "hatintime_chapterinfo_dlc2.metro.Metro_RumbiFactory"
|
||||
}
|
||||
|
||||
# Guarantee that the first level a player can access is a location dense area beatable with no items
|
||||
guaranteed_first_acts = [
|
||||
"Welcome to Mafia Town",
|
||||
"Barrel Battle",
|
||||
"She Came from Outer Space",
|
||||
"Down with the Mafia!",
|
||||
"Heating Up Mafia Town", # Removed in umbrella logic
|
||||
"The Golden Vault",
|
||||
|
||||
"Contractual Obligations", # Removed in painting logic
|
||||
"Queen Vanessa's Manor", # Removed in umbrella/painting logic
|
||||
]
|
||||
|
||||
purple_time_rifts = [
|
||||
"Time Rift - Mafia of Cooks",
|
||||
"Time Rift - Dead Bird Studio",
|
||||
"Time Rift - Sleepy Subcon",
|
||||
"Time Rift - Alpine Skyline",
|
||||
"Time Rift - Deep Sea",
|
||||
"Time Rift - Tour",
|
||||
"Time Rift - Rumbi Factory",
|
||||
]
|
||||
|
||||
# Acts blacklisted in act shuffle
|
||||
# entrance: region
|
||||
blacklisted_acts = {
|
||||
"Battle of the Birds - Finale A": "Award Ceremony",
|
||||
"Time's End - Act 1": "The Finale",
|
||||
}
|
||||
|
||||
|
||||
def create_regions(world: World):
|
||||
w = world
|
||||
mw = world.multiworld
|
||||
p = world.player
|
||||
|
||||
# ------------------------------------------- HUB -------------------------------------------------- #
|
||||
menu = create_region(w, "Menu")
|
||||
spaceship = create_region_and_connect(w, "Spaceship", "Save File -> Spaceship", menu)
|
||||
create_rift_connections(w, create_region(w, "Time Rift - Gallery"))
|
||||
create_rift_connections(w, create_region(w, "Time Rift - The Lab"))
|
||||
|
||||
# ------------------------------------------- MAFIA TOWN ------------------------------------------- #
|
||||
mafia_town = create_region_and_connect(w, "Mafia Town", "Telescope -> Mafia Town", spaceship)
|
||||
mt_act1 = create_region_and_connect(w, "Welcome to Mafia Town", "Mafia Town - Act 1", mafia_town)
|
||||
mt_act2 = create_region_and_connect(w, "Barrel Battle", "Mafia Town - Act 2", mafia_town)
|
||||
mt_act3 = create_region_and_connect(w, "She Came from Outer Space", "Mafia Town - Act 3", mafia_town)
|
||||
mt_act4 = create_region_and_connect(w, "Down with the Mafia!", "Mafia Town - Act 4", mafia_town)
|
||||
mt_act6 = create_region_and_connect(w, "Heating Up Mafia Town", "Mafia Town - Act 6", mafia_town)
|
||||
mt_act5 = create_region_and_connect(w, "Cheating the Race", "Mafia Town - Act 5", mafia_town)
|
||||
mt_act7 = create_region_and_connect(w, "The Golden Vault", "Mafia Town - Act 7", mafia_town)
|
||||
|
||||
# ------------------------------------------- BOTB ------------------------------------------------- #
|
||||
botb = create_region_and_connect(w, "Battle of the Birds", "Telescope -> Battle of the Birds", spaceship)
|
||||
dbs = create_region_and_connect(w, "Dead Bird Studio", "Battle of the Birds - Act 1", botb)
|
||||
create_region_and_connect(w, "Murder on the Owl Express", "Battle of the Birds - Act 2", botb)
|
||||
create_region_and_connect(w, "Picture Perfect", "Battle of the Birds - Act 3", botb)
|
||||
create_region_and_connect(w, "Train Rush", "Battle of the Birds - Act 4", botb)
|
||||
create_region_and_connect(w, "The Big Parade", "Battle of the Birds - Act 5", botb)
|
||||
create_region_and_connect(w, "Award Ceremony", "Battle of the Birds - Finale A", botb)
|
||||
create_region_and_connect(w, "Dead Bird Studio Basement", "Battle of the Birds - Finale B", botb)
|
||||
create_rift_connections(w, create_region(w, "Time Rift - Dead Bird Studio"))
|
||||
create_rift_connections(w, create_region(w, "Time Rift - The Owl Express"))
|
||||
create_rift_connections(w, create_region(w, "Time Rift - The Moon"))
|
||||
|
||||
# Items near the Dead Bird Studio elevator can be reached from the basement act
|
||||
ev_area = create_region_and_connect(w, "Dead Bird Studio - Elevator Area", "DBS -> Elevator Area", dbs)
|
||||
connect_regions(mw.get_region("Dead Bird Studio Basement", p), ev_area, "DBS Basement -> Elevator Area", p)
|
||||
|
||||
# ------------------------------------------- SUBCON FOREST --------------------------------------- #
|
||||
subcon_forest = create_region_and_connect(w, "Subcon Forest", "Telescope -> Subcon Forest", spaceship)
|
||||
sf_act1 = create_region_and_connect(w, "Contractual Obligations", "Subcon Forest - Act 1", subcon_forest)
|
||||
sf_act2 = create_region_and_connect(w, "The Subcon Well", "Subcon Forest - Act 2", subcon_forest)
|
||||
sf_act3 = create_region_and_connect(w, "Toilet of Doom", "Subcon Forest - Act 3", subcon_forest)
|
||||
sf_act4 = create_region_and_connect(w, "Queen Vanessa's Manor", "Subcon Forest - Act 4", subcon_forest)
|
||||
sf_act5 = create_region_and_connect(w, "Mail Delivery Service", "Subcon Forest - Act 5", subcon_forest)
|
||||
create_region_and_connect(w, "Your Contract has Expired", "Subcon Forest - Finale", subcon_forest)
|
||||
|
||||
# ------------------------------------------- ALPINE SKYLINE ------------------------------------------ #
|
||||
alpine_skyline = create_region_and_connect(w, "Alpine Skyline", "Telescope -> Alpine Skyline", spaceship)
|
||||
alpine_freeroam = create_region_and_connect(w, "Alpine Free Roam", "Alpine Skyline - Free Roam", alpine_skyline)
|
||||
alpine_area = create_region_and_connect(w, "Alpine Skyline Area", "AFR -> Alpine Skyline Area", alpine_freeroam)
|
||||
goat_village = create_region_and_connect(w, "Goat Village", "ASA -> Goat Village", alpine_area)
|
||||
|
||||
create_region_and_connect(w, "The Birdhouse", "-> The Birdhouse", alpine_area)
|
||||
create_region_and_connect(w, "The Lava Cake", "-> The Lava Cake", alpine_area)
|
||||
create_region_and_connect(w, "The Windmill", "-> The Windmill", alpine_area)
|
||||
create_region_and_connect(w, "The Twilight Bell", "-> The Twilight Bell", alpine_area)
|
||||
|
||||
illness = create_region_and_connect(w, "The Illness has Spread", "Alpine Skyline - Finale", alpine_skyline)
|
||||
connect_regions(illness, alpine_area, "TIHS -> Alpine Skyline Area", p)
|
||||
connect_regions(illness, goat_village, "TIHS -> Goat Village", p)
|
||||
create_rift_connections(w, create_region(w, "Time Rift - Alpine Skyline"))
|
||||
create_rift_connections(w, create_region(w, "Time Rift - The Twilight Bell"))
|
||||
create_rift_connections(w, create_region(w, "Time Rift - Curly Tail Trail"))
|
||||
|
||||
# ------------------------------------------- OTHER -------------------------------------------------- #
|
||||
mt_area: Region = create_region(w, "Mafia Town Area")
|
||||
mt_area_humt: Region = create_region(w, "Mafia Town Area (HUMT)")
|
||||
connect_regions(mt_area, mt_area_humt, "MT Area -> MT Area (HUMT)", p)
|
||||
connect_regions(mt_act1, mt_area, "Mafia Town Entrance WTMT", p)
|
||||
connect_regions(mt_act2, mt_area, "Mafia Town Entrance BB", p)
|
||||
connect_regions(mt_act3, mt_area, "Mafia Town Entrance SCFOS", p)
|
||||
connect_regions(mt_act4, mt_area, "Mafia Town Entrance DWTM", p)
|
||||
connect_regions(mt_act5, mt_area, "Mafia Town Entrance CTR", p)
|
||||
connect_regions(mt_act6, mt_area_humt, "Mafia Town Entrance HUMT", p)
|
||||
connect_regions(mt_act7, mt_area, "Mafia Town Entrance TGV", p)
|
||||
|
||||
create_rift_connections(w, create_region(w, "Time Rift - Mafia of Cooks"))
|
||||
create_rift_connections(w, create_region(w, "Time Rift - Sewers"))
|
||||
create_rift_connections(w, create_region(w, "Time Rift - Bazaar"))
|
||||
|
||||
sf_area: Region = create_region(w, "Subcon Forest Area")
|
||||
connect_regions(sf_act1, sf_area, "Subcon Forest Entrance CO", p)
|
||||
connect_regions(sf_act2, sf_area, "Subcon Forest Entrance SW", p)
|
||||
connect_regions(sf_act3, sf_area, "Subcon Forest Entrance TOD", p)
|
||||
connect_regions(sf_act4, sf_area, "Subcon Forest Entrance QVM", p)
|
||||
connect_regions(sf_act5, sf_area, "Subcon Forest Entrance MDS", p)
|
||||
|
||||
create_rift_connections(w, create_region(w, "Time Rift - Sleepy Subcon"))
|
||||
create_rift_connections(w, create_region(w, "Time Rift - Pipe"))
|
||||
create_rift_connections(w, create_region(w, "Time Rift - Village"))
|
||||
|
||||
badge_seller = create_badge_seller(w)
|
||||
connect_regions(mt_area, badge_seller, "MT Area -> Badge Seller", p)
|
||||
connect_regions(mt_area_humt, badge_seller, "MT Area (HUMT) -> Badge Seller", p)
|
||||
connect_regions(sf_area, badge_seller, "SF Area -> Badge Seller", p)
|
||||
connect_regions(mw.get_region("Dead Bird Studio", p), badge_seller, "DBS -> Badge Seller", p)
|
||||
connect_regions(mw.get_region("Picture Perfect", p), badge_seller, "PP -> Badge Seller", p)
|
||||
connect_regions(mw.get_region("Train Rush", p), badge_seller, "TR -> Badge Seller", p)
|
||||
connect_regions(mw.get_region("Goat Village", p), badge_seller, "GV -> Badge Seller", p)
|
||||
|
||||
times_end = create_region_and_connect(w, "Time's End", "Telescope -> Time's End", spaceship)
|
||||
create_region_and_connect(w, "The Finale", "Time's End - Act 1", times_end)
|
||||
|
||||
# ------------------------------------------- DLC1 ------------------------------------------------- #
|
||||
if mw.EnableDLC1[p].value > 0:
|
||||
arctic_cruise = create_region_and_connect(w, "The Arctic Cruise", "Telescope -> The Arctic Cruise", spaceship)
|
||||
cruise_ship = create_region(w, "Cruise Ship")
|
||||
|
||||
ac_act1 = create_region_and_connect(w, "Bon Voyage!", "The Arctic Cruise - Act 1", arctic_cruise)
|
||||
ac_act2 = create_region_and_connect(w, "Ship Shape", "The Arctic Cruise - Act 2", arctic_cruise)
|
||||
ac_act3 = create_region_and_connect(w, "Rock the Boat", "The Arctic Cruise - Finale", arctic_cruise)
|
||||
|
||||
connect_regions(ac_act1, cruise_ship, "Cruise Ship Entrance BV", p)
|
||||
connect_regions(ac_act2, cruise_ship, "Cruise Ship Entrance SS", p)
|
||||
connect_regions(ac_act3, cruise_ship, "Cruise Ship Entrance RTB", p)
|
||||
create_rift_connections(w, create_region(w, "Time Rift - Balcony"))
|
||||
create_rift_connections(w, create_region(w, "Time Rift - Deep Sea"))
|
||||
create_rift_connections(w, create_region(w, "Time Rift - Tour"))
|
||||
|
||||
if mw.Tasksanity[p].value > 0:
|
||||
create_tasksanity_locations(w)
|
||||
|
||||
# force recache
|
||||
mw.get_region("Time Rift - Deep Sea", p)
|
||||
|
||||
connect_regions(mw.get_region("Cruise Ship", p), badge_seller, "CS -> Badge Seller", p)
|
||||
|
||||
if mw.EnableDLC2[p].value > 0:
|
||||
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)
|
||||
|
||||
yellow = create_region_and_connect(w, "Yellow Overpass Station", "-> Yellow Overpass Station", metro_freeroam)
|
||||
green = create_region_and_connect(w, "Green Clean Station", "-> Green Clean Station", metro_freeroam)
|
||||
pink = create_region_and_connect(w, "Pink Paw Station", "-> Pink Paw Station", metro_freeroam)
|
||||
create_region_and_connect(w, "Bluefin Tunnel", "-> Bluefin Tunnel", metro_freeroam) # No manhole
|
||||
|
||||
create_region_and_connect(w, "Yellow Overpass Manhole", "-> Yellow Overpass Manhole", yellow)
|
||||
create_region_and_connect(w, "Green Clean Manhole", "-> Green Clean Manhole", green)
|
||||
create_region_and_connect(w, "Pink Paw Manhole", "-> Pink Paw Manhole", pink)
|
||||
|
||||
create_rift_connections(w, create_region(w, "Time Rift - Rumbi Factory"))
|
||||
create_thug_shops(w)
|
||||
|
||||
# force recache
|
||||
mw.get_region("Time Rift - Sewers", p)
|
||||
|
||||
|
||||
def create_rift_connections(world: World, region: Region):
|
||||
i = 1
|
||||
for name in rift_access_regions[region.name]:
|
||||
act_region = world.multiworld.get_region(name, world.player)
|
||||
entrance_name = "{name} Portal - Entrance {num}"
|
||||
connect_regions(act_region, region, entrance_name.format(name=region.name, num=i), world.player)
|
||||
i += 1
|
||||
|
||||
|
||||
def create_tasksanity_locations(world: World):
|
||||
ship_shape: Region = world.multiworld.get_region("Ship Shape", world.player)
|
||||
id_start: int = 300204
|
||||
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):
|
||||
region_list: typing.List[Region] = get_act_regions(world)
|
||||
world.multiworld.random.shuffle(region_list)
|
||||
|
||||
separate_rifts: bool = bool(world.multiworld.ActRandomizer[world.player].value == 1)
|
||||
|
||||
for region in region_list.copy():
|
||||
if (act_chapters[region.name] == "Alpine Skyline" or act_chapters[region.name] == "Nyakuza Metro") \
|
||||
and "Time Rift" not in region.name:
|
||||
region_list.remove(region)
|
||||
region_list.append(region)
|
||||
|
||||
for region in region_list.copy():
|
||||
if "Time Rift" in region.name:
|
||||
region_list.remove(region)
|
||||
region_list.append(region)
|
||||
|
||||
# Reverse the list, so we can do what we want to do first
|
||||
region_list.reverse()
|
||||
|
||||
shuffled_list: typing.List[Region] = []
|
||||
mapped_list: typing.List[Region] = []
|
||||
rift_dict: typing.Dict[str, Region] = {}
|
||||
first_chapter: Region = get_first_chapter_region(world)
|
||||
has_guaranteed: bool = False
|
||||
|
||||
i: int = 0
|
||||
while i < len(region_list):
|
||||
region = region_list[i]
|
||||
i += 1
|
||||
|
||||
# Get the first accessible act, so we can map that to something first
|
||||
if not has_guaranteed:
|
||||
if act_chapters[region.name] != first_chapter.name:
|
||||
continue
|
||||
|
||||
if region.name not in act_entrances.keys() or "Act 1" not in act_entrances[region.name] \
|
||||
and "Free Roam" not in act_entrances[region.name]:
|
||||
continue
|
||||
|
||||
i = 0
|
||||
|
||||
# Already mapped to something else
|
||||
if region in mapped_list:
|
||||
continue
|
||||
|
||||
mapped_list.append(region)
|
||||
|
||||
# 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.append(region)
|
||||
break
|
||||
|
||||
if world.multiworld.VanillaMetro[world.player].value > 0 and region.name == "Nyakuza Free Roam":
|
||||
candidate_list.append(region)
|
||||
break
|
||||
|
||||
if region.name == "Rush Hour":
|
||||
if world.multiworld.EndGoal[world.player].value == 2 or \
|
||||
world.multiworld.VanillaMetro[world.player].value == 2:
|
||||
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:
|
||||
continue
|
||||
|
||||
# Not completable without Umbrella
|
||||
if world.multiworld.UmbrellaLogic[world.player].value > 0 \
|
||||
and (candidate.name == "Heating Up Mafia Town" or candidate.name == "Queen Vanessa's Manor"):
|
||||
continue
|
||||
|
||||
# Subcon sphere 1 is too small without painting unlocks, and no acts are completable either
|
||||
if world.multiworld.ShuffleSubconPaintings[world.player].value > 0 \
|
||||
and "Subcon Forest" in act_entrances[candidate.name]:
|
||||
continue
|
||||
|
||||
candidate_list.append(candidate)
|
||||
has_guaranteed = True
|
||||
break
|
||||
|
||||
# Already mapped onto something else
|
||||
if candidate in shuffled_list:
|
||||
continue
|
||||
|
||||
if separate_rifts:
|
||||
# Don't map Time Rifts to normal acts
|
||||
if "Time Rift" in region.name and "Time Rift" not in candidate.name:
|
||||
continue
|
||||
|
||||
# Don't map normal acts to Time Rifts
|
||||
if "Time Rift" not in region.name and "Time Rift" in candidate.name:
|
||||
continue
|
||||
|
||||
# Separate purple rifts
|
||||
if region.name in purple_time_rifts and candidate.name not in purple_time_rifts \
|
||||
or region.name not in purple_time_rifts and candidate.name in purple_time_rifts:
|
||||
continue
|
||||
|
||||
# Don't map Alpine to its own finale
|
||||
if region.name == "The Illness has Spread" and candidate.name == "Alpine Free Roam":
|
||||
continue
|
||||
|
||||
# Ditto for Metro
|
||||
if region.name == "Rush Hour" and candidate.name == "Nyakuza Free Roam":
|
||||
continue
|
||||
|
||||
if region.name in rift_access_regions and candidate.name in rift_access_regions[region.name]:
|
||||
continue
|
||||
|
||||
candidate_list.append(candidate)
|
||||
|
||||
candidate: Region = candidate_list[world.multiworld.random.randint(0, len(candidate_list)-1)]
|
||||
shuffled_list.append(candidate)
|
||||
|
||||
# Vanilla
|
||||
if candidate.name == region.name:
|
||||
if region.name in rift_access_regions.keys():
|
||||
rift_dict.setdefault(region.name, candidate)
|
||||
|
||||
world.update_chapter_act_info(region, candidate)
|
||||
continue
|
||||
|
||||
if region.name in rift_access_regions.keys():
|
||||
connect_time_rift(world, region, candidate)
|
||||
rift_dict.setdefault(region.name, candidate)
|
||||
else:
|
||||
if candidate.name in rift_access_regions.keys():
|
||||
for e in candidate.entrances.copy():
|
||||
e.parent_region.exits.remove(e)
|
||||
e.connected_region.entrances.remove(e)
|
||||
del e.parent_region
|
||||
del e.connected_region
|
||||
|
||||
entrance = world.multiworld.get_entrance(act_entrances[region.name], world.player)
|
||||
reconnect_regions(entrance, world.multiworld.get_region(act_chapters[region.name], world.player), candidate)
|
||||
|
||||
world.update_chapter_act_info(region, candidate)
|
||||
|
||||
for name in blacklisted_acts.values():
|
||||
if not is_act_blacklisted(world, name):
|
||||
continue
|
||||
|
||||
region: Region = world.multiworld.get_region(name, world.player)
|
||||
world.update_chapter_act_info(region, region)
|
||||
|
||||
set_rift_rules(world, rift_dict)
|
||||
|
||||
|
||||
def connect_time_rift(world: World, time_rift: Region, exit_region: Region):
|
||||
count: int = len(rift_access_regions[time_rift.name])
|
||||
i: int = 1
|
||||
while i <= count:
|
||||
name = format("%s Portal - Entrance %i" % (time_rift.name, i))
|
||||
entrance: Entrance = world.multiworld.get_entrance(name, world.player)
|
||||
reconnect_regions(entrance, entrance.parent_region, exit_region)
|
||||
i += 1
|
||||
|
||||
|
||||
def get_act_regions(world: World) -> typing.List[Region]:
|
||||
act_list: typing.List[Region] = []
|
||||
for region in world.multiworld.get_regions(world.player):
|
||||
if region.name in chapter_act_info.keys():
|
||||
if not is_act_blacklisted(world, region.name):
|
||||
act_list.append(region)
|
||||
|
||||
return act_list
|
||||
|
||||
|
||||
def is_act_blacklisted(world: World, name: str) -> bool:
|
||||
if name == "The Finale":
|
||||
return world.multiworld.EndGoal[world.player].value == 1
|
||||
|
||||
return name in blacklisted_acts.values()
|
||||
|
||||
|
||||
def create_region(world: World, name: str) -> Region:
|
||||
reg = Region(name, world.player, world.multiworld)
|
||||
|
||||
for (key, data) in location_table.items():
|
||||
if data.nyakuza_thug != "":
|
||||
continue
|
||||
|
||||
if data.region == name:
|
||||
if key in storybook_pages.keys() \
|
||||
and world.multiworld.ShuffleStorybookPages[world.player].value == 0:
|
||||
continue
|
||||
|
||||
location = HatInTimeLocation(world.player, key, data.id, reg)
|
||||
reg.locations.append(location)
|
||||
if location.name in shop_locations:
|
||||
world.shop_locs.append(location.name)
|
||||
|
||||
world.multiworld.regions.append(reg)
|
||||
return reg
|
||||
|
||||
|
||||
def create_badge_seller(world: World) -> Region:
|
||||
badge_seller = Region("Badge Seller", world.player, world.multiworld)
|
||||
world.multiworld.regions.append(badge_seller)
|
||||
count: int = 0
|
||||
max_items: int = 0
|
||||
|
||||
if world.multiworld.BadgeSellerMaxItems[world.player].value > 0:
|
||||
max_items = world.multiworld.random.randint(world.multiworld.BadgeSellerMinItems[world.player].value,
|
||||
world.multiworld.BadgeSellerMaxItems[world.player].value)
|
||||
|
||||
if max_items <= 0:
|
||||
world.badge_seller_count = 0
|
||||
return badge_seller
|
||||
|
||||
for (key, data) in shop_locations.items():
|
||||
if "Badge Seller" not in key:
|
||||
continue
|
||||
|
||||
location = HatInTimeLocation(world.player, key, data.id, badge_seller)
|
||||
badge_seller.locations.append(location)
|
||||
world.shop_locs.append(location.name)
|
||||
|
||||
count += 1
|
||||
if count >= max_items:
|
||||
break
|
||||
|
||||
world.badge_seller_count = max_items
|
||||
return badge_seller
|
||||
|
||||
|
||||
def connect_regions(start_region: Region, exit_region: Region, entrancename: str, player: int):
|
||||
entrance = Entrance(player, entrancename, start_region)
|
||||
start_region.exits.append(entrance)
|
||||
entrance.connect(exit_region)
|
||||
|
||||
|
||||
# Takes an entrance, removes its old connections, and reconnects it between the two regions specified.
|
||||
def reconnect_regions(entrance: Entrance, start_region: Region, exit_region: Region):
|
||||
if entrance in entrance.connected_region.entrances:
|
||||
entrance.connected_region.entrances.remove(entrance)
|
||||
|
||||
if entrance in entrance.parent_region.exits:
|
||||
entrance.parent_region.exits.remove(entrance)
|
||||
|
||||
if entrance in start_region.exits:
|
||||
start_region.exits.remove(entrance)
|
||||
|
||||
if entrance in exit_region.entrances:
|
||||
exit_region.entrances.remove(entrance)
|
||||
|
||||
entrance.parent_region = start_region
|
||||
start_region.exits.append(entrance)
|
||||
entrance.connect(exit_region)
|
||||
|
||||
|
||||
def create_region_and_connect(world: World,
|
||||
name: str, entrancename: str, connected_region: Region, is_exit: bool = True) -> Region:
|
||||
|
||||
reg: Region = create_region(world, name)
|
||||
entrance_region: Region
|
||||
exit_region: Region
|
||||
|
||||
if is_exit:
|
||||
entrance_region = connected_region
|
||||
exit_region = reg
|
||||
else:
|
||||
entrance_region = reg
|
||||
exit_region = connected_region
|
||||
|
||||
connect_regions(entrance_region, exit_region, entrancename, world.player)
|
||||
return reg
|
||||
|
||||
|
||||
def get_first_chapter_region(world: World) -> Region:
|
||||
start_chapter: ChapterIndex = world.multiworld.StartingChapter[world.player]
|
||||
return world.multiworld.get_region(chapter_regions.get(start_chapter), world.player)
|
||||
|
||||
|
||||
def get_act_original_chapter(world: World, act_name: str) -> Region:
|
||||
return world.multiworld.get_region(act_chapters[act_name], world.player)
|
||||
|
||||
|
||||
def create_thug_shops(world: World):
|
||||
min_items: int = world.multiworld.NyakuzaThugMinShopItems[world.player].value
|
||||
max_items: int = world.multiworld.NyakuzaThugMaxShopItems[world.player].value
|
||||
count: int = -1
|
||||
step: int = 0
|
||||
old_name: str = ""
|
||||
|
||||
for key, data in shop_locations.items():
|
||||
if data.nyakuza_thug == "":
|
||||
continue
|
||||
|
||||
if old_name != "" and old_name == data.nyakuza_thug:
|
||||
continue
|
||||
|
||||
try:
|
||||
if world.nyakuza_thug_items[data.nyakuza_thug] <= 0:
|
||||
continue
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
if count == -1:
|
||||
count = world.multiworld.random.randint(min_items, max_items)
|
||||
world.nyakuza_thug_items.setdefault(data.nyakuza_thug, count)
|
||||
if count <= 0:
|
||||
continue
|
||||
|
||||
if count >= 1:
|
||||
region = world.multiworld.get_region(data.region, world.player)
|
||||
loc = HatInTimeLocation(world.player, key, data.id, region)
|
||||
region.locations.append(loc)
|
||||
world.shop_locs.append(loc.name)
|
||||
|
||||
step += 1
|
||||
if step >= count:
|
||||
old_name = data.nyakuza_thug
|
||||
step = 0
|
||||
count = -1
|
||||
|
||||
|
||||
def create_events(world: World) -> int:
|
||||
count: int = 0
|
||||
|
||||
for (name, data) in event_locs.items():
|
||||
if not is_location_valid(world, name):
|
||||
continue
|
||||
|
||||
event: Location = create_event(name, world.multiworld.get_region(data.region, world.player), world)
|
||||
|
||||
if data.act_complete_event:
|
||||
act_completion: str = format("Act Completion (%s)" % data.region)
|
||||
event.access_rule = world.multiworld.get_location(act_completion, world.player).access_rule
|
||||
|
||||
count += 1
|
||||
|
||||
return count
|
||||
|
||||
|
||||
def create_event(name: str, region: Region, world: World) -> Location:
|
||||
event = HatInTimeLocation(world.player, name, None, region)
|
||||
region.locations.append(event)
|
||||
event.place_locked_item(HatInTimeItem(name, ItemClassification.progression, None, world.player))
|
||||
return event
|
||||
682
worlds/ahit/Rules.py
Normal file
682
worlds/ahit/Rules.py
Normal file
@@ -0,0 +1,682 @@
|
||||
from worlds.AutoWorld import World, CollectionState
|
||||
from worlds.generic.Rules import add_rule, set_rule
|
||||
from .Locations import location_table, tihs_locations, zipline_unlocks, is_location_valid, contract_locations, \
|
||||
shop_locations
|
||||
from .Types import HatType, ChapterIndex
|
||||
from BaseClasses import Location, Entrance, Region
|
||||
import typing
|
||||
|
||||
|
||||
act_connections = {
|
||||
"Mafia Town - Act 2": ["Mafia Town - Act 1"],
|
||||
"Mafia Town - Act 3": ["Mafia Town - Act 1"],
|
||||
"Mafia Town - Act 4": ["Mafia Town - Act 2", "Mafia Town - Act 3"],
|
||||
"Mafia Town - Act 6": ["Mafia Town - Act 4"],
|
||||
"Mafia Town - Act 7": ["Mafia Town - Act 4"],
|
||||
"Mafia Town - Act 5": ["Mafia Town - Act 6", "Mafia Town - Act 7"],
|
||||
|
||||
"Battle of the Birds - Act 2": ["Battle of the Birds - Act 1"],
|
||||
"Battle of the Birds - Act 3": ["Battle of the Birds - Act 1"],
|
||||
"Battle of the Birds - Act 4": ["Battle of the Birds - Act 2", "Battle of the Birds - Act 3"],
|
||||
"Battle of the Birds - Act 5": ["Battle of the Birds - Act 2", "Battle of the Birds - Act 3"],
|
||||
"Battle of the Birds - Finale A": ["Battle of the Birds - Act 4", "Battle of the Birds - Act 5"],
|
||||
"Battle of the Birds - Finale B": ["Battle of the Birds - Finale A"],
|
||||
|
||||
"Subcon Forest - Finale": ["Subcon Forest - Act 1", "Subcon Forest - Act 2",
|
||||
"Subcon Forest - Act 3", "Subcon Forest - Act 4",
|
||||
"Subcon Forest - Act 5"],
|
||||
|
||||
"The Arctic Cruise - Act 2": ["The Arctic Cruise - Act 1"],
|
||||
"The Arctic Cruise - Finale": ["The Arctic Cruise - Act 2"],
|
||||
}
|
||||
|
||||
|
||||
def can_use_hat(state: CollectionState, world: World, hat: HatType) -> bool:
|
||||
return get_remaining_hat_cost(state, world, hat) <= 0
|
||||
|
||||
|
||||
def get_remaining_hat_cost(state: CollectionState, world: World, hat: HatType) -> int:
|
||||
cost: int = 0
|
||||
for h in world.hat_craft_order:
|
||||
cost += world.hat_yarn_costs.get(h)
|
||||
if h == hat:
|
||||
break
|
||||
|
||||
return max(cost - state.count("Yarn", world.player), 0)
|
||||
|
||||
|
||||
def can_sdj(state: CollectionState, world: World):
|
||||
return can_use_hat(state, world, HatType.SPRINT)
|
||||
|
||||
|
||||
def can_use_hookshot(state: CollectionState, world: World):
|
||||
return state.has("Hookshot 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]))
|
||||
|
||||
|
||||
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)
|
||||
if not state.can_reach(entrance.connected_region, player=world.player):
|
||||
return False
|
||||
|
||||
if "Free Roam" in entrance.connected_region.name:
|
||||
return True
|
||||
|
||||
name: str = format("Act Completion (%s)" % entrance.connected_region.name)
|
||||
return world.multiworld.get_location(name, world.player).access_rule(state)
|
||||
|
||||
|
||||
def can_clear_alpine(state: CollectionState, world: World) -> bool:
|
||||
return state.has("Birdhouse Cleared", world.player) and state.has("Lava Cake Cleared", world.player) \
|
||||
and state.has("Windmill Cleared", world.player) and state.has("Twilight Bell Cleared", world.player)
|
||||
|
||||
|
||||
def can_clear_metro(state: CollectionState, world: World) -> bool:
|
||||
return state.has("Nyakuza Intro Cleared", world.player) \
|
||||
and state.has("Yellow Overpass Station Cleared", world.player) \
|
||||
and state.has("Yellow Overpass Manhole Cleared", world.player) \
|
||||
and state.has("Green Clean Station Cleared", world.player) \
|
||||
and state.has("Green Clean Manhole Cleared", world.player) \
|
||||
and state.has("Bluefin Tunnel Cleared", world.player) \
|
||||
and state.has("Pink Paw Station Cleared", world.player) \
|
||||
and state.has("Pink Paw Manhole Cleared", world.player)
|
||||
|
||||
|
||||
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)
|
||||
|
||||
# First, chapter access
|
||||
starting_chapter = ChapterIndex(mw.StartingChapter[p].value)
|
||||
w.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:
|
||||
final_chapter = ChapterIndex.METRO
|
||||
chapter_list.append(ChapterIndex.FINALE)
|
||||
|
||||
if dlc1:
|
||||
chapter_list.append(ChapterIndex.CRUISE)
|
||||
|
||||
if dlc2 and final_chapter is not ChapterIndex.METRO:
|
||||
chapter_list.append(ChapterIndex.METRO)
|
||||
|
||||
chapter_list.remove(starting_chapter)
|
||||
mw.random.shuffle(chapter_list)
|
||||
|
||||
if starting_chapter is not ChapterIndex.ALPINE and dlc1 or dlc2:
|
||||
index1: int = 69
|
||||
index2: int = 69
|
||||
lowest_index: int
|
||||
chapter_list.remove(ChapterIndex.ALPINE)
|
||||
|
||||
if dlc1:
|
||||
index1 = chapter_list.index(ChapterIndex.CRUISE)
|
||||
|
||||
if dlc2 and final_chapter is not ChapterIndex.METRO:
|
||||
index2 = chapter_list.index(ChapterIndex.METRO)
|
||||
|
||||
lowest_index = min(index1, index2)
|
||||
if lowest_index == 0:
|
||||
pos = 0
|
||||
else:
|
||||
pos = mw.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
|
||||
|
||||
cost_increment: int = mw.ChapterCostIncrement[p].value
|
||||
min_difference: int = mw.ChapterCostMinDifference[p].value
|
||||
last_cost: int = 0
|
||||
cost: int
|
||||
loop_count: int = 0
|
||||
|
||||
for chapter in chapter_list:
|
||||
min_range: int = lowest_cost + (cost_increment * loop_count)
|
||||
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)))
|
||||
|
||||
cost = mw.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)
|
||||
last_cost = cost
|
||||
loop_count += 1
|
||||
|
||||
w.set_chapter_cost(final_chapter, mw.random.randint(mw.FinalChapterMinCost[p].value,
|
||||
mw.FinalChapterMaxCost[p].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(mw.get_entrance("Telescope -> Battle of the Birds", p),
|
||||
lambda state: state.has("Time Piece", p, w.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(mw.get_entrance("Telescope -> Alpine Skyline", p),
|
||||
lambda state: state.has("Time Piece", p, w.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))
|
||||
|
||||
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)))
|
||||
|
||||
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))
|
||||
|
||||
if mw.ActRandomizer[p].value == 0:
|
||||
set_default_rift_rules(w)
|
||||
|
||||
location: Location
|
||||
for (key, data) in location_table.items():
|
||||
if not is_location_valid(w, key):
|
||||
continue
|
||||
|
||||
if key in contract_locations.keys():
|
||||
continue
|
||||
|
||||
location = mw.get_location(key, p)
|
||||
|
||||
# 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" and key not in tihs_locations:
|
||||
add_rule(location, lambda state: state.can_reach("Alpine Free Roam", "Region", p), "and")
|
||||
|
||||
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")
|
||||
|
||||
for hat in data.required_hats:
|
||||
if hat is not HatType.NONE:
|
||||
add_rule(location, lambda state: can_use_hat(state, w, hat))
|
||||
|
||||
if data.required_tps > 0:
|
||||
add_rule(location, lambda state: state.has("Time Piece", p, data.required_tps))
|
||||
|
||||
if data.hookshot:
|
||||
add_rule(location, lambda state: can_use_hookshot(state, w))
|
||||
|
||||
if data.umbrella and mw.UmbrellaLogic[p].value > 0:
|
||||
add_rule(location, lambda state: state.has("Umbrella", p))
|
||||
|
||||
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))
|
||||
else: # Can bypass with Dweller Mask
|
||||
add_rule(location, lambda state: can_hit_bells(state, w) or can_use_hat(state, w, HatType.DWELLER))
|
||||
|
||||
if data.paintings > 0 and mw.ShuffleSubconPaintings[p].value > 0:
|
||||
value: int = data.paintings
|
||||
add_rule(location, lambda state: state.count("Progressive Painting Unlock", p) >= value)
|
||||
|
||||
set_specific_rules(w)
|
||||
|
||||
if mw.LogicDifficulty[p].value >= 1:
|
||||
mw.SDJLogic[p].value = 1
|
||||
|
||||
if mw.SDJLogic[p].value > 0:
|
||||
set_sdj_rules(world)
|
||||
|
||||
if mw.ShuffleAlpineZiplines[p].value > 0:
|
||||
set_alps_zipline_rules(w)
|
||||
|
||||
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)
|
||||
region: Region = entrance.connected_region
|
||||
access_rules: typing.List[typing.Callable[[CollectionState], bool]] = []
|
||||
entrance.parent_region.exits.remove(entrance)
|
||||
del entrance.parent_region
|
||||
|
||||
# Entrances to this act that we have to set access_rules on
|
||||
entrances: typing.List[Entrance] = []
|
||||
|
||||
for act in acts:
|
||||
act_entrance: Entrance = mw.get_entrance(act, p)
|
||||
|
||||
required_region = act_entrance.connected_region
|
||||
name: str = format("%s: Connection %i" % (key, i))
|
||||
new_entrance: Entrance = connect_regions(required_region, region, name, p)
|
||||
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
|
||||
access_rules.append(rule)
|
||||
|
||||
i += 1
|
||||
|
||||
for e in entrances:
|
||||
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))
|
||||
|
||||
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)
|
||||
|
||||
|
||||
def set_specific_rules(world: World):
|
||||
mw = world.multiworld
|
||||
w = world
|
||||
p = world.player
|
||||
dlc1: bool = bool(mw.EnableDLC1[p].value > 0)
|
||||
|
||||
add_rule(mw.get_entrance("Alpine Skyline - Finale", p),
|
||||
lambda state: can_clear_alpine(state, w))
|
||||
|
||||
# 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))
|
||||
|
||||
add_rule(mw.get_location("Alpine Skyline - Yellow Band Hills", p),
|
||||
lambda state: can_use_hat(state, w, 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(mw.get_location("Rock the Boat - Post Captain Rescue", p),
|
||||
lambda state: can_use_hat(state, w, HatType.ICE))
|
||||
|
||||
add_rule(mw.get_location("Act Completion (Rock the Boat)", p),
|
||||
lambda state: can_use_hat(state, w, 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")
|
||||
|
||||
# Expert logic
|
||||
if mw.LogicDifficulty[p].value >= 2:
|
||||
set_rule(mw.get_location("Alpine Skyline - The Twilight Path", p), lambda state: True)
|
||||
else:
|
||||
add_rule(mw.get_entrance("-> The Twilight Bell", p),
|
||||
lambda state: can_use_hat(state, w, 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))
|
||||
|
||||
# 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(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))
|
||||
|
||||
# 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))
|
||||
|
||||
# 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))
|
||||
|
||||
# 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))
|
||||
|
||||
# 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))
|
||||
|
||||
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(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))
|
||||
|
||||
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))
|
||||
|
||||
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))
|
||||
|
||||
add_rule(mw.get_entrance("Subcon Forest - Act 2", p),
|
||||
lambda state: state.has("Snatcher's Contract - The Subcon Well", p))
|
||||
|
||||
add_rule(mw.get_entrance("Subcon Forest - Act 3", p),
|
||||
lambda state: state.has("Snatcher's Contract - Toilet of Doom", p))
|
||||
|
||||
add_rule(mw.get_entrance("Subcon Forest - Act 4", p),
|
||||
lambda state: state.has("Snatcher's Contract - Queen Vanessa's Manor", p))
|
||||
|
||||
add_rule(mw.get_entrance("Subcon Forest - Act 5", p),
|
||||
lambda state: state.has("Snatcher's Contract - Mail Delivery Service", p))
|
||||
|
||||
if mw.ShuffleSubconPaintings[p].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(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))
|
||||
|
||||
if mw.EnableDLC1[p].value > 0:
|
||||
add_rule(mw.get_entrance("Cruise Ship Entrance BV", p), lambda state: can_use_hookshot(state, w))
|
||||
|
||||
# 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))
|
||||
|
||||
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))
|
||||
|
||||
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(mw.get_entrance("Nyakuza Metro - Finale", p),
|
||||
lambda state: can_clear_metro(state, w))
|
||||
|
||||
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))
|
||||
|
||||
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")
|
||||
|
||||
|
||||
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")
|
||||
|
||||
add_rule(world.multiworld.get_location("Subcon Forest - Green and Purple Dweller Rocks", world.player),
|
||||
lambda state: can_sdj(state, world), "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")
|
||||
|
||||
|
||||
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))
|
||||
|
||||
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("-> The Windmill", world.player),
|
||||
lambda state: state.has("Zipline Unlock - The Windmill Path", world.player))
|
||||
|
||||
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 (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))
|
||||
|
||||
|
||||
def reg_act_connection(world: World, region: typing.Union[str, Region], unlocked_entrance: typing.Union[str, Entrance]):
|
||||
reg: Region
|
||||
entrance: Entrance
|
||||
if isinstance(region, str):
|
||||
reg = world.multiworld.get_region(region, world.player)
|
||||
else:
|
||||
reg = region
|
||||
|
||||
if isinstance(unlocked_entrance, str):
|
||||
entrance = world.multiworld.get_entrance(unlocked_entrance, world.player)
|
||||
else:
|
||||
entrance = unlocked_entrance
|
||||
|
||||
world.multiworld.register_indirect_condition(reg, entrance)
|
||||
|
||||
|
||||
# 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)))
|
||||
|
||||
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)))
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
for entrance in regions["Time Rift - Mafia of Cooks"].entrances:
|
||||
add_rule(entrance, lambda state: has_relic_combo(state, w, "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)
|
||||
|
||||
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)
|
||||
|
||||
for entrance in regions["Time Rift - Dead Bird Studio"].entrances:
|
||||
add_rule(entrance, lambda state: has_relic_combo(state, w, "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))
|
||||
|
||||
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))
|
||||
|
||||
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))
|
||||
|
||||
for entrance in regions["Time Rift - Curly Tail Trail"].entrances:
|
||||
add_rule(entrance, lambda state: state.has("Windmill Cleared", p))
|
||||
|
||||
for entrance in regions["Time Rift - The Twilight Bell"].entrances:
|
||||
add_rule(entrance, lambda state: state.has("Twilight Bell Cleared", p))
|
||||
|
||||
for entrance in regions["Time Rift - Alpine Skyline"].entrances:
|
||||
add_rule(entrance, lambda state: has_relic_combo(state, w, "Crayon"))
|
||||
|
||||
if mw.EnableDLC1[p].value > 0:
|
||||
for entrance in regions["Time Rift - Balcony"].entrances:
|
||||
add_rule(entrance, lambda state: can_clear_act(state, w, "The Arctic Cruise - Finale"))
|
||||
|
||||
for entrance in regions["Time Rift - Deep Sea"].entrances:
|
||||
add_rule(entrance, lambda state: has_relic_combo(state, w, "Cake"))
|
||||
|
||||
if mw.EnableDLC2[p].value > 0:
|
||||
for entrance in regions["Time Rift - Rumbi Factory"].entrances:
|
||||
add_rule(entrance, lambda state: has_relic_combo(state, w, "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 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 mw.get_region("Time Rift - Sewers", p).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)
|
||||
|
||||
for entrance in mw.get_region("Time Rift - Bazaar", p).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)
|
||||
|
||||
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 mw.get_region("Time Rift - The Owl Express", p).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)
|
||||
|
||||
for entrance in mw.get_region("Time Rift - The Moon", p).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)
|
||||
|
||||
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 mw.get_region("Time Rift - Pipe", p).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))
|
||||
|
||||
for entrance in mw.get_region("Time Rift - Village", p).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))
|
||||
|
||||
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 mw.get_region("Time Rift - Curly Tail Trail", p).entrances:
|
||||
add_rule(entrance, lambda state: state.has("Windmill Cleared", p))
|
||||
|
||||
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 mw.get_region("Time Rift - Alpine Skyline", p).entrances:
|
||||
add_rule(entrance, lambda state: has_relic_combo(state, w, "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"))
|
||||
|
||||
for entrance in mw.get_region("Time Rift - Deep Sea", p).entrances:
|
||||
add_rule(entrance, lambda state: has_relic_combo(state, w, "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"))
|
||||
|
||||
|
||||
def connect_regions(start_region: Region, exit_region: Region, entrancename: str, player: int) -> Entrance:
|
||||
entrance = Entrance(player, entrancename, start_region)
|
||||
start_region.exits.append(entrance)
|
||||
entrance.connect(exit_region)
|
||||
return entrance
|
||||
28
worlds/ahit/Types.py
Normal file
28
worlds/ahit/Types.py
Normal file
@@ -0,0 +1,28 @@
|
||||
from enum import IntEnum, IntFlag
|
||||
|
||||
|
||||
class HatType(IntEnum):
|
||||
NONE = -1
|
||||
SPRINT = 0
|
||||
BREWING = 1
|
||||
ICE = 2
|
||||
DWELLER = 3
|
||||
TIME_STOP = 4
|
||||
|
||||
|
||||
class HatDLC(IntFlag):
|
||||
none = 0b000
|
||||
dlc1 = 0b001
|
||||
dlc2 = 0b010
|
||||
death_wish = 0b100
|
||||
|
||||
|
||||
class ChapterIndex(IntEnum):
|
||||
SPACESHIP = 0
|
||||
MAFIA = 1
|
||||
BIRDS = 2
|
||||
SUBCON = 3
|
||||
ALPINE = 4
|
||||
FINALE = 5
|
||||
CRUISE = 6
|
||||
METRO = 7
|
||||
276
worlds/ahit/__init__.py
Normal file
276
worlds/ahit/__init__.py
Normal file
@@ -0,0 +1,276 @@
|
||||
from BaseClasses import Item, ItemClassification, Region, LocationProgressType
|
||||
|
||||
from .Items import HatInTimeItem, item_table, item_frequencies, item_dlc_enabled, junk_weights,\
|
||||
create_item, create_multiple_items, create_junk_items, relic_groups, act_contracts, alps_hooks, \
|
||||
get_total_time_pieces
|
||||
|
||||
from .Regions import create_region, create_regions, connect_regions, randomize_act_entrances, chapter_act_info, \
|
||||
create_events, chapter_regions, act_chapters
|
||||
|
||||
from .Locations import HatInTimeLocation, location_table, get_total_locations, contract_locations, is_location_valid, \
|
||||
get_location_names
|
||||
|
||||
from .Types import HatDLC, HatType, ChapterIndex
|
||||
from .Options import ahit_options, slot_data_options, adjust_options
|
||||
from worlds.AutoWorld import World
|
||||
from .Rules import set_rules
|
||||
import typing
|
||||
|
||||
|
||||
class HatInTimeWorld(World):
|
||||
"""
|
||||
A Hat in Time is a cute-as-heck 3D platformer featuring a little girl who stitches hats for wicked powers!
|
||||
Freely explore giant worlds and recover Time Pieces to travel to new heights!
|
||||
"""
|
||||
|
||||
game = "A Hat in Time"
|
||||
data_version = 1
|
||||
|
||||
item_name_to_id = {name: data.code for name, data in item_table.items()}
|
||||
location_name_to_id = get_location_names()
|
||||
|
||||
option_definitions = ahit_options
|
||||
|
||||
hat_craft_order: typing.List[HatType]
|
||||
hat_yarn_costs: typing.Dict[HatType, int]
|
||||
chapter_timepiece_costs: typing.Dict[ChapterIndex, int]
|
||||
act_connections: typing.Dict[str, str] = {}
|
||||
nyakuza_thug_items: typing.Dict[str, int] = {}
|
||||
shop_locs: typing.List[str] = []
|
||||
item_name_groups = relic_groups
|
||||
badge_seller_count: int = 0
|
||||
|
||||
def generate_early(self):
|
||||
adjust_options(self)
|
||||
|
||||
# If our starting chapter is 4 and act rando isn't on, force hookshot into inventory
|
||||
# If starting chapter is 3 and painting shuffle is enabled, and act rando isn't, give one free painting unlock
|
||||
start_chapter: int = self.multiworld.StartingChapter[self.player].value
|
||||
|
||||
if start_chapter == 4 or start_chapter == 3:
|
||||
if self.multiworld.ActRandomizer[self.player].value == 0:
|
||||
if start_chapter == 4:
|
||||
self.multiworld.push_precollected(self.create_item("Hookshot Badge"))
|
||||
|
||||
if start_chapter == 3 and self.multiworld.ShuffleSubconPaintings[self.player].value > 0:
|
||||
self.multiworld.push_precollected(self.create_item("Progressive Painting Unlock"))
|
||||
|
||||
if self.multiworld.StartWithCompassBadge[self.player].value > 0:
|
||||
self.multiworld.push_precollected(self.create_item("Compass Badge"))
|
||||
|
||||
def create_regions(self):
|
||||
self.nyakuza_thug_items = {}
|
||||
self.shop_locs = []
|
||||
create_regions(self)
|
||||
|
||||
# place default contract locations if contract shuffle is off so logic can still utilize them
|
||||
if self.multiworld.ShuffleActContracts[self.player].value == 0:
|
||||
for name in contract_locations.keys():
|
||||
self.multiworld.get_location(name, self.player).place_locked_item(create_item(self, name))
|
||||
else:
|
||||
# The bag trap contract check needs to be excluded, because if the player has the Subcon Well contract,
|
||||
# the trap will not activate, locking the player out of the check permanently
|
||||
self.multiworld.get_location("Snatcher's Contract - The Subcon Well",
|
||||
self.player).progress_type = LocationProgressType.EXCLUDED
|
||||
|
||||
def create_items(self):
|
||||
self.hat_yarn_costs = {HatType.SPRINT: -1, HatType.BREWING: -1, HatType.ICE: -1,
|
||||
HatType.DWELLER: -1, HatType.TIME_STOP: -1}
|
||||
|
||||
self.hat_craft_order = [HatType.SPRINT, HatType.BREWING, HatType.ICE,
|
||||
HatType.DWELLER, HatType.TIME_STOP]
|
||||
|
||||
self.topology_present = self.multiworld.ActRandomizer[self.player].value
|
||||
|
||||
# Item Pool
|
||||
itempool: typing.List[Item] = []
|
||||
self.calculate_yarn_costs()
|
||||
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):
|
||||
yarn_pool[i].classification = ItemClassification.progression
|
||||
|
||||
itempool += yarn_pool
|
||||
|
||||
if self.multiworld.RandomizeHatOrder[self.player].value > 0:
|
||||
self.multiworld.random.shuffle(self.hat_craft_order)
|
||||
|
||||
for name in item_table.keys():
|
||||
if name == "Yarn":
|
||||
continue
|
||||
|
||||
if not item_dlc_enabled(self, name):
|
||||
continue
|
||||
|
||||
item_type: ItemClassification = item_table.get(name).classification
|
||||
if item_type is ItemClassification.filler or item_type is ItemClassification.trap:
|
||||
continue
|
||||
|
||||
if name in act_contracts.keys() and self.multiworld.ShuffleActContracts[self.player].value == 0:
|
||||
continue
|
||||
|
||||
if name in alps_hooks.keys() and self.multiworld.ShuffleAlpineZiplines[self.player].value == 0:
|
||||
continue
|
||||
|
||||
if name == "Progressive Painting Unlock" \
|
||||
and self.multiworld.ShuffleSubconPaintings[self.player].value == 0:
|
||||
continue
|
||||
|
||||
if name == "Time Piece":
|
||||
tp_count: int = 40
|
||||
max_extra: int = 0
|
||||
if self.multiworld.EnableDLC1[self.player].value > 0:
|
||||
max_extra += 6
|
||||
|
||||
if self.multiworld.EnableDLC2[self.player].value > 0:
|
||||
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):
|
||||
tp_list[i].classification = ItemClassification.progression
|
||||
|
||||
itempool += tp_list
|
||||
continue
|
||||
|
||||
itempool += create_multiple_items(self, name, item_frequencies.get(name, 1))
|
||||
|
||||
create_events(self)
|
||||
total_locations: int = get_total_locations(self)
|
||||
itempool += create_junk_items(self, total_locations-len(itempool))
|
||||
self.multiworld.itempool += itempool
|
||||
|
||||
def set_rules(self):
|
||||
self.act_connections = {}
|
||||
self.chapter_timepiece_costs = {ChapterIndex.MAFIA: -1,
|
||||
ChapterIndex.BIRDS: -1,
|
||||
ChapterIndex.SUBCON: -1,
|
||||
ChapterIndex.ALPINE: -1,
|
||||
ChapterIndex.FINALE: -1,
|
||||
ChapterIndex.CRUISE: -1,
|
||||
ChapterIndex.METRO: -1}
|
||||
|
||||
if self.multiworld.ActRandomizer[self.player].value > 0:
|
||||
randomize_act_entrances(self)
|
||||
|
||||
set_rules(self)
|
||||
|
||||
def create_item(self, name: str) -> Item:
|
||||
return create_item(self, name)
|
||||
|
||||
def fill_slot_data(self) -> dict:
|
||||
slot_data: dict = {"SprintYarnCost": self.hat_yarn_costs[HatType.SPRINT],
|
||||
"BrewingYarnCost": self.hat_yarn_costs[HatType.BREWING],
|
||||
"IceYarnCost": self.hat_yarn_costs[HatType.ICE],
|
||||
"DwellerYarnCost": self.hat_yarn_costs[HatType.DWELLER],
|
||||
"TimeStopYarnCost": self.hat_yarn_costs[HatType.TIME_STOP],
|
||||
"Chapter1Cost": self.chapter_timepiece_costs[ChapterIndex.MAFIA],
|
||||
"Chapter2Cost": self.chapter_timepiece_costs[ChapterIndex.BIRDS],
|
||||
"Chapter3Cost": self.chapter_timepiece_costs[ChapterIndex.SUBCON],
|
||||
"Chapter4Cost": self.chapter_timepiece_costs[ChapterIndex.ALPINE],
|
||||
"Chapter5Cost": self.chapter_timepiece_costs[ChapterIndex.FINALE],
|
||||
"Chapter6Cost": self.chapter_timepiece_costs[ChapterIndex.CRUISE],
|
||||
"Chapter7Cost": self.chapter_timepiece_costs[ChapterIndex.METRO],
|
||||
"Hat1": int(self.hat_craft_order[0]),
|
||||
"Hat2": int(self.hat_craft_order[1]),
|
||||
"Hat3": int(self.hat_craft_order[2]),
|
||||
"Hat4": int(self.hat_craft_order[3]),
|
||||
"Hat5": int(self.hat_craft_order[4]),
|
||||
"BadgeSellerItemCount": self.badge_seller_count,
|
||||
"SeedNumber": self.multiworld.seed} # For shop prices
|
||||
|
||||
if self.multiworld.ActRandomizer[self.player].value > 0:
|
||||
for name in self.act_connections.keys():
|
||||
slot_data[name] = self.act_connections[name]
|
||||
|
||||
if self.multiworld.EnableDLC2[self.player].value > 0:
|
||||
for name in self.nyakuza_thug_items.keys():
|
||||
slot_data[name] = self.nyakuza_thug_items[name]
|
||||
|
||||
for option_name in slot_data_options:
|
||||
option = getattr(self.multiworld, option_name)[self.player]
|
||||
slot_data[option_name] = option.value
|
||||
|
||||
return slot_data
|
||||
|
||||
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"]
|
||||
metro_regions = ["Yellow Overpass Station", "Green Clean Station", "Bluefin Tunnel", "Pink Paw Station"]
|
||||
|
||||
for key, data in location_table.items():
|
||||
if not is_location_valid(self, key):
|
||||
continue
|
||||
|
||||
location = self.multiworld.get_location(key, self.player)
|
||||
region_name: str
|
||||
|
||||
if data.region in alpine_regions:
|
||||
region_name = "Alpine Free Roam"
|
||||
elif data.region in metro_regions:
|
||||
region_name = "Nyakuza Free Roam"
|
||||
elif data.region in chapter_act_info.keys():
|
||||
region_name = location.parent_region.name
|
||||
else:
|
||||
continue
|
||||
|
||||
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:
|
||||
ship_shape_region = self.get_shuffled_region("Ship Shape")
|
||||
id_start: int = 300204
|
||||
for i in range(self.multiworld.TasksanityCheckCount[self.player].value):
|
||||
new_hint_data[id_start+i] = ship_shape_region
|
||||
|
||||
hint_data[self.player] = new_hint_data
|
||||
|
||||
def write_spoiler_header(self, spoiler_handle: typing.TextIO):
|
||||
for i in self.chapter_timepiece_costs.keys():
|
||||
spoiler_handle.write("Chapter %i Cost: %i\n" % (i, self.chapter_timepiece_costs[ChapterIndex(i)]))
|
||||
|
||||
for hat in self.hat_craft_order:
|
||||
spoiler_handle.write("Hat Cost: %s: %i\n" % (hat, self.hat_yarn_costs[hat]))
|
||||
|
||||
def calculate_yarn_costs(self):
|
||||
mw = self.multiworld
|
||||
p = self.player
|
||||
min_yarn_cost = int(min(mw.YarnCostMin[p].value, mw.YarnCostMax[p].value))
|
||||
max_yarn_cost = int(max(mw.YarnCostMin[p].value, mw.YarnCostMax[p].value))
|
||||
|
||||
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))
|
||||
self.hat_yarn_costs[HatType(i)] = cost
|
||||
max_cost += cost
|
||||
|
||||
available_yarn = mw.YarnAvailable[p].value
|
||||
if max_cost > available_yarn:
|
||||
mw.YarnAvailable[p].value = max_cost
|
||||
available_yarn = max_cost
|
||||
|
||||
# make sure we always have at least 8 extra
|
||||
if max_cost + 8 > available_yarn:
|
||||
mw.YarnAvailable[p].value += (max_cost + 8) - available_yarn
|
||||
|
||||
def set_chapter_cost(self, chapter: ChapterIndex, cost: int):
|
||||
self.chapter_timepiece_costs[chapter] = cost
|
||||
|
||||
def get_chapter_cost(self, chapter: ChapterIndex) -> int:
|
||||
return self.chapter_timepiece_costs.get(chapter)
|
||||
|
||||
# Sets an act entrance in slot data by specifying the Hat_ChapterActInfo, to be used in-game
|
||||
def update_chapter_act_info(self, original_region: Region, new_region: Region):
|
||||
original_act_info = chapter_act_info[original_region.name]
|
||||
new_act_info = chapter_act_info[new_region.name]
|
||||
self.act_connections[original_act_info] = new_act_info
|
||||
|
||||
def get_shuffled_region(self, region: str) -> str:
|
||||
ci: str = chapter_act_info[region]
|
||||
for key, val in self.act_connections.items():
|
||||
if val == ci:
|
||||
for name in chapter_act_info.keys():
|
||||
if chapter_act_info[name] == key:
|
||||
return name
|
||||
Reference in New Issue
Block a user