This commit is contained in:
CookieCat
2023-08-27 18:46:20 -04:00
parent 9ad0032eb4
commit 45ccb9909e
7 changed files with 3135 additions and 0 deletions

190
worlds/ahit/Items.py Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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