diff --git a/worlds/ahit/DeathWishLocations.py b/worlds/ahit/DeathWishLocations.py index f51d4948ee..f3e546f6c9 100644 --- a/worlds/ahit/DeathWishLocations.py +++ b/worlds/ahit/DeathWishLocations.py @@ -139,19 +139,19 @@ dw_classes = { def create_dw_regions(world: World): - if world.multiworld.DWExcludeAnnoyingContracts[world.player].value > 0: + if world.options.DWExcludeAnnoyingContracts.value > 0: for name in annoying_dws: world.get_excluded_dws().append(name) - if world.multiworld.DWEnableBonus[world.player].value == 0 \ - or world.multiworld.DWAutoCompleteBonuses[world.player].value > 0: + if world.options.DWEnableBonus.value == 0 \ + or world.options.DWAutoCompleteBonuses.value > 0: for name in death_wishes: world.get_excluded_bonuses().append(name) - elif world.multiworld.DWExcludeAnnoyingBonuses[world.player].value > 0: + elif world.options.DWExcludeAnnoyingBonuses.value > 0: for name in annoying_bonuses: world.get_excluded_bonuses().append(name) - if world.multiworld.DWExcludeCandles[world.player].value > 0: + if world.options.DWExcludeCandles.value > 0: for name in dw_candles: if name in world.get_excluded_dws(): continue @@ -162,9 +162,9 @@ def create_dw_regions(world: World): entrance = connect_regions(spaceship, dw_map, "-> Death Wish Map", world.player) add_rule(entrance, lambda state: state.has("Time Piece", world.player, - world.multiworld.DWTimePieceRequirement[world.player].value)) + world.options.DWTimePieceRequirement.value)) - if world.multiworld.DWShuffle[world.player].value > 0: + if world.options.DWShuffle.value > 0: dw_list: List[str] = [] for name in death_wishes.keys(): if not world.is_dlc2() and name == "Snatcher Coins in Nyakuza Metro" or world.is_dw_excluded(name): @@ -173,8 +173,8 @@ def create_dw_regions(world: World): dw_list.append(name) world.random.shuffle(dw_list) - count = world.random.randint(world.multiworld.DWShuffleCountMin[world.player].value, - world.multiworld.DWShuffleCountMax[world.player].value) + count = world.random.randint(world.options.DWShuffleCountMin.value, + world.options.DWShuffleCountMax.value) dw_shuffle: List[str] = [] total = min(len(dw_list), count) @@ -182,7 +182,7 @@ def create_dw_regions(world: World): dw_shuffle.append(dw_list[i]) # Seal the Deal is always last if it's the goal - if world.multiworld.EndGoal[world.player].value == 3: + if world.options.EndGoal.value == 3: if "Seal the Deal" in dw_shuffle: dw_shuffle.remove("Seal the Deal") diff --git a/worlds/ahit/DeathWishRules.py b/worlds/ahit/DeathWishRules.py index 5a97518499..648549cee0 100644 --- a/worlds/ahit/DeathWishRules.py +++ b/worlds/ahit/DeathWishRules.py @@ -105,7 +105,7 @@ def set_dw_rules(world: World): set_enemy_rules(world) dw_list: List[str] = [] - if world.multiworld.DWShuffle[world.player].value > 0: + if world.options.DWShuffle.value > 0: dw_list = world.get_dw_shuffle() else: for name in death_wishes.keys(): @@ -124,12 +124,12 @@ def set_dw_rules(world: World): temp_list.append(main_objective) temp_list.append(full_clear) - if world.multiworld.DWShuffle[world.player].value == 0: + if world.options.DWShuffle.value == 0: if name in dw_stamp_costs.keys(): for entrance in dw.entrances: add_rule(entrance, lambda state, n=name: get_total_dw_stamps(state, world) >= dw_stamp_costs[n]) - if world.multiworld.DWEnableBonus[world.player].value == 0: + if world.options.DWEnableBonus.value == 0: # place nothing, but let the locations exist still, so we can use them for bonus stamp rules full_clear.address = None full_clear.place_locked_item(HatInTimeItem("Nothing", ItemClassification.filler, None, world.player)) @@ -165,10 +165,10 @@ def set_dw_rules(world: World): for misc in data.misc_required: add_rule(loc, lambda state, item=misc: state.has(item, world.player)) - if data.umbrella and world.multiworld.UmbrellaLogic[world.player].value > 0: + if data.umbrella and world.options.UmbrellaLogic.value > 0: add_rule(loc, lambda state: state.has("Umbrella", world.player)) - if data.paintings > 0 and world.multiworld.ShuffleSubconPaintings[world.player].value > 0: + if data.paintings > 0 and world.options.ShuffleSubconPaintings.value > 0: add_rule(loc, lambda state, paintings=data.paintings: has_paintings(state, world, paintings)) if data.hit_requirement > 0: @@ -184,11 +184,11 @@ def set_dw_rules(world: World): elif loc.name == full_clear.name: add_rule(loc, main_rule) # Only set bonus stamp rules if we don't auto complete bonuses - if world.multiworld.DWAutoCompleteBonuses[world.player].value == 0 \ + if world.options.DWAutoCompleteBonuses.value == 0 \ and not world.is_bonus_excluded(loc.name): add_rule(bonus_stamps, loc.access_rule) - if world.multiworld.DWShuffle[world.player].value > 0: + if world.options.DWShuffle.value > 0: dw_shuffle = world.get_dw_shuffle() for i in range(len(dw_shuffle)): if i == 0: @@ -217,7 +217,7 @@ def set_dw_rules(world: World): for rule in access_rules: add_rule(entrance, rule) - if world.multiworld.EndGoal[world.player].value == 3: + if world.options.EndGoal.value == 3: world.multiworld.completion_condition[world.player] = lambda state: state.has("1 Stamp - Seal the Deal", world.player) @@ -269,7 +269,7 @@ def modify_dw_rules(world: World, name: str): def get_total_dw_stamps(state: CollectionState, world: World) -> int: - if world.multiworld.DWShuffle[world.player].value > 0: + if world.options.DWShuffle.value > 0: return 999 # no stamp costs in death wish shuffle count: int = 0 @@ -303,7 +303,7 @@ def set_candle_dw_rules(name: str, world: World): # No Ice Hat/painting required in Expert for Toilet Zero Jumps # This painting wall can only be skipped via cherry hover. - if get_difficulty(world) < Difficulty.EXPERT or world.multiworld.NoPaintingSkips[world.player].value == 1: + if get_difficulty(world) < Difficulty.EXPERT or world.options.NoPaintingSkips.value == 1: 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) and has_paintings(state, world, 1, False)) @@ -383,13 +383,13 @@ def create_enemy_events(world: World): continue if area == "Time Rift - Tour" and (not world.is_dlc1() - or world.multiworld.ExcludeTour[world.player].value > 0): + or world.options.ExcludeTour.value > 0): continue if area == "Bluefin Tunnel" and not world.is_dlc2(): continue - if world.multiworld.DWShuffle[world.player].value > 0 and area in death_wishes.keys() \ + if world.options.DWShuffle.value > 0 and area in death_wishes.keys() \ and area not in world.get_dw_shuffle(): continue @@ -400,14 +400,14 @@ def create_enemy_events(world: World): 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): + if name == "Time Rift - Tour" and (not world.is_dlc1() or world.options.ExcludeTour.value > 0): continue - if world.multiworld.DWShuffle[world.player].value > 0 and name in death_wishes.keys() \ + if world.options.DWShuffle.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) + region = world.options.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) @@ -428,13 +428,13 @@ 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.options.ExcludeTour.value > 0): continue 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.options.DWShuffle.value > 0 and area in death_wishes \ and area not in world.get_dw_shuffle(): continue diff --git a/worlds/ahit/Items.py b/worlds/ahit/Items.py index 869f998a9d..3a13b3e3c8 100644 --- a/worlds/ahit/Items.py +++ b/worlds/ahit/Items.py @@ -8,13 +8,13 @@ from typing import Optional, List, Dict def create_itempool(world: World) -> List[Item]: itempool: List[Item] = [] - if not world.is_dw_only() and world.multiworld.HatItems[world.player].value == 0: + if not world.is_dw_only() and world.options.HatItems.value == 0: calculate_yarn_costs(world) yarn_pool: List[Item] = create_multiple_items(world, "Yarn", - world.multiworld.YarnAvailable[world.player].value, + world.options.YarnAvailable.value, ItemClassification.progression_skip_balancing) - for i in range(int(len(yarn_pool) * (0.01 * world.multiworld.YarnBalancePercent[world.player].value))): + for i in range(int(len(yarn_pool) * (0.01 * world.options.YarnBalancePercent.value))): yarn_pool[i].classification = ItemClassification.progression itempool += yarn_pool @@ -26,7 +26,7 @@ def create_itempool(world: World) -> List[Item]: if not item_dlc_enabled(world, name): continue - if world.multiworld.HatItems[world.player].value == 0 and name in hat_type_to_item.values(): + if world.options.HatItems.value == 0 and name in hat_type_to_item.values(): continue item_type: ItemClassification = item_table.get(name).classification @@ -37,7 +37,7 @@ def create_itempool(world: World) -> List[Item]: continue else: if name == "Scooter Badge": - if world.multiworld.CTRLogic[world.player].value >= 1 or get_difficulty(world) >= Difficulty.MODERATE: + if world.options.CTRLogic.value >= 1 or get_difficulty(world) >= Difficulty.MODERATE: item_type = ItemClassification.progression elif name == "No Bonk Badge": if get_difficulty(world) >= Difficulty.MODERATE: @@ -50,17 +50,17 @@ def create_itempool(world: World) -> List[Item]: if item_type is ItemClassification.filler or item_type is ItemClassification.trap: continue - if name in act_contracts.keys() and world.multiworld.ShuffleActContracts[world.player].value == 0: + if name in act_contracts.keys() and world.options.ShuffleActContracts.value == 0: continue - if name in alps_hooks.keys() and world.multiworld.ShuffleAlpineZiplines[world.player].value == 0: + if name in alps_hooks.keys() and world.options.ShuffleAlpineZiplines.value == 0: continue if name == "Progressive Painting Unlock" \ - and world.multiworld.ShuffleSubconPaintings[world.player].value == 0: + and world.options.ShuffleSubconPaintings.value == 0: continue - if world.multiworld.StartWithCompassBadge[world.player].value > 0 and name == "Compass Badge": + if world.options.StartWithCompassBadge.value > 0 and name == "Compass Badge": continue if name == "Time Piece": @@ -72,10 +72,10 @@ def create_itempool(world: World) -> List[Item]: if world.is_dlc2(): max_extra += 10 - tp_count += min(max_extra, world.multiworld.MaxExtraTimePieces[world.player].value) + tp_count += min(max_extra, world.options.MaxExtraTimePieces.value) tp_list: List[Item] = create_multiple_items(world, name, tp_count, item_type) - for i in range(int(len(tp_list) * (0.01 * world.multiworld.TimePieceBalancePercent[world.player].value))): + for i in range(int(len(tp_list) * (0.01 * world.options.TimePieceBalancePercent.value))): tp_list[i].classification = ItemClassification.progression itempool += tp_list @@ -90,8 +90,8 @@ def create_itempool(world: World) -> List[Item]: def calculate_yarn_costs(world: World): mw = world.multiworld p = world.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)) + min_yarn_cost = int(min(world.options.YarnCostMin.value, world.options.YarnCostMax.value)) + max_yarn_cost = int(max(world.options.YarnCostMin.value, world.options.YarnCostMax.value)) max_cost: int = 0 for i in range(5): @@ -99,13 +99,13 @@ def calculate_yarn_costs(world: World): world.get_hat_yarn_costs()[HatType(i)] = cost max_cost += cost - available_yarn: int = mw.YarnAvailable[p].value + available_yarn: int = world.options.YarnAvailable.value if max_cost > available_yarn: - mw.YarnAvailable[p].value = max_cost + world.options.YarnAvailable.value = max_cost available_yarn = max_cost - if max_cost + mw.MinExtraYarn[p].value > available_yarn: - mw.YarnAvailable[p].value += (max_cost + mw.MinExtraYarn[p].value) - available_yarn + if max_cost + world.options.MinExtraYarn.value > available_yarn: + world.options.YarnAvailable.value += (max_cost + world.options.MinExtraYarn.value) - available_yarn def item_dlc_enabled(world: World, name: str) -> bool: @@ -141,7 +141,7 @@ def create_multiple_items(world: World, name: str, count: int = 1, def create_junk_items(world: World, count: int) -> List[Item]: - trap_chance = world.multiworld.TrapChance[world.player].value + trap_chance = world.options.TrapChance.value junk_pool: List[Item] = [] junk_list: Dict[str, int] = {} trap_list: Dict[str, int] = {} @@ -157,11 +157,11 @@ def create_junk_items(world: World, count: int) -> List[Item]: elif trap_chance > 0 and ic == ItemClassification.trap: if name == "Baby Trap": - trap_list[name] = world.multiworld.BabyTrapWeight[world.player].value + trap_list[name] = world.options.BabyTrapWeight.value elif name == "Laser Trap": - trap_list[name] = world.multiworld.LaserTrapWeight[world.player].value + trap_list[name] = world.options.LaserTrapWeight.value elif name == "Parade Trap": - trap_list[name] = world.multiworld.ParadeTrapWeight[world.player].value + trap_list[name] = world.options.ParadeTrapWeight.value for i in range(count): if trap_chance > 0 and world.random.randint(1, 100) <= trap_chance: diff --git a/worlds/ahit/Locations.py b/worlds/ahit/Locations.py index 00ec578624..2bc1c27080 100644 --- a/worlds/ahit/Locations.py +++ b/worlds/ahit/Locations.py @@ -12,20 +12,20 @@ def get_total_locations(world: World) -> int: if is_location_valid(world, name): total += 1 - if world.is_dlc1() and world.multiworld.Tasksanity[world.player].value > 0: - total += world.multiworld.TasksanityCheckCount[world.player].value + if world.is_dlc1() and world.options.Tasksanity.value > 0: + total += world.options.TasksanityCheckCount.value if world.is_dw(): - if world.multiworld.DWShuffle[world.player].value > 0: + if world.options.DWShuffle.value > 0: total += len(world.get_dw_shuffle()) - if world.multiworld.DWEnableBonus[world.player].value > 0: + if world.options.DWEnableBonus.value > 0: total += len(world.get_dw_shuffle()) else: total += 37 if world.is_dlc2(): total += 1 - if world.multiworld.DWEnableBonus[world.player].value > 0: + if world.options.DWEnableBonus.value > 0: total += 37 if world.is_dlc2(): total += 1 @@ -56,11 +56,11 @@ def is_location_valid(world: World, location: str) -> bool: if not location_dlc_enabled(world, location): return False - if world.multiworld.ShuffleStorybookPages[world.player].value == 0 \ + if world.options.ShuffleStorybookPages.value == 0 \ and location in storybook_pages.keys(): return False - if world.multiworld.ShuffleActContracts[world.player].value == 0 \ + if world.options.ShuffleActContracts.value == 0 \ and location in contract_locations.keys(): return False @@ -68,23 +68,23 @@ def is_location_valid(world: World, location: str) -> bool: return False data = location_table.get(location) or event_locs.get(location) - if world.multiworld.ExcludeTour[world.player].value > 0 and data.region == "Time Rift - Tour": + if world.options.ExcludeTour.value > 0 and data.region == "Time Rift - Tour": return False # No need for all those event items if we're not doing candles if data.dlc_flags & HatDLC.death_wish: - if world.multiworld.DWExcludeCandles[world.player].value > 0 and location in event_locs.keys(): + if world.options.DWExcludeCandles.value > 0 and location in event_locs.keys(): return False - if world.multiworld.DWShuffle[world.player].value > 0 \ + if world.options.DWShuffle.value > 0 \ and data.region in death_wishes and data.region not in world.get_dw_shuffle(): return False if location in zero_jumps: - if world.multiworld.DWShuffle[world.player].value > 0 and "Zero Jumps" not in world.get_dw_shuffle(): + if world.options.DWShuffle.value > 0 and "Zero Jumps" not in world.get_dw_shuffle(): return False - difficulty: int = world.multiworld.LogicDifficulty[world.player].value + difficulty: int = world.options.LogicDifficulty.value if location in zero_jumps_hard and difficulty < int(Difficulty.HARD): return False diff --git a/worlds/ahit/Options.py b/worlds/ahit/Options.py index 863f940f0a..67bc5b56e6 100644 --- a/worlds/ahit/Options.py +++ b/worlds/ahit/Options.py @@ -1,6 +1,7 @@ -import typing -from worlds.AutoWorld import World -from Options import Option, Range, Toggle, DeathLink, Choice, OptionDict +from typing import List +from dataclasses import dataclass +from worlds.AutoWorld import World, PerGameCommonOptions +from Options import Range, Toggle, DeathLink, Choice, OptionDict def adjust_options(world: World): @@ -594,119 +595,118 @@ class ParadeTrapWeight(Range): default = 20 -ahit_options: typing.Dict[str, type(Option)] = { +@dataclass +class AHITOptions(PerGameCommonOptions): + EndGoal: EndGoal + ActRandomizer: ActRandomizer + ActPlando: ActPlando + ShuffleAlpineZiplines: ShuffleAlpineZiplines + FinaleShuffle: FinaleShuffle + LogicDifficulty: LogicDifficulty + YarnBalancePercent: YarnBalancePercent + TimePieceBalancePercent: TimePieceBalancePercent + RandomizeHatOrder: RandomizeHatOrder + UmbrellaLogic: UmbrellaLogic + StartWithCompassBadge: StartWithCompassBadge + CompassBadgeMode: CompassBadgeMode + ShuffleStorybookPages: ShuffleStorybookPages + ShuffleActContracts: ShuffleActContracts + ShuffleSubconPaintings: ShuffleSubconPaintings + NoPaintingSkips: NoPaintingSkips + StartingChapter: StartingChapter + CTRLogic: CTRLogic - "EndGoal": EndGoal, - "ActRandomizer": ActRandomizer, - "ActPlando": ActPlando, - "ShuffleAlpineZiplines": ShuffleAlpineZiplines, - "FinaleShuffle": FinaleShuffle, - "LogicDifficulty": LogicDifficulty, - "YarnBalancePercent": YarnBalancePercent, - "TimePieceBalancePercent": TimePieceBalancePercent, - "RandomizeHatOrder": RandomizeHatOrder, - "UmbrellaLogic": UmbrellaLogic, - "StartWithCompassBadge": StartWithCompassBadge, - "CompassBadgeMode": CompassBadgeMode, - "ShuffleStorybookPages": ShuffleStorybookPages, - "ShuffleActContracts": ShuffleActContracts, - "ShuffleSubconPaintings": ShuffleSubconPaintings, - "NoPaintingSkips": NoPaintingSkips, - "StartingChapter": StartingChapter, - "CTRLogic": CTRLogic, + EnableDLC1: EnableDLC1 + Tasksanity: Tasksanity + TasksanityTaskStep: TasksanityTaskStep + TasksanityCheckCount: TasksanityCheckCount + ExcludeTour: ExcludeTour + ShipShapeCustomTaskGoal: ShipShapeCustomTaskGoal - "EnableDLC1": EnableDLC1, - "Tasksanity": Tasksanity, - "TasksanityTaskStep": TasksanityTaskStep, - "TasksanityCheckCount": TasksanityCheckCount, - "ExcludeTour": ExcludeTour, - "ShipShapeCustomTaskGoal": ShipShapeCustomTaskGoal, + EnableDeathWish: EnableDeathWish + DWShuffle: DWShuffle + DWShuffleCountMin: DWShuffleCountMin + DWShuffleCountMax: DWShuffleCountMax + DeathWishOnly: DeathWishOnly + DWEnableBonus: DWEnableBonus + DWAutoCompleteBonuses: DWAutoCompleteBonuses + DWExcludeAnnoyingContracts: DWExcludeAnnoyingContracts + DWExcludeAnnoyingBonuses: DWExcludeAnnoyingBonuses + DWExcludeCandles: DWExcludeCandles + DWTimePieceRequirement: DWTimePieceRequirement - "EnableDeathWish": EnableDeathWish, - "DWShuffle": DWShuffle, - "DWShuffleCountMin": DWShuffleCountMin, - "DWShuffleCountMax": DWShuffleCountMax, - "DeathWishOnly": DeathWishOnly, - "DWEnableBonus": DWEnableBonus, - "DWAutoCompleteBonuses": DWAutoCompleteBonuses, - "DWExcludeAnnoyingContracts": DWExcludeAnnoyingContracts, - "DWExcludeAnnoyingBonuses": DWExcludeAnnoyingBonuses, - "DWExcludeCandles": DWExcludeCandles, - "DWTimePieceRequirement": DWTimePieceRequirement, + EnableDLC2: EnableDLC2 + BaseballBat: BaseballBat + MetroMinPonCost: MetroMinPonCost + MetroMaxPonCost: MetroMaxPonCost + NyakuzaThugMinShopItems: NyakuzaThugMinShopItems + NyakuzaThugMaxShopItems: NyakuzaThugMaxShopItems - "EnableDLC2": EnableDLC2, - "BaseballBat": BaseballBat, - "MetroMinPonCost": MetroMinPonCost, - "MetroMaxPonCost": MetroMaxPonCost, - "NyakuzaThugMinShopItems": NyakuzaThugMinShopItems, - "NyakuzaThugMaxShopItems": NyakuzaThugMaxShopItems, + LowestChapterCost: LowestChapterCost + HighestChapterCost: HighestChapterCost + ChapterCostIncrement: ChapterCostIncrement + ChapterCostMinDifference: ChapterCostMinDifference + MaxExtraTimePieces: MaxExtraTimePieces - "LowestChapterCost": LowestChapterCost, - "HighestChapterCost": HighestChapterCost, - "ChapterCostIncrement": ChapterCostIncrement, - "ChapterCostMinDifference": ChapterCostMinDifference, - "MaxExtraTimePieces": MaxExtraTimePieces, + FinalChapterMinCost: FinalChapterMinCost + FinalChapterMaxCost: FinalChapterMaxCost - "FinalChapterMinCost": FinalChapterMinCost, - "FinalChapterMaxCost": FinalChapterMaxCost, + YarnCostMin: YarnCostMin + YarnCostMax: YarnCostMax + YarnAvailable: YarnAvailable + MinExtraYarn: MinExtraYarn + HatItems: HatItems - "YarnCostMin": YarnCostMin, - "YarnCostMax": YarnCostMax, - "YarnAvailable": YarnAvailable, - "MinExtraYarn": MinExtraYarn, - "HatItems": HatItems, + MinPonCost: MinPonCost + MaxPonCost: MaxPonCost + BadgeSellerMinItems: BadgeSellerMinItems + BadgeSellerMaxItems: BadgeSellerMaxItems - "MinPonCost": MinPonCost, - "MaxPonCost": MaxPonCost, - "BadgeSellerMinItems": BadgeSellerMinItems, - "BadgeSellerMaxItems": BadgeSellerMaxItems, + TrapChance: TrapChance + BabyTrapWeight: BabyTrapWeight + LaserTrapWeight: LaserTrapWeight + ParadeTrapWeight: ParadeTrapWeight - "TrapChance": TrapChance, - "BabyTrapWeight": BabyTrapWeight, - "LaserTrapWeight": LaserTrapWeight, - "ParadeTrapWeight": ParadeTrapWeight, + death_link: DeathLink - "death_link": DeathLink, -} -slot_data_options: typing.Dict[str, type(Option)] = { +slot_data_options: List[str] = [ + "EndGoal", + "ActRandomizer", + "ShuffleAlpineZiplines", + "LogicDifficulty", + "CTRLogic", + "RandomizeHatOrder", + "UmbrellaLogic", + "StartWithCompassBadge", + "CompassBadgeMode", + "ShuffleStorybookPages", + "ShuffleActContracts", + "ShuffleSubconPaintings", + "NoPaintingSkips", + "HatItems", - "EndGoal": EndGoal, - "ActRandomizer": ActRandomizer, - "ShuffleAlpineZiplines": ShuffleAlpineZiplines, - "LogicDifficulty": LogicDifficulty, - "CTRLogic": CTRLogic, - "RandomizeHatOrder": RandomizeHatOrder, - "UmbrellaLogic": UmbrellaLogic, - "StartWithCompassBadge": StartWithCompassBadge, - "CompassBadgeMode": CompassBadgeMode, - "ShuffleStorybookPages": ShuffleStorybookPages, - "ShuffleActContracts": ShuffleActContracts, - "ShuffleSubconPaintings": ShuffleSubconPaintings, - "NoPaintingSkips": NoPaintingSkips, - "HatItems": HatItems, + "EnableDLC1", + "Tasksanity", + "TasksanityTaskStep", + "TasksanityCheckCount", + "ShipShapeCustomTaskGoal", + "ExcludeTour", - "EnableDLC1": EnableDLC1, - "Tasksanity": Tasksanity, - "TasksanityTaskStep": TasksanityTaskStep, - "TasksanityCheckCount": TasksanityCheckCount, - "ShipShapeCustomTaskGoal": ShipShapeCustomTaskGoal, - "ExcludeTour": ExcludeTour, + "EnableDeathWish", + "DWShuffle", + "DeathWishOnly", + "DWEnableBonus", + "DWAutoCompleteBonuses", + "DWTimePieceRequirement", - "EnableDeathWish": EnableDeathWish, - "DWShuffle": DWShuffle, - "DeathWishOnly": DeathWishOnly, - "DWEnableBonus": DWEnableBonus, - "DWAutoCompleteBonuses": DWAutoCompleteBonuses, - "DWTimePieceRequirement": DWTimePieceRequirement, + "EnableDLC2", + "MetroMinPonCost", + "MetroMaxPonCost", + "BaseballBat", - "EnableDLC2": EnableDLC2, - "MetroMinPonCost": MetroMinPonCost, - "MetroMaxPonCost": MetroMaxPonCost, - "BaseballBat": BaseballBat, + "MinPonCost", + "MaxPonCost", - "MinPonCost": MinPonCost, - "MaxPonCost": MaxPonCost, - - "death_link": DeathLink, -} + "death_link", +] diff --git a/worlds/ahit/Regions.py b/worlds/ahit/Regions.py index 59186d68ff..70f7ede3b7 100644 --- a/worlds/ahit/Regions.py +++ b/worlds/ahit/Regions.py @@ -270,7 +270,6 @@ blacklisted_combos = { def create_regions(world: World): w = world - mw = world.multiworld p = world.player # ------------------------------------------- HUB -------------------------------------------------- # @@ -311,7 +310,7 @@ def create_regions(world: World): ev_area = create_region_and_connect(w, "Dead Bird Studio - Elevator Area", "DBS -> Elevator Area", dbs) post_ev_area = create_region_and_connect(w, "Dead Bird Studio - Post Elevator Area", "DBS -> Post Elevator Area", dbs) connect_regions(basement, ev_area, "DBS Basement -> Elevator Area", p) - if world.multiworld.LogicDifficulty[world.player].value >= int(Difficulty.EXPERT): + if world.options.LogicDifficulty.value >= int(Difficulty.EXPERT): connect_regions(basement, post_ev_area, "DBS Basement -> Post Elevator Area", p) # ------------------------------------------- SUBCON FOREST --------------------------------------- # @@ -397,10 +396,10 @@ def create_regions(world: World): create_rift_connections(w, create_region(w, "Time Rift - Balcony")) create_rift_connections(w, create_region(w, "Time Rift - Deep Sea")) - if mw.ExcludeTour[world.player].value == 0: + if w.options.ExcludeTour.value == 0: create_rift_connections(w, create_region(w, "Time Rift - Tour")) - if mw.Tasksanity[p].value > 0: + if w.options.Tasksanity.value > 0: create_tasksanity_locations(w) connect_regions(cruise_ship, badge_seller, "CS -> Badge Seller", p) @@ -440,7 +439,7 @@ def create_rift_connections(world: World, region: Region): def create_tasksanity_locations(world: World): ship_shape: Region = world.multiworld.get_region("Ship Shape", world.player) id_start: int = get_tasksanity_start_id() - for i in range(world.multiworld.TasksanityCheckCount[world.player].value): + for i in range(world.options.TasksanityCheckCount.value): location = HatInTimeLocation(world.player, f"Tasksanity Check {i+1}", id_start+i, ship_shape) ship_shape.locations.append(location) @@ -449,10 +448,10 @@ def is_valid_plando(world: World, region: str) -> bool: if region in blacklisted_acts.values(): return False - if region not in world.multiworld.ActPlando[world.player].keys(): + if region not in world.options.ActPlando.keys(): return False - act = world.multiworld.ActPlando[world.player].get(region) + act = world.options.ActPlando.get(region) if act in blacklisted_acts.values(): return False @@ -461,10 +460,10 @@ def is_valid_plando(world: World, region: str) -> bool: and region in act_entrances.keys() and ("Act 1" in act_entrances[region] or "Free Roam" in act_entrances[region]) if is_first_act: - if act_chapters[act] == "Subcon Forest" and world.multiworld.ShuffleSubconPaintings[world.player].value > 0: + if act_chapters[act] == "Subcon Forest" and world.options.ShuffleSubconPaintings.value > 0: return False - if world.multiworld.UmbrellaLogic[world.player].value > 0 \ + if world.options.UmbrellaLogic.value > 0 \ and (act == "Heating Up Mafia Town" or act == "Queen Vanessa's Manor"): return False @@ -484,7 +483,7 @@ def is_valid_plando(world: World, region: str) -> bool: if region == "Time Rift - The Owl Express" and act == "Murder on the Owl Express": return False - return any(a.name == world.multiworld.ActPlando[world.player].get(region) for a in + return any(a.name == world.options.ActPlando.get(region) for a in world.multiworld.get_regions(world.player)) @@ -492,7 +491,7 @@ def randomize_act_entrances(world: World): region_list: typing.List[Region] = get_act_regions(world) world.random.shuffle(region_list) - separate_rifts: bool = bool(world.multiworld.ActRandomizer[world.player].value == 1) + separate_rifts: bool = bool(world.options.ActRandomizer.value == 1) for region in region_list.copy(): if (act_chapters[region.name] == "Alpine Skyline" or act_chapters[region.name] == "Nyakuza Metro") \ @@ -511,14 +510,14 @@ def randomize_act_entrances(world: World): region_list.append(region) for region in region_list.copy(): - if region.name in world.multiworld.ActPlando[world.player].keys(): + if region.name in world.options.ActPlando.keys(): if is_valid_plando(world, region.name): region_list.remove(region) region_list.append(region) else: print("Disallowing act plando for", world.multiworld.player_name[world.player], - "-", region.name, ":", world.multiworld.ActPlando[world.player].get(region.name)) + "-", region.name, ":", world.options.ActPlando.get(region.name)) # Reverse the list, so we can do what we want to do first region_list.reverse() @@ -543,7 +542,7 @@ def randomize_act_entrances(world: World): and "Free Roam" not in act_entrances[region.name]: continue - if region.name in world.multiworld.ActPlando[world.player].keys() and is_valid_plando(world, region.name): + if region.name in world.options.ActPlando.keys() and is_valid_plando(world, region.name): has_guaranteed = True i = 0 @@ -562,16 +561,16 @@ def randomize_act_entrances(world: World): if candidate.name not in guaranteed_first_acts: continue - if candidate.name in world.multiworld.ActPlando[world.player].values(): + if candidate.name in world.options.ActPlando.values(): continue # Not completable without Umbrella - if world.multiworld.UmbrellaLogic[world.player].value > 0 \ + if world.options.UmbrellaLogic.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 \ + if world.options.ShuffleSubconPaintings.value > 0 \ and "Subcon Forest" in act_entrances[candidate.name]: continue @@ -579,10 +578,10 @@ def randomize_act_entrances(world: World): has_guaranteed = True break - if region.name in world.multiworld.ActPlando[world.player].keys() and is_valid_plando(world, region.name): + if region.name in world.options.ActPlando.keys() and is_valid_plando(world, region.name): candidate_list.clear() candidate_list.append( - world.multiworld.get_region(world.multiworld.ActPlando[world.player].get(region.name), world.player)) + world.multiworld.get_region(world.options.ActPlando.get(region.name), world.player)) break # Already mapped onto something else @@ -607,12 +606,12 @@ def randomize_act_entrances(world: World): continue # Prevent Contractual Obligations from being inaccessible if contracts are not shuffled - if world.multiworld.ShuffleActContracts[world.player].value == 0: + if world.options.ShuffleActContracts.value == 0: if (region.name == "Your Contract has Expired" or region.name == "The Subcon Well") \ and candidate.name == "Contractual Obligations": continue - if world.multiworld.FinaleShuffle[world.player].value > 0 and region.name in chapter_finales: + if world.options.FinaleShuffle.value > 0 and region.name in chapter_finales: if candidate.name not in chapter_finales: continue @@ -687,17 +686,17 @@ def get_act_regions(world: World) -> typing.List[Region]: def is_act_blacklisted(world: World, name: str) -> bool: - plando: bool = name in world.multiworld.ActPlando[world.player].keys() \ - or name in world.multiworld.ActPlando[world.player].values() + plando: bool = name in world.options.ActPlando.keys() \ + or name in world.options.ActPlando.values() if name == "The Finale": - return not plando and world.multiworld.EndGoal[world.player].value == 1 + return not plando and world.options.EndGoal.value == 1 if name == "Rush Hour": - return not plando and world.multiworld.EndGoal[world.player].value == 2 + return not plando and world.options.EndGoal.value == 2 if name == "Time Rift - Tour": - return world.multiworld.ExcludeTour[world.player].value > 0 + return world.options.ExcludeTour.value > 0 return name in blacklisted_acts.values() @@ -714,7 +713,7 @@ def create_region(world: World, name: str) -> Region: if data.region == name: if key in storybook_pages.keys() \ - and world.multiworld.ShuffleStorybookPages[world.player].value == 0: + and world.options.ShuffleStorybookPages.value == 0: continue location = HatInTimeLocation(world.player, key, data.id, reg) @@ -732,9 +731,9 @@ def create_badge_seller(world: World) -> Region: count: int = 0 max_items: int = 0 - if world.multiworld.BadgeSellerMaxItems[world.player].value > 0: - max_items = world.random.randint(world.multiworld.BadgeSellerMinItems[world.player].value, - world.multiworld.BadgeSellerMaxItems[world.player].value) + if world.options.BadgeSellerMaxItems.value > 0: + max_items = world.random.randint(world.options.BadgeSellerMinItems.value, + world.options.BadgeSellerMaxItems.value) if max_items <= 0: world.set_badge_seller_count(0) @@ -801,7 +800,7 @@ def create_region_and_connect(world: World, def get_first_chapter_region(world: World) -> Region: - start_chapter: ChapterIndex = world.multiworld.StartingChapter[world.player] + start_chapter: ChapterIndex = world.options.StartingChapter.value return world.multiworld.get_region(chapter_regions.get(start_chapter), world.player) @@ -826,11 +825,11 @@ def get_shuffled_region(self, region: str) -> str: def create_thug_shops(world: World): - min_items: int = min(world.multiworld.NyakuzaThugMinShopItems[world.player].value, - world.multiworld.NyakuzaThugMaxShopItems[world.player].value) + min_items: int = min(world.options.NyakuzaThugMinShopItems.value, + world.options.NyakuzaThugMaxShopItems.value) - max_items: int = max(world.multiworld.NyakuzaThugMaxShopItems[world.player].value, - world.multiworld.NyakuzaThugMinShopItems[world.player].value) + max_items: int = max(world.options.NyakuzaThugMaxShopItems.value, + world.options.NyakuzaThugMinShopItems.value) count: int = -1 step: int = 0 old_name: str = "" diff --git a/worlds/ahit/Rules.py b/worlds/ahit/Rules.py index 7eb09bedfc..f971526482 100644 --- a/worlds/ahit/Rules.py +++ b/worlds/ahit/Rules.py @@ -32,7 +32,7 @@ act_connections = { def can_use_hat(state: CollectionState, world: World, hat: HatType) -> bool: - if world.multiworld.HatItems[world.player].value > 0: + if world.options.HatItems.value > 0: return state.has(hat_type_to_item[hat], world.player) return state.count("Yarn", world.player) >= get_hat_cost(world, hat) @@ -54,19 +54,19 @@ def can_sdj(state: CollectionState, world: World): def painting_logic(world: World) -> bool: - return world.multiworld.ShuffleSubconPaintings[world.player].value > 0 + return world.options.ShuffleSubconPaintings.value > 0 # -1 = Normal, 0 = Moderate, 1 = Hard, 2 = Expert def get_difficulty(world: World) -> Difficulty: - return Difficulty(world.multiworld.LogicDifficulty[world.player].value) + return Difficulty(world.options.LogicDifficulty.value) def has_paintings(state: CollectionState, world: World, count: int, allow_skip: bool = True) -> bool: if not painting_logic(world): return True - if world.multiworld.NoPaintingSkips[world.player].value == 0 and allow_skip: + if world.options.NoPaintingSkips.value == 0 and allow_skip: # In Moderate there is a very easy trick to skip all the walls, except for the one guarding the boss arena if get_difficulty(world) >= Difficulty.MODERATE: return True @@ -75,7 +75,7 @@ def has_paintings(state: CollectionState, world: World, count: int, allow_skip: def zipline_logic(world: World) -> bool: - return world.multiworld.ShuffleAlpineZiplines[world.player].value > 0 + return world.options.ShuffleAlpineZiplines.value > 0 def can_use_hookshot(state: CollectionState, world: World): @@ -83,7 +83,7 @@ def can_use_hookshot(state: CollectionState, world: World): def can_hit(state: CollectionState, world: World, umbrella_only: bool = False): - if world.multiworld.UmbrellaLogic[world.player].value == 0: + if world.options.UmbrellaLogic.value == 0: return True return state.has("Umbrella", world.player) or not umbrella_only and can_use_hat(state, world, HatType.BREWING) @@ -132,7 +132,7 @@ def can_clear_metro(state: CollectionState, world: World) -> bool: def set_rules(world: World): # First, chapter access - starting_chapter = ChapterIndex(world.multiworld.StartingChapter[world.player].value) + starting_chapter = ChapterIndex(world.options.StartingChapter.value) world.set_chapter_cost(starting_chapter, 0) # Chapter costs increase progressively. Randomly decide the chapter order, except for Finale @@ -140,10 +140,10 @@ def set_rules(world: World): ChapterIndex.SUBCON, ChapterIndex.ALPINE] final_chapter = ChapterIndex.FINALE - if world.multiworld.EndGoal[world.player].value == 2: + if world.options.EndGoal.value == 2: final_chapter = ChapterIndex.METRO chapter_list.append(ChapterIndex.FINALE) - elif world.multiworld.EndGoal[world.player].value == 3: + elif world.options.EndGoal.value == 3: final_chapter = None chapter_list.append(ChapterIndex.FINALE) @@ -185,11 +185,11 @@ def set_rules(world: World): else: chapter_list.insert(world.random.randint(index+1, len(chapter_list)), ChapterIndex.METRO) - lowest_cost: int = world.multiworld.LowestChapterCost[world.player].value - highest_cost: int = world.multiworld.HighestChapterCost[world.player].value + lowest_cost: int = world.options.LowestChapterCost.value + highest_cost: int = world.options.HighestChapterCost.value - cost_increment: int = world.multiworld.ChapterCostIncrement[world.player].value - min_difference: int = world.multiworld.ChapterCostMinDifference[world.player].value + cost_increment: int = world.options.ChapterCostIncrement.value + min_difference: int = world.options.ChapterCostMinDifference.value last_cost: int = 0 cost: int loop_count: int = 0 @@ -213,8 +213,8 @@ def set_rules(world: World): if final_chapter is not None: world.set_chapter_cost(final_chapter, world.random.randint( - world.multiworld.FinalChapterMinCost[world.player].value, - world.multiworld.FinalChapterMaxCost[world.player].value)) + world.options.FinalChapterMinCost.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))) @@ -243,7 +243,7 @@ def set_rules(world: World): and state.has("Time Piece", world.player, world.get_chapter_cost(ChapterIndex.METRO)) and can_use_hat(state, world, HatType.DWELLER) and can_use_hat(state, world, HatType.ICE)) - if world.multiworld.ActRandomizer[world.player].value == 0: + if world.options.ActRandomizer.value == 0: set_default_rift_rules(world) table = location_table | event_locs @@ -267,10 +267,10 @@ def set_rules(world: World): if data.hookshot: add_rule(location, lambda state: can_use_hookshot(state, world)) - if data.umbrella and world.multiworld.UmbrellaLogic[world.player].value > 0: + if data.umbrella and world.options.UmbrellaLogic.value > 0: add_rule(location, lambda state: state.has("Umbrella", world.player)) - if data.paintings > 0 and world.multiworld.ShuffleSubconPaintings[world.player].value > 0: + if data.paintings > 0 and world.options.ShuffleSubconPaintings.value > 0: add_rule(location, lambda state, paintings=data.paintings: has_paintings(state, world, paintings)) if data.hit_requirement > 0: @@ -288,7 +288,7 @@ def set_rules(world: World): # Illness starts the player past the intro alpine_entrance = world.multiworld.get_entrance("AFR -> Alpine Skyline Area", world.player) add_rule(alpine_entrance, lambda state: can_use_hookshot(state, world)) - if world.multiworld.UmbrellaLogic[world.player].value > 0: + if world.options.UmbrellaLogic.value > 0: add_rule(alpine_entrance, lambda state: state.has("Umbrella", world.player)) if zipline_logic(world): @@ -356,9 +356,9 @@ def set_rules(world: World): set_event_rules(world) - if world.multiworld.EndGoal[world.player].value == 1: + if world.options.EndGoal.value == 1: world.multiworld.completion_condition[world.player] = lambda state: state.has("Time Piece Cluster", world.player) - elif world.multiworld.EndGoal[world.player].value == 2: + elif world.options.EndGoal.value == 2: world.multiworld.completion_condition[world.player] = lambda state: state.has("Rush Hour Cleared", world.player) @@ -551,7 +551,7 @@ def set_expert_rules(world: World): world.multiworld.get_region("Subcon Forest Area", world.player), "Subcon Forest Entrance YCHE", world.player) - if world.multiworld.NoPaintingSkips[world.player].value > 0: + if world.options.NoPaintingSkips.value > 0: add_rule(entrance, lambda state: has_paintings(state, world, 1)) set_rule(world.multiworld.get_location("Act Completion (Toilet of Doom)", world.player), @@ -630,7 +630,7 @@ def set_mafia_town_rules(world: World): add_rule(world.multiworld.get_location("Mafia Town - Above Boats", world.player), lambda state: state.has("HUMT Access", world.player), "or") - ctr_logic: int = world.multiworld.CTRLogic[world.player].value + ctr_logic: int = world.options.CTRLogic.value if ctr_logic == 3: set_rule(world.multiworld.get_location("Act Completion (Cheating the Race)", world.player), lambda state: True) elif ctr_logic == 2: @@ -643,7 +643,7 @@ def set_mafia_town_rules(world: World): def set_botb_rules(world: World): - if world.multiworld.UmbrellaLogic[world.player].value == 0 and get_difficulty(world) < Difficulty.MODERATE: + if world.options.UmbrellaLogic.value == 0 and get_difficulty(world) < Difficulty.MODERATE: set_rule(world.multiworld.get_location("Dead Bird Studio - DJ Grooves Sign Chest", world.player), lambda state: state.has("Umbrella", world.player) or can_use_hat(state, world, HatType.BREWING)) set_rule(world.multiworld.get_location("Dead Bird Studio - Tepee Chest", world.player), diff --git a/worlds/ahit/__init__.py b/worlds/ahit/__init__.py index 047b788535..8dd16d4a90 100644 --- a/worlds/ahit/__init__.py +++ b/worlds/ahit/__init__.py @@ -3,7 +3,7 @@ from .Items import item_table, create_item, relic_groups, act_contracts, create_ 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 .Options import AHITOptions, slot_data_options, adjust_options 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 @@ -49,7 +49,8 @@ class HatInTimeWorld(World): 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 + options_dataclass = AHITOptions + options: AHITOptions act_connections: Dict[str, str] = {} shop_locs: List[str] = [] item_name_groups = relic_groups @@ -58,7 +59,7 @@ class HatInTimeWorld(World): def generate_early(self): adjust_options(self) - if self.multiworld.StartWithCompassBadge[self.player].value > 0: + if self.options.StartWithCompassBadge.value > 0: self.multiworld.push_precollected(self.create_item("Compass Badge")) if self.is_dw_only(): @@ -66,14 +67,14 @@ class HatInTimeWorld(World): # 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 + start_chapter: int = self.options.StartingChapter.value if start_chapter == 4 or start_chapter == 3: - if self.multiworld.ActRandomizer[self.player].value == 0: + if self.options.ActRandomizer.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: + if start_chapter == 3 and self.options.ShuffleSubconPaintings.value > 0: self.multiworld.push_precollected(self.create_item("Progressive Painting Unlock")) def create_regions(self): @@ -83,11 +84,11 @@ class HatInTimeWorld(World): nyakuza_thug_items[self.player] = {} badge_seller_count[self.player] = 0 self.shop_locs = [] - self.topology_present = self.multiworld.ActRandomizer[self.player].value + self.topology_present = self.options.ActRandomizer.value create_regions(self) - if self.multiworld.EnableDeathWish[self.player].value > 0: + if self.options.EnableDeathWish.value > 0: create_dw_regions(self) if self.is_dw_only(): @@ -100,7 +101,7 @@ class HatInTimeWorld(World): create_enemy_events(self) # place vanilla contract locations if contract shuffle is off - if self.multiworld.ShuffleActContracts[self.player].value == 0: + if self.options.ShuffleActContracts.value == 0: for name in contract_locations.keys(): self.multiworld.get_location(name, self.player).place_locked_item(create_item(self, name)) @@ -111,9 +112,9 @@ class HatInTimeWorld(World): hat_craft_order[self.player] = [HatType.SPRINT, HatType.BREWING, HatType.ICE, HatType.DWELLER, HatType.TIME_STOP] - if self.multiworld.HatItems[self.player].value == 0 and self.multiworld.RandomizeHatOrder[self.player].value > 0: + if self.options.HatItems.value == 0 and self.options.RandomizeHatOrder.value > 0: self.random.shuffle(hat_craft_order[self.player]) - if self.multiworld.RandomizeHatOrder[self.player].value == 2: + if self.options.RandomizeHatOrder.value == 2: hat_craft_order[self.player].remove(HatType.TIME_STOP) hat_craft_order[self.player].append(HatType.TIME_STOP) @@ -137,12 +138,12 @@ class HatInTimeWorld(World): self.multiworld.completion_condition[self.player] = lambda state: state.has("Death Wish Only Mode", self.player) - if self.multiworld.DWEnableBonus[self.player].value == 0: + if self.options.DWEnableBonus.value == 0: for name in death_wishes: if name == "Snatcher Coins in Nyakuza Metro" and not self.is_dlc2(): continue - if self.multiworld.DWShuffle[self.player].value > 0 and name not in self.get_dw_shuffle(): + if self.options.DWShuffle.value > 0 and name not in self.get_dw_shuffle(): continue full_clear = self.multiworld.get_location(f"{name} - All Clear", self.player) @@ -152,7 +153,7 @@ class HatInTimeWorld(World): return - if self.multiworld.ActRandomizer[self.player].value > 0: + if self.options.ActRandomizer.value > 0: randomize_act_entrances(self) set_rules(self) @@ -175,7 +176,7 @@ class HatInTimeWorld(World): "SeedNumber": str(self.multiworld.seed), # For shop prices "SeedName": self.multiworld.seed_name} - if self.multiworld.HatItems[self.player].value == 0: + 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]) @@ -187,7 +188,7 @@ class HatInTimeWorld(World): slot_data.setdefault("Hat4", int(hat_craft_order[self.player][3])) slot_data.setdefault("Hat5", int(hat_craft_order[self.player][4])) - if self.multiworld.ActRandomizer[self.player].value > 0: + if self.options.ActRandomizer.value > 0: for name in self.act_connections.keys(): slot_data[name] = self.act_connections[name] @@ -198,14 +199,14 @@ class HatInTimeWorld(World): if self.is_dw(): i: int = 0 for name in excluded_dws[self.player]: - if self.multiworld.EndGoal[self.player].value == 3 and name == "Seal the Deal": + if self.options.EndGoal.value == 3 and name == "Seal the Deal": continue slot_data[f"excluded_dw{i}"] = dw_classes[name] i += 1 i = 0 - if self.multiworld.DWAutoCompleteBonuses[self.player].value == 0: + if self.options.DWAutoCompleteBonuses.value == 0: for name in excluded_bonuses[self.player]: if name in excluded_dws[self.player]: continue @@ -213,19 +214,19 @@ class HatInTimeWorld(World): slot_data[f"excluded_bonus{i}"] = dw_classes[name] i += 1 - if self.multiworld.DWShuffle[self.player].value > 0: + if self.options.DWShuffle.value > 0: shuffled_dws = self.get_dw_shuffle() for i in range(len(shuffled_dws)): slot_data[f"dw_{i}"] = dw_classes[shuffled_dws[i]] - for option_name in slot_data_options: - option = getattr(self.multiworld, option_name)[self.player] - slot_data[option_name] = option.value + for name, value in self.options.as_dict(*self.options_dataclass.type_hints).items(): + if name in slot_data_options: + slot_data[name] = value return slot_data def extend_hint_information(self, hint_data: Dict[int, Dict[int, str]]): - if self.is_dw_only() or self.multiworld.ActRandomizer[self.player].value == 0: + if self.is_dw_only() or self.options.ActRandomizer.value == 0: return new_hint_data = {} @@ -250,10 +251,10 @@ class HatInTimeWorld(World): new_hint_data[location.address] = get_shuffled_region(self, region_name) - if self.is_dlc1() and self.multiworld.Tasksanity[self.player].value > 0: + if self.is_dlc1() and self.options.Tasksanity.value > 0: ship_shape_region = get_shuffled_region(self, "Ship Shape") id_start: int = get_tasksanity_start_id() - for i in range(self.multiworld.TasksanityCheckCount[self.player].value): + for i in range(self.options.TasksanityCheckCount.value): new_hint_data[id_start+i] = ship_shape_region hint_data[self.player] = new_hint_data @@ -281,16 +282,16 @@ class HatInTimeWorld(World): return chapter_timepiece_costs[self.player] def is_dlc1(self) -> bool: - return self.multiworld.EnableDLC1[self.player].value > 0 + return self.options.EnableDLC1.value > 0 def is_dlc2(self) -> bool: - return self.multiworld.EnableDLC2[self.player].value > 0 + return self.options.EnableDLC2.value > 0 def is_dw(self) -> bool: - return self.multiworld.EnableDeathWish[self.player].value > 0 + return self.options.EnableDeathWish.value > 0 def is_dw_only(self) -> bool: - return self.is_dw() and self.multiworld.DeathWishOnly[self.player].value > 0 + return self.is_dw() and self.options.DeathWishOnly.value > 0 def get_excluded_dws(self): return excluded_dws[self.player] @@ -300,7 +301,7 @@ class HatInTimeWorld(World): def is_dw_excluded(self, name: str) -> bool: # don't exclude Seal the Deal if it's our goal - if self.multiworld.EndGoal[self.player].value == 3 and name == "Seal the Deal" \ + if self.options.EndGoal.value == 3 and name == "Seal the Deal" \ and f"{name} - Main Objective" not in self.multiworld.exclude_locations[self.player]: return False