mirror of
https://github.com/ArchipelagoMW/Archipelago.git
synced 2026-03-23 14:23:32 -07:00
a
This commit is contained in:
@@ -1,10 +1,11 @@
|
||||
from .Locations import HatInTimeLocation, death_wishes
|
||||
from .Items import HatInTimeItem
|
||||
from .Types import HatInTimeLocation, HatInTimeItem
|
||||
from .Regions import connect_regions, create_region
|
||||
from BaseClasses import Region, LocationProgressType, ItemClassification
|
||||
from worlds.generic.Rules import add_rule
|
||||
from worlds.AutoWorld import World
|
||||
from typing import List
|
||||
from .Locations import death_wishes
|
||||
|
||||
|
||||
dw_prereqs = {
|
||||
"So You're Back From Outer Space": ["Beat the Heat"],
|
||||
@@ -82,11 +83,9 @@ annoying_bonuses = [
|
||||
"Snatcher's Hit List",
|
||||
"10 Seconds until Self-Destruct",
|
||||
"Killing Two Birds",
|
||||
"Snatcher Coins in Battle of the Birds",
|
||||
"Zero Jumps",
|
||||
"Bird Sanctuary",
|
||||
"Wound-Up Windmill",
|
||||
"Snatcher Coins in Alpine Skyline",
|
||||
"Seal the Deal",
|
||||
]
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
from worlds.AutoWorld import World, CollectionState
|
||||
from .Locations import LocData, death_wishes, HatInTimeLocation
|
||||
from .Rules import can_use_hat, can_use_hookshot, can_hit, zipline_logic, has_paintings, get_difficulty
|
||||
from .Types import HatType, Difficulty
|
||||
from .Rules import can_use_hat, can_use_hookshot, can_hit, zipline_logic, get_difficulty
|
||||
from .Types import HatType, Difficulty, HatInTimeLocation, HatInTimeItem, LocData, HatDLC
|
||||
from .DeathWishLocations import dw_prereqs, dw_candles
|
||||
from .Items import HatInTimeItem
|
||||
from BaseClasses import Entrance, Location, ItemClassification
|
||||
from worlds.generic.Rules import add_rule, set_rule
|
||||
from typing import List, Callable
|
||||
from .Regions import act_chapters
|
||||
from .Locations import zero_jumps, zero_jumps_expert, zero_jumps_hard, death_wishes
|
||||
|
||||
# Any speedruns expect the player to have Sprint Hat
|
||||
dw_requirements = {
|
||||
@@ -81,6 +81,23 @@ dw_stamp_costs = {
|
||||
"Seal the Deal": 70,
|
||||
}
|
||||
|
||||
required_snatcher_coins = {
|
||||
"Snatcher Coins in Mafia Town": ["Snatcher Coin - Top of HQ", "Snatcher Coin - Top of Tower",
|
||||
"Snatcher Coin - Under Ruined Tower"],
|
||||
|
||||
"Snatcher Coins in Battle of the Birds": ["Snatcher Coin - Top of Red House", "Snatcher Coin - Train Rush",
|
||||
"Snatcher Coin - Picture Perfect"],
|
||||
|
||||
"Snatcher Coins in Subcon Forest": ["Snatcher Coin - Swamp Tree", "Snatcher Coin - Manor Roof",
|
||||
"Snatcher Coin - Giant Time Piece"],
|
||||
|
||||
"Snatcher Coins in Alpine Skyline": ["Snatcher Coin - Goat Village Top", "Snatcher Coin - Lava Cake",
|
||||
"Snatcher Coin - Windmill"],
|
||||
|
||||
"Snatcher Coins in Nyakuza Metro": ["Snatcher Coin - Green Clean Tower", "Snatcher Coin - Bluefin Cat Train",
|
||||
"Snatcher Coin - Pink Paw Fence"],
|
||||
}
|
||||
|
||||
|
||||
def set_dw_rules(world: World):
|
||||
if "Snatcher's Hit List" not in world.get_excluded_dws() \
|
||||
@@ -219,11 +236,8 @@ def modify_dw_rules(world: World, name: str):
|
||||
add_rule(main_objective, lambda state: state.has("Umbrella", world.player))
|
||||
|
||||
elif name == "The Mustache Gauntlet":
|
||||
# Need a way to kill fire crows without being burned.
|
||||
add_rule(main_objective, lambda state: state.has("Umbrella", world.player)
|
||||
or can_use_hat(state, world, HatType.ICE) or can_use_hat(state, world, HatType.BREWING))
|
||||
add_rule(full_clear, lambda state: state.has("Umbrella", world.player)
|
||||
or can_use_hat(state, world, HatType.ICE))
|
||||
|
||||
elif name == "Vault Codes in the Wind":
|
||||
# Sprint is normally expected here
|
||||
@@ -236,16 +250,21 @@ def modify_dw_rules(world: World, name: str):
|
||||
set_rule(main_objective, lambda state: True)
|
||||
|
||||
elif name == "Mafia's Jumps":
|
||||
# Main objective without Ice, still expected for bonuses
|
||||
if difficulty >= Difficulty.HARD:
|
||||
set_rule(main_objective, lambda state: True)
|
||||
set_rule(full_clear, lambda state: can_use_hat(state, world, HatType.ICE))
|
||||
set_rule(full_clear, lambda state: True)
|
||||
|
||||
elif name == "So You're Back from Outer Space":
|
||||
# Without Hookshot
|
||||
if difficulty >= Difficulty.HARD:
|
||||
set_rule(main_objective, lambda state: True)
|
||||
|
||||
elif name == "Wound-Up Windmill":
|
||||
# No badge pin required. Player can switch to One Hit Hero after the checkpoint and do level without it.
|
||||
if difficulty >= Difficulty.MODERATE:
|
||||
set_rule(full_clear, lambda state: can_use_hookshot(state, world)
|
||||
and state.has("One-Hit Hero Badge", world.player))
|
||||
|
||||
if name in dw_candles:
|
||||
set_candle_dw_rules(name, world)
|
||||
|
||||
@@ -268,7 +287,7 @@ def get_total_dw_stamps(state: CollectionState, world: World) -> int:
|
||||
if state.has(f"2 Stamps - {name}", world.player):
|
||||
count += 2
|
||||
elif name not in dw_candles:
|
||||
# all non-candle bonus requirements allow the player to get the other stamp (like not having One Hit Hero)
|
||||
# most non-candle bonus requirements allow the player to get the other stamp (like not having One Hit Hero)
|
||||
count += 1
|
||||
|
||||
return count
|
||||
@@ -281,7 +300,13 @@ def set_candle_dw_rules(name: str, world: World):
|
||||
if name == "Zero Jumps":
|
||||
add_rule(main_objective, lambda state: get_zero_jump_clear_count(state, world) >= 1)
|
||||
add_rule(full_clear, lambda state: get_zero_jump_clear_count(state, world) >= 4
|
||||
and state.has("Train Rush Cleared", world.player) and can_use_hat(state, world, HatType.ICE))
|
||||
and state.has("Train Rush (Zero Jumps)", world.player) and can_use_hat(state, world, HatType.ICE))
|
||||
|
||||
# No Ice Hat/painting required in Expert for Toilet Zero Jumps
|
||||
if get_difficulty(world) >= Difficulty.EXPERT:
|
||||
set_rule(world.multiworld.get_location("Toilet of Doom (Zero Jumps)", world.player),
|
||||
lambda state: can_use_hookshot(state, world)
|
||||
and can_hit(state, world))
|
||||
|
||||
elif name == "Snatcher's Hit List":
|
||||
add_rule(main_objective, lambda state: state.has("Mafia Goon", world.player))
|
||||
@@ -289,74 +314,33 @@ def set_candle_dw_rules(name: str, world: World):
|
||||
|
||||
elif name == "Camera Tourist":
|
||||
add_rule(main_objective, lambda state: get_reachable_enemy_count(state, world) >= 8)
|
||||
add_rule(full_clear, lambda state: can_reach_all_bosses(state, world))
|
||||
add_rule(full_clear, lambda state: can_reach_all_bosses(state, world)
|
||||
and state.has("Triple Enemy Picture", world.player))
|
||||
|
||||
elif name == "Snatcher Coins in Mafia Town":
|
||||
add_rule(main_objective, lambda state: state.has("MT Access", world.player)
|
||||
or state.has("HUMT Access", world.player))
|
||||
|
||||
add_rule(full_clear, lambda state: state.has("CTR Access", world.player)
|
||||
or state.has("HUMT Access", world.player)
|
||||
and can_hit(state, world, True)
|
||||
or state.has("DWTM Access", world.player)
|
||||
or state.has("TGV Access", world.player))
|
||||
|
||||
elif name == "Snatcher Coins in Battle of the Birds":
|
||||
add_rule(main_objective, lambda state: state.has("PP Access", world.player)
|
||||
or state.has("DBS Access", world.player)
|
||||
or state.has("Train Rush Cleared", world.player))
|
||||
|
||||
add_rule(full_clear, lambda state: state.has("PP Access", world.player)
|
||||
and state.has("DBS Access", world.player)
|
||||
and state.has("Train Rush Cleared", world.player))
|
||||
|
||||
elif name == "Snatcher Coins in Subcon Forest":
|
||||
add_rule(main_objective, lambda state: state.has("SF Access", world.player))
|
||||
|
||||
add_rule(main_objective, lambda state: has_paintings(state, world, 1) and (can_use_hookshot(state, world)
|
||||
or can_hit(state, world) or can_use_hat(state, world, HatType.DWELLER))
|
||||
or has_paintings(state, world, 3))
|
||||
|
||||
add_rule(full_clear, lambda state: has_paintings(state, world, 3) and can_use_hookshot(state, world)
|
||||
and (can_hit(state, world) or can_use_hat(state, world, HatType.DWELLER)))
|
||||
|
||||
elif name == "Snatcher Coins in Alpine Skyline":
|
||||
add_rule(main_objective, lambda state: state.has("LC Access", world.player)
|
||||
or state.has("WM Access", world.player))
|
||||
|
||||
add_rule(full_clear, lambda state: state.has("LC Access", world.player)
|
||||
and state.has("WM Access", world.player))
|
||||
|
||||
elif name == "Snatcher Coins in Nyakuza Metro":
|
||||
add_rule(main_objective, lambda state: state.has("Bluefin Tunnel Cleared", world.player)
|
||||
or (state.has("Nyakuza Intro Cleared", world.player)
|
||||
and (state.has("Metro Ticket - Pink", world.player)
|
||||
or state.has("Metro Ticket - Yellow", world.player)
|
||||
and state.has("Metro Ticket - Blue", world.player))))
|
||||
|
||||
add_rule(full_clear, lambda state: state.has("Bluefin Tunnel Cleared", world.player)
|
||||
and (state.has("Nyakuza Intro Cleared", world.player)
|
||||
and (state.has("Metro Ticket - Pink", world.player)
|
||||
or state.has("Metro Ticket - Yellow", world.player)
|
||||
and state.has("Metro Ticket - Blue", world.player))))
|
||||
elif "Snatcher Coins" in name:
|
||||
for coin in required_snatcher_coins[name]:
|
||||
add_rule(main_objective, lambda state: state.has(coin, world.player), "or")
|
||||
add_rule(full_clear, lambda state: state.has(coin, world.player))
|
||||
|
||||
|
||||
def get_zero_jump_clear_count(state: CollectionState, world: World) -> int:
|
||||
total: int = 0
|
||||
|
||||
for name, hats in zero_jumps.items():
|
||||
if not state.has(f"{name} Cleared", world.player):
|
||||
for name in act_chapters.keys():
|
||||
n = f"{name} (Zero Jumps)"
|
||||
if n not in zero_jumps:
|
||||
continue
|
||||
|
||||
valid: bool = True
|
||||
if get_difficulty(world) < Difficulty.HARD and n in zero_jumps_hard:
|
||||
continue
|
||||
|
||||
for hat in hats:
|
||||
if not can_use_hat(state, world, hat):
|
||||
valid = False
|
||||
break
|
||||
if get_difficulty(world) < Difficulty.EXPERT and n in zero_jumps_expert:
|
||||
continue
|
||||
|
||||
if valid:
|
||||
total += 1
|
||||
if not state.has(n, world.player):
|
||||
continue
|
||||
|
||||
total += 1
|
||||
|
||||
return total
|
||||
|
||||
@@ -399,7 +383,7 @@ def create_enemy_events(world: World):
|
||||
if area == "Bluefin Tunnel" and not world.is_dlc2():
|
||||
continue
|
||||
|
||||
if world.multiworld.DWShuffle[world.player].value > 0 and area in death_wishes \
|
||||
if world.multiworld.DWShuffle[world.player].value > 0 and area in death_wishes.keys() \
|
||||
and area not in world.get_dw_shuffle():
|
||||
continue
|
||||
|
||||
@@ -409,6 +393,22 @@ def create_enemy_events(world: World):
|
||||
region.locations.append(event)
|
||||
event.show_in_spoiler = False
|
||||
|
||||
for name in triple_enemy_locations:
|
||||
if name == "Time Rift - Tour" and (not world.is_dlc1() or world.multiworld.ExcludeTour[world.player].value > 0):
|
||||
continue
|
||||
|
||||
if world.multiworld.DWShuffle[world.player].value > 0 and name in death_wishes.keys() \
|
||||
and name not in world.get_dw_shuffle():
|
||||
continue
|
||||
|
||||
region = world.multiworld.get_region(name, world.player)
|
||||
event = HatInTimeLocation(world.player, f"Triple Enemy Picture - {name}", None, region)
|
||||
event.place_locked_item(HatInTimeItem("Triple Enemy Picture", ItemClassification.progression, None, world.player))
|
||||
region.locations.append(event)
|
||||
event.show_in_spoiler = False
|
||||
if name == "The Mustache Gauntlet":
|
||||
add_rule(event, lambda state: can_use_hookshot(state, world) and can_use_hat(state, world, HatType.DWELLER))
|
||||
|
||||
|
||||
def set_enemy_rules(world: World):
|
||||
no_tourist = "Camera Tourist" in world.get_excluded_dws() or "Camera Tourist" in world.get_excluded_bonuses()
|
||||
@@ -422,7 +422,7 @@ def set_enemy_rules(world: World):
|
||||
continue
|
||||
|
||||
if area == "Time Rift - Tour" and (not world.is_dlc1()
|
||||
or world.multiworld.ExcludeTour[world.player].value > 0):
|
||||
or world.multiworld.ExcludeTour[world.player].value > 0):
|
||||
continue
|
||||
|
||||
if area == "Bluefin Tunnel" and not world.is_dlc2():
|
||||
@@ -463,17 +463,6 @@ def set_enemy_rules(world: World):
|
||||
add_rule(event, lambda state: can_use_hookshot(state, world))
|
||||
|
||||
|
||||
# Zero Jumps completable levels, with required hats if any
|
||||
zero_jumps = {
|
||||
"Welcome to Mafia Town": [],
|
||||
"Cheating the Race": [HatType.TIME_STOP],
|
||||
"Picture Perfect": [],
|
||||
"Train Rush": [HatType.ICE],
|
||||
"Contractual Obligations": [],
|
||||
"Your Contract has Expired": [],
|
||||
"Mail Delivery Service": [], # rule for needing sprint is already on act completion
|
||||
}
|
||||
|
||||
# Enemies for Snatcher's Hit List/Camera Tourist, and where to find them
|
||||
hit_list = {
|
||||
"Mafia Goon": ["Mafia Town Area", "Time Rift - Mafia of Cooks", "Time Rift - Tour",
|
||||
@@ -523,6 +512,17 @@ hit_list = {
|
||||
"Mustache Girl": ["The Finale", "Boss Rush", "No More Bad Guys"],
|
||||
}
|
||||
|
||||
# Camera Tourist has a bonus that requires getting three different types of enemies in one picture.
|
||||
triple_enemy_locations = [
|
||||
"She Came from Outer Space",
|
||||
"She Speedran from Outer Space",
|
||||
"Mafia's Jumps",
|
||||
"The Mustache Gauntlet",
|
||||
"The Birdhouse",
|
||||
"Bird Sanctuary",
|
||||
"Time Rift - Tour",
|
||||
]
|
||||
|
||||
bosses = [
|
||||
"Mafia Boss",
|
||||
"Conductor",
|
||||
|
||||
@@ -1,19 +1,9 @@
|
||||
from BaseClasses import Item, ItemClassification
|
||||
from worlds.AutoWorld import World
|
||||
from .Types import HatDLC, HatType, hat_type_to_item, Difficulty
|
||||
from .Types import HatDLC, HatType, hat_type_to_item, Difficulty, ItemData, HatInTimeItem
|
||||
from .Locations import get_total_locations
|
||||
from .Rules import get_difficulty
|
||||
from typing import Optional, NamedTuple, List, Dict
|
||||
|
||||
|
||||
class ItemData(NamedTuple):
|
||||
code: Optional[int]
|
||||
classification: ItemClassification
|
||||
dlc_flags: Optional[HatDLC] = HatDLC.none
|
||||
|
||||
|
||||
class HatInTimeItem(Item):
|
||||
game: str = "A Hat in Time"
|
||||
from typing import Optional, List, Dict
|
||||
|
||||
|
||||
def create_itempool(world: World) -> List[Item]:
|
||||
@@ -185,86 +175,86 @@ def create_junk_items(world: World, count: int) -> List[Item]:
|
||||
|
||||
|
||||
ahit_items = {
|
||||
"Yarn": ItemData(300001, ItemClassification.progression_skip_balancing),
|
||||
"Time Piece": ItemData(300002, ItemClassification.progression_skip_balancing),
|
||||
"Yarn": ItemData(2000300001, ItemClassification.progression_skip_balancing),
|
||||
"Time Piece": ItemData(2000300002, ItemClassification.progression_skip_balancing),
|
||||
|
||||
# for HatItems option
|
||||
"Sprint Hat": ItemData(300049, ItemClassification.progression),
|
||||
"Brewing Hat": ItemData(300050, ItemClassification.progression),
|
||||
"Ice Hat": ItemData(300051, ItemClassification.progression),
|
||||
"Dweller Mask": ItemData(300052, ItemClassification.progression),
|
||||
"Time Stop Hat": ItemData(300053, ItemClassification.progression),
|
||||
"Sprint Hat": ItemData(2000300049, ItemClassification.progression),
|
||||
"Brewing Hat": ItemData(2000300050, ItemClassification.progression),
|
||||
"Ice Hat": ItemData(2000300051, ItemClassification.progression),
|
||||
"Dweller Mask": ItemData(2000300052, ItemClassification.progression),
|
||||
"Time Stop Hat": ItemData(2000300053, 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),
|
||||
"Relic (Burger Patty)": ItemData(2000300006, ItemClassification.progression),
|
||||
"Relic (Burger Cushion)": ItemData(2000300007, ItemClassification.progression),
|
||||
"Relic (Mountain Set)": ItemData(2000300008, ItemClassification.progression),
|
||||
"Relic (Train)": ItemData(2000300009, ItemClassification.progression),
|
||||
"Relic (UFO)": ItemData(2000300010, ItemClassification.progression),
|
||||
"Relic (Cow)": ItemData(2000300011, ItemClassification.progression),
|
||||
"Relic (Cool Cow)": ItemData(2000300012, ItemClassification.progression),
|
||||
"Relic (Tin-foil Hat Cow)": ItemData(2000300013, ItemClassification.progression),
|
||||
"Relic (Crayon Box)": ItemData(2000300014, ItemClassification.progression),
|
||||
"Relic (Red Crayon)": ItemData(2000300015, ItemClassification.progression),
|
||||
"Relic (Blue Crayon)": ItemData(2000300016, ItemClassification.progression),
|
||||
"Relic (Green Crayon)": ItemData(2000300017, 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.useful),
|
||||
"One-Hit Hero Badge": ItemData(300038, ItemClassification.progression, HatDLC.death_wish),
|
||||
"Camera Badge": ItemData(300042, ItemClassification.progression, HatDLC.death_wish),
|
||||
"Projectile Badge": ItemData(2000300024, ItemClassification.useful),
|
||||
"Fast Hatter Badge": ItemData(2000300025, ItemClassification.useful),
|
||||
"Hover Badge": ItemData(2000300026, ItemClassification.useful),
|
||||
"Hookshot Badge": ItemData(2000300027, ItemClassification.progression),
|
||||
"Item Magnet Badge": ItemData(2000300028, ItemClassification.useful),
|
||||
"No Bonk Badge": ItemData(2000300029, ItemClassification.useful),
|
||||
"Compass Badge": ItemData(2000300030, ItemClassification.useful),
|
||||
"Scooter Badge": ItemData(2000300031, ItemClassification.useful),
|
||||
"One-Hit Hero Badge": ItemData(2000300038, ItemClassification.progression, HatDLC.death_wish),
|
||||
"Camera Badge": ItemData(2000300042, ItemClassification.progression, HatDLC.death_wish),
|
||||
|
||||
# Other
|
||||
"Badge Pin": ItemData(300043, ItemClassification.useful),
|
||||
"Umbrella": ItemData(300033, ItemClassification.progression),
|
||||
"Progressive Painting Unlock": ItemData(300003, ItemClassification.progression),
|
||||
"Badge Pin": ItemData(2000300043, ItemClassification.useful),
|
||||
"Umbrella": ItemData(2000300033, ItemClassification.progression),
|
||||
"Progressive Painting Unlock": ItemData(2000300003, 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),
|
||||
"Random Cosmetic": ItemData(300044, ItemClassification.filler),
|
||||
"25 Pons": ItemData(2000300034, ItemClassification.filler),
|
||||
"50 Pons": ItemData(2000300035, ItemClassification.filler),
|
||||
"100 Pons": ItemData(2000300036, ItemClassification.filler),
|
||||
"Health Pon": ItemData(2000300037, ItemClassification.filler),
|
||||
"Random Cosmetic": ItemData(2000300044, ItemClassification.filler),
|
||||
|
||||
# Traps
|
||||
"Baby Trap": ItemData(300039, ItemClassification.trap),
|
||||
"Laser Trap": ItemData(300040, ItemClassification.trap),
|
||||
"Parade Trap": ItemData(300041, ItemClassification.trap),
|
||||
"Baby Trap": ItemData(2000300039, ItemClassification.trap),
|
||||
"Laser Trap": ItemData(2000300040, ItemClassification.trap),
|
||||
"Parade Trap": ItemData(2000300041, 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),
|
||||
"Relic (Cake Stand)": ItemData(2000300018, ItemClassification.progression, HatDLC.dlc1),
|
||||
"Relic (Cake)": ItemData(2000300019, ItemClassification.progression, HatDLC.dlc1),
|
||||
"Relic (Cake Slice)": ItemData(2000300020, ItemClassification.progression, HatDLC.dlc1),
|
||||
"Relic (Shortcake)": ItemData(2000300021, 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),
|
||||
"Relic (Necklace Bust)": ItemData(2000300022, ItemClassification.progression, HatDLC.dlc2),
|
||||
"Relic (Necklace)": ItemData(2000300023, ItemClassification.progression, HatDLC.dlc2),
|
||||
"Metro Ticket - Yellow": ItemData(2000300045, ItemClassification.progression, HatDLC.dlc2),
|
||||
"Metro Ticket - Green": ItemData(2000300046, ItemClassification.progression, HatDLC.dlc2),
|
||||
"Metro Ticket - Blue": ItemData(2000300047, ItemClassification.progression, HatDLC.dlc2),
|
||||
"Metro Ticket - Pink": ItemData(2000300048, ItemClassification.progression, HatDLC.dlc2),
|
||||
}
|
||||
|
||||
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),
|
||||
"Snatcher's Contract - The Subcon Well": ItemData(2000300200, ItemClassification.progression),
|
||||
"Snatcher's Contract - Toilet of Doom": ItemData(2000300201, ItemClassification.progression),
|
||||
"Snatcher's Contract - Queen Vanessa's Manor": ItemData(2000300202, ItemClassification.progression),
|
||||
"Snatcher's Contract - Mail Delivery Service": ItemData(2000300203, 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),
|
||||
"Zipline Unlock - The Birdhouse Path": ItemData(2000300204, ItemClassification.progression),
|
||||
"Zipline Unlock - The Lava Cake Path": ItemData(2000300205, ItemClassification.progression),
|
||||
"Zipline Unlock - The Windmill Path": ItemData(2000300206, ItemClassification.progression),
|
||||
"Zipline Unlock - The Twilight Bell Path": ItemData(2000300207, ItemClassification.progression),
|
||||
}
|
||||
|
||||
relic_groups = {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -532,11 +532,9 @@ class DWExcludeAnnoyingBonuses(Toggle):
|
||||
- Snatcher's Hit List
|
||||
- 10 Seconds until Self-Destruct
|
||||
- Killing Two Birds
|
||||
- Snatcher Coins in Battle of the Birds
|
||||
- Zero Jumps
|
||||
- Bird Sanctuary
|
||||
- Wound-Up Windmill
|
||||
- Snatcher Coins in Alpine Skyline
|
||||
- Seal the Deal"""
|
||||
display_name = "Exclude Annoying Death Wish Full Completions"
|
||||
default = 1
|
||||
@@ -674,6 +672,7 @@ slot_data_options: typing.Dict[str, type(Option)] = {
|
||||
"CTRLogic": CTRLogic,
|
||||
"RandomizeHatOrder": RandomizeHatOrder,
|
||||
"UmbrellaLogic": UmbrellaLogic,
|
||||
"StartWithCompassBadge": StartWithCompassBadge,
|
||||
"CompassBadgeMode": CompassBadgeMode,
|
||||
"ShuffleStorybookPages": ShuffleStorybookPages,
|
||||
"ShuffleActContracts": ShuffleActContracts,
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
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, get_tasksanity_start_id
|
||||
from .Items import HatInTimeItem
|
||||
from .Types import ChapterIndex, Difficulty
|
||||
from .Types import ChapterIndex, Difficulty, HatInTimeLocation, HatInTimeItem
|
||||
from .Locations import location_table, storybook_pages, event_locs, is_location_valid, \
|
||||
shop_locations, get_tasksanity_start_id, snatcher_coins, zero_jumps, zero_jumps_expert, zero_jumps_hard
|
||||
import typing
|
||||
from .Rules import set_rift_rules
|
||||
from .Rules import set_rift_rules, get_difficulty
|
||||
|
||||
|
||||
# ChapterIndex: region
|
||||
@@ -881,6 +880,16 @@ def create_events(world: World) -> int:
|
||||
if not is_location_valid(world, name):
|
||||
continue
|
||||
|
||||
if world.is_dw():
|
||||
if name in snatcher_coins.keys():
|
||||
name = f"{name} ({data.region})"
|
||||
elif name in zero_jumps:
|
||||
if get_difficulty(world) < Difficulty.HARD and name in zero_jumps_hard:
|
||||
continue
|
||||
|
||||
if get_difficulty(world) < Difficulty.EXPERT and name in zero_jumps_expert:
|
||||
continue
|
||||
|
||||
event: Location = create_event(name, world.multiworld.get_region(data.region, world.player), world)
|
||||
event.show_in_spoiler = False
|
||||
count += 1
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
from worlds.AutoWorld import World, CollectionState
|
||||
from worlds.generic.Rules import add_rule, set_rule
|
||||
from .Locations import location_table, zipline_unlocks, is_location_valid, contract_locations, \
|
||||
shop_locations, event_locs
|
||||
from .Types import HatType, ChapterIndex, hat_type_to_item, Difficulty
|
||||
shop_locations, event_locs, snatcher_coins
|
||||
from .Types import HatType, ChapterIndex, hat_type_to_item, Difficulty, HatDLC
|
||||
from BaseClasses import Location, Entrance, Region
|
||||
import typing
|
||||
|
||||
@@ -62,7 +62,7 @@ def get_difficulty(world: World) -> Difficulty:
|
||||
return Difficulty(world.multiworld.LogicDifficulty[world.player].value)
|
||||
|
||||
|
||||
def has_paintings(state: CollectionState, world: World, count: int) -> bool:
|
||||
def has_paintings(state: CollectionState, world: World, count: int, surf: bool = True) -> bool:
|
||||
if not painting_logic(world):
|
||||
return True
|
||||
|
||||
@@ -71,11 +71,11 @@ def has_paintings(state: CollectionState, world: World, count: int) -> bool:
|
||||
return True
|
||||
|
||||
# All paintings can be skipped with No Bonk, very easily, if the player knows
|
||||
if get_difficulty(world) >= Difficulty.MODERATE and can_surf(state, world):
|
||||
if surf and get_difficulty(world) >= Difficulty.MODERATE and can_surf(state, world):
|
||||
return True
|
||||
|
||||
paintings: int = state.count("Progressive Painting Unlock", world.player)
|
||||
if get_difficulty(world) >= Difficulty.MODERATE:
|
||||
if surf and get_difficulty(world) >= Difficulty.MODERATE:
|
||||
# Green+Yellow paintings can also be skipped easily
|
||||
if count == 1 or paintings >= 1 and count == 3:
|
||||
return True
|
||||
@@ -264,6 +264,10 @@ def set_rules(world: World):
|
||||
if key in contract_locations.keys():
|
||||
continue
|
||||
|
||||
if data.dlc_flags is HatDLC.death_wish or data.dlc_flags is HatDLC.dlc2_dw:
|
||||
if key in snatcher_coins.keys():
|
||||
key = f"{key} ({data.region})"
|
||||
|
||||
location = world.multiworld.get_location(key, world.player)
|
||||
|
||||
for hat in data.required_hats:
|
||||
@@ -277,7 +281,10 @@ def set_rules(world: World):
|
||||
add_rule(location, lambda state: state.has("Umbrella", world.player))
|
||||
|
||||
if data.paintings > 0 and world.multiworld.ShuffleSubconPaintings[world.player].value > 0:
|
||||
add_rule(location, lambda state, paintings=data.paintings: has_paintings(state, world, paintings))
|
||||
if "Toilet of Doom" not in key:
|
||||
add_rule(location, lambda state, paintings=data.paintings: has_paintings(state, world, paintings))
|
||||
else:
|
||||
add_rule(location, lambda state, paintings=data.paintings: has_paintings(state, world, paintings, False))
|
||||
|
||||
if data.hit_requirement > 0:
|
||||
if data.hit_requirement == 1:
|
||||
@@ -402,6 +409,10 @@ def set_moderate_rules(world: World):
|
||||
# Moderate: Gallery without Brewing Hat
|
||||
set_rule(world.multiworld.get_location("Act Completion (Time Rift - Gallery)", world.player), lambda state: True)
|
||||
|
||||
# Moderate: Above Boats via Ice Hat Sliding
|
||||
add_rule(world.multiworld.get_location("Mafia Town - Above Boats", world.player),
|
||||
lambda state: can_use_hat(state, world, HatType.ICE), "or")
|
||||
|
||||
# Moderate: Clock Tower Chest + Ruined Tower with nothing
|
||||
add_rule(world.multiworld.get_location("Mafia Town - Clock Tower Chest", world.player), lambda state: True)
|
||||
add_rule(world.multiworld.get_location("Mafia Town - Top of Ruined Tower", world.player), lambda state: True)
|
||||
@@ -430,6 +441,13 @@ def set_moderate_rules(world: World):
|
||||
set_rule(world.multiworld.get_location("Alpine Skyline - The Birdhouse: Dweller Platforms Relic", world.player),
|
||||
lambda state: True)
|
||||
|
||||
# Moderate: Twilight Path without Dweller Mask
|
||||
set_rule(world.multiworld.get_location("Alpine Skyline - The Twilight Path", world.player), lambda state: True)
|
||||
|
||||
# Moderate: Finale without Hookshot
|
||||
set_rule(world.multiworld.get_location("Act Completion (The Finale)", world.player),
|
||||
lambda state: can_use_hat(state, world, HatType.DWELLER))
|
||||
|
||||
if world.is_dlc1():
|
||||
# Moderate: clear Rock the Boat without Ice Hat
|
||||
add_rule(world.multiworld.get_location("Rock the Boat - Post Captain Rescue", world.player), lambda state: True)
|
||||
@@ -451,13 +469,6 @@ def set_moderate_rules(world: World):
|
||||
# The player can quite literally walk past the fan from the side without Time Stop.
|
||||
set_rule(world.multiworld.get_location("Pink Paw Station - Behind Fan", world.player), lambda state: True)
|
||||
|
||||
# The player can't jump back down to the manhole due to a fall damage volume preventing them from doing so
|
||||
set_rule(world.multiworld.get_location("Act Completion (Pink Paw Manhole)", world.player),
|
||||
lambda state: (state.has("Metro Ticket - Pink", world.player)
|
||||
or state.has("Metro Ticket - Yellow", world.player)
|
||||
and state.has("Metro Ticket - Blue", world.player))
|
||||
and can_use_hat(state, world, HatType.ICE))
|
||||
|
||||
# Moderate: clear Rush Hour without Hookshot
|
||||
set_rule(world.multiworld.get_location("Act Completion (Rush Hour)", world.player),
|
||||
lambda state: state.has("Metro Ticket - Pink", world.player)
|
||||
@@ -473,14 +484,13 @@ def set_hard_rules(world: World):
|
||||
lambda state: can_use_hat(state, world, HatType.SPRINT)
|
||||
and state.has("Scooter Badge", world.player), "or")
|
||||
|
||||
# Hard: Cross Subcon boss arena gap with No Bonk + SDJ, allowing access to the boss arena chest
|
||||
# Doing this in reverse from YCHE is expert logic, which expects you to cherry hover
|
||||
add_rule(world.multiworld.get_location("Subcon Forest - Boss Arena Chest", world.player),
|
||||
lambda state: can_surf(state, world) and can_sdj(state, world), "or")
|
||||
|
||||
set_rule(world.multiworld.get_location("Subcon Forest - Dweller Floating Rocks", world.player),
|
||||
lambda state: has_paintings(state, world, 3))
|
||||
|
||||
# Cherry bridge over boss arena gap (painting still expected)
|
||||
set_rule(world.multiworld.get_location("Subcon Forest - Boss Arena Chest", world.player),
|
||||
lambda state: has_paintings(state, world, 1, False))
|
||||
|
||||
# SDJ
|
||||
add_rule(world.multiworld.get_location("Subcon Forest - Long Tree Climb Chest", world.player),
|
||||
lambda state: can_sdj(state, world)
|
||||
@@ -492,13 +502,14 @@ def set_hard_rules(world: World):
|
||||
add_rule(world.multiworld.get_location("Act Completion (Time Rift - Curly Tail Trail)", world.player),
|
||||
lambda state: can_sdj(state, world), "or")
|
||||
|
||||
add_rule(world.multiworld.get_location("Act Completion (The Finale)", world.player),
|
||||
lambda state: can_use_hat(state, world, HatType.DWELLER) and can_sdj(state, world), "or")
|
||||
|
||||
# Hard: Mystifying Time Mesa time trial without hats
|
||||
set_rule(world.multiworld.get_location("Alpine Skyline - Mystifying Time Mesa: Zipline", world.player),
|
||||
lambda state: can_use_hookshot(state, world))
|
||||
|
||||
# Finale Telescope with only Ice Hat
|
||||
add_rule(world.multiworld.get_entrance("Telescope -> Time's End", world.player),
|
||||
lambda state: can_use_hat(state, world, HatType.ICE), "or")
|
||||
|
||||
if world.is_dlc1():
|
||||
# Hard: clear Deep Sea without Dweller Mask
|
||||
set_rule(world.multiworld.get_location("Act Completion (Time Rift - Deep Sea)", world.player),
|
||||
@@ -515,6 +526,10 @@ def set_hard_rules(world: World):
|
||||
|
||||
|
||||
def set_expert_rules(world: World):
|
||||
# Finale Telescope with no hats
|
||||
set_rule(world.multiworld.get_entrance("Telescope -> Time's End", world.player),
|
||||
lambda state: state.has("Time Piece", world.player, world.get_chapter_cost(ChapterIndex.FINALE)))
|
||||
|
||||
# Expert: Mafia Town - Above Boats with nothing
|
||||
set_rule(world.multiworld.get_location("Mafia Town - Above Boats", world.player), lambda state: True)
|
||||
|
||||
@@ -526,8 +541,6 @@ def set_expert_rules(world: World):
|
||||
|
||||
# Expert: get to and clear Twilight Bell without Dweller Mask.
|
||||
# Dweller Mask OR Sprint Hat OR Brewing Hat OR Time Stop + Umbrella required to complete act.
|
||||
set_rule(world.multiworld.get_location("Alpine Skyline - The Twilight Path", world.player), lambda state: True)
|
||||
|
||||
add_rule(world.multiworld.get_entrance("-> The Twilight Bell", world.player),
|
||||
lambda state: can_use_hookshot(state, world), "or")
|
||||
|
||||
@@ -640,10 +653,6 @@ def set_subcon_rules(world: World):
|
||||
and (not painting_logic(world) or has_paintings(state, world, 1))
|
||||
or state.has("YCHE Access", world.player))
|
||||
|
||||
if world.multiworld.UmbrellaLogic[world.player].value > 0:
|
||||
add_rule(world.multiworld.get_location("Act Completion (Toilet of Doom)", world.player),
|
||||
lambda state: can_hit(state, world))
|
||||
|
||||
set_rule(world.multiworld.get_location("Act Completion (Time Rift - Village)", world.player),
|
||||
lambda state: can_use_hat(state, world, HatType.BREWING) or state.has("Umbrella", world.player)
|
||||
or can_use_hat(state, world, HatType.DWELLER))
|
||||
@@ -907,9 +916,12 @@ def set_event_rules(world: World):
|
||||
if not is_location_valid(world, name):
|
||||
continue
|
||||
|
||||
if (data.dlc_flags is HatDLC.death_wish or data.dlc_flags is HatDLC.dlc2_dw) and name in snatcher_coins.keys():
|
||||
name = f"{name} ({data.region})"
|
||||
|
||||
event: Location = world.multiworld.get_location(name, world.player)
|
||||
|
||||
if data.act_complete_event:
|
||||
if data.act_event:
|
||||
add_rule(event, world.multiworld.get_location(f"Act Completion ({data.region})", world.player).access_rule)
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,14 @@
|
||||
from enum import IntEnum, IntFlag
|
||||
from typing import NamedTuple, Optional, List
|
||||
from BaseClasses import Location, Item, ItemClassification
|
||||
|
||||
|
||||
class HatInTimeLocation(Location):
|
||||
game: str = "A Hat in Time"
|
||||
|
||||
|
||||
class HatInTimeItem(Item):
|
||||
game: str = "A Hat in Time"
|
||||
|
||||
|
||||
class HatType(IntEnum):
|
||||
@@ -15,6 +25,7 @@ class HatDLC(IntFlag):
|
||||
dlc1 = 0b001
|
||||
dlc2 = 0b010
|
||||
death_wish = 0b100
|
||||
dlc2_dw = 0b0110 # for Snatcher Coins in Nyakuza Metro
|
||||
|
||||
|
||||
class ChapterIndex(IntEnum):
|
||||
@@ -35,6 +46,30 @@ class Difficulty(IntEnum):
|
||||
EXPERT = 2
|
||||
|
||||
|
||||
class LocData(NamedTuple):
|
||||
id: Optional[int] = 0
|
||||
region: Optional[str] = ""
|
||||
required_hats: Optional[List[HatType]] = [HatType.NONE]
|
||||
hookshot: Optional[bool] = False
|
||||
dlc_flags: Optional[HatDLC] = HatDLC.none
|
||||
paintings: Optional[int] = 0 # Paintings required for Subcon painting shuffle
|
||||
misc_required: Optional[List[str]] = []
|
||||
|
||||
# For UmbrellaLogic setting
|
||||
umbrella: Optional[bool] = False # Umbrella required for this check
|
||||
hit_requirement: Optional[int] = 0 # Hit required. 1 = Umbrella/Brewing only, 2 = bypass w/Dweller Mask (bells)
|
||||
|
||||
# Other
|
||||
act_event: Optional[bool] = False # Only used for event locations. Copy access rule from act completion
|
||||
nyakuza_thug: Optional[str] = "" # Name of Nyakuza thug NPC (for metro shops)
|
||||
|
||||
|
||||
class ItemData(NamedTuple):
|
||||
code: Optional[int]
|
||||
classification: ItemClassification
|
||||
dlc_flags: Optional[HatDLC] = HatDLC.none
|
||||
|
||||
|
||||
hat_type_to_item = {
|
||||
HatType.SPRINT: "Sprint Hat",
|
||||
HatType.BREWING: "Brewing Hat",
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
from BaseClasses import Item, ItemClassification, LocationProgressType, Tutorial
|
||||
from .Items import HatInTimeItem, item_table, create_item, relic_groups, act_contracts, create_itempool
|
||||
from BaseClasses import Item, ItemClassification, Tutorial
|
||||
from .Items import item_table, create_item, relic_groups, act_contracts, create_itempool
|
||||
from .Regions import create_regions, randomize_act_entrances, chapter_act_info, create_events, get_shuffled_region
|
||||
from .Locations import location_table, contract_locations, is_location_valid, get_location_names, get_tasksanity_start_id
|
||||
from .Rules import set_rules
|
||||
from .Options import ahit_options, slot_data_options, adjust_options
|
||||
from .Types import HatType, ChapterIndex
|
||||
from .Types import HatType, ChapterIndex, HatInTimeItem
|
||||
from .DeathWishLocations import create_dw_regions, dw_classes, death_wishes
|
||||
from .DeathWishRules import set_dw_rules, create_enemy_events
|
||||
from worlds.AutoWorld import World, WebWorld
|
||||
|
||||
Reference in New Issue
Block a user