The Witness: v4 Content Update (#1338)

## New Features:

- EP Shuffle (Individual or Obelisk Sides, with varying difficulty levels)
- Ability to play without Puzzle Randomization (I.e. vanilla + AP layer)
- Pet the Dog to get a Puzzle Skip :) (No, really.)

## Changes:

- Starting inventory behavior improved (Consider starting items like doors and lasers logically even if they aren't part of the mode)
- Audio Log hint system improved (On low hint counts, you will no longer get the same locations hinted every time, i.e. always hints are shuffled)

## Fixes:

- Many fixes to symbol requirements
- Fixes to "shuffle_postgame" (What checks are evaluated as "postgame" in specific modes)
- Logically irrelevant doors are now "useful" instead of "progression"
This commit is contained in:
NewSoupVi
2023-02-01 21:18:07 +01:00
committed by GitHub
parent 3cef39a387
commit 4de7ebd8b0
22 changed files with 2557 additions and 297 deletions

View File

@@ -13,13 +13,6 @@ class StaticWitnessLocations:
"""
ID_START = 158000
TYPE_OFFSETS = {
"General": 0,
"Discard": 600,
"Vault": 650,
"Laser": 700,
}
EXTRA_LOCATIONS = {
"Tutorial Front Left",
"Tutorial Back Left",
@@ -143,7 +136,214 @@ class StaticWitnessLocations:
"Theater Mountain Video",
"Town RGB Room Left",
"Town RGB Room Right",
"Town Sound Room Right",
"Swamp Purple Underwater",
"First Hallway EP",
"Tutorial Cloud EP",
"Tutorial Patio Flowers EP",
"Tutorial Gate EP",
"Outside Tutorial Garden EP",
"Outside Tutorial Town Sewer EP",
"Outside Tutorial Path EP",
"Outside Tutorial Tractor EP",
"Main Island Thundercloud EP",
"Glass Factory Vase EP",
"Symmetry Island Glass Factory Black Line Reflection EP",
"Symmetry Island Glass Factory Black Line EP",
"Desert Sand Snake EP",
"Desert Facade Right EP",
"Desert Facade Left EP",
"Desert Stairs Left EP",
"Desert Stairs Right EP",
"Desert Broken Wall Straight EP",
"Desert Broken Wall Bend EP",
"Desert Shore EP",
"Desert Island EP",
"Desert Pond Room Near Reflection EP",
"Desert Pond Room Far Reflection EP",
"Desert Flood Room EP",
"Desert Elevator EP",
"Quarry Shore EP",
"Quarry Entrance Pipe EP",
"Quarry Sand Pile EP",
"Quarry Rock Line EP",
"Quarry Rock Line Reflection EP",
"Quarry Railroad EP",
"Quarry Mill Ramp EP",
"Quarry Mill Lift EP",
"Quarry Boathouse Moving Ramp EP",
"Quarry Boathouse Hook EP",
"Shadows Quarry Mill Rooftop Vent EP",
"Treehouse Beach Rock Shadow EP",
"Treehouse Beach Sand Shadow EP",
"Treehouse Beach Both Orange Bridges EP",
"Keep Red Flowers EP",
"Keep Purple Flowers EP",
"Shipwreck Circle Near EP",
"Shipwreck Circle Left EP",
"Shipwreck Circle Far EP",
"Shipwreck Stern EP",
"Shipwreck Rope Inner EP",
"Shipwreck Rope Outer EP",
"Shipwreck Couch EP",
"Keep Pressure Plates 1 EP",
"Keep Pressure Plates 2 EP",
"Keep Pressure Plates 3 EP",
"Keep Pressure Plates 4 Left Exit EP",
"Keep Pressure Plates 4 Right Exit EP",
"Keep Path EP",
"Keep Hedges EP",
"Monastery Facade Left Near EP",
"Monastery Facade Left Far Short EP",
"Monastery Facade Left Far Long EP",
"Monastery Facade Right Near EP",
"Monastery Facade Left Stairs EP",
"Monastery Facade Right Stairs EP",
"Monastery Grass Stairs EP",
"Monastery Left Shutter EP",
"Monastery Middle Shutter EP",
"Monastery Right Shutter EP",
"Town Windmill First Blade EP",
"Town Windmill Second Blade EP",
"Town Windmill Third Blade EP",
"Town Tower Underside First EP",
"Town Tower Underside Second EP",
"Town Tower Underside Third EP",
"Town Tower Underside Fourth EP",
"Town RGB House Red EP",
"Town RGB House Green EP",
"Town Maze Bridge Underside EP",
"Town Black Line Redirect EP",
"Town Black Line Church EP",
"Town Brown Bridge EP",
"Town Black Line Tower EP",
"Theater Eclipse EP",
"Theater Window EP",
"Theater Door EP",
"Theater Church EP",
"Jungle Long Arch Moss EP",
"Jungle Straight Left Moss EP",
"Jungle Pop-up Wall Moss EP",
"Jungle Short Arch Moss EP",
"Jungle Entrance EP",
"Jungle Tree Halo EP",
"Jungle Bamboo CCW EP",
"Jungle Bamboo CW EP",
"River Green Leaf Moss EP",
"River Monastery Garden Left EP",
"River Monastery Garden Right EP",
"River Monastery Wall EP",
"Bunker Tinted Door EP",
"Bunker Green Room Flowers EP",
"Swamp Purple Sand Middle EP",
"Swamp Purple Sand Top EP",
"Swamp Purple Sand Bottom EP",
"Swamp Sliding Bridge Left EP",
"Swamp Sliding Bridge Right EP",
"Swamp Cyan Underwater Sliding Bridge EP",
"Swamp Rotating Bridge CCW EP",
"Swamp Rotating Bridge CW EP",
"Swamp Boat EP",
"Swamp Long Bridge Side EP",
"Swamp Purple Underwater Right EP",
"Swamp Purple Underwater Left EP",
"Treehouse Buoy EP",
"Treehouse Right Orange Bridge EP",
"Treehouse Burned House Beach EP",
"Mountainside Cloud Cycle EP",
"Mountainside Bush EP",
"Mountainside Apparent River EP",
"Mountaintop River Shape EP",
"Mountaintop Arch Black EP",
"Mountaintop Arch White Right EP",
"Mountaintop Arch White Left EP",
"Mountain Bottom Floor Yellow Bridge EP",
"Mountain Bottom Floor Blue Bridge EP",
"Mountain Floor 2 Pink Bridge EP",
"Caves Skylight EP",
"Challenge Water EP",
"Tunnels Theater Flowers EP",
"Boat Desert EP",
"Boat Shipwreck CCW Underside EP",
"Boat Shipwreck Green EP",
"Boat Shipwreck CW Underside EP",
"Boat Bunker Yellow Line EP",
"Boat Town Long Sewer EP",
"Boat Tutorial EP",
"Boat Tutorial Reflection EP",
"Boat Tutorial Moss EP",
"Boat Cargo Box EP",
"Desert Obelisk Side 1",
"Desert Obelisk Side 2",
"Desert Obelisk Side 3",
"Desert Obelisk Side 4",
"Desert Obelisk Side 5",
"Monastery Obelisk Side 1",
"Monastery Obelisk Side 2",
"Monastery Obelisk Side 3",
"Monastery Obelisk Side 4",
"Monastery Obelisk Side 5",
"Monastery Obelisk Side 6",
"Treehouse Obelisk Side 1",
"Treehouse Obelisk Side 2",
"Treehouse Obelisk Side 3",
"Treehouse Obelisk Side 4",
"Treehouse Obelisk Side 5",
"Treehouse Obelisk Side 6",
"River Obelisk Side 1",
"River Obelisk Side 2",
"River Obelisk Side 3",
"River Obelisk Side 4",
"River Obelisk Side 5",
"River Obelisk Side 6",
"Quarry Obelisk Side 1",
"Quarry Obelisk Side 2",
"Quarry Obelisk Side 3",
"Quarry Obelisk Side 4",
"Town Obelisk Side 1",
"Town Obelisk Side 2",
"Town Obelisk Side 3",
"Town Obelisk Side 4",
"Town Obelisk Side 5",
"Town Obelisk Side 6",
}
OBELISK_SIDES = {
"Desert Obelisk Side 1",
"Desert Obelisk Side 2",
"Desert Obelisk Side 3",
"Desert Obelisk Side 4",
"Desert Obelisk Side 5",
"Monastery Obelisk Side 1",
"Monastery Obelisk Side 2",
"Monastery Obelisk Side 3",
"Monastery Obelisk Side 4",
"Monastery Obelisk Side 5",
"Monastery Obelisk Side 6",
"Treehouse Obelisk Side 1",
"Treehouse Obelisk Side 2",
"Treehouse Obelisk Side 3",
"Treehouse Obelisk Side 4",
"Treehouse Obelisk Side 5",
"Treehouse Obelisk Side 6",
"River Obelisk Side 1",
"River Obelisk Side 2",
"River Obelisk Side 3",
"River Obelisk Side 4",
"River Obelisk Side 5",
"River Obelisk Side 6",
"Quarry Obelisk Side 1",
"Quarry Obelisk Side 2",
"Quarry Obelisk Side 3",
"Quarry Obelisk Side 4",
"Town Obelisk Side 1",
"Town Obelisk Side 2",
"Town Obelisk Side 3",
"Town Obelisk Side 4",
"Town Obelisk Side 5",
"Town Obelisk Side 6",
}
CAVES_LOCATIONS = {
@@ -170,8 +370,12 @@ class StaticWitnessLocations:
"Caves Left Upstairs Left Row 5",
"Tunnels Vault Box",
"Mountain Bottom Floor Discard",
"Theater Challenge Video",
"Caves Skylight EP",
"Challenge Water EP",
"Tunnels Theater Flowers EP",
"Tutorial Gate EP",
}
MOUNTAIN_UNREACHABLE_FROM_BEHIND = {
@@ -183,6 +387,10 @@ class StaticWitnessLocations:
"Mountain Floor 1 Trash Pillar 2",
"Mountain Floor 2 Near Row 5",
"Mountain Floor 2 Far Row 6",
"Mountain Bottom Floor Yellow Bridge EP",
"Mountain Bottom Floor Blue Bridge EP",
"Mountain Floor 2 Pink Bridge EP",
}
MOUNTAIN_REACHABLE_FROM_BEHIND = {
@@ -213,10 +421,11 @@ class StaticWitnessLocations:
def get_event_name(panel_hex):
"""
Returns the event name of any given panel.
Currently this is always "Panelname Solved"
"""
return StaticWitnessLogic.CHECKS_BY_HEX[panel_hex]["checkName"] + " Solved"
action = " Opened" if StaticWitnessLogic.CHECKS_BY_HEX[panel_hex]["panelType"] == "Door" else " Solved"
return StaticWitnessLogic.CHECKS_BY_HEX[panel_hex]["checkName"] + action
def __init__(self):
all_loc_to_id = {
@@ -286,11 +495,26 @@ class WitnessPlayerLocations:
if is_option_enabled(world, player, "shuffle_vault_boxes"):
self.PANEL_TYPES_TO_SHUFFLE.add("Vault")
if get_option_value(world, player, "shuffle_EPs") == 1:
self.PANEL_TYPES_TO_SHUFFLE.add("EP")
elif get_option_value(world, player, "shuffle_EPs") == 2:
self.PANEL_TYPES_TO_SHUFFLE.add("Obelisk Side")
for obelisk_loc in StaticWitnessLocations.OBELISK_SIDES:
obelisk_loc_hex = StaticWitnessLogic.CHECKS_BY_NAME[obelisk_loc]["checkHex"]
if player_logic.REQUIREMENTS_BY_HEX[obelisk_loc_hex] == frozenset({frozenset()}):
self.CHECK_LOCATIONS.discard(obelisk_loc)
self.CHECK_LOCATIONS = self.CHECK_LOCATIONS | player_logic.ADDED_CHECKS
if not is_option_enabled(world, player, "shuffle_postgame"):
self.CHECK_LOCATIONS -= postgame
self.CHECK_LOCATIONS -= {
StaticWitnessLogic.CHECKS_BY_HEX[panel]["checkName"]
for panel in player_logic.PRECOMPLETED_LOCATIONS
}
self.CHECK_LOCATIONS.discard(StaticWitnessLogic.CHECKS_BY_HEX[player_logic.VICTORY_LOCATION]["checkName"])
self.CHECK_LOCATIONS = self.CHECK_LOCATIONS - {
@@ -301,8 +525,13 @@ class WitnessPlayerLocations:
self.CHECK_PANELHEX_TO_ID = {
StaticWitnessLogic.CHECKS_BY_NAME[ch]["checkHex"]: StaticWitnessLocations.ALL_LOCATIONS_TO_ID[ch]
for ch in self.CHECK_LOCATIONS
if StaticWitnessLogic.CHECKS_BY_NAME[ch]["panelType"] in self.PANEL_TYPES_TO_SHUFFLE
}
dog_hex = StaticWitnessLogic.CHECKS_BY_NAME["Town Pet the Dog"]["checkHex"]
dog_id = StaticWitnessLocations.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])
)
@@ -317,9 +546,9 @@ class WitnessPlayerLocations:
}
check_dict = {
location: StaticWitnessLocations.get_id(StaticWitnessLogic.CHECKS_BY_NAME[location]["checkHex"])
for location in self.CHECK_LOCATIONS
if StaticWitnessLogic.CHECKS_BY_NAME[location]["panelType"] in self.PANEL_TYPES_TO_SHUFFLE
StaticWitnessLogic.CHECKS_BY_HEX[location]["checkName"]:
StaticWitnessLocations.get_id(StaticWitnessLogic.CHECKS_BY_HEX[location]["checkHex"])
for location in self.CHECK_PANELHEX_TO_ID
}
self.CHECK_LOCATION_TABLE = {**self.EVENT_LOCATION_TABLE, **check_dict}