From e61d521ba8df5a1dfd1dda44a4e7c7e9989865a9 Mon Sep 17 00:00:00 2001 From: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com> Date: Sat, 24 Aug 2024 02:08:04 +0200 Subject: [PATCH] The Witness: Shuffle Dog (#3425) * Town Pet the Dog * Add shuffle dog to options presets * I cri evritim * I guess it's as good a time as any * :( * fix the soft conflict * add all the shuffle dog options to some of the unit tests bc why not * Laser Panels are just 'General' now, I'm pretty sure * Could I really call it allsanity? --- worlds/witness/__init__.py | 20 +++++++++++-------- worlds/witness/data/static_locations.py | 2 ++ worlds/witness/data/static_logic.py | 3 +++ worlds/witness/locations.py | 6 +----- worlds/witness/options.py | 14 +++++++++++-- worlds/witness/player_items.py | 2 +- worlds/witness/player_logic.py | 5 ++++- worlds/witness/presets.py | 6 ++++++ .../witness/test/test_roll_other_options.py | 3 +++ 9 files changed, 44 insertions(+), 17 deletions(-) diff --git a/worlds/witness/__init__.py b/worlds/witness/__init__.py index 02d11373..33c63edd 100644 --- a/worlds/witness/__init__.py +++ b/worlds/witness/__init__.py @@ -189,12 +189,13 @@ class WitnessWorld(World): event_locations.append(location_obj) # Place other locked items - dog_puzzle_skip = self.create_item("Puzzle Skip") - self.get_location("Town Pet the Dog").place_locked_item(dog_puzzle_skip) - self.own_itempool.append(dog_puzzle_skip) + if self.options.shuffle_dog == "puzzle_skip": + dog_puzzle_skip = self.create_item("Puzzle Skip") + self.get_location("Town Pet the Dog").place_locked_item(dog_puzzle_skip) - self.items_placed_early.append("Puzzle Skip") + self.own_itempool.append(dog_puzzle_skip) + self.items_placed_early.append("Puzzle Skip") if self.options.early_symbol_item: # Pick an early item to place on the tutorial gate. @@ -213,7 +214,7 @@ class WitnessWorld(World): self.own_itempool.append(gate_item) self.items_placed_early.append(random_early_item) - # There are some really restrictive settings in The Witness. + # There are some really restrictive options in The Witness. # They are rarely played, but when they are, we add some extra sphere 1 locations. # This is done both to prevent generation failures, but also to make the early game less linear. # Only sweeps for events because having this behavior be random based on Tutorial Gate would be strange. @@ -221,11 +222,14 @@ class WitnessWorld(World): state = CollectionState(self.multiworld) state.sweep_for_advancements(locations=event_locations) - num_early_locs = sum(1 for loc in self.multiworld.get_reachable_locations(state, self.player) if loc.address) + num_early_locs = sum( + 1 for loc in self.multiworld.get_reachable_locations(state, self.player) + if loc.address and not loc.item + ) - # Adjust the needed size for sphere 1 based on how restrictive the settings are in terms of items + # Adjust the needed size for sphere 1 based on how restrictive the options are in terms of items - needed_size = 3 + needed_size = 2 needed_size += self.options.puzzle_randomization == "sigma_expert" needed_size += self.options.shuffle_symbols needed_size += self.options.shuffle_doors > 0 diff --git a/worlds/witness/data/static_locations.py b/worlds/witness/data/static_locations.py index d9566080..5c5ad554 100644 --- a/worlds/witness/data/static_locations.py +++ b/worlds/witness/data/static_locations.py @@ -104,6 +104,8 @@ GENERAL_LOCATIONS = { "Town RGB House Upstairs Right", "Town RGB House Sound Room Right", + "Town Pet the Dog", + "Windmill Theater Entry Panel", "Theater Exit Left Panel", "Theater Exit Right Panel", diff --git a/worlds/witness/data/static_logic.py b/worlds/witness/data/static_logic.py index b61b0f9d..87e10152 100644 --- a/worlds/witness/data/static_logic.py +++ b/worlds/witness/data/static_logic.py @@ -147,6 +147,9 @@ class StaticWitnessLogicObj: elif "EP" in entity_name: entity_type = "EP" location_type = "EP" + elif "Pet the Dog" in entity_name: + entity_type = "Event" + location_type = "Good Boi" elif entity_hex.startswith("0xFF"): entity_type = "Event" location_type = None diff --git a/worlds/witness/locations.py b/worlds/witness/locations.py index d095b8be..49a4437c 100644 --- a/worlds/witness/locations.py +++ b/worlds/witness/locations.py @@ -19,7 +19,7 @@ class WitnessPlayerLocations: def __init__(self, world: "WitnessWorld", player_logic: WitnessPlayerLogic) -> None: """Defines locations AFTER logic changes due to options""" - self.PANEL_TYPES_TO_SHUFFLE = {"General", "Laser"} + self.PANEL_TYPES_TO_SHUFFLE = {"General", "Good Boi"} self.CHECK_LOCATIONS = static_witness_locations.GENERAL_LOCATIONS.copy() if world.options.shuffle_discarded_panels: @@ -53,10 +53,6 @@ class WitnessPlayerLocations: if static_witness_logic.ENTITIES_BY_NAME[ch]["locationType"] in self.PANEL_TYPES_TO_SHUFFLE } - dog_hex = static_witness_logic.ENTITIES_BY_NAME["Town Pet the Dog"]["entity_hex"] - dog_id = static_witness_locations.ALL_LOCATIONS_TO_ID["Town Pet the Dog"] - self.CHECK_PANELHEX_TO_ID[dog_hex] = dog_id - self.CHECK_PANELHEX_TO_ID = dict( sorted(self.CHECK_PANELHEX_TO_ID.items(), key=lambda item: item[1]) ) diff --git a/worlds/witness/options.py b/worlds/witness/options.py index 6f7222d5..f91e5218 100644 --- a/worlds/witness/options.py +++ b/worlds/witness/options.py @@ -129,12 +129,18 @@ class ShuffleEnvironmentalPuzzles(Choice): option_obelisk_sides = 2 -class ShuffleDog(Toggle): +class ShuffleDog(Choice): """ - Adds petting the Town dog into the location pool. + Adds petting the dog statue in Town into the location pool. + Alternatively, you can force it to be a Puzzle Skip. """ display_name = "Pet the Dog" + option_off = 0 + option_puzzle_skip = 1 + option_random_item = 2 + default = 1 + class EnvironmentalPuzzlesDifficulty(Choice): """ @@ -424,6 +430,7 @@ class TheWitnessOptions(PerGameCommonOptions): laser_hints: LaserHints death_link: DeathLink death_link_amnesty: DeathLinkAmnesty + shuffle_dog: ShuffleDog witness_option_groups = [ @@ -471,5 +478,8 @@ witness_option_groups = [ ElevatorsComeToYou, DeathLink, DeathLinkAmnesty, + ]), + OptionGroup("Silly Options", [ + ShuffleDog, ]) ] diff --git a/worlds/witness/player_items.py b/worlds/witness/player_items.py index 44a959f2..3e09fe2d 100644 --- a/worlds/witness/player_items.py +++ b/worlds/witness/player_items.py @@ -215,7 +215,7 @@ class WitnessPlayerItems: item = self.item_data[item_name] if isinstance(item.definition, ProgressiveItemDefinition): # Note: we need to reference the static table here rather than the player-specific one because the child - # items were removed from the pool when we pruned out all progression items not in the settings. + # items were removed from the pool when we pruned out all progression items not in the options. output[cast(int, item.ap_code)] = [cast(int, static_witness_items.ITEM_DATA[child_item].ap_code) for child_item in item.definition.child_item_names] return output diff --git a/worlds/witness/player_logic.py b/worlds/witness/player_logic.py index 3321983d..7313d823 100644 --- a/worlds/witness/player_logic.py +++ b/worlds/witness/player_logic.py @@ -609,6 +609,9 @@ class WitnessPlayerLogic: adjustment_linesets_in_order.append(get_complex_doors()) adjustment_linesets_in_order.append(get_complex_additional_panels()) + if not world.options.shuffle_dog: + adjustment_linesets_in_order.append(["Disabled Locations:", "0xFFF80 (Town Pet the Dog)"]) + if world.options.shuffle_boat: adjustment_linesets_in_order.append(get_boat()) @@ -890,7 +893,7 @@ class WitnessPlayerLogic: ) def determine_unrequired_entities(self, world: "WitnessWorld") -> None: - """Figure out which major items are actually useless in this world's settings""" + """Figure out which major items are actually useless in this world's options""" # Gather quick references to relevant options eps_shuffled = world.options.shuffle_EPs diff --git a/worlds/witness/presets.py b/worlds/witness/presets.py index 2a53484a..105514c9 100644 --- a/worlds/witness/presets.py +++ b/worlds/witness/presets.py @@ -37,6 +37,8 @@ witness_option_presets: Dict[str, Dict[str, Any]] = { "laser_hints": LaserHints.default, "death_link": DeathLink.default, "death_link_amnesty": DeathLinkAmnesty.default, + + "shuffle_dog": ShuffleDog.default, }, # For relative beginners who want to move to the next step. @@ -73,6 +75,8 @@ witness_option_presets: Dict[str, Dict[str, Any]] = { "laser_hints": LaserHints.default, "death_link": DeathLink.default, "death_link_amnesty": DeathLinkAmnesty.default, + + "shuffle_dog": ShuffleDog.default, }, # Allsanity but without the BS (no expert, no tedious EPs). @@ -109,5 +113,7 @@ witness_option_presets: Dict[str, Dict[str, Any]] = { "laser_hints": LaserHints.default, "death_link": DeathLink.default, "death_link_amnesty": DeathLinkAmnesty.default, + + "shuffle_dog": ShuffleDog.option_random_item, }, } diff --git a/worlds/witness/test/test_roll_other_options.py b/worlds/witness/test/test_roll_other_options.py index 3912ce25..bea278a0 100644 --- a/worlds/witness/test/test_roll_other_options.py +++ b/worlds/witness/test/test_roll_other_options.py @@ -12,6 +12,7 @@ class TestExpertNonRandomizedEPs(WitnessTestBase): "victory_condition": "challenge", "shuffle_discarded_panels": False, "shuffle_boat": False, + "shuffle_dog": "off", } @@ -24,6 +25,7 @@ class TestVanillaAutoElevatorsPanels(WitnessTestBase): "early_caves": True, "shuffle_vault_boxes": True, "mountain_lasers": 11, + "shuffle_dog": "puzzle_skip", } @@ -46,6 +48,7 @@ class TestMaxEntityShuffle(WitnessTestBase): "obelisk_keys": True, "shuffle_lasers": "anywhere", "victory_condition": "mountain_box_long", + "shuffle_dog": "random_item", }