The Witness 0.3.4 features (#780)

New options:

Shuffle Doors: Many doors in the game will open on their own upon receiving an item ("key").
Variant - Shuffle Door/Control Panels: Many panels in the game that open doors or control devices in the world will be off until receiving their respective item ("key").
Shuffle Lasers: Lasers no longer activate by solving the laser panel, instead you will get an item that activates the laser.
Shuffle Symbols: Now that there is something else to shuffle (doors / door panels), you can turn off Symbol Rando.
Shuffle Postgame (replaces "Shuffle Hard"): The randomizer will now determine by your settings which panels are in the "postgame" - Meaning they can only be accessed after you can complete your win condition anyway.
This commit is contained in:
NewSoupVi
2022-07-17 12:56:22 +02:00
committed by GitHub
parent 472e114fb9
commit bd4850b2b5
21 changed files with 2058 additions and 994 deletions

View File

@@ -22,6 +22,21 @@ class WitnessLogic(LogicMixin):
def _witness_has_lasers(self, world, player: int, amount: int) -> bool:
lasers = 0
if is_option_enabled(world, player, "shuffle_lasers"):
lasers += int(self.has("Symmetry Laser", player))
lasers += int(self.has("Desert Laser", player)
and self.has("Desert Laser Redirection", player))
lasers += int(self.has("Town Laser", player))
lasers += int(self.has("Monastery Laser", player))
lasers += int(self.has("Keep Laser", player))
lasers += int(self.has("Quarry Laser", player))
lasers += int(self.has("Treehouse Laser", player))
lasers += int(self.has("Jungle Laser", player))
lasers += int(self.has("Bunker Laser", player))
lasers += int(self.has("Swamp Laser", player))
lasers += int(self.has("Shadows Laser", player))
return lasers >= amount
lasers += int(self.has("Symmetry Laser Activation", player))
lasers += int(self.has("Desert Laser Activation", player)
and self.has("Desert Laser Redirection", player))
@@ -48,11 +63,8 @@ class WitnessLogic(LogicMixin):
if (check_name + " Solved" in locat.EVENT_LOCATION_TABLE
and not self.has(player_logic.EVENT_ITEM_PAIRS[check_name + " Solved"], player)):
return False
if panel not in player_logic.ORIGINAL_EVENT_PANELS and not self.can_reach(check_name, "Location", player):
return False
if (panel in player_logic.ORIGINAL_EVENT_PANELS
and check_name + " Solved" not in locat.EVENT_LOCATION_TABLE
and not self._witness_safe_manual_panel_check(panel, world, player, player_logic, locat)):
if (check_name + " Solved" not in locat.EVENT_LOCATION_TABLE
and not self._witness_meets_item_requirements(panel, world, player, player_logic, locat)):
return False
return True
@@ -79,8 +91,10 @@ class WitnessLogic(LogicMixin):
if not self._witness_has_lasers(world, player, get_option_value(world, player, "challenge_lasers")):
valid_option = False
break
elif item in player_logic.ORIGINAL_EVENT_PANELS:
valid_option = self._witness_can_solve_panel(item, world, player, player_logic, locat)
elif item in player_logic.EVENT_PANELS:
if not self._witness_can_solve_panel(item, world, player, player_logic, locat):
valid_option = False
break
elif not self.has(item, player):
valid_option = False
break
@@ -90,24 +104,6 @@ class WitnessLogic(LogicMixin):
return False
def _witness_safe_manual_panel_check(self, panel, world, player, player_logic: WitnessPlayerLogic, locat):
"""
nested can_reach can cause problems, but only if the region being
checked is neither of the two original regions from the first
can_reach.
A nested can_reach is okay here because the only panels this
function is called on are panels that exist on either side of all
connections they are required for.
The spoiler log looks so much nicer this way,
it gets rid of a bunch of event items, only leaving a couple. :)
"""
region = StaticWitnessLogic.CHECKS_BY_HEX[panel]["region"]["name"]
return (
self._witness_meets_item_requirements(panel, world, player, player_logic, locat)
and self.can_reach(region, "Region", player)
)
def _witness_can_solve_panels(self, panel_hex_to_solve_set, world, player, player_logic: WitnessPlayerLogic, locat):
"""
Checks whether a set of panels can be solved.
@@ -120,7 +116,12 @@ class WitnessLogic(LogicMixin):
valid_option = True
for panel in option:
if not self._witness_can_solve_panel(panel, world, player, player_logic, locat):
if panel in player_logic.DOOR_ITEMS_BY_ID:
if all({not self.has(item, player) for item in player_logic.DOOR_ITEMS_BY_ID[panel]}):
valid_option = False
break
elif not self._witness_can_solve_panel(panel, world, player, player_logic, locat):
valid_option = False
break