From e53e75de5ff282a2bd97fb9e73aa6d2ac201199b Mon Sep 17 00:00:00 2001 From: CookieCat Date: Tue, 26 Mar 2024 19:32:11 -0400 Subject: [PATCH] More stuff from review --- worlds/ahit/DeathWishLocations.py | 18 ++-- worlds/ahit/DeathWishRules.py | 31 +++--- worlds/ahit/Items.py | 2 +- worlds/ahit/Locations.py | 144 +++++++++++++++++-------- worlds/ahit/Options.py | 7 +- worlds/ahit/Regions.py | 17 ++- worlds/ahit/Rules.py | 114 ++++++++------------ worlds/ahit/Types.py | 1 + worlds/ahit/__init__.py | 169 +++++++++++------------------- 9 files changed, 245 insertions(+), 258 deletions(-) diff --git a/worlds/ahit/DeathWishLocations.py b/worlds/ahit/DeathWishLocations.py index 00902262ad..a6f19cd3e2 100644 --- a/worlds/ahit/DeathWishLocations.py +++ b/worlds/ahit/DeathWishLocations.py @@ -149,21 +149,21 @@ dw_classes = { def create_dw_regions(world: "HatInTimeWorld"): if world.options.DWExcludeAnnoyingContracts.value > 0: for name in annoying_dws: - world.get_excluded_dws().append(name) + world.excluded_dws.append(name) if world.options.DWEnableBonus.value == 0 \ or world.options.DWAutoCompleteBonuses.value > 0: for name in death_wishes: - world.get_excluded_bonuses().append(name) + world.excluded_bonuses.append(name) elif world.options.DWExcludeAnnoyingBonuses.value > 0: for name in annoying_bonuses: - world.get_excluded_bonuses().append(name) + world.excluded_bonuses.append(name) if world.options.DWExcludeCandles.value > 0: for name in dw_candles: - if name in world.get_excluded_dws(): + if name in world.excluded_dws: continue - world.get_excluded_dws().append(name) + world.excluded_dws.append(name) spaceship = world.multiworld.get_region("Spaceship", world.player) dw_map: Region = create_region(world, "Death Wish Map") @@ -193,7 +193,7 @@ def create_dw_regions(world: "HatInTimeWorld"): dw_shuffle.append("Seal the Deal") - world.set_dw_shuffle(dw_shuffle) + world.dw_shuffle = dw_shuffle prev_dw: Region for i in range(len(dw_shuffle)): name = dw_shuffle[i] @@ -220,7 +220,7 @@ def create_dw_regions(world: "HatInTimeWorld"): bonus_stamps.place_locked_item(HatInTimeItem(f"2 Stamps - {name}", ItemClassification.progression, None, world.player)) - if name in world.get_excluded_dws(): + if name in world.excluded_dws: main_objective.progress_type = LocationProgressType.EXCLUDED full_clear.progress_type = LocationProgressType.EXCLUDED elif world.is_bonus_excluded(name): @@ -232,7 +232,7 @@ def create_dw_regions(world: "HatInTimeWorld"): else: for key, loc_id in death_wishes.items(): if key == "Snatcher Coins in Nyakuza Metro" and not world.is_dlc2(): - world.get_excluded_dws().append(key) + world.excluded_dws.append(key) continue dw = create_region(world, key) @@ -258,7 +258,7 @@ def create_dw_regions(world: "HatInTimeWorld"): bonus_stamps.place_locked_item(HatInTimeItem(f"2 Stamps - {key}", ItemClassification.progression, None, world.player)) - if key in world.get_excluded_dws(): + if key in world.excluded_dws: main_objective.progress_type = LocationProgressType.EXCLUDED full_clear.progress_type = LocationProgressType.EXCLUDED elif world.is_bonus_excluded(key): diff --git a/worlds/ahit/DeathWishRules.py b/worlds/ahit/DeathWishRules.py index 27f8a4db86..e363813746 100644 --- a/worlds/ahit/DeathWishRules.py +++ b/worlds/ahit/DeathWishRules.py @@ -103,13 +103,13 @@ required_snatcher_coins = { def set_dw_rules(world: "HatInTimeWorld"): - if "Snatcher's Hit List" not in world.get_excluded_dws() \ - or "Camera Tourist" not in world.get_excluded_dws(): + if "Snatcher's Hit List" not in world.excluded_dws \ + or "Camera Tourist" not in world.excluded_dws: set_enemy_rules(world) dw_list: List[str] = [] if world.options.DWShuffle.value > 0: - dw_list = world.get_dw_shuffle() + dw_list = world.dw_shuffle else: for name in death_wishes.keys(): dw_list.append(name) @@ -196,13 +196,12 @@ def set_dw_rules(world: "HatInTimeWorld"): add_rule(bonus_stamps, loc.access_rule) if world.options.DWShuffle.value > 0: - dw_shuffle = world.get_dw_shuffle() - for i in range(len(dw_shuffle)): + for i in range(len(world.dw_shuffle)): if i == 0: continue - name = dw_shuffle[i] - prev_dw = world.multiworld.get_region(dw_shuffle[i-1], world.player) + name = world.dw_shuffle[i] + prev_dw = world.multiworld.get_region(world.dw_shuffle[i-1], world.player) entrance = world.multiworld.get_entrance(f"{prev_dw.name} -> {name}", world.player) add_rule(entrance, lambda state, n=prev_dw.name: state.has(f"1 Stamp - {n}", world.player)) else: @@ -330,10 +329,16 @@ def set_candle_dw_rules(name: str, world: "HatInTimeWorld"): and state.has("Triple Enemy Picture", world.player)) elif "Snatcher Coins" in name: + coins: List[str] = [] for coin in required_snatcher_coins[name]: - add_rule(main_objective, lambda state: state.has(coin, world.player), "or") + coins.append(coin) add_rule(full_clear, lambda state: state.has(coin, world.player)) + # any coin works for the main objective + add_rule(main_objective, lambda state: state.has(coins[0], world.player) + or state.has(coins[1], world.player) + or state.has(coins[2], world.player)) + def get_zero_jump_clear_count(state: CollectionState, world: "HatInTimeWorld") -> int: total = 0 @@ -378,7 +383,7 @@ def can_reach_all_bosses(state: CollectionState, world: "HatInTimeWorld") -> boo def create_enemy_events(world: "HatInTimeWorld"): - no_tourist = "Camera Tourist" in world.get_excluded_dws() or "Camera Tourist" in world.get_excluded_bonuses() + no_tourist = "Camera Tourist" in world.excluded_dws or "Camera Tourist" in world.excluded_bonuses for enemy, regions in hit_list.items(): if no_tourist and enemy in bosses: @@ -395,7 +400,7 @@ def create_enemy_events(world: "HatInTimeWorld"): if area == "Bluefin Tunnel" and not world.is_dlc2(): continue if world.options.DWShuffle.value > 0 and area in death_wishes.keys() \ - and area not in world.get_dw_shuffle(): + and area not in world.dw_shuffle: continue region = world.multiworld.get_region(area, world.player) @@ -409,7 +414,7 @@ def create_enemy_events(world: "HatInTimeWorld"): continue if world.options.DWShuffle.value > 0 and name in death_wishes.keys() \ - and name not in world.get_dw_shuffle(): + and name not in world.dw_shuffle: continue region = world.multiworld.get_region(name, world.player) @@ -422,7 +427,7 @@ def create_enemy_events(world: "HatInTimeWorld"): def set_enemy_rules(world: "HatInTimeWorld"): - no_tourist = "Camera Tourist" in world.get_excluded_dws() or "Camera Tourist" in world.get_excluded_bonuses() + no_tourist = "Camera Tourist" in world.excluded_dws or "Camera Tourist" in world.excluded_bonuses for enemy, regions in hit_list.items(): if no_tourist and enemy in bosses: @@ -440,7 +445,7 @@ def set_enemy_rules(world: "HatInTimeWorld"): continue if world.options.DWShuffle.value > 0 and area in death_wishes \ - and area not in world.get_dw_shuffle(): + and area not in world.dw_shuffle: continue event = world.multiworld.get_location(f"{enemy} - {area}", world.player) diff --git a/worlds/ahit/Items.py b/worlds/ahit/Items.py index f05b3ba446..111864e271 100644 --- a/worlds/ahit/Items.py +++ b/worlds/ahit/Items.py @@ -97,7 +97,7 @@ def calculate_yarn_costs(world: "HatInTimeWorld"): max_cost = 0 for i in range(5): cost: int = mw.random.randint(min(min_yarn_cost, max_yarn_cost), max(max_yarn_cost, min_yarn_cost)) - world.get_hat_yarn_costs()[HatType(i)] = cost + world.hat_yarn_costs[HatType(i)] = cost max_cost += cost available_yarn: int = world.options.YarnAvailable.value diff --git a/worlds/ahit/Locations.py b/worlds/ahit/Locations.py index bb06d8a33a..11ab5fe2b2 100644 --- a/worlds/ahit/Locations.py +++ b/worlds/ahit/Locations.py @@ -12,7 +12,7 @@ def get_total_locations(world: "HatInTimeWorld") -> int: total = 0 if not world.is_dw_only(): - for (name) in location_table.keys(): + for name in location_table.keys(): if is_location_valid(world, name): total += 1 @@ -21,9 +21,9 @@ def get_total_locations(world: "HatInTimeWorld") -> int: if world.is_dw(): if world.options.DWShuffle.value > 0: - total += len(world.get_dw_shuffle()) + total += len(world.dw_shuffle) if world.options.DWEnableBonus.value > 0: - total += len(world.get_dw_shuffle()) + total += len(world.dw_shuffle) else: total += 37 if world.is_dlc2(): @@ -81,11 +81,11 @@ def is_location_valid(world: "HatInTimeWorld", location: str) -> bool: return False if world.options.DWShuffle.value > 0 \ - and data.region in death_wishes and data.region not in world.get_dw_shuffle(): + and data.region in death_wishes and data.region not in world.dw_shuffle: return False if location in zero_jumps: - if world.options.DWShuffle.value > 0 and "Zero Jumps" not in world.get_dw_shuffle(): + if world.options.DWShuffle.value > 0 and "Zero Jumps" not in world.dw_shuffle: return False difficulty: int = world.options.LogicDifficulty.value @@ -298,10 +298,10 @@ ahit_locations = { # Alpine Skyline "Alpine Skyline - Goat Village: Below Hookpoint": LocData(2000334856, "Alpine Skyline Area (TIHS)"), "Alpine Skyline - Goat Village: Hidden Branch": LocData(2000334855, "Alpine Skyline Area (TIHS)"), - "Alpine Skyline - Goat Refinery": LocData(2000333635, "Alpine Skyline Area (TIHS)"), - "Alpine Skyline - Bird Pass Fork": LocData(2000335911, "Alpine Skyline Area (TIHS)"), + "Alpine Skyline - Goat Refinery": LocData(2000333635, "Alpine Skyline Area (TIHS)", hookshot=True), + "Alpine Skyline - Bird Pass Fork": LocData(2000335911, "Alpine Skyline Area (TIHS)", hookshot=True), - "Alpine Skyline - Yellow Band Hills": LocData(2000335756, "Alpine Skyline Area (TIHS)", + "Alpine Skyline - Yellow Band Hills": LocData(2000335756, "Alpine Skyline Area (TIHS)", hookshot=True, required_hats=[HatType.BREWING]), "Alpine Skyline - The Purrloined Village: Horned Stone": LocData(2000335561, "Alpine Skyline Area"), @@ -318,7 +318,7 @@ ahit_locations = { "Alpine Skyline - Mystifying Time Mesa: Zipline": LocData(2000337058, "Alpine Skyline Area"), "Alpine Skyline - Mystifying Time Mesa: Gate Puzzle": LocData(2000336052, "Alpine Skyline Area"), - "Alpine Skyline - Ember Summit": LocData(2000336311, "Alpine Skyline Area (TIHS)"), + "Alpine Skyline - Ember Summit": LocData(2000336311, "Alpine Skyline Area (TIHS)", hookshot=True), "Alpine Skyline - The Lava Cake: Center Fence Cage": LocData(2000335448, "The Lava Cake"), "Alpine Skyline - The Lava Cake: Outer Island Chest": LocData(2000334291, "The Lava Cake"), "Alpine Skyline - The Lava Cake: Dweller Pillars": LocData(2000335417, "The Lava Cake"), @@ -327,7 +327,7 @@ ahit_locations = { "Alpine Skyline - The Twilight Bell: Wide Purple Platform": LocData(2000336478, "The Twilight Bell"), "Alpine Skyline - The Twilight Bell: Ice Platform": LocData(2000335826, "The Twilight Bell"), "Alpine Skyline - Goat Outpost Horn": LocData(2000334760, "Alpine Skyline Area"), - "Alpine Skyline - Windy Passage": LocData(2000334776, "Alpine Skyline Area (TIHS)"), + "Alpine Skyline - Windy Passage": LocData(2000334776, "Alpine Skyline Area (TIHS)", hookshot=True), "Alpine Skyline - The Windmill: Inside Pon Cluster": LocData(2000336395, "The Windmill"), "Alpine Skyline - The Windmill: Entrance": LocData(2000335783, "The Windmill"), "Alpine Skyline - The Windmill: Dropdown": LocData(2000335815, "The Windmill"), @@ -867,54 +867,112 @@ zero_jumps = { dlc_flags=HatDLC.dlc2_dw), } -# noinspection PyDictDuplicateKeys snatcher_coins = { - "Snatcher Coin - Top of HQ": LocData(0, "Down with the Mafia!", dlc_flags=HatDLC.death_wish), - "Snatcher Coin - Top of HQ": LocData(0, "Cheating the Race", dlc_flags=HatDLC.death_wish), + "Snatcher Coin - Top of HQ (DWTM)": LocData(0, "Down with the Mafia!", snatcher_coin="Snatcher Coin - Top of HQ", + dlc_flags=HatDLC.death_wish), - "Snatcher Coin - Top of HQ": LocData(0, "Heating Up Mafia Town", - hit_type=HitType.umbrella, dlc_flags=HatDLC.death_wish), + "Snatcher Coin - Top of HQ (CTR)": LocData(0, "Cheating the Race", snatcher_coin="Snatcher Coin - Top of HQ", + dlc_flags=HatDLC.death_wish), - "Snatcher Coin - Top of HQ": LocData(0, "The Golden Vault", dlc_flags=HatDLC.death_wish), - "Snatcher Coin - Top of HQ": LocData(0, "Beat the Heat", dlc_flags=HatDLC.death_wish), + "Snatcher Coin - Top of HQ (HUMT)": LocData(0, "Heating Up Mafia Town", snatcher_coin="Snatcher Coin - Top of HQ", + hit_type=HitType.umbrella, dlc_flags=HatDLC.death_wish), - "Snatcher Coin - Top of Tower": LocData(0, "Mafia Town Area (HUMT)", dlc_flags=HatDLC.death_wish), - "Snatcher Coin - Top of Tower": LocData(0, "Beat the Heat", dlc_flags=HatDLC.death_wish), - "Snatcher Coin - Top of Tower": LocData(0, "Collect-a-thon", dlc_flags=HatDLC.death_wish), - "Snatcher Coin - Top of Tower": LocData(0, "She Speedran from Outer Space", dlc_flags=HatDLC.death_wish), - "Snatcher Coin - Top of Tower": LocData(0, "Mafia's Jumps", dlc_flags=HatDLC.death_wish), - "Snatcher Coin - Under Ruined Tower": LocData(0, "Mafia Town Area", dlc_flags=HatDLC.death_wish), - "Snatcher Coin - Under Ruined Tower": LocData(0, "Collect-a-thon", dlc_flags=HatDLC.death_wish), - "Snatcher Coin - Under Ruined Tower": LocData(0, "She Speedran from Outer Space", dlc_flags=HatDLC.death_wish), + "Snatcher Coin - Top of HQ (TGV)": LocData(0, "The Golden Vault", snatcher_coin="Snatcher Coin - Top of HQ", + dlc_flags=HatDLC.death_wish), - "Snatcher Coin - Top of Red House": LocData(0, "Dead Bird Studio - Elevator Area", dlc_flags=HatDLC.death_wish), - "Snatcher Coin - Top of Red House": LocData(0, "Security Breach", dlc_flags=HatDLC.death_wish), - "Snatcher Coin - Train Rush": LocData(0, "Train Rush", hookshot=True, dlc_flags=HatDLC.death_wish), + "Snatcher Coin - Top of HQ (DW: BTH)": LocData(0, "Beat the Heat", snatcher_coin="Snatcher Coin - Top of HQ", + dlc_flags=HatDLC.death_wish), - "Snatcher Coin - Train Rush": LocData(0, "10 Seconds until Self-Destruct", hookshot=True, + "Snatcher Coin - Top of Tower": LocData(0, "Mafia Town Area (HUMT)", snatcher_coin="Snatcher Coin - Top of Tower", + dlc_flags=HatDLC.death_wish), + + "Snatcher Coin - Top of Tower (DW: BTH)": LocData(0, "Beat the Heat", snatcher_coin="Snatcher Coin - Top of Tower", + dlc_flags=HatDLC.death_wish), + + "Snatcher Coin - Top of Tower (DW: CAT)": LocData(0, "Collect-a-thon", snatcher_coin="Snatcher Coin - Top of Tower", + dlc_flags=HatDLC.death_wish), + + "Snatcher Coin - Top of Tower (SSFOS)": LocData(0, "She Speedran from Outer Space", + snatcher_coin="Snatcher Coin - Top of Tower", + dlc_flags=HatDLC.death_wish), + + "Snatcher Coin - Top of Tower (DW: MJ)": LocData(0, "Mafia's Jumps", snatcher_coin="Snatcher Coin - Top of Tower", + dlc_flags=HatDLC.death_wish), + + "Snatcher Coin - Under Ruined Tower": LocData(0, "Mafia Town Area", + snatcher_coin="Snatcher Coin - Under Ruined Tower", + dlc_flags=HatDLC.death_wish), + + "Snatcher Coin - Under Ruined Tower (DW: CAT)": LocData(0, "Collect-a-thon", + snatcher_coin="Snatcher Coin - Under Ruined Tower", + dlc_flags=HatDLC.death_wish), + + "Snatcher Coin - Under Ruined Tower (DW: SSFOS)": LocData(0, "She Speedran from Outer Space", + snatcher_coin="Snatcher Coin - Under Ruined Tower", + dlc_flags=HatDLC.death_wish), + + "Snatcher Coin - Top of Red House (DBS)": LocData(0, "Dead Bird Studio - Elevator Area", + snatcher_coin="Snatcher Coin - Top of Red House", + dlc_flags=HatDLC.death_wish), + + "Snatcher Coin - Top of Red House (DW: SB)": LocData(0, "Security Breach", + snatcher_coin="Snatcher Coin - Top of Red House", + dlc_flags=HatDLC.death_wish), + + "Snatcher Coin - Train Rush": LocData(0, "Train Rush", snatcher_coin="Snatcher Coin - Train Rush", + hookshot=True, dlc_flags=HatDLC.death_wish), + + "Snatcher Coin - Train Rush (10 Seconds)": LocData(0, "10 Seconds until Self-Destruct", + snatcher_coin="Snatcher Coin - Train Rush", + hookshot=True, dlc_flags=HatDLC.death_wish), + + "Snatcher Coin - Picture Perfect": LocData(0, "Picture Perfect", snatcher_coin="Snatcher Coin - Picture Perfect", + dlc_flags=HatDLC.death_wish), + + "Snatcher Coin - Swamp Tree": LocData(0, "Subcon Forest Area", snatcher_coin="Snatcher Coin - Swamp Tree", + hookshot=True, paintings=1, dlc_flags=HatDLC.death_wish), - "Snatcher Coin - Picture Perfect": LocData(0, "Picture Perfect", dlc_flags=HatDLC.death_wish), + "Snatcher Coin - Swamp Tree (Speedrun Well)": LocData(0, "Speedrun Well", + snatcher_coin="Snatcher Coin - Swamp Tree", + hookshot=True, dlc_flags=HatDLC.death_wish), - "Snatcher Coin - Swamp Tree": LocData(0, "Subcon Forest Area", hookshot=True, paintings=1, + "Snatcher Coin - Manor Roof": LocData(0, "Subcon Forest Area", snatcher_coin="Snatcher Coin - Manor Roof", + hit_type=HitType.dweller_bell, paintings=1, dlc_flags=HatDLC.death_wish), - "Snatcher Coin - Swamp Tree": LocData(0, "Speedrun Well", hookshot=True, dlc_flags=HatDLC.death_wish), + "Snatcher Coin - Giant Time Piece": LocData(0, "Subcon Forest Area", + snatcher_coin="Snatcher Coin - Giant Time Piece", + paintings=3, dlc_flags=HatDLC.death_wish), - "Snatcher Coin - Manor Roof": LocData(0, "Subcon Forest Area", hit_type=HitType.dweller_bell, paintings=1, - dlc_flags=HatDLC.death_wish), + "Snatcher Coin - Goat Village Top": LocData(0, "Alpine Skyline Area (TIHS)", + snatcher_coin="Snatcher Coin - Goat Village Top", + dlc_flags=HatDLC.death_wish), - "Snatcher Coin - Giant Time Piece": LocData(0, "Subcon Forest Area", paintings=3, dlc_flags=HatDLC.death_wish), + "Snatcher Coin - Goat Village Top (Illness Speedrun)": LocData(0, "The Illness has Speedrun", + snatcher_coin="Snatcher Coin - Goat Village Top", + dlc_flags=HatDLC.death_wish), - "Snatcher Coin - Goat Village Top": LocData(0, "Alpine Skyline Area (TIHS)", dlc_flags=HatDLC.death_wish), - "Snatcher Coin - Goat Village Top": LocData(0, "The Illness has Speedrun", dlc_flags=HatDLC.death_wish), - "Snatcher Coin - Lava Cake": LocData(0, "The Lava Cake", dlc_flags=HatDLC.death_wish), - "Snatcher Coin - Windmill": LocData(0, "The Windmill", dlc_flags=HatDLC.death_wish), - "Snatcher Coin - Windmill": LocData(0, "Wound-Up Windmill", hookshot=True, dlc_flags=HatDLC.death_wish), + "Snatcher Coin - Lava Cake": LocData(0, "The Lava Cake", snatcher_coin="Snatcher Coin - Lava Cake", + dlc_flags=HatDLC.death_wish), - "Snatcher Coin - Green Clean Tower": LocData(0, "Green Clean Station", dlc_flags=HatDLC.dlc2_dw), - "Snatcher Coin - Bluefin Cat Train": LocData(0, "Bluefin Tunnel", dlc_flags=HatDLC.dlc2_dw), - "Snatcher Coin - Pink Paw Fence": LocData(0, "Pink Paw Station", dlc_flags=HatDLC.dlc2_dw), + "Snatcher Coin - Windmill": LocData(0, "The Windmill", snatcher_coin="Snatcher Coin - Windmill", + dlc_flags=HatDLC.death_wish), + + "Snatcher Coin - Windmill (DW: WUW)": LocData(0, "Wound-Up Windmill", snatcher_coin="Snatcher Coin - Windmill", + hookshot=True, dlc_flags=HatDLC.death_wish), + + "Snatcher Coin - Green Clean Tower": LocData(0, "Green Clean Station", + snatcher_coin="Snatcher Coin - Green Clean Tower", + dlc_flags=HatDLC.dlc2_dw), + + "Snatcher Coin - Bluefin Cat Train": LocData(0, "Bluefin Tunnel", + snatcher_coin="Snatcher Coin - Bluefin Tunnel", + dlc_flags=HatDLC.dlc2_dw), + + "Snatcher Coin - Pink Paw Fence": LocData(0, "Pink Paw Station", + snatcher_coin="Snatcher Coin - Pink Paw Fence", + dlc_flags=HatDLC.dlc2_dw), } event_locs = { diff --git a/worlds/ahit/Options.py b/worlds/ahit/Options.py index 69be748e6c..eb4f833748 100644 --- a/worlds/ahit/Options.py +++ b/worlds/ahit/Options.py @@ -1,5 +1,5 @@ from typing import List, TYPE_CHECKING -from schema import Schema +from schema import Schema, Optional from dataclasses import dataclass from worlds.AutoWorld import PerGameCommonOptions from Options import Range, Toggle, DeathLink, Choice, OptionDict, DefaultOnToggle @@ -128,7 +128,7 @@ class ActPlando(OptionDict): """Plando acts onto other acts. For example, \"Train Rush\": \"Alpine Free Roam\"""" display_name = "Act Plando" schema = Schema({ - str: str + Optional(str): str }) @@ -516,7 +516,8 @@ class DWShuffleCountMax(Range): class DWEnableBonus(Toggle): - """In Death Wish, add a location for completing all of a DW contract's bonuses, in addition to the location for completing the DW contract normally. + """In Death Wish, add a location for completing all of a DW contract's bonuses, + in addition to the location for completing the DW contract normally. WARNING!! Only for the brave! This option can create VERY DIFFICULT SEEDS! ONLY turn this on if you know what you are doing to yourself and everyone else in the multiworld! Using Peace and Tranquility to auto-complete the bonuses will NOT count!""" diff --git a/worlds/ahit/Regions.py b/worlds/ahit/Regions.py index 2b4ec06bae..aa26db17d2 100644 --- a/worlds/ahit/Regions.py +++ b/worlds/ahit/Regions.py @@ -788,7 +788,7 @@ def create_badge_seller(world: "HatInTimeWorld") -> Region: world.options.BadgeSellerMaxItems.value) if max_items <= 0: - world.set_badge_seller_count(0) + world.badge_seller_count = 0 return badge_seller for (key, data) in shop_locations.items(): @@ -803,7 +803,7 @@ def create_badge_seller(world: "HatInTimeWorld") -> Region: if count >= max_items: break - world.set_badge_seller_count(max_items) + world.badge_seller_count = max_items return badge_seller @@ -867,9 +867,9 @@ def update_chapter_act_info(world: "HatInTimeWorld", original_region: Region, ne world.act_connections[original_act_info] = new_act_info -def get_shuffled_region(self, region: str) -> str: +def get_shuffled_region(world: "HatInTimeWorld", region: str) -> str: ci: str = chapter_act_info[region] - for key, val in self.act_connections.items(): + for key, val in world.act_connections.items(): if val == ci: for name in chapter_act_info.keys(): if chapter_act_info[name] == key: @@ -882,7 +882,6 @@ def create_thug_shops(world: "HatInTimeWorld"): count = -1 step = 0 old_name = "" - thug_items = world.get_nyakuza_thug_items() for key, data in shop_locations.items(): if data.nyakuza_thug == "": @@ -892,14 +891,14 @@ def create_thug_shops(world: "HatInTimeWorld"): continue try: - if thug_items[data.nyakuza_thug] <= 0: + if world.nyakuza_thug_items[data.nyakuza_thug] <= 0: continue except KeyError: pass if count == -1: count = world.random.randint(min_items, max_items) - thug_items.setdefault(data.nyakuza_thug, count) + world.nyakuza_thug_items.setdefault(data.nyakuza_thug, count) if count <= 0: continue @@ -915,8 +914,6 @@ def create_thug_shops(world: "HatInTimeWorld"): step = 0 count = -1 - world.set_nyakuza_thug_items(thug_items) - def create_events(world: "HatInTimeWorld") -> int: count = 0 @@ -928,7 +925,7 @@ def create_events(world: "HatInTimeWorld") -> int: item_name: str = name if world.is_dw(): if name in snatcher_coins.keys(): - name = f"{name} ({data.region})" + item_name = data.snatcher_coin elif name in zero_jumps: if get_difficulty(world) < Difficulty.HARD and name in zero_jumps_hard: continue diff --git a/worlds/ahit/Rules.py b/worlds/ahit/Rules.py index 0d43e72a3b..929700eddc 100644 --- a/worlds/ahit/Rules.py +++ b/worlds/ahit/Rules.py @@ -1,8 +1,8 @@ from worlds.AutoWorld import 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, snatcher_coins -from .Types import HatType, ChapterIndex, hat_type_to_item, Difficulty, HatDLC, HitType + shop_locations, event_locs +from .Types import HatType, ChapterIndex, hat_type_to_item, Difficulty, HitType from BaseClasses import Location, Entrance, Region from typing import TYPE_CHECKING, List, Callable, Union, Dict @@ -43,9 +43,8 @@ def can_use_hat(state: CollectionState, world: "HatInTimeWorld", hat: HatType) - def get_hat_cost(world: "HatInTimeWorld", hat: HatType) -> int: cost = 0 - costs = world.get_hat_yarn_costs() - for h in world.get_hat_craft_order(): - cost += costs[h] + for h in world.hat_craft_order: + cost += world.hat_yarn_costs[h] if h == hat: break @@ -136,7 +135,7 @@ def can_clear_metro(state: CollectionState, world: "HatInTimeWorld") -> bool: def set_rules(world: "HatInTimeWorld"): # First, chapter access starting_chapter = ChapterIndex(world.options.StartingChapter.value) - world.set_chapter_cost(starting_chapter, 0) + world.chapter_timepiece_costs[starting_chapter] = 0 # Chapter costs increase progressively. Randomly decide the chapter order, except for Finale chapter_list: List[ChapterIndex] = [ChapterIndex.MAFIA, ChapterIndex.BIRDS, @@ -160,8 +159,8 @@ def set_rules(world: "HatInTimeWorld"): world.random.shuffle(chapter_list) if starting_chapter is not ChapterIndex.ALPINE and (world.is_dlc1() or world.is_dlc2()): - index1: int = 69 - index2: int = 69 + index1 = 69 + index2 = 69 pos: int lowest_index: int chapter_list.remove(ChapterIndex.ALPINE) @@ -180,75 +179,63 @@ def set_rules(world: "HatInTimeWorld"): chapter_list.insert(pos, ChapterIndex.ALPINE) - if world.is_dlc1() and world.is_dlc2() and final_chapter is not ChapterIndex.METRO: - chapter_list.remove(ChapterIndex.METRO) - index = chapter_list.index(ChapterIndex.CRUISE) - if index >= len(chapter_list): - chapter_list.append(ChapterIndex.METRO) - else: - chapter_list.insert(world.random.randint(index+1, len(chapter_list)), ChapterIndex.METRO) - lowest_cost: int = world.options.LowestChapterCost.value highest_cost: int = world.options.HighestChapterCost.value cost_increment: int = world.options.ChapterCostIncrement.value min_difference: int = world.options.ChapterCostMinDifference.value last_cost = 0 - loop_count = 0 - for chapter in chapter_list: - min_range: int = lowest_cost + (cost_increment * loop_count) + for i, chapter in enumerate(chapter_list): + min_range: int = lowest_cost + (cost_increment * i) if min_range >= highest_cost: min_range = highest_cost-1 value: int = world.random.randint(min_range, min(highest_cost, max(lowest_cost, last_cost + cost_increment))) - cost = world.random.randint(value, min(value + cost_increment, highest_cost)) - if loop_count >= 1: + if i >= 1: if last_cost + min_difference > cost: cost = last_cost + min_difference cost = min(cost, highest_cost) - world.set_chapter_cost(chapter, cost) + world.chapter_timepiece_costs[chapter] = cost last_cost = cost - loop_count += 1 if final_chapter is not None: - world.set_chapter_cost(final_chapter, world.random.randint( + world.chapter_timepiece_costs[final_chapter] = world.random.randint( world.options.FinalChapterMinCost.value, - world.options.FinalChapterMaxCost.value)) + world.options.FinalChapterMaxCost.value) add_rule(world.multiworld.get_entrance("Telescope -> Mafia Town", world.player), - lambda state: state.has("Time Piece", world.player, world.get_chapter_cost(ChapterIndex.MAFIA))) + lambda state: state.has("Time Piece", world.player, world.chapter_timepiece_costs[ChapterIndex.MAFIA])) add_rule(world.multiworld.get_entrance("Telescope -> Battle of the Birds", world.player), - lambda state: state.has("Time Piece", world.player, world.get_chapter_cost(ChapterIndex.BIRDS))) + lambda state: state.has("Time Piece", world.player, world.chapter_timepiece_costs[ChapterIndex.BIRDS])) add_rule(world.multiworld.get_entrance("Telescope -> Subcon Forest", world.player), - lambda state: state.has("Time Piece", world.player, world.get_chapter_cost(ChapterIndex.SUBCON))) + lambda state: state.has("Time Piece", world.player, world.chapter_timepiece_costs[ChapterIndex.SUBCON])) add_rule(world.multiworld.get_entrance("Telescope -> Alpine Skyline", world.player), - lambda state: state.has("Time Piece", world.player, world.get_chapter_cost(ChapterIndex.ALPINE))) + lambda state: state.has("Time Piece", world.player, world.chapter_timepiece_costs[ChapterIndex.ALPINE])) add_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)) + lambda state: state.has("Time Piece", world.player, world.chapter_timepiece_costs[ChapterIndex.FINALE]) and can_use_hat(state, world, HatType.BREWING) and can_use_hat(state, world, HatType.DWELLER)) if world.is_dlc1(): add_rule(world.multiworld.get_entrance("Telescope -> The Arctic Cruise", world.player), - lambda state: state.has("Time Piece", world.player, world.get_chapter_cost(ChapterIndex.ALPINE)) - and state.has("Time Piece", world.player, world.get_chapter_cost(ChapterIndex.CRUISE))) + lambda state: state.has("Time Piece", world.player, world.chapter_timepiece_costs[ChapterIndex.ALPINE]) + and state.has("Time Piece", world.player, world.chapter_timepiece_costs[ChapterIndex.CRUISE])) if world.is_dlc2(): add_rule(world.multiworld.get_entrance("Telescope -> Nyakuza Metro", world.player), - lambda state: state.has("Time Piece", world.player, world.get_chapter_cost(ChapterIndex.ALPINE)) - and state.has("Time Piece", world.player, world.get_chapter_cost(ChapterIndex.METRO)) + lambda state: state.has("Time Piece", world.player, world.chapter_timepiece_costs[ChapterIndex.ALPINE]) + and state.has("Time Piece", world.player, world.chapter_timepiece_costs[ChapterIndex.METRO]) and can_use_hat(state, world, HatType.DWELLER) and can_use_hat(state, world, HatType.ICE)) if world.options.ActRandomizer.value == 0: set_default_rift_rules(world) table = {**location_table, **event_locs} - loc: Location for (key, data) in table.items(): if not is_location_valid(world, key): continue @@ -256,9 +243,6 @@ def set_rules(world: "HatInTimeWorld"): if key in contract_locations.keys(): continue - if data.dlc_flags & HatDLC.death_wish and key in snatcher_coins.keys(): - key = f"{key} ({data.region})" - loc = world.multiworld.get_location(key, world.player) for hat in data.required_hats: @@ -319,33 +303,12 @@ def set_rules(world: "HatInTimeWorld"): add_rule(world.multiworld.get_location(loc, world.player), lambda state, z=zipline: state.has(z, world.player)) - for loc in world.multiworld.get_region("Alpine Skyline Area (TIHS)", world.player).locations: - if "Goat Village" in loc.name: - continue - # This needs some special handling - if loc.name == "Alpine Skyline - Goat Refinery": - add_rule(loc, lambda state: state.has("AFR Access", world.player) - and can_use_hookshot(state, world) - and can_hit(state, world, True)) - - difficulty: Difficulty = Difficulty(world.options.LogicDifficulty.value) - if difficulty >= Difficulty.MODERATE: - add_rule(loc, lambda state: state.has("TIHS Access", world.player) - and can_use_hat(state, world, HatType.SPRINT), "or") - elif difficulty >= Difficulty.HARD: - add_rule(loc, lambda state: state.has("TIHS Access", world.player, "or")) - - continue - - add_rule(loc, lambda state: can_use_hookshot(state, world)) - dummy_entrances: List[Entrance] = [] for (key, acts) in act_connections.items(): if "Arctic Cruise" in key and not world.is_dlc1(): continue - i: int = 1 entrance: Entrance = world.multiworld.get_entrance(key, world.player) region: Region = entrance.connected_region access_rules: List[Callable[[CollectionState], bool]] = [] @@ -354,7 +317,7 @@ def set_rules(world: "HatInTimeWorld"): # Entrances to this act that we have to set access_rules on entrances: List[Entrance] = [] - for act in acts: + for i, act in enumerate(acts, start=1): act_entrance: Entrance = world.multiworld.get_entrance(act, world.player) access_rules.append(act_entrance.access_rule) required_region = act_entrance.connected_region @@ -369,8 +332,6 @@ def set_rules(world: "HatInTimeWorld"): rule = world.multiworld.get_location(name, world.player).access_rule access_rules.append(rule) - i += 1 - for e in entrances: for rules in access_rules: add_rule(e, rules) @@ -389,7 +350,7 @@ def set_rules(world: "HatInTimeWorld"): def set_specific_rules(world: "HatInTimeWorld"): add_rule(world.multiworld.get_location("Mafia Boss Shop Item", world.player), lambda state: state.has("Time Piece", world.player, 12) - and state.has("Time Piece", world.player, world.get_chapter_cost(ChapterIndex.BIRDS))) + and state.has("Time Piece", world.player, world.chapter_timepiece_costs[ChapterIndex.BIRDS])) add_rule(world.multiworld.get_location("Spaceship - Rumbi Abuse", world.player), lambda state: state.has("Time Piece", world.player, 4)) @@ -457,6 +418,11 @@ def set_moderate_rules(world: "HatInTimeWorld"): set_rule(world.multiworld.get_location("Alpine Skyline - Mystifying Time Mesa: Zipline", world.player), lambda state: can_use_hookshot(state, world)) + # Moderate: Goat Refinery from TIHS with Sprint only + add_rule(world.multiworld.get_location("Alpine Skyline - Goat Refinery", world.player), + lambda state: state.has("TIHS Access", world.player) + and can_use_hat(state, world, HatType.SPRINT), "or") + # 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)) @@ -530,6 +496,10 @@ def set_hard_rules(world: "HatInTimeWorld"): add_rule(world.multiworld.get_entrance("Telescope -> Time's End", world.player), lambda state: can_use_hat(state, world, HatType.ICE), "or") + # Hard: Goat Refinery from TIHS with nothing + add_rule(world.multiworld.get_location("Alpine Skyline - Goat Refinery", world.player), + lambda state: state.has("TIHS Access", world.player, "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), @@ -555,7 +525,7 @@ def set_hard_rules(world: "HatInTimeWorld"): def set_expert_rules(world: "HatInTimeWorld"): # 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))) + lambda state: state.has("Time Piece", world.player, world.chapter_timepiece_costs[ChapterIndex.FINALE])) # Expert: Mafia Town - Above Boats, Top of Lighthouse, and Hot Air Balloon with nothing set_rule(world.multiworld.get_location("Mafia Town - Above Boats", world.player), lambda state: True) @@ -753,6 +723,11 @@ def set_alps_rules(world: "HatInTimeWorld"): add_rule(world.multiworld.get_entrance("Alpine Skyline - Finale", world.player), lambda state: can_clear_alpine(state, world)) + add_rule(world.multiworld.get_location("Alpine Skyline - Goat Refinery", world.player), + lambda state: state.has("AFR Access", world.player) + and can_use_hookshot(state, world) + and can_hit(state, world, True)) + def set_dlc1_rules(world: "HatInTimeWorld"): add_rule(world.multiworld.get_entrance("Cruise Ship Entrance BV", world.player), @@ -810,11 +785,11 @@ def set_rift_rules(world: "HatInTimeWorld", regions: Dict[str, Region]): # 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, world, HatType.BREWING) - and state.has("Time Piece", world.player, world.get_chapter_cost(ChapterIndex.BIRDS))) + and state.has("Time Piece", world.player, world.chapter_timepiece_costs[ChapterIndex.BIRDS])) for entrance in regions["Time Rift - The Lab"].entrances: add_rule(entrance, lambda state: can_use_hat(state, world, HatType.DWELLER) - and state.has("Time Piece", world.player, world.get_chapter_cost(ChapterIndex.ALPINE))) + and state.has("Time Piece", world.player, world.chapter_timepiece_costs[ChapterIndex.ALPINE])) for entrance in regions["Time Rift - Sewers"].entrances: add_rule(entrance, lambda state: can_clear_act(state, world, "Mafia Town - Act 4")) @@ -895,11 +870,11 @@ def set_default_rift_rules(world: "HatInTimeWorld"): for entrance in world.multiworld.get_region("Time Rift - Gallery", world.player).entrances: add_rule(entrance, lambda state: can_use_hat(state, world, HatType.BREWING) - and state.has("Time Piece", world.player, world.get_chapter_cost(ChapterIndex.BIRDS))) + and state.has("Time Piece", world.player, world.chapter_timepiece_costs[ChapterIndex.BIRDS])) for entrance in world.multiworld.get_region("Time Rift - The Lab", world.player).entrances: add_rule(entrance, lambda state: can_use_hat(state, world, HatType.DWELLER) - and state.has("Time Piece", world.player, world.get_chapter_cost(ChapterIndex.ALPINE))) + and state.has("Time Piece", world.player, world.chapter_timepiece_costs[ChapterIndex.ALPINE])) for entrance in world.multiworld.get_region("Time Rift - Sewers", world.player).entrances: add_rule(entrance, lambda state: can_clear_act(state, world, "Mafia Town - Act 4")) @@ -970,9 +945,6 @@ def set_event_rules(world: "HatInTimeWorld"): if not is_location_valid(world, name): continue - if data.dlc_flags & HatDLC.death_wish and name in snatcher_coins.keys(): - name = f"{name} ({data.region})" - event: Location = world.multiworld.get_location(name, world.player) if data.act_event: diff --git a/worlds/ahit/Types.py b/worlds/ahit/Types.py index 418590a1dd..fb6185188f 100644 --- a/worlds/ahit/Types.py +++ b/worlds/ahit/Types.py @@ -69,6 +69,7 @@ class LocData(NamedTuple): # 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) + snatcher_coin: Optional[str] = "" # Only for Snatcher Coin event locations, name of the Snatcher Coin item class ItemData(NamedTuple): diff --git a/worlds/ahit/__init__.py b/worlds/ahit/__init__.py index f4e2837ed7..676b16b70c 100644 --- a/worlds/ahit/__init__.py +++ b/worlds/ahit/__init__.py @@ -1,4 +1,4 @@ -from BaseClasses import Item, ItemClassification, Tutorial, Location +from BaseClasses import Item, ItemClassification, Tutorial, Location, MultiWorld 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, TASKSANITY_START_ID, \ @@ -24,15 +24,6 @@ components.append(Component("A Hat in Time Client", "AHITClient", func=launch_cl icon_paths['yatta'] = local_path('data', 'yatta.png') -hat_craft_order: Dict[int, List[HatType]] = {} -hat_yarn_costs: Dict[int, Dict[HatType, int]] = {} -chapter_timepiece_costs: Dict[int, Dict[ChapterIndex, int]] = {} -excluded_dws: Dict[int, List[str]] = {} -excluded_bonuses: Dict[int, List[str]] = {} -dw_shuffle: Dict[int, List[str]] = {} -nyakuza_thug_items: Dict[int, Dict[str, int]] = {} -badge_seller_count: Dict[int, int] = {} - class AWebInTime(WebWorld): theme = "partyTime" @@ -60,11 +51,33 @@ class HatInTimeWorld(World): options_dataclass = AHITOptions options: AHITOptions - act_connections: Dict[str, str] = {} - shop_locs: List[str] = [] item_name_groups = relic_groups web = AWebInTime() + def __init__(self, multiworld: "MultiWorld", player: int): + super().__init__(multiworld, player) + self.act_connections: Dict[str, str] = {} + self.shop_locs: List[str] = [] + + self.hat_craft_order: List[HatType] = [HatType.SPRINT, HatType.BREWING, HatType.ICE, + HatType.DWELLER, HatType.TIME_STOP] + + self.hat_yarn_costs: Dict[HatType, int] = {HatType.SPRINT: -1, HatType.BREWING: -1, HatType.ICE: -1, + HatType.DWELLER: -1, HatType.TIME_STOP: -1} + + self.chapter_timepiece_costs: Dict[ChapterIndex, int] = {ChapterIndex.MAFIA: -1, + ChapterIndex.BIRDS: -1, + ChapterIndex.SUBCON: -1, + ChapterIndex.ALPINE: -1, + ChapterIndex.FINALE: -1, + ChapterIndex.CRUISE: -1, + ChapterIndex.METRO: -1} + self.excluded_dws: List[str] = [] + self.excluded_bonuses: List[str] = [] + self.dw_shuffle: List[str] = [] + self.nyakuza_thug_items: Dict[str, int] = {} + self.badge_seller_count: int = 0 + def generate_early(self): adjust_options(self) @@ -87,12 +100,6 @@ class HatInTimeWorld(World): self.multiworld.push_precollected(self.create_item("Progressive Painting Unlock")) def create_regions(self): - excluded_dws[self.player] = [] - excluded_bonuses[self.player] = [] - dw_shuffle[self.player] = [] - nyakuza_thug_items[self.player] = {} - badge_seller_count[self.player] = 0 - self.shop_locs = [] # noinspection PyClassVar self.topology_present = bool(self.options.ActRandomizer.value) @@ -105,8 +112,8 @@ class HatInTimeWorld(World): create_events(self) if self.is_dw(): - if "Snatcher's Hit List" not in self.get_excluded_dws() \ - or "Camera Tourist" not in self.get_excluded_dws(): + if "Snatcher's Hit List" not in self.excluded_dws \ + or "Camera Tourist" not in self.excluded_dws: create_enemy_events(self) # place vanilla contract locations if contract shuffle is off @@ -115,30 +122,15 @@ class HatInTimeWorld(World): self.multiworld.get_location(name, self.player).place_locked_item(create_item(self, name)) def create_items(self): - hat_yarn_costs[self.player] = {HatType.SPRINT: -1, HatType.BREWING: -1, HatType.ICE: -1, - HatType.DWELLER: -1, HatType.TIME_STOP: -1} - - hat_craft_order[self.player] = [HatType.SPRINT, HatType.BREWING, HatType.ICE, - HatType.DWELLER, HatType.TIME_STOP] - if self.options.HatItems.value == 0 and self.options.RandomizeHatOrder.value > 0: - self.random.shuffle(hat_craft_order[self.player]) + self.random.shuffle(self.hat_craft_order) if self.options.RandomizeHatOrder.value == 2: - hat_craft_order[self.player].remove(HatType.TIME_STOP) - hat_craft_order[self.player].append(HatType.TIME_STOP) + self.hat_craft_order.remove(HatType.TIME_STOP) + self.hat_craft_order.append(HatType.TIME_STOP) self.multiworld.itempool += create_itempool(self) def set_rules(self): - self.act_connections = {} - chapter_timepiece_costs[self.player] = {ChapterIndex.MAFIA: -1, - ChapterIndex.BIRDS: -1, - ChapterIndex.SUBCON: -1, - ChapterIndex.ALPINE: -1, - ChapterIndex.FINALE: -1, - ChapterIndex.CRUISE: -1, - ChapterIndex.METRO: -1} - if self.is_dw_only(): # we already have all items if this is the case, no need for rules self.multiworld.push_precollected(HatInTimeItem("Death Wish Only Mode", ItemClassification.progression, @@ -152,7 +144,7 @@ class HatInTimeWorld(World): if name == "Snatcher Coins in Nyakuza Metro" and not self.is_dlc2(): continue - if self.options.DWShuffle.value > 0 and name not in self.get_dw_shuffle(): + if self.options.DWShuffle.value > 0 and name not in self.dw_shuffle: continue full_clear = self.multiworld.get_location(f"{name} - All Clear", self.player) @@ -174,41 +166,41 @@ class HatInTimeWorld(World): return create_item(self, name) def fill_slot_data(self) -> dict: - slot_data: dict = {"Chapter1Cost": chapter_timepiece_costs[self.player][ChapterIndex.MAFIA], - "Chapter2Cost": chapter_timepiece_costs[self.player][ChapterIndex.BIRDS], - "Chapter3Cost": chapter_timepiece_costs[self.player][ChapterIndex.SUBCON], - "Chapter4Cost": chapter_timepiece_costs[self.player][ChapterIndex.ALPINE], - "Chapter5Cost": chapter_timepiece_costs[self.player][ChapterIndex.FINALE], - "Chapter6Cost": chapter_timepiece_costs[self.player][ChapterIndex.CRUISE], - "Chapter7Cost": chapter_timepiece_costs[self.player][ChapterIndex.METRO], - "BadgeSellerItemCount": badge_seller_count[self.player], + slot_data: dict = {"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], + "BadgeSellerItemCount": self.badge_seller_count, "SeedNumber": str(self.multiworld.seed), # For shop prices "SeedName": self.multiworld.seed_name, "TotalLocations": get_total_locations(self)} if self.options.HatItems.value == 0: - slot_data.setdefault("SprintYarnCost", hat_yarn_costs[self.player][HatType.SPRINT]) - slot_data.setdefault("BrewingYarnCost", hat_yarn_costs[self.player][HatType.BREWING]) - slot_data.setdefault("IceYarnCost", hat_yarn_costs[self.player][HatType.ICE]) - slot_data.setdefault("DwellerYarnCost", hat_yarn_costs[self.player][HatType.DWELLER]) - slot_data.setdefault("TimeStopYarnCost", hat_yarn_costs[self.player][HatType.TIME_STOP]) - slot_data.setdefault("Hat1", int(hat_craft_order[self.player][0])) - slot_data.setdefault("Hat2", int(hat_craft_order[self.player][1])) - slot_data.setdefault("Hat3", int(hat_craft_order[self.player][2])) - slot_data.setdefault("Hat4", int(hat_craft_order[self.player][3])) - slot_data.setdefault("Hat5", int(hat_craft_order[self.player][4])) + slot_data.setdefault("SprintYarnCost", self.hat_yarn_costs[HatType.SPRINT]) + slot_data.setdefault("BrewingYarnCost", self.hat_yarn_costs[HatType.BREWING]) + slot_data.setdefault("IceYarnCost", self.hat_yarn_costs[HatType.ICE]) + slot_data.setdefault("DwellerYarnCost", self.hat_yarn_costs[HatType.DWELLER]) + slot_data.setdefault("TimeStopYarnCost", self.hat_yarn_costs[HatType.TIME_STOP]) + slot_data.setdefault("Hat1", int(self.hat_craft_order[0])) + slot_data.setdefault("Hat2", int(self.hat_craft_order[1])) + slot_data.setdefault("Hat3", int(self.hat_craft_order[2])) + slot_data.setdefault("Hat4", int(self.hat_craft_order[3])) + slot_data.setdefault("Hat5", int(self.hat_craft_order[4])) if self.options.ActRandomizer.value > 0: for name in self.act_connections.keys(): slot_data[name] = self.act_connections[name] if self.is_dlc2() and not self.is_dw_only(): - for name in nyakuza_thug_items[self.player].keys(): - slot_data[name] = nyakuza_thug_items[self.player][name] + for name in self.nyakuza_thug_items.keys(): + slot_data[name] = self.nyakuza_thug_items[name] if self.is_dw(): i = 0 - for name in excluded_dws[self.player]: + for name in self.excluded_dws: if self.options.EndGoal.value == 3 and name == "Seal the Deal": continue @@ -217,15 +209,15 @@ class HatInTimeWorld(World): i = 0 if self.options.DWAutoCompleteBonuses.value == 0: - for name in excluded_bonuses[self.player]: - if name in excluded_dws[self.player]: + for name in self.excluded_bonuses: + if name in self.excluded_dws: continue slot_data[f"excluded_bonus{i}"] = dw_classes[name] i += 1 if self.options.DWShuffle.value > 0: - shuffled_dws = self.get_dw_shuffle() + shuffled_dws = self.dw_shuffle for i in range(len(shuffled_dws)): slot_data[f"dw_{i}"] = dw_classes[shuffled_dws[i]] @@ -281,26 +273,11 @@ class HatInTimeWorld(World): hint_data[self.player] = new_hint_data def write_spoiler_header(self, spoiler_handle: TextIO): - for i in self.get_chapter_costs(): - spoiler_handle.write("Chapter %i Cost: %i\n" % (i, self.get_chapter_costs()[ChapterIndex(i)])) + for i in self.chapter_timepiece_costs: + spoiler_handle.write("Chapter %i Cost: %i\n" % (i, self.chapter_timepiece_costs[ChapterIndex(i)])) - for hat in hat_craft_order[self.player]: - spoiler_handle.write("Hat Cost: %s: %i\n" % (hat, hat_yarn_costs[self.player][hat])) - - def set_chapter_cost(self, chapter: ChapterIndex, cost: int): - chapter_timepiece_costs[self.player][chapter] = cost - - def get_chapter_cost(self, chapter: ChapterIndex) -> int: - return chapter_timepiece_costs[self.player][chapter] - - def get_hat_craft_order(self): - return hat_craft_order[self.player] - - def get_hat_yarn_costs(self): - return hat_yarn_costs[self.player] - - def get_chapter_costs(self): - return chapter_timepiece_costs[self.player] + for hat in self.hat_craft_order: + spoiler_handle.write("Hat Cost: %s: %i\n" % (hat, self.hat_yarn_costs[hat])) def is_dlc1(self) -> bool: return self.options.EnableDLC1.value > 0 @@ -314,43 +291,19 @@ class HatInTimeWorld(World): def is_dw_only(self) -> bool: return self.is_dw() and self.options.DeathWishOnly.value > 0 - def get_excluded_dws(self): - return excluded_dws[self.player] - - def get_excluded_bonuses(self): - return excluded_bonuses[self.player] - def is_dw_excluded(self, name: str) -> bool: # don't exclude Seal the Deal if it's our goal if self.options.EndGoal.value == 3 and name == "Seal the Deal" \ and f"{name} - Main Objective" not in self.options.exclude_locations: return False - if name in excluded_dws[self.player]: + if name in self.excluded_dws: return True return f"{name} - Main Objective" in self.options.exclude_locations def is_bonus_excluded(self, name: str) -> bool: - if self.is_dw_excluded(name) or name in excluded_bonuses[self.player]: + if self.is_dw_excluded(name) or name in self.excluded_bonuses: return True return f"{name} - All Clear" in self.options.exclude_locations - - def get_dw_shuffle(self): - return dw_shuffle[self.player] - - def set_dw_shuffle(self, shuffle: List[str]): - dw_shuffle[self.player] = shuffle - - def get_badge_seller_count(self) -> int: - return badge_seller_count[self.player] - - def set_badge_seller_count(self, value: int): - badge_seller_count[self.player] = value - - def get_nyakuza_thug_items(self): - return nyakuza_thug_items[self.player] - - def set_nyakuza_thug_items(self, items: Dict[str, int]): - nyakuza_thug_items[self.player] = items