From f47b026bda2bb5a7de39b6cd0a0d1cb00c5ba243 Mon Sep 17 00:00:00 2001 From: CookieCat Date: Sat, 11 May 2024 22:05:11 -0400 Subject: [PATCH] Finish up review stuff --- worlds/ahit/DeathWishLocations.py | 85 ++++++++------------- worlds/ahit/DeathWishRules.py | 123 +++++++++++++----------------- worlds/ahit/__init__.py | 3 +- 3 files changed, 89 insertions(+), 122 deletions(-) diff --git a/worlds/ahit/DeathWishLocations.py b/worlds/ahit/DeathWishLocations.py index d614035f27..2866e2eb8c 100644 --- a/worlds/ahit/DeathWishLocations.py +++ b/worlds/ahit/DeathWishLocations.py @@ -151,8 +151,7 @@ def create_dw_regions(world: "HatInTimeWorld"): for name in annoying_dws: world.excluded_dws.append(name) - if world.options.DWEnableBonus.value == 0 \ - or world.options.DWAutoCompleteBonuses.value > 0: + if world.options.DWEnableBonus.value == 0 or world.options.DWAutoCompleteBonuses.value > 0: for name in death_wishes: world.excluded_bonuses.append(name) elif world.options.DWExcludeAnnoyingBonuses.value > 0: @@ -161,9 +160,8 @@ def create_dw_regions(world: "HatInTimeWorld"): if world.options.DWExcludeCandles.value > 0: for name in dw_candles: - if name in world.excluded_dws: - continue - world.excluded_dws.append(name) + if name not in world.excluded_dws: + world.excluded_dws.append(name) spaceship = world.multiworld.get_region("Spaceship", world.player) dw_map: Region = create_region(world, "Death Wish Map") @@ -171,8 +169,10 @@ def create_dw_regions(world: "HatInTimeWorld"): add_rule(entrance, lambda state: state.has("Time Piece", world.player, world.options.DWTimePieceRequirement.value)) if world.options.DWShuffle.value > 0: + # Connect Death Wishes randomly to one another in a linear sequence dw_list: List[str] = [] for name in death_wishes.keys(): + # Don't shuffle excluded or invalid Death Wishes if not world.is_dlc2() and name == "Snatcher Coins in Nyakuza Metro" or world.is_dw_excluded(name): continue @@ -180,7 +180,6 @@ def create_dw_regions(world: "HatInTimeWorld"): world.random.shuffle(dw_list) count = world.random.randint(world.options.DWShuffleCountMin.value, world.options.DWShuffleCountMax.value) - dw_shuffle: List[str] = [] total = min(len(dw_list), count) for i in range(total): @@ -199,64 +198,46 @@ def create_dw_regions(world: "HatInTimeWorld"): name = dw_shuffle[i] dw = create_region(world, name) connect_regions(prev_dw, dw, f"{prev_dw.name} -> {name}", world.player) - - loc_id = death_wishes[name] - main_objective = HatInTimeLocation(world.player, f"{name} - Main Objective", loc_id, dw) - full_clear = HatInTimeLocation(world.player, f"{name} - All Clear", loc_id + 1, dw) - main_stamp = HatInTimeLocation(world.player, f"Main Stamp - {name}", None, dw) - bonus_stamps = HatInTimeLocation(world.player, f"Bonus Stamps - {name}", None, dw) - main_stamp.show_in_spoiler = False - bonus_stamps.show_in_spoiler = False - dw.locations.append(main_stamp) - dw.locations.append(bonus_stamps) - - main_stamp.place_locked_item(HatInTimeItem(f"1 Stamp - {name}", - ItemClassification.progression, None, world.player)) - bonus_stamps.place_locked_item(HatInTimeItem(f"2 Stamps - {name}", - ItemClassification.progression, None, world.player)) - - if name in world.excluded_dws: - main_objective.progress_type = LocationProgressType.EXCLUDED - full_clear.progress_type = LocationProgressType.EXCLUDED - elif world.is_bonus_excluded(name): - full_clear.progress_type = LocationProgressType.EXCLUDED - - dw.locations.append(main_objective) - dw.locations.append(full_clear) + create_dw_locations(world, dw) prev_dw = dw else: - for key, loc_id in death_wishes.items(): + # DWShuffle is disabled, use vanilla connections + for key in death_wishes.keys(): if key == "Snatcher Coins in Nyakuza Metro" and not world.is_dlc2(): world.excluded_dws.append(key) continue dw = create_region(world, key) - if key == "Beat the Heat": - connect_regions(dw_map, dw, "-> Beat the Heat", world.player) + connect_regions(dw_map, dw, f"{dw_map.name} -> Beat the Heat", world.player) elif key in dw_prereqs.keys(): for name in dw_prereqs[key]: parent = world.multiworld.get_region(name, world.player) connect_regions(parent, dw, f"{parent.name} -> {key}", world.player) - main_objective = HatInTimeLocation(world.player, f"{key} - Main Objective", loc_id, dw) - full_clear = HatInTimeLocation(world.player, f"{key} - All Clear", loc_id+1, dw) - main_stamp = HatInTimeLocation(world.player, f"Main Stamp - {key}", None, dw) - bonus_stamps = HatInTimeLocation(world.player, f"Bonus Stamps - {key}", None, dw) - main_stamp.show_in_spoiler = False - bonus_stamps.show_in_spoiler = False - dw.locations.append(main_stamp) - dw.locations.append(bonus_stamps) - main_stamp.place_locked_item(HatInTimeItem(f"1 Stamp - {key}", - ItemClassification.progression, None, world.player)) - bonus_stamps.place_locked_item(HatInTimeItem(f"2 Stamps - {key}", - ItemClassification.progression, None, world.player)) + create_dw_locations(world, dw) - if key in world.excluded_dws: - main_objective.progress_type = LocationProgressType.EXCLUDED - full_clear.progress_type = LocationProgressType.EXCLUDED - elif world.is_bonus_excluded(key): - full_clear.progress_type = LocationProgressType.EXCLUDED - dw.locations.append(main_objective) - dw.locations.append(full_clear) +def create_dw_locations(world: "HatInTimeWorld", dw: Region): + loc_id = death_wishes[dw.name] + main_objective = HatInTimeLocation(world.player, f"{dw.name} - Main Objective", loc_id, dw) + full_clear = HatInTimeLocation(world.player, f"{dw.name} - All Clear", loc_id + 1, dw) + main_stamp = HatInTimeLocation(world.player, f"Main Stamp - {dw.name}", None, dw) + bonus_stamps = HatInTimeLocation(world.player, f"Bonus Stamps - {dw.name}", None, dw) + main_stamp.show_in_spoiler = False + bonus_stamps.show_in_spoiler = False + dw.locations.append(main_stamp) + dw.locations.append(bonus_stamps) + main_stamp.place_locked_item(HatInTimeItem(f"1 Stamp - {dw.name}", + ItemClassification.progression, None, world.player)) + bonus_stamps.place_locked_item(HatInTimeItem(f"2 Stamps - {dw.name}", + ItemClassification.progression, None, world.player)) + + if dw.name in world.excluded_dws: + main_objective.progress_type = LocationProgressType.EXCLUDED + full_clear.progress_type = LocationProgressType.EXCLUDED + elif world.is_bonus_excluded(dw.name): + full_clear.progress_type = LocationProgressType.EXCLUDED + + dw.locations.append(main_objective) + dw.locations.append(full_clear) \ No newline at end of file diff --git a/worlds/ahit/DeathWishRules.py b/worlds/ahit/DeathWishRules.py index cd22f711a2..5b94e0911f 100644 --- a/worlds/ahit/DeathWishRules.py +++ b/worlds/ahit/DeathWishRules.py @@ -103,8 +103,7 @@ required_snatcher_coins = { def set_dw_rules(world: "HatInTimeWorld"): - if "Snatcher's Hit List" not in world.excluded_dws \ - or "Camera Tourist" not in world.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] = [] @@ -119,81 +118,33 @@ def set_dw_rules(world: "HatInTimeWorld"): continue dw = world.multiworld.get_region(name, world.player) - temp_list: List[Location] = [] - main_objective = world.multiworld.get_location(f"{name} - Main Objective", world.player) - full_clear = world.multiworld.get_location(f"{name} - All Clear", world.player) - main_stamp = world.multiworld.get_location(f"Main Stamp - {name}", world.player) - bonus_stamps = world.multiworld.get_location(f"Bonus Stamps - {name}", world.player) - temp_list.append(main_objective) - temp_list.append(full_clear) - 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]) + main_objective = world.multiworld.get_location(f"{name} - Main Objective", world.player) + all_clear = world.multiworld.get_location(f"{name} - All Clear", world.player) + main_stamp = world.multiworld.get_location(f"Main Stamp - {name}", world.player) + bonus_stamps = world.multiworld.get_location(f"Bonus Stamps - {name}", world.player) 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)) - full_clear.show_in_spoiler = False + all_clear.address = None + all_clear.place_locked_item(HatInTimeItem("Nothing", ItemClassification.filler, None, world.player)) + all_clear.show_in_spoiler = False # No need for rules if excluded - stamps will be auto-granted if world.is_dw_excluded(name): continue - # Specific Rules modify_dw_rules(world, name) - - main_rule: Callable[[CollectionState], bool] - for i in range(len(temp_list)): - loc = temp_list[i] - data: LocData - - if loc.name == main_objective.name: - data = dw_requirements.get(name) - else: - data = dw_bonus_requirements.get(name) - - if data is None: - continue - - if data.hookshot: - add_rule(loc, lambda state: can_use_hookshot(state, world)) - - for hat in data.required_hats: - if hat is not HatType.NONE: - add_rule(loc, lambda state, h=hat: can_use_hat(state, world, h)) - - for misc in data.misc_required: - add_rule(loc, lambda state, item=misc: state.has(item, world.player)) - - 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_type is not HitType.none and world.options.UmbrellaLogic.value > 0: - if data.hit_type == HitType.umbrella: - add_rule(loc, lambda state: state.has("Umbrella", world.player)) - - elif data.hit_type == HitType.umbrella_or_brewing: - add_rule(loc, lambda state: state.has("Umbrella", world.player) - or can_use_hat(state, world, HatType.BREWING)) - - elif data.hit_type == HitType.dweller_bell: - add_rule(loc, lambda state: state.has("Umbrella", world.player) - or can_use_hat(state, world, HatType.BREWING) - or can_use_hat(state, world, HatType.DWELLER)) - - main_rule = main_objective.access_rule - - if loc.name == main_objective.name: - add_rule(main_stamp, loc.access_rule) - 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.options.DWAutoCompleteBonuses.value == 0 \ - and not world.is_bonus_excluded(loc.name): - add_rule(bonus_stamps, loc.access_rule) + add_dw_rules(world, main_objective) + add_dw_rules(world, all_clear) + add_rule(main_stamp, main_objective.access_rule) + add_rule(all_clear, main_objective.access_rule) + # Only set bonus stamp rules if we don't auto complete bonuses + if world.options.DWAutoCompleteBonuses.value == 0 and not world.is_bonus_excluded(all_clear.name): + add_rule(bonus_stamps, all_clear.access_rule) if world.options.DWShuffle.value > 0: for i in range(len(world.dw_shuffle)-1): @@ -221,8 +172,45 @@ def set_dw_rules(world: "HatInTimeWorld"): add_rule(entrance, rule) if world.options.EndGoal.value == 3: - world.multiworld.completion_condition[world.player] = lambda state: state.has("1 Stamp - Seal the Deal", - world.player) + world.multiworld.completion_condition[world.player] = lambda state: \ + state.has("1 Stamp - Seal the Deal", world.player) + + +def add_dw_rules(world: "HatInTimeWorld", loc: Location): + bonus: bool = "All Clear" in loc.name + if not bonus: + data = dw_requirements.get(loc.name) + else: + data = dw_bonus_requirements.get(loc.name) + + if data is None: + return + + if data.hookshot: + add_rule(loc, lambda state: can_use_hookshot(state, world)) + + for hat in data.required_hats: + if hat is not HatType.NONE: + add_rule(loc, lambda state, h=hat: can_use_hat(state, world, h)) + + for misc in data.misc_required: + add_rule(loc, lambda state, item=misc: state.has(item, world.player)) + + 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_type is not HitType.none and world.options.UmbrellaLogic.value > 0: + if data.hit_type == HitType.umbrella: + add_rule(loc, lambda state: state.has("Umbrella", world.player)) + + elif data.hit_type == HitType.umbrella_or_brewing: + add_rule(loc, lambda state: state.has("Umbrella", world.player) + or can_use_hat(state, world, HatType.BREWING)) + + elif data.hit_type == HitType.dweller_bell: + add_rule(loc, lambda state: state.has("Umbrella", world.player) + or can_use_hat(state, world, HatType.BREWING) + or can_use_hat(state, world, HatType.DWELLER)) def modify_dw_rules(world: "HatInTimeWorld", name: str): @@ -380,8 +368,7 @@ def can_reach_all_bosses(state: CollectionState, world: "HatInTimeWorld") -> boo def create_enemy_events(world: "HatInTimeWorld"): - no_tourist = "Camera Tourist" in world.excluded_dws or "Camera Tourist" in world.excluded_bonuses - + no_tourist = "Camera Tourist" in world.excluded_dws for enemy, regions in hit_list.items(): if no_tourist and enemy in bosses: continue diff --git a/worlds/ahit/__init__.py b/worlds/ahit/__init__.py index c0caf019cf..1ecfaa7552 100644 --- a/worlds/ahit/__init__.py +++ b/worlds/ahit/__init__.py @@ -115,8 +115,7 @@ class HatInTimeWorld(World): create_events(self) if self.is_dw(): - if "Snatcher's Hit List" not in self.excluded_dws \ - or "Camera Tourist" not in self.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