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?
This commit is contained in:
NewSoupVi 2024-08-24 02:08:04 +02:00 committed by GitHub
parent 6efa065867
commit e61d521ba8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 44 additions and 17 deletions

View File

@ -189,11 +189,12 @@ class WitnessWorld(World):
event_locations.append(location_obj) event_locations.append(location_obj)
# Place other locked items # Place other locked items
if self.options.shuffle_dog == "puzzle_skip":
dog_puzzle_skip = self.create_item("Puzzle Skip") dog_puzzle_skip = self.create_item("Puzzle Skip")
self.get_location("Town Pet the Dog").place_locked_item(dog_puzzle_skip) self.get_location("Town Pet the Dog").place_locked_item(dog_puzzle_skip)
self.own_itempool.append(dog_puzzle_skip) self.own_itempool.append(dog_puzzle_skip)
self.items_placed_early.append("Puzzle Skip") self.items_placed_early.append("Puzzle Skip")
if self.options.early_symbol_item: if self.options.early_symbol_item:
@ -213,7 +214,7 @@ class WitnessWorld(World):
self.own_itempool.append(gate_item) self.own_itempool.append(gate_item)
self.items_placed_early.append(random_early_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. # 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. # 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. # 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 = CollectionState(self.multiworld)
state.sweep_for_advancements(locations=event_locations) 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.puzzle_randomization == "sigma_expert"
needed_size += self.options.shuffle_symbols needed_size += self.options.shuffle_symbols
needed_size += self.options.shuffle_doors > 0 needed_size += self.options.shuffle_doors > 0

View File

@ -104,6 +104,8 @@ GENERAL_LOCATIONS = {
"Town RGB House Upstairs Right", "Town RGB House Upstairs Right",
"Town RGB House Sound Room Right", "Town RGB House Sound Room Right",
"Town Pet the Dog",
"Windmill Theater Entry Panel", "Windmill Theater Entry Panel",
"Theater Exit Left Panel", "Theater Exit Left Panel",
"Theater Exit Right Panel", "Theater Exit Right Panel",

View File

@ -147,6 +147,9 @@ class StaticWitnessLogicObj:
elif "EP" in entity_name: elif "EP" in entity_name:
entity_type = "EP" entity_type = "EP"
location_type = "EP" location_type = "EP"
elif "Pet the Dog" in entity_name:
entity_type = "Event"
location_type = "Good Boi"
elif entity_hex.startswith("0xFF"): elif entity_hex.startswith("0xFF"):
entity_type = "Event" entity_type = "Event"
location_type = None location_type = None

View File

@ -19,7 +19,7 @@ class WitnessPlayerLocations:
def __init__(self, world: "WitnessWorld", player_logic: WitnessPlayerLogic) -> None: def __init__(self, world: "WitnessWorld", player_logic: WitnessPlayerLogic) -> None:
"""Defines locations AFTER logic changes due to options""" """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() self.CHECK_LOCATIONS = static_witness_locations.GENERAL_LOCATIONS.copy()
if world.options.shuffle_discarded_panels: 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 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( self.CHECK_PANELHEX_TO_ID = dict(
sorted(self.CHECK_PANELHEX_TO_ID.items(), key=lambda item: item[1]) sorted(self.CHECK_PANELHEX_TO_ID.items(), key=lambda item: item[1])
) )

View File

@ -129,12 +129,18 @@ class ShuffleEnvironmentalPuzzles(Choice):
option_obelisk_sides = 2 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" display_name = "Pet the Dog"
option_off = 0
option_puzzle_skip = 1
option_random_item = 2
default = 1
class EnvironmentalPuzzlesDifficulty(Choice): class EnvironmentalPuzzlesDifficulty(Choice):
""" """
@ -424,6 +430,7 @@ class TheWitnessOptions(PerGameCommonOptions):
laser_hints: LaserHints laser_hints: LaserHints
death_link: DeathLink death_link: DeathLink
death_link_amnesty: DeathLinkAmnesty death_link_amnesty: DeathLinkAmnesty
shuffle_dog: ShuffleDog
witness_option_groups = [ witness_option_groups = [
@ -471,5 +478,8 @@ witness_option_groups = [
ElevatorsComeToYou, ElevatorsComeToYou,
DeathLink, DeathLink,
DeathLinkAmnesty, DeathLinkAmnesty,
]),
OptionGroup("Silly Options", [
ShuffleDog,
]) ])
] ]

View File

@ -215,7 +215,7 @@ class WitnessPlayerItems:
item = self.item_data[item_name] item = self.item_data[item_name]
if isinstance(item.definition, ProgressiveItemDefinition): if isinstance(item.definition, ProgressiveItemDefinition):
# Note: we need to reference the static table here rather than the player-specific one because the child # 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) 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] for child_item in item.definition.child_item_names]
return output return output

View File

@ -609,6 +609,9 @@ class WitnessPlayerLogic:
adjustment_linesets_in_order.append(get_complex_doors()) adjustment_linesets_in_order.append(get_complex_doors())
adjustment_linesets_in_order.append(get_complex_additional_panels()) 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: if world.options.shuffle_boat:
adjustment_linesets_in_order.append(get_boat()) adjustment_linesets_in_order.append(get_boat())
@ -890,7 +893,7 @@ class WitnessPlayerLogic:
) )
def determine_unrequired_entities(self, world: "WitnessWorld") -> None: 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 # Gather quick references to relevant options
eps_shuffled = world.options.shuffle_EPs eps_shuffled = world.options.shuffle_EPs

View File

@ -37,6 +37,8 @@ witness_option_presets: Dict[str, Dict[str, Any]] = {
"laser_hints": LaserHints.default, "laser_hints": LaserHints.default,
"death_link": DeathLink.default, "death_link": DeathLink.default,
"death_link_amnesty": DeathLinkAmnesty.default, "death_link_amnesty": DeathLinkAmnesty.default,
"shuffle_dog": ShuffleDog.default,
}, },
# For relative beginners who want to move to the next step. # 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, "laser_hints": LaserHints.default,
"death_link": DeathLink.default, "death_link": DeathLink.default,
"death_link_amnesty": DeathLinkAmnesty.default, "death_link_amnesty": DeathLinkAmnesty.default,
"shuffle_dog": ShuffleDog.default,
}, },
# Allsanity but without the BS (no expert, no tedious EPs). # 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, "laser_hints": LaserHints.default,
"death_link": DeathLink.default, "death_link": DeathLink.default,
"death_link_amnesty": DeathLinkAmnesty.default, "death_link_amnesty": DeathLinkAmnesty.default,
"shuffle_dog": ShuffleDog.option_random_item,
}, },
} }

View File

@ -12,6 +12,7 @@ class TestExpertNonRandomizedEPs(WitnessTestBase):
"victory_condition": "challenge", "victory_condition": "challenge",
"shuffle_discarded_panels": False, "shuffle_discarded_panels": False,
"shuffle_boat": False, "shuffle_boat": False,
"shuffle_dog": "off",
} }
@ -24,6 +25,7 @@ class TestVanillaAutoElevatorsPanels(WitnessTestBase):
"early_caves": True, "early_caves": True,
"shuffle_vault_boxes": True, "shuffle_vault_boxes": True,
"mountain_lasers": 11, "mountain_lasers": 11,
"shuffle_dog": "puzzle_skip",
} }
@ -46,6 +48,7 @@ class TestMaxEntityShuffle(WitnessTestBase):
"obelisk_keys": True, "obelisk_keys": True,
"shuffle_lasers": "anywhere", "shuffle_lasers": "anywhere",
"victory_condition": "mountain_box_long", "victory_condition": "mountain_box_long",
"shuffle_dog": "random_item",
} }