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
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 2058 additions and 994 deletions

View File

@ -1,30 +0,0 @@
100 - 0x01A54 - None - Glass Factory Entry Door
105 - 0x000B0 - 0x0343A - Door to Symmetry Island Lower
107 - 0x1C349 - 0x00076 - Door to Symmetry Island Upper
110 - 0x0C339 - 0x09F94 - Door to Desert Flood Light Room
111 - 0x1C2DF,0x1831E,0x1C260,0x1831C,0x1C2F3,0x1831D,0x1C2B1,0x1831B - None - Desert Flood Room Flood Controls
120 - 0x03678 - None - Quarry Mill Ramp Control
122 - 0x03679 - 0x014E8 - Quarry Mill Elevator Control
125 - 0x03852 - 0x034D4,0x021D5 - Quarry Boathouse Ramp Height Control
127 - 0x03858 - 0x021AE - Quarry Boathouse Ramp Horizontal Control
131 - 0x334DB,0x334DC - None - Shadows Door Timer
150 - 0x00B10 - None - Monastery Entry Door Left
151 - 0x00C92 - None - Monastery Entry Door Right
162 - 0x28998 - None - Town Door to RGB House
163 - 0x28A0D - 0x28998 - Town Door to Church
166 - 0x28A79 - None - Town Maze Panel (Drop-Down Staircase)
169 - 0x17F5F - None - Windmill Door
200 - 0x0288C - None - Treehouse First & Second Door
202 - 0x0A182 - None - Treehouse Third Door
205 - 0x2700B - None - Treehouse Laser House Door Timer
208 - 0x17CBC - None - Treehouse Shortcut Drop-Down Bridge
175 - 0x17CAB - 0x002C7 - Jungle Popup Wall
180 - 0x17C2E - None - Bunker Entry Door
183 - 0x0A099 - 0x09DAF - Inside Bunker Door to Bunker Proper
186 - 0x0A079 - None - Bunker Elevator Control
190 - 0x0056E - None - Swamp Entry Door
192 - 0x00609,0x18488 - 0x181A9 - Swamp Sliding Bridge
195 - 0x181F5 - None - Swamp Rotating Bridge
197 - 0x17C0A - None - Swamp Maze Control
300 - 0x0042D - None - Mountaintop River Shape Panel (Shortcut to Secret Area)
310 - 0x17CDF,0x17CC8,0x17CA6,0x09DB8,0x17C95,0x0A054 - None - Boat

View File

@ -1,5 +0,0 @@
Event Items:
Shortcut to Secret Area Opens - 0x0042D
Region Changes:
Inside Mountain Secret Area (Inside Mountain Secret Area) - Inside Mountain Path to Secret Area - 0x00FF8 - Main Island - 0x021D7 | 0x0042D - Main Island - 0x17CF2

View File

@ -7,37 +7,48 @@ from Options import Toggle, DefaultOnToggle, Option, Range, Choice
# "Play the randomizer in hardmode"
# display_name = "Hard Mode"
# class UnlockSymbols(DefaultOnToggle):
# "All Puzzle symbols of a specific panel need to be unlocked before the panel can be used"
# display_name = "Unlock Symbols"
class DisableNonRandomizedPuzzles(DefaultOnToggle):
"""Disable puzzles that cannot be randomized.
Non randomized puzzles are Shadows, Monastery, and Greenhouse.
"""Disables puzzles that cannot be randomized.
This includes many puzzles that heavily involve the environment, such as Shadows, Monastery or Orchard.
The lasers for those areas will be activated as you solve optional puzzles throughout the island."""
display_name = "Disable non randomized puzzles"
class EarlySecretArea(Toggle):
"""The Mountainside shortcut to the Mountain Secret Area is open from the start.
"""Opens the Mountainside shortcut to the Mountain Secret Area from the start.
(Otherwise known as "UTM", "Caves" or the "Challenge Area")"""
display_name = "Early Secret Area"
class ShuffleSymbols(DefaultOnToggle):
"""You will need to unlock puzzle symbols as items to be able to solve the panels that contain those symbols."""
"""You will need to unlock puzzle symbols as items to be able to solve the panels that contain those symbols.
If you turn this off, there will be no progression items in the game unless you turn on door shuffle."""
display_name = "Shuffle Symbols"
class ShuffleDoors(Toggle):
"""Many doors around the island will have their panels turned off initially.
You will need to find the items that power the panels to open those doors."""
class ShuffleLasers(Toggle):
"""If on, the 11 lasers are turned into items and will activate on their own upon receiving them.
Note: There is a visual bug that can occur with the Desert Laser. It does not affect gameplay - The Laser can still
be redirected as normal, for both applications of redirection."""
display_name = "Shuffle Lasers"
class ShuffleDoors(Choice):
"""If on, opening doors will require their respective "keys".
If set to "panels", those keys will unlock the panels on doors.
In "doors_simple" and "doors_complex", the doors will magically open by themselves upon receiving the key."""
display_name = "Shuffle Doors"
option_none = 0
option_panels = 1
option_doors_simple = 2
option_doors_complex = 3
option_max = 4
class ShuffleDiscardedPanels(Toggle):
"""Discarded Panels will have items on them.
Solving certain Discarded Panels may still be necessary even if off!"""
"""Add Discarded Panels into the location pool.
Solving certain Discarded Panels may still be necessary to beat the game, even if this is off."""
display_name = "Shuffle Discarded Panels"
@ -52,9 +63,10 @@ class ShuffleUncommonLocations(Toggle):
display_name = "Shuffle Uncommon Locations"
class ShuffleHardLocations(Toggle):
"""Adds some harder locations into the game, e.g. Mountain Secret Area panels"""
display_name = "Shuffle Hard Locations"
class ShufflePostgame(Toggle):
"""Adds locations into the pool that are guaranteed to be locked behind your goal. Use this if you don't play with
forfeit on victory."""
display_name = "Shuffle Postgame"
class VictoryCondition(Choice):
@ -103,16 +115,17 @@ class PuzzleSkipAmount(Range):
the_witness_options: Dict[str, type] = {
# "hard_mode": HardMode,
"shuffle_symbols": ShuffleSymbols,
"shuffle_doors": ShuffleDoors,
"shuffle_lasers": ShuffleLasers,
"disable_non_randomized_puzzles": DisableNonRandomizedPuzzles,
"shuffle_discarded_panels": ShuffleDiscardedPanels,
"shuffle_vault_boxes": ShuffleVaultBoxes,
"shuffle_uncommon": ShuffleUncommonLocations,
"shuffle_hard": ShuffleHardLocations,
"shuffle_postgame": ShufflePostgame,
"victory_condition": VictoryCondition,
"trap_percentage": TrapPercentage,
"early_secret_area": EarlySecretArea,
# "shuffle_symbols": ShuffleSymbols,
# "shuffle_doors": ShuffleDoors,
"mountain_lasers": MountainLasers,
"challenge_lasers": ChallengeLasers,
"puzzle_skip_amount": PuzzleSkipAmount,

View File

@ -1,6 +1,8 @@
Progression:
0 - Dots
1 - Colored Dots
2 - Full Dots
3 - Invisible Dots
5 - Sound Dots
10 - Symmetry
20 - Triangles
@ -12,6 +14,7 @@ Progression:
61 - Stars + Same Colored Symbol
71 - Black/White Squares
72 - Colored Squares
80 - Arrows
Usefuls:
101 - Functioning Brain - False
@ -23,3 +26,173 @@ Boosts:
Traps:
600 - Slowness
610 - Power Surge
Doors:
1100 - Glass Factory Entry Door (Panel) - 0x01A54
1105 - Door to Symmetry Island Lower (Panel) - 0x000B0
1107 - Door to Symmetry Island Upper (Panel) - 0x1C349
1110 - Door to Desert Flood Light Room (Panel) - 0x0C339
1111 - Desert Flood Room Flood Controls (Panel) - 0x1C2DF,0x1831E,0x1C260,0x1831C,0x1C2F3,0x1831D,0x1C2B1,0x1831B
1119 - Quarry Door to Mill (Panel) - 0x01E5A,0x01E59
1120 - Quarry Mill Ramp Controls (Panel) - 0x03678,0x03676
1122 - Quarry Mill Elevator Controls (Panel) - 0x03679,0x03675
1125 - Quarry Boathouse Ramp Height Control (Panel) - 0x03852
1127 - Quarry Boathouse Ramp Horizontal Control (Panel) - 0x03858
1131 - Shadows Door Timer (Panel) - 0x334DB,0x334DC
1150 - Monastery Entry Door Left (Panel) - 0x00B10
1151 - Monastery Entry Door Right (Panel) - 0x00C92
1162 - Town Door to RGB House (Panel) - 0x28998
1163 - Town Door to Church (Panel) - 0x28A0D
1166 - Town Maze Panel (Drop-Down Staircase) (Panel) - 0x28A79
1169 - Windmill Door (Panel) - 0x17F5F
1200 - Treehouse First & Second Doors (Panel) - 0x0288C,0x02886
1202 - Treehouse Third Door (Panel) - 0x0A182
1205 - Treehouse Laser House Door Timer (Panel) - 0x2700B,0x334DC
1208 - Treehouse Shortcut Drop-Down Bridge (Panel) - 0x17CBC
1175 - Jungle Popup Wall (Panel) - 0x17CAB
1180 - Bunker Entry Door (Panel) - 0x17C2E
1183 - Inside Bunker Door to Bunker Proper (Panel) - 0x0A099
1186 - Bunker Elevator Control (Panel) - 0x0A079
1190 - Swamp Entry Door (Panel) - 0x0056E
1192 - Swamp Sliding Bridge (Panel) - 0x00609,0x18488
1195 - Swamp Rotating Bridge (Panel) - 0x181F5
1197 - Swamp Maze Control (Panel) - 0x17C0A
1310 - Boat - 0x17CDF,0x17CC8,0x17CA6,0x09DB8,0x17C95,0x0A054
1400 - Caves Mountain Shortcut - 0x2D73F
1500 - Symmetry Laser - 0x00509
1501 - Desert Laser - 0x012FB,0x01317
1502 - Quarry Laser - 0x01539
1503 - Shadows Laser - 0x181B3
1504 - Keep Laser - 0x014BB
1505 - Monastery Laser - 0x17C65
1506 - Town Laser - 0x032F9
1507 - Jungle Laser - 0x00274
1508 - Bunker Laser - 0x0C2B2
1509 - Swamp Laser - 0x00BF6
1510 - Treehouse Laser - 0x028A4
1600 - Outside Tutorial Optional Door - 0x03BA2
1603 - Outside Tutorial Outpost Entry Door - 0x0A170
1606 - Outside Tutorial Outpost Exit Door - 0x04CA3
1609 - Glass Factory Entry Door - 0x01A29
1612 - Glass Factory Back Wall - 0x0D7ED
1615 - Symmetry Island Lower Door - 0x17F3E
1618 - Symmetry Island Upper Door - 0x18269
1619 - Orchard Middle Gate - 0x03307
1620 - Orchard Final Gate - 0x03313
1621 - Desert Door to Flood Light Room - 0x09FEE
1624 - Desert Door to Pond Room - 0x0C2C3
1627 - Desert Door to Water Levels Room - 0x0A24B
1630 - Desert Door to Elevator Room - 0x0C316
1633 - Quarry Main Entry 1 - 0x09D6F
1636 - Quarry Main Entry 2 - 0x17C07
1639 - Quarry Door to Mill - 0x02010
1642 - Quarry Mill Side Door - 0x275FF
1645 - Quarry Mill Rooftop Shortcut - 0x17CE8
1648 - Quarry Mill Stairs - 0x0368A
1651 - Quarry Boathouse Boat Staircase - 0x2769B,0x27163
1653 - Quarry Boathouse First Barrier - 0x17C50
1654 - Quarry Boathouse Shortcut - 0x3865F
1656 - Shadows Timed Door - 0x19B24
1657 - Shadows Laser Room Right Door - 0x194B2
1660 - Shadows Laser Room Left Door - 0x19665
1663 - Shadows Barrier to Quarry - 0x19865,0x0A2DF
1666 - Shadows Barrier to Ledge - 0x1855B,0x19ADE
1669 - Keep Hedge Maze 1 Exit Door - 0x01954
1672 - Keep Pressure Plates 1 Exit Door - 0x01BEC
1675 - Keep Hedge Maze 2 Shortcut - 0x018CE
1678 - Keep Hedge Maze 2 Exit Door - 0x019D8
1681 - Keep Hedge Maze 3 Shortcut - 0x019B5
1684 - Keep Hedge Maze 3 Exit Door - 0x019E6
1687 - Keep Hedge Maze 4 Shortcut - 0x0199A
1690 - Keep Hedge Maze 4 Exit Door - 0x01A0E
1693 - Keep Pressure Plates 2 Exit Door - 0x01BEA
1696 - Keep Pressure Plates 3 Exit Door - 0x01CD5
1699 - Keep Pressure Plates 4 Exit Door - 0x01D40
1702 - Keep Shortcut to Shadows - 0x09E3D
1705 - Keep Tower Shortcut - 0x04F8F
1708 - Monastery Shortcut - 0x0364E
1711 - Monastery Inner Door - 0x0C128
1714 - Monastery Outer Door - 0x0C153
1717 - Monastery Door to Garden - 0x03750
1718 - Town Cargo Box Door - 0x0A0C9
1720 - Town Wooden Roof Staircase - 0x034F5
1723 - Town Tinted Door to RGB House - 0x28A61
1726 - Town Door to Church - 0x03BB0
1729 - Town Maze Staircase - 0x28AA2
1732 - Town Windmill Door - 0x1845B
1735 - Town RGB House Staircase - 0x2897B
1738 - Town Tower Blue Panels Door - 0x27798
1741 - Town Tower Lattice Door - 0x27799
1744 - Town Tower Environmental Set Door - 0x2779A
1747 - Town Tower Wooden Roof Set Door - 0x2779C
1750 - Theater Entry Door - 0x17F88
1753 - Theater Exit Door Left - 0x0A16D
1756 - Theater Exit Door Right - 0x3CCDF
1759 - Jungle Bamboo Shortcut to River - 0x3873B
1760 - Jungle Popup Wall - 0x1475B
1762 - River Shortcut to Monastery Garden - 0x0CF2A
1765 - Bunker Bunker Entry Door - 0x0C2A4
1768 - Bunker Tinted Glass Door - 0x17C79
1771 - Bunker Door to Ultraviolet Room - 0x0C2A3
1774 - Bunker Door to Elevator - 0x0A08D
1777 - Swamp Entry Door - 0x00C1C
1780 - Swamp Door to Broken Shapers - 0x184B7
1783 - Swamp Platform Shortcut Door - 0x38AE6
1786 - Swamp Cyan Water Pump - 0x04B7F
1789 - Swamp Door to Rotated Shapers - 0x18507
1792 - Swamp Red Water Pump - 0x183F2
1795 - Swamp Red Underwater Exit - 0x305D5
1798 - Swamp Blue Water Pump - 0x18482
1801 - Swamp Purple Water Pump - 0x0A1D6
1804 - Swamp Near Laser Shortcut - 0x2D880
1807 - Treehouse First Door - 0x0C309
1810 - Treehouse Second Door - 0x0C310
1813 - Treehouse Beyond Yellow Bridge Door - 0x0A181
1816 - Treehouse Drawbridge - 0x0C32D
1819 - Treehouse Timed Door to Laser House - 0x0C323
1822 - Inside Mountain First Layer Exit Door - 0x09E54
1825 - Inside Mountain Second Layer Staircase Near - 0x09FFB
1828 - Inside Mountain Second Layer Exit Door - 0x09EDD
1831 - Inside Mountain Second Layer Staircase Far - 0x09E07
1834 - Inside Mountain Giant Puzzle Exit Door - 0x09F89
1840 - Inside Mountain Door to Final Room - 0x0C141
1843 - Inside Mountain Bottom Layer Rock - 0x17F33
1846 - Inside Mountain Door to Secret Area - 0x2D77D
1849 - Caves Pillar Door - 0x019A5
1855 - Caves Swamp Shortcut - 0x2D859
1858 - Challenge Entry Door - 0x0A19A
1861 - Challenge Door to Theater Walkway - 0x0348A
1864 - Theater Walkway Door to Windmill Interior - 0x27739
1867 - Theater Walkway Door to Desert Elevator Room - 0x27263
1870 - Theater Walkway Door to Town - 0x09E87
1903 - Outside Tutorial Outpost Doors - 0x03BA2,0x0A170,0x04CA3
1906 - Symmetry Island Doors - 0x17F3E,0x18269
1909 - Orchard Gates - 0x03313,0x03307
1912 - Desert Doors - 0x09FEE,0x0C2C3,0x0A24B,0x0C316
1915 - Quarry Main Entry - 0x09D6F
1918 - Quarry Mill Shortcuts - 0x17C07,0x17CE8,0x0368A
1921 - Quarry Boathouse Barriers - 0x17C50,0x3865F
1924 - Shadows Laser Room Door - 0x194B2,0x19665
1927 - Shadows Barriers - 0x19865,0x0A2DF,0x1855B,0x19ADE
1930 - Keep Hedge Maze Doors - 0x01954,0x018CE,0x019D8,0x019B5,0x019E6,0x0199A,0x01A0E
1933 - Keep Pressure Plates Doors - 0x01BEC,0x01BEA,0x01CD5,0x01D40
1936 - Keep Shortcuts - 0x09E3D,0x04F8F
1939 - Monastery Entry Door - 0x0C128,0x0C153
1942 - Monastery Shortcuts - 0x0364E,0x03750
1945 - Town Doors - 0x0A0C9,0x034F5,0x28A61,0x03BB0,0x28AA2,0x1845B,0x2897B
1948 - Town Tower Doors - 0x27798,0x27799,0x2779A,0x2779C
1951 - Theater Exit Door - 0x0A16D,0x3CCDF
1954 - Jungle & River Shortcuts - 0x3873B,0x0CF2A
1957 - Bunker Doors - 0x0C2A4,0x17C79,0x0C2A3,0x0A08D
1960 - Swamp Doors - 0x00C1C,0x184B7,0x38AE6,0x18507
1963 - Swamp Water Pumps - 0x04B7F,0x183F2,0x305D5,0x18482,0x0A1D6
1966 - Treehouse Entry Doors - 0x0C309,0x0C310,0x0A181
1975 - Inside Mountain Second Layer Stairs & Doors - 0x09FFB,0x09EDD,0x09E07
1978 - Inside Mountain Bottom Layer Doors to Caves - 0x17F33,0x2D77D
1981 - Caves Doors to Challenge - 0x019A5,0x0A19A
1984 - Caves Exits to Main Island - 0x2D859,0x2D73F
1987 - Theater Walkway Doors - 0x27739,0x27263,0x09E87

File diff suppressed because it is too large Load Diff

View File

@ -35,7 +35,7 @@ class WitnessWorld(World):
"""
game = "The Witness"
topology_present = False
data_version = 2
data_version = 5
static_logic = StaticWitnessLogic()
static_locat = StaticWitnessLocations()
@ -53,11 +53,18 @@ class WitnessWorld(World):
'seed': self.world.random.randint(0, 1000000),
'victory_location': int(self.player_logic.VICTORY_LOCATION, 16),
'panelhex_to_id': self.locat.CHECK_PANELHEX_TO_ID,
'doorhex_to_id': self.player_logic.DOOR_DICT_FOR_CLIENT,
'door_connections_to_sever': self.player_logic.DOOR_CONNECTIONS_TO_SEVER
'item_id_to_door_hexes': self.items.ITEM_ID_TO_DOOR_HEX,
'door_hexes': self.items.DOORS,
'symbols_not_in_the_game': self.items.SYMBOLS_NOT_IN_THE_GAME
}
def generate_early(self):
if not (is_option_enabled(self.world, self.player, "shuffle_symbols")
or get_option_value(self.world, self.player, "shuffle_doors")
or is_option_enabled(self.world, self.player, "shuffle_lasers")):
raise Exception("This Witness world doesn't have any progression items. Please turn on Symbol Shuffle, Door"
" Shuffle or Laser Shuffle")
self.player_logic = WitnessPlayerLogic(self.world, self.player)
self.locat = WitnessPlayerLocations(self.world, self.player, self.player_logic)
self.items = WitnessPlayerItems(self.locat, self.world, self.player, self.player_logic)
@ -78,11 +85,11 @@ class WitnessWorld(World):
less_junk = 0
# Put good item on first check if symbol shuffle is on
# symbols = is_option_enabled(self.world, self.player, "shuffle_symbols")
symbols = True
symbols = is_option_enabled(self.world, self.player, "shuffle_symbols")
if symbols:
random_good_item = self.world.random.choice(self.items.GOOD_ITEMS)
first_check = self.world.get_location(
"Tutorial Gate Open", self.player
)
@ -91,6 +98,10 @@ class WitnessWorld(World):
less_junk = 1
for item in self.player_logic.STARTING_INVENTORY:
self.world.push_precollected(items_by_name[item])
pool.remove(items_by_name[item])
for item in self.items.EXTRA_AMOUNTS:
witness_item = self.create_item(item)
for i in range(0, self.items.EXTRA_AMOUNTS[item]):

View File

@ -51,12 +51,15 @@ class StaticWitnessItems:
def __init__(self):
item_tab = dict()
for item in StaticWitnessLogic.ALL_SYMBOL_ITEMS.union(StaticWitnessLogic.ALL_DOOR_ITEMS):
for item in StaticWitnessLogic.ALL_SYMBOL_ITEMS:
if item[0] == "11 Lasers" or item == "7 Lasers":
continue
item_tab[item[0]] = ItemData(158000 + item[1], True, False)
for item in StaticWitnessLogic.ALL_DOOR_ITEMS:
item_tab[item[0]] = ItemData(158000 + item[1], True, False)
for item in StaticWitnessLogic.ALL_TRAPS:
item_tab[item[0]] = ItemData(
158000 + item[1], False, False, True
@ -89,23 +92,39 @@ class WitnessPlayerItems:
self.ITEM_TABLE = copy.copy(StaticWitnessItems.ALL_ITEM_TABLE)
self.PROGRESSION_TABLE = dict()
self.ITEM_ID_TO_DOOR_HEX = dict()
self.DOORS = set()
self.SYMBOLS_NOT_IN_THE_GAME = set()
self.EXTRA_AMOUNTS = {
"Functioning Brain": 1,
"Puzzle Skip": get_option_value(world, player, "puzzle_skip_amount")
}
for item in StaticWitnessLogic.ALL_SYMBOL_ITEMS.union(StaticWitnessLogic.ALL_DOOR_ITEMS):
if item not in player_logic.PROG_ITEMS_ACTUALLY_IN_THE_GAME:
if item[0] not in player_logic.PROG_ITEMS_ACTUALLY_IN_THE_GAME:
del self.ITEM_TABLE[item[0]]
if item in StaticWitnessLogic.ALL_SYMBOL_ITEMS:
self.SYMBOLS_NOT_IN_THE_GAME.add(StaticWitnessItems.ALL_ITEM_TABLE[item[0]].code)
else:
self.PROGRESSION_TABLE[item[0]] = self.ITEM_TABLE[item[0]]
for entity_hex, items in player_logic.DOOR_ITEMS_BY_ID.items():
entity_hex_int = int(entity_hex, 16)
self.DOORS.add(entity_hex_int)
for item in items:
item_id = StaticWitnessItems.ALL_ITEM_TABLE[item].code
self.ITEM_ID_TO_DOOR_HEX.setdefault(item_id, set()).add(entity_hex_int)
symbols = is_option_enabled(world, player, "shuffle_symbols")
if "shuffle_symbols" not in the_witness_options.keys():
symbols = True
doors = is_option_enabled(world, player, "shuffle_doors")
doors = get_option_value(world, player, "shuffle_doors")
if doors and symbols:
self.GOOD_ITEMS = [
@ -117,10 +136,10 @@ class WitnessPlayerItems:
"Shapers", "Symmetry"
]
if is_option_enabled(world, player, "shuffle_discarded_panels"):
self.GOOD_ITEMS.append("Triangles")
if not is_option_enabled(world, player, "disable_non_randomized_puzzles"):
self.GOOD_ITEMS.append("Colored Squares")
if is_option_enabled(world, player, "shuffle_discarded_panels"):
self.GOOD_ITEMS.append("Triangles")
if not is_option_enabled(world, player, "disable_non_randomized_puzzles"):
self.GOOD_ITEMS.append("Colored Squares")
for event_location in locat.EVENT_LOCATION_TABLE:
location = player_logic.EVENT_ITEM_PAIRS[event_location]

View File

@ -2,7 +2,7 @@
Defines constants for different types of locations in the game
"""
from .Options import is_option_enabled
from .Options import is_option_enabled, get_option_value
from .player_logic import StaticWitnessLogic, WitnessPlayerLogic
@ -42,7 +42,7 @@ class StaticWitnessLocations:
"Symmetry Island Colored Dots 6",
"Symmetry Island Fading Lines 7",
"Symmetry Island Scenery Outlines 5",
"Symmetry Island Laser",
"Symmetry Island Laser Panel",
"Orchard Apple Tree 5",
@ -52,7 +52,7 @@ class StaticWitnessLocations:
"Desert Artificial Light Reflection 3",
"Desert Pond Reflection 5",
"Desert Flood Reflection 6",
"Desert Laser",
"Desert Laser Panel",
"Quarry Mill Eraser and Dots 6",
"Quarry Mill Eraser and Squares 8",
@ -63,34 +63,34 @@ class StaticWitnessLocations:
"Quarry Boathouse Stars & Eraser & Shapers 2",
"Quarry Boathouse Stars & Eraser & Shapers 5",
"Quarry Discard",
"Quarry Laser",
"Quarry Laser Panel",
"Shadows Lower Avoid 8",
"Shadows Environmental Avoid 8",
"Shadows Follow 5",
"Shadows Laser",
"Shadows Laser Panel",
"Keep Hedge Maze 4",
"Keep Pressure Plates 4",
"Keep Discard",
"Keep Laser Hedges",
"Keep Laser Pressure Plates",
"Keep Laser Panel Hedges",
"Keep Laser Panel Pressure Plates",
"Shipwreck Vault Box",
"Shipwreck Discard",
"Monastery Rhombic Avoid 3",
"Monastery Branch Follow 2",
"Monastery Laser",
"Monastery Laser Panel",
"Town Cargo Box Discard",
"Town Hexagonal Reflection",
"Town Square Avoid",
"Town Church Lattice",
"Town Rooftop Discard",
"Town Symmetry Squares 5 + Dots",
"Town Full Dot Grid Shapers 5",
"Town Shapers & Dots & Eraser",
"Town Laser",
"Town Laser Panel",
"Theater Discard",
@ -98,7 +98,7 @@ class StaticWitnessLocations:
"Jungle Waves 3",
"Jungle Waves 7",
"Jungle Popup Wall 6",
"Jungle Laser",
"Jungle Laser Panel",
"River Vault Box",
@ -106,7 +106,7 @@ class StaticWitnessLocations:
"Bunker Drawn Squares 9",
"Bunker Drawn Squares through Tinted Glass 3",
"Bunker Drop-Down Door Squares 2",
"Bunker Laser",
"Bunker Laser Panel",
"Swamp Seperatable Shapers 6",
"Swamp Combinable Shapers 8",
@ -117,7 +117,7 @@ class StaticWitnessLocations:
"Swamp Red Underwater Negative Shapers 4",
"Swamp More Rotated Shapers 4",
"Swamp Blue Underwater Negative Shapers 5",
"Swamp Laser",
"Swamp Laser Panel",
"Treehouse Yellow Bridge 9",
"Treehouse First Purple Bridge 5",
@ -125,21 +125,12 @@ class StaticWitnessLocations:
"Treehouse Green Bridge 7",
"Treehouse Green Bridge Discard",
"Treehouse Left Orange Bridge 15",
"Treehouse Burned House Discard",
"Treehouse Burnt House Discard",
"Treehouse Right Orange Bridge 12",
"Treehouse Laser",
"Treehouse Laser Panel",
"Mountaintop Discard",
"Mountaintop Vault Box",
"Inside Mountain Obscured Vision 5",
"Inside Mountain Moving Background 7",
"Inside Mountain Physically Obstructed 3",
"Inside Mountain Angled Inside Trash 2",
"Inside Mountain Color Cycle 5",
"Inside Mountain Same Solution 6",
"Inside Mountain Elevator Discard",
"Inside Mountain Giant Puzzle",
}
UNCOMMON_LOCATIONS = {
@ -156,35 +147,53 @@ class StaticWitnessLocations:
"Swamp Underwater Back Optional",
}
HARD_LOCATIONS = {
"Inside Mountain Secret Area Dot Grid Triangles 4",
"Inside Mountain Secret Area Symmetry Triangles",
"Inside Mountain Secret Area Stars & Squares and Triangles 2",
"Inside Mountain Secret Area Shapers and Triangles 2",
"Inside Mountain Secret Area Symmetry Shapers",
"Inside Mountain Secret Area Broken and Negative Shapers",
"Inside Mountain Secret Area Broken Shapers",
CAVES_LOCATIONS = {
"Inside Mountain Caves Dot Grid Triangles 4",
"Inside Mountain Caves Symmetry Triangles",
"Inside Mountain Caves Stars & Squares and Triangles 2",
"Inside Mountain Caves Shapers and Triangles 2",
"Inside Mountain Caves Symmetry Shapers",
"Inside Mountain Caves Broken and Negative Shapers",
"Inside Mountain Caves Broken Shapers",
"Inside Mountain Secret Area Rainbow Squares",
"Inside Mountain Secret Area Squares & Stars and Colored Eraser",
"Inside Mountain Secret Area Rotated Broken Shapers",
"Inside Mountain Secret Area Stars and Squares",
"Inside Mountain Secret Area Lone Pillar",
"Inside Mountain Secret Area Wooden Beam Shapers",
"Inside Mountain Secret Area Wooden Beam Squares and Shapers",
"Inside Mountain Secret Area Wooden Beam Stars and Squares",
"Inside Mountain Secret Area Wooden Beam Shapers and Stars",
"Inside Mountain Secret Area Upstairs Invisible Dots 8",
"Inside Mountain Secret Area Upstairs Invisible Dot Symmetry 3",
"Inside Mountain Secret Area Upstairs Dot Grid Negative Shapers",
"Inside Mountain Secret Area Upstairs Dot Grid Rotated Shapers",
"Inside Mountain Caves Rainbow Squares",
"Inside Mountain Caves Squares & Stars and Colored Eraser",
"Inside Mountain Caves Rotated Broken Shapers",
"Inside Mountain Caves Stars and Squares",
"Inside Mountain Caves Lone Pillar",
"Inside Mountain Caves Wooden Beam Shapers",
"Inside Mountain Caves Wooden Beam Squares and Shapers",
"Inside Mountain Caves Wooden Beam Stars and Squares",
"Inside Mountain Caves Wooden Beam Shapers and Stars",
"Inside Mountain Caves Upstairs Invisible Dots 8",
"Inside Mountain Caves Upstairs Invisible Dot Symmetry 3",
"Inside Mountain Caves Upstairs Dot Grid Negative Shapers",
"Inside Mountain Caves Upstairs Dot Grid Rotated Shapers",
"Challenge Vault Box",
"Theater Walkway Vault Box",
"Inside Mountain Bottom Layer Discard",
"Theater Challenge Video",
}
MOUNTAIN_UNREACHABLE_FROM_BEHIND = {
"Mountaintop Trap Door Triple Exit",
"Inside Mountain Obscured Vision 5",
"Inside Mountain Moving Background 7",
"Inside Mountain Physically Obstructed 3",
"Inside Mountain Angled Inside Trash 2",
"Inside Mountain Color Cycle 5",
"Inside Mountain Same Solution 6",
}
MOUNTAIN_REACHABLE_FROM_BEHIND = {
"Inside Mountain Elevator Discard",
"Inside Mountain Giant Puzzle",
"Inside Mountain Final Room Left Pillar 4",
"Inside Mountain Final Room Right Pillar 4",
}
ALL_LOCATIONS_TO_ID = dict()
@staticmethod
@ -193,12 +202,7 @@ class StaticWitnessLocations:
Calculates the location ID for any given location
"""
panel_offset = StaticWitnessLogic.CHECKS_BY_HEX[chex]["idOffset"]
type_offset = StaticWitnessLocations.TYPE_OFFSETS[
StaticWitnessLogic.CHECKS_BY_HEX[chex]["panelType"]
]
return StaticWitnessLocations.ID_START + panel_offset + type_offset
return StaticWitnessLogic.CHECKS_BY_HEX[chex]["id"]
@staticmethod
def get_event_name(panel_hex):
@ -213,6 +217,7 @@ class StaticWitnessLocations:
all_loc_to_id = {
panel_obj["checkName"]: self.get_id(chex)
for chex, panel_obj in StaticWitnessLogic.CHECKS_BY_HEX.items()
if panel_obj["id"]
}
all_loc_to_id = dict(
@ -229,12 +234,34 @@ class WitnessPlayerLocations:
"""
def __init__(self, world, player, player_logic: WitnessPlayerLogic):
"""Defines locations AFTER logic changes due to options"""
self.PANEL_TYPES_TO_SHUFFLE = {"General", "Laser"}
self.CHECK_LOCATIONS = (
StaticWitnessLocations.GENERAL_LOCATIONS
)
"""Defines locations AFTER logic changes due to options"""
doors = get_option_value(world, player, "shuffle_doors")
earlyutm = is_option_enabled(world, player, "early_secret_area")
victory = get_option_value(world, player, "victory_condition")
lasers = get_option_value(world, player, "challenge_lasers")
laser_shuffle = get_option_value(world, player, "shuffle_lasers")
postgame = set()
postgame = postgame | StaticWitnessLocations.CAVES_LOCATIONS
postgame = postgame | StaticWitnessLocations.MOUNTAIN_REACHABLE_FROM_BEHIND
postgame = postgame | StaticWitnessLocations.MOUNTAIN_UNREACHABLE_FROM_BEHIND
self.CHECK_LOCATIONS = self.CHECK_LOCATIONS | postgame
if earlyutm or doors >= 2 or (victory == 1 and (lasers <= 11 or laser_shuffle)):
postgame -= StaticWitnessLocations.CAVES_LOCATIONS
if doors >= 2:
postgame -= StaticWitnessLocations.MOUNTAIN_REACHABLE_FROM_BEHIND
if victory != 2:
postgame -= StaticWitnessLocations.MOUNTAIN_UNREACHABLE_FROM_BEHIND
if is_option_enabled(world, player, "shuffle_discarded_panels"):
self.PANEL_TYPES_TO_SHUFFLE.add("Discard")
@ -245,18 +272,11 @@ class WitnessPlayerLocations:
if is_option_enabled(world, player, "shuffle_uncommon"):
self.CHECK_LOCATIONS = self.CHECK_LOCATIONS | StaticWitnessLocations.UNCOMMON_LOCATIONS
if is_option_enabled(world, player, "shuffle_hard"):
self.CHECK_LOCATIONS = self.CHECK_LOCATIONS | StaticWitnessLocations.HARD_LOCATIONS
if is_option_enabled(world, player, "shuffle_symbols") and is_option_enabled(world, player, "shuffle_doors"):
if is_option_enabled(world, player, "disable_non_randomized_puzzles"):
# This particular combination of logic settings leads to logic so restrictive that generation can fail
# Hence, we add some extra sphere 0 locations
self.CHECK_LOCATIONS = self.CHECK_LOCATIONS | StaticWitnessLocations.EXTRA_LOCATIONS
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 = self.CHECK_LOCATIONS - {
StaticWitnessLogic.CHECKS_BY_HEX[check_hex]["checkName"]
for check_hex in player_logic.COMPLETELY_DISABLED_CHECKS
@ -272,7 +292,7 @@ class WitnessPlayerLocations:
)
event_locations = {
p for p in player_logic.NECESSARY_EVENT_PANELS
p for p in player_logic.EVENT_PANELS
}
self.EVENT_LOCATION_TABLE = {

View File

@ -18,22 +18,15 @@ When the world has parsed its options, a second function is called to finalize t
import copy
from BaseClasses import MultiWorld
from .static_logic import StaticWitnessLogic
from .utils import define_new_region, get_disable_unrandomized_list, parse_lambda, get_early_utm_list
from .utils import define_new_region, get_disable_unrandomized_list, parse_lambda, get_early_utm_list, \
get_symbol_shuffle_list, get_door_panel_shuffle_list, get_doors_complex_list, get_doors_max_list, \
get_doors_simple_list, get_laser_shuffle
from .Options import is_option_enabled, get_option_value, the_witness_options
class WitnessPlayerLogic:
"""WITNESS LOGIC CLASS"""
def update_door_dict(self, panel_hex):
item_id = StaticWitnessLogic.ALL_DOOR_ITEM_IDS_BY_HEX.get(panel_hex)
if item_id is None:
return
self.DOOR_DICT_FOR_CLIENT[panel_hex] = item_id
self.DOOR_CONNECTIONS_TO_SEVER.update(StaticWitnessLogic.CONNECTIONS_TO_SEVER_BY_DOOR_HEX[panel_hex])
def reduce_req_within_region(self, panel_hex):
"""
Panels in this game often only turn on when other panels are solved.
@ -43,35 +36,42 @@ class WitnessPlayerLogic:
Panels outside of the same region will still be checked manually.
"""
these_items = self.DEPENDENT_REQUIREMENTS_BY_HEX[panel_hex]["items"]
check_obj = StaticWitnessLogic.CHECKS_BY_HEX[panel_hex]
real_items = {item[0] for item in self.PROG_ITEMS_ACTUALLY_IN_THE_GAME}
these_items = frozenset({frozenset()})
if check_obj["id"]:
these_items = self.DEPENDENT_REQUIREMENTS_BY_HEX[panel_hex]["items"]
these_items = frozenset({
subset.intersection(real_items)
subset.intersection(self.PROG_ITEMS_ACTUALLY_IN_THE_GAME)
for subset in these_items
})
if panel_hex in self.DOOR_ITEMS_BY_ID:
door_items = frozenset({frozenset([item]) for item in self.DOOR_ITEMS_BY_ID[panel_hex]})
all_options = set()
for items_option in these_items:
for dependentItem in door_items:
all_options.add(items_option.union(dependentItem))
return frozenset(all_options)
these_panels = self.DEPENDENT_REQUIREMENTS_BY_HEX[panel_hex]["panels"]
if StaticWitnessLogic.DOOR_NAMES_BY_HEX.get(panel_hex) in real_items:
self.update_door_dict(panel_hex)
these_panels = frozenset({frozenset()})
if these_panels == frozenset({frozenset()}):
return these_items
all_options = set()
check_obj = StaticWitnessLogic.CHECKS_BY_HEX[panel_hex]
for option in these_panels:
dependent_items_for_option = frozenset({frozenset()})
for option_panel in option:
new_items = set()
dep_obj = StaticWitnessLogic.CHECKS_BY_HEX.get(option_panel)
if option_panel in {"7 Lasers", "11 Lasers"}:
new_items = frozenset({frozenset([option_panel])})
# If a panel turns on when a panel in a different region turns on,
@ -101,8 +101,34 @@ class WitnessPlayerLogic:
return frozenset(all_options)
def make_single_adjustment(self, adj_type, line):
from . import StaticWitnessItems
"""Makes a single logic adjustment based on additional logic file"""
if adj_type == "Items":
if line not in StaticWitnessItems.ALL_ITEM_TABLE:
raise RuntimeError("Item \"" + line + "\" does not exit.")
self.PROG_ITEMS_ACTUALLY_IN_THE_GAME.add(line)
if line in StaticWitnessLogic.ALL_DOOR_ITEMS_AS_DICT:
panel_hexes = StaticWitnessLogic.ALL_DOOR_ITEMS_AS_DICT[line][2]
for panel_hex in panel_hexes:
self.DOOR_ITEMS_BY_ID.setdefault(panel_hex, set()).add(line)
return
if adj_type == "Remove Items":
self.PROG_ITEMS_ACTUALLY_IN_THE_GAME.discard(line)
if line in StaticWitnessLogic.ALL_DOOR_ITEMS_AS_DICT:
panel_hexes = StaticWitnessLogic.ALL_DOOR_ITEMS_AS_DICT[line][2]
for panel_hex in panel_hexes:
if panel_hex in self.DOOR_ITEMS_BY_ID:
self.DOOR_ITEMS_BY_ID[panel_hex].discard(line)
if adj_type == "Starting Inventory":
self.STARTING_INVENTORY.add(line)
if adj_type == "Event Items":
line_split = line.split(" - ")
hex_set = line_split[1].split(",")
@ -130,18 +156,20 @@ class WitnessPlayerLogic:
if adj_type == "Requirement Changes":
line_split = line.split(" - ")
required_items = parse_lambda(line_split[2])
items_actually_in_the_game = {item[0] for item in StaticWitnessLogic.ALL_SYMBOL_ITEMS}
required_items = frozenset(
subset.intersection(items_actually_in_the_game)
for subset in required_items
)
requirement = {
"panels": parse_lambda(line_split[1]),
"items": required_items
}
if len(line_split) > 2:
required_items = parse_lambda(line_split[2])
items_actually_in_the_game = {item[0] for item in StaticWitnessLogic.ALL_SYMBOL_ITEMS}
required_items = frozenset(
subset.intersection(items_actually_in_the_game)
for subset in required_items
)
requirement["items"] = required_items
self.DEPENDENT_REQUIREMENTS_BY_HEX[line_split[0]] = requirement
return
@ -151,11 +179,6 @@ class WitnessPlayerLogic:
self.COMPLETELY_DISABLED_CHECKS.add(panel_hex)
self.PROG_ITEMS_ACTUALLY_IN_THE_GAME = {
item for item in self.PROG_ITEMS_ACTUALLY_IN_THE_GAME
if item[0] != StaticWitnessLogic.DOOR_NAMES_BY_HEX.get(panel_hex)
}
return
if adj_type == "Region Changes":
@ -189,18 +212,25 @@ class WitnessPlayerLogic:
adjustment_linesets_in_order.append(get_disable_unrandomized_list())
if is_option_enabled(world, player, "shuffle_symbols") or "shuffle_symbols" not in the_witness_options.keys():
self.PROG_ITEMS_ACTUALLY_IN_THE_GAME.update(StaticWitnessLogic.ALL_SYMBOL_ITEMS)
adjustment_linesets_in_order.append(get_symbol_shuffle_list())
if is_option_enabled(world, player, "shuffle_doors"):
self.PROG_ITEMS_ACTUALLY_IN_THE_GAME.update(StaticWitnessLogic.ALL_DOOR_ITEMS)
if get_option_value(world, player, "shuffle_doors") == 1:
adjustment_linesets_in_order.append(get_door_panel_shuffle_list())
if get_option_value(world, player, "shuffle_doors") == 2:
adjustment_linesets_in_order.append(get_doors_simple_list())
if get_option_value(world, player, "shuffle_doors") == 3:
adjustment_linesets_in_order.append(get_doors_complex_list())
if get_option_value(world, player, "shuffle_doors") == 4:
adjustment_linesets_in_order.append(get_doors_max_list())
if is_option_enabled(world, player, "early_secret_area"):
adjustment_linesets_in_order.append(get_early_utm_list())
else:
self.PROG_ITEMS_ACTUALLY_IN_THE_GAME = {
item for item in self.PROG_ITEMS_ACTUALLY_IN_THE_GAME
if item[0] != "Mountaintop River Shape Power On"
}
if is_option_enabled(world, player, "shuffle_lasers"):
adjustment_linesets_in_order.append(get_laser_shuffle())
for adjustment_lineset in adjustment_linesets_in_order:
current_adjustment_type = None
@ -233,62 +263,32 @@ class WitnessPlayerLogic:
pair = (name, self.EVENT_ITEM_NAMES[panel])
return pair
def _regions_are_adjacent(self, region1, region2):
for connection in self.CONNECTIONS_BY_REGION_NAME[region1]:
if connection[0] == region2:
return True
for connection in self.CONNECTIONS_BY_REGION_NAME[region2]:
if connection[0] == region1:
return True
return False
def make_event_panel_lists(self):
"""
Special event panel data structures
"""
for region_conn in self.CONNECTIONS_BY_REGION_NAME.values():
for region_and_option in region_conn:
for panelset in region_and_option[1]:
for panel in panelset:
self.EVENT_PANELS_FROM_REGIONS.add(panel)
self.ALWAYS_EVENT_NAMES_BY_HEX[self.VICTORY_LOCATION] = "Victory"
self.ORIGINAL_EVENT_PANELS.update(self.EVENT_PANELS_FROM_PANELS)
self.ORIGINAL_EVENT_PANELS.update(self.EVENT_PANELS_FROM_REGIONS)
for region_name, connections in self.CONNECTIONS_BY_REGION_NAME.items():
for connection in connections:
for panel_req in connection[1]:
for panel in panel_req:
if panel == "TrueOneWay":
continue
for panel in self.EVENT_PANELS_FROM_REGIONS:
for region_name, region in StaticWitnessLogic.ALL_REGIONS_BY_NAME.items():
for connection in self.CONNECTIONS_BY_REGION_NAME[region_name]:
connected_r = connection[0]
if connected_r not in StaticWitnessLogic.ALL_REGIONS_BY_NAME:
continue
if region_name == "Boat" or connected_r == "Boat":
continue
connected_r = StaticWitnessLogic.ALL_REGIONS_BY_NAME[connected_r]
if not any([panel in option for option in connection[1]]):
continue
if panel not in region["panels"] | connected_r["panels"]:
self.NECESSARY_EVENT_PANELS.add(panel)
if StaticWitnessLogic.CHECKS_BY_HEX[panel]["region"]["name"] != region_name:
self.EVENT_PANELS_FROM_REGIONS.add(panel)
for event_panel in self.EVENT_PANELS_FROM_PANELS:
for panel, panel_req in self.REQUIREMENTS_BY_HEX.items():
if any([event_panel in item_set for item_set in panel_req]):
region1 = StaticWitnessLogic.CHECKS_BY_HEX[panel]["region"]["name"]
region2 = StaticWitnessLogic.CHECKS_BY_HEX[event_panel]["region"]["name"]
if not self._regions_are_adjacent(region1, region2):
self.NECESSARY_EVENT_PANELS.add(event_panel)
self.EVENT_PANELS.update(self.EVENT_PANELS_FROM_PANELS)
self.EVENT_PANELS.update(self.EVENT_PANELS_FROM_REGIONS)
for always_hex, always_item in self.ALWAYS_EVENT_NAMES_BY_HEX.items():
self.ALWAYS_EVENT_HEX_CODES.add(always_hex)
self.NECESSARY_EVENT_PANELS.add(always_hex)
self.EVENT_PANELS.add(always_hex)
self.EVENT_ITEM_NAMES[always_hex] = always_item
for panel in self.NECESSARY_EVENT_PANELS:
for panel in self.EVENT_PANELS:
pair = self.make_event_item_pair(panel)
self.EVENT_ITEM_PAIRS[pair[0]] = pair[1]
@ -297,8 +297,8 @@ class WitnessPlayerLogic:
self.EVENT_PANELS_FROM_REGIONS = set()
self.PROG_ITEMS_ACTUALLY_IN_THE_GAME = set()
self.DOOR_DICT_FOR_CLIENT = dict()
self.DOOR_CONNECTIONS_TO_SEVER = set()
self.DOOR_ITEMS_BY_ID = dict()
self.STARTING_INVENTORY = set()
self.CONNECTIONS_BY_REGION_NAME = copy.copy(StaticWitnessLogic.STATIC_CONNECTIONS_BY_REGION_NAME)
self.DEPENDENT_REQUIREMENTS_BY_HEX = copy.copy(StaticWitnessLogic.STATIC_DEPENDENT_REQUIREMENTS_BY_HEX)
@ -306,8 +306,7 @@ class WitnessPlayerLogic:
# Determining which panels need to be events is a difficult process.
# At the end, we will have EVENT_ITEM_PAIRS for all the necessary ones.
self.ORIGINAL_EVENT_PANELS = set()
self.NECESSARY_EVENT_PANELS = set()
self.EVENT_PANELS = set()
self.EVENT_ITEM_PAIRS = dict()
self.ALWAYS_EVENT_HEX_CODES = set()
self.COMPLETELY_DISABLED_CHECKS = set()
@ -320,42 +319,63 @@ class WitnessPlayerLogic:
"0x00037": "Monastery Branch Panels Activate",
"0x0A079": "Access to Bunker Laser",
"0x0A3B5": "Door to Tutorial Discard Opens",
"0x00139": "Keep Hedges 2 Turns On",
"0x019DC": "Keep Hedges 3 Turns On",
"0x019E7": "Keep Hedges 4 Turns On",
"0x01D3F": "Keep Laser Panel (Pressure Plates) Activates",
"0x09F7F": "Mountain Access",
"0x0367C": "Quarry Laser Mill Requirement Met",
"0x009A1": "Swamp Rotating Bridge Near Side",
"0x009A1": "Swamp Rotated Shapers 1 Activates",
"0x00006": "Swamp Cyan Water Drains",
"0x00990": "Swamp Broken Shapers 1 Activates",
"0x0A8DC": "Lower Avoid 6 Activates",
"0x0000A": "Swamp More Rotated Shapers 1 Access",
"0x09ED8": "Inside Mountain Second Layer Both Light Bridges Solved",
"0x09E86": "Inside Mountain Second Layer Blue Bridge Access",
"0x09ED8": "Inside Mountain Second Layer Yellow Bridge Access",
"0x0A3D0": "Quarry Laser Boathouse Requirement Met",
"0x00596": "Swamp Red Water Drains",
"0x28B39": "Town Tower 4th Door Opens",
"0x00E3A": "Swamp Purple Water Drains",
"0x0343A": "Door to Symmetry Island Powers On",
"0xFFF00": "Inside Mountain Bottom Layer Discard Turns On"
"0xFFF00": "Inside Mountain Bottom Layer Discard Turns On",
"0x17CA6": "All Boat Panels Turn On",
"0x17CDF": "All Boat Panels Turn On",
"0x09DB8": "All Boat Panels Turn On",
"0x17C95": "All Boat Panels Turn On",
"0x03BB0": "Town Church Lattice Vision From Outside",
"0x28AC1": "Town Shapers & Dots & Eraser Turns On",
"0x28A69": "Town Tower 1st Door Opens",
"0x28ACC": "Town Tower 2nd Door Opens",
"0x28AD9": "Town Tower 3rd Door Opens",
"0x28B39": "Town Tower 4th Door Opens",
"0x03675": "Quarry Mill Ramp Activation From Above",
"0x03679": "Quarry Mill Lift Lowering While Standing On It",
"0x2FAF6": "Tutorial Gate Secret Solution Knowledge",
"0x079DF": "Town Hexagonal Reflection Turns On",
"0x17DA2": "Right Orange Bridge Fully Extended",
"0x19B24": "Shadows Lower Avoid Patterns Visible",
"0x2700B": "Open Door to Treehouse Laser House",
"0x00055": "Orchard Apple Trees 4 Turns On",
}
self.ALWAYS_EVENT_NAMES_BY_HEX = {
"0x0360D": "Symmetry Laser Activation",
"0x03608": "Desert Laser Activation",
"0x00509": "Symmetry Laser Activation",
"0x012FB": "Desert Laser Activation",
"0x09F98": "Desert Laser Redirection",
"0x03612": "Quarry Laser Activation",
"0x19650": "Shadows Laser Activation",
"0x0360E": "Keep Laser Activation",
"0x03317": "Keep Laser Activation",
"0x17CA4": "Monastery Laser Activation",
"0x032F5": "Town Laser Activation",
"0x03616": "Jungle Laser Activation",
"0x09DE0": "Bunker Laser Activation",
"0x03615": "Swamp Laser Activation",
"0x03613": "Treehouse Laser Activation",
"0x01539": "Quarry Laser Activation",
"0x181B3": "Shadows Laser Activation",
"0x014BB": "Keep Laser Activation",
"0x17C65": "Monastery Laser Activation",
"0x032F9": "Town Laser Activation",
"0x00274": "Jungle Laser Activation",
"0x0C2B2": "Bunker Laser Activation",
"0x00BF6": "Swamp Laser Activation",
"0x028A4": "Treehouse Laser Activation",
"0x03535": "Shipwreck Video Pattern Knowledge",
"0x03542": "Mountain Video Pattern Knowledge",
"0x0339E": "Desert Video Pattern Knowledge",
"0x03481": "Tutorial Video Pattern Knowledge",
"0x03702": "Jungle Video Pattern Knowledge",
"0x2FAF6": "Theater Walkway Video Pattern Knowledge",
"0x0356B": "Challenge Video Pattern Knowledge",
"0x09F7F": "Mountaintop Trap Door Turns On",
"0x17C34": "Mountain Access",
}

View File

@ -33,6 +33,10 @@ class WitnessRegions:
source_region = world.get_region(source, player)
target_region = world.get_region(target, player)
#print(source_region)
#print(target_region)
#print("---")
connection = Entrance(
player,
source + " to " + target + " via " + str(panel_hex_to_solve_set),
@ -76,10 +80,17 @@ class WitnessRegions:
for connection in player_logic.CONNECTIONS_BY_REGION_NAME[region_name]:
if connection[0] == "Entry":
continue
self.connect(world, player, region_name,
connection[0], player_logic, connection[1])
self.connect(world, player, connection[0],
region_name, player_logic, connection[1])
if connection[1] == frozenset({frozenset(["TrueOneWay"])}):
self.connect(world, player, region_name, connection[0], player_logic, frozenset({frozenset()}))
continue
for subset in connection[1]:
if all({panel in player_logic.DOOR_ITEMS_BY_ID for panel in subset}):
if all({StaticWitnessLogic.CHECKS_BY_HEX[panel]["id"] is None for panel in subset}):
self.connect(world, player, connection[0], region_name, player_logic, frozenset({subset}))
self.connect(world, player, region_name, connection[0], player_logic, connection[1])
world.get_entrance("The Splashscreen?", player).connect(
world.get_region('First Hallway', player)

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

View File

@ -1,18 +1,16 @@
Event Items:
Shadows Laser Activation - 0x00021,0x17D28,0x17C71
Keep Laser Activation - 0x03317
Bunker Laser Activation - 0x00061,0x17D01,0x17C42
Monastery Laser Activation - 0x00A5B,0x17CE7,0x17FA9,0x17CA4
Town Tower 4th Door Opens - 0x17CFB,0x3C12B,0x00B8D,0x17CF7
Monastery Laser Activation - 0x00A5B,0x17CE7,0x17FA9,0x17CA4
Bunker Laser Activation - 0x00061,0x17D01,0x17C42
Shadows Laser Activation - 0x00021,0x17D28,0x17C71
Requirement Changes:
0x17CA4 - True - True
0x28B39 - 0x2896A - Reflection
0x17C65 - 0x00A5B | 0x17CE7 | 0x17FA9 | 0x17CA4
0x0C2B2 - 0x00061 | 0x17D01 | 0x17C42
0x181B3 - 0x00021 | 0x17D28 | 0x17C71
0x28B39 - True - Reflection
0x17CAB - True - True
Region Changes:
Quarry (Quarry) - Outside Quarry - 0x17C09 - Quarry Mill - 0x275ED - Quarry Mill - 0x17CAC
Disabled Locations:
0x03505 (Tutorial Gate Close)
0x0C335 (Tutorial Pillar)

View File

@ -0,0 +1,31 @@
Items:
Glass Factory Entry Door (Panel)
Door to Symmetry Island Lower (Panel)
Door to Symmetry Island Upper (Panel)
Door to Desert Flood Light Room (Panel)
Desert Flood Room Flood Controls (Panel)
Quarry Door to Mill (Panel)
Quarry Mill Ramp Controls (Panel)
Quarry Mill Elevator Controls (Panel)
Quarry Boathouse Ramp Height Control (Panel)
Quarry Boathouse Ramp Horizontal Control (Panel)
Shadows Door Timer (Panel)
Monastery Entry Door Left (Panel)
Monastery Entry Door Right (Panel)
Town Door to RGB House (Panel)
Town Door to Church (Panel)
Town Maze Panel (Drop-Down Staircase) (Panel)
Windmill Door (Panel)
Treehouse First & Second Doors (Panel)
Treehouse Third Door (Panel)
Treehouse Laser House Door Timer (Panel)
Treehouse Shortcut Drop-Down Bridge (Panel)
Jungle Popup Wall (Panel)
Bunker Entry Door (Panel)
Inside Bunker Door to Bunker Proper (Panel)
Bunker Elevator Control (Panel)
Swamp Entry Door (Panel)
Swamp Sliding Bridge (Panel)
Swamp Rotating Bridge (Panel)
Swamp Maze Control (Panel)
Boat

View File

@ -0,0 +1,201 @@
Items:
Outside Tutorial Optional Door
Outside Tutorial Outpost Entry Door
Outside Tutorial Outpost Exit Door
Glass Factory Entry Door
Glass Factory Back Wall
Symmetry Island Lower Door
Symmetry Island Upper Door
Orchard Middle Gate
Orchard Final Gate
Desert Door to Flood Light Room
Desert Door to Pond Room
Desert Door to Water Levels Room
Desert Door to Elevator Room
Quarry Main Entry 1
Quarry Main Entry 2
Quarry Door to Mill
Quarry Mill Side Door
Quarry Mill Rooftop Shortcut
Quarry Mill Stairs
Quarry Boathouse Boat Staircase
Quarry Boathouse First Barrier
Quarry Boathouse Shortcut
Shadows Timed Door
Shadows Laser Room Right Door
Shadows Laser Room Left Door
Shadows Barrier to Quarry
Shadows Barrier to Ledge
Keep Hedge Maze 1 Exit Door
Keep Pressure Plates 1 Exit Door
Keep Hedge Maze 2 Shortcut
Keep Hedge Maze 2 Exit Door
Keep Hedge Maze 3 Shortcut
Keep Hedge Maze 3 Exit Door
Keep Hedge Maze 4 Shortcut
Keep Hedge Maze 4 Exit Door
Keep Pressure Plates 2 Exit Door
Keep Pressure Plates 3 Exit Door
Keep Pressure Plates 4 Exit Door
Keep Shortcut to Shadows
Keep Tower Shortcut
Monastery Shortcut
Monastery Inner Door
Monastery Outer Door
Monastery Door to Garden
Town Cargo Box Door
Town Wooden Roof Staircase
Town Tinted Door to RGB House
Town Door to Church
Town Maze Staircase
Town Windmill Door
Town RGB House Staircase
Town Tower Blue Panels Door
Town Tower Lattice Door
Town Tower Environmental Set Door
Town Tower Wooden Roof Set Door
Theater Entry Door
Theater Exit Door Left
Theater Exit Door Right
Jungle Bamboo Shortcut to River
Jungle Popup Wall
River Shortcut to Monastery Garden
Bunker Bunker Entry Door
Bunker Tinted Glass Door
Bunker Door to Ultraviolet Room
Bunker Door to Elevator
Swamp Entry Door
Swamp Door to Broken Shapers
Swamp Platform Shortcut Door
Swamp Cyan Water Pump
Swamp Door to Rotated Shapers
Swamp Red Water Pump
Swamp Red Underwater Exit
Swamp Blue Water Pump
Swamp Purple Water Pump
Swamp Near Laser Shortcut
Treehouse First Door
Treehouse Second Door
Treehouse Beyond Yellow Bridge Door
Treehouse Drawbridge
Treehouse Timed Door to Laser House
Inside Mountain First Layer Exit Door
Inside Mountain Second Layer Staircase Near
Inside Mountain Second Layer Exit Door
Inside Mountain Second Layer Staircase Far
Inside Mountain Giant Puzzle Exit Door
Inside Mountain Door to Final Room
Inside Mountain Bottom Layer Rock
Inside Mountain Door to Secret Area
Caves Pillar Door
Caves Mountain Shortcut
Caves Swamp Shortcut
Challenge Entry Door
Challenge Door to Theater Walkway
Theater Walkway Door to Windmill Interior
Theater Walkway Door to Desert Elevator Room
Theater Walkway Door to Town
Added Locations:
Outside Tutorial Door to Outpost Panel
Outside Tutorial Exit Door from Outpost Panel
Glass Factory Entry Door Panel
Glass Factory Vertical Symmetry 5
Symmetry Island Door to Symmetry Island Lower Panel
Symmetry Island Door to Symmetry Island Upper Panel
Orchard Apple Tree 3
Orchard Apple Tree 5
Desert Door to Desert Flood Light Room Panel
Desert Artificial Light Reflection 3
Desert Door to Water Levels Room Panel
Desert Flood Reflection 6
Quarry Door to Quarry 1 Panel
Quarry Door to Quarry 2 Panel
Quarry Door to Mill Right
Quarry Door to Mill Left
Quarry Mill Ground Floor Shortcut Door Panel
Quarry Mill Door to Outside Quarry Stairs Panel
Quarry Mill Stair Control
Quarry Boathouse Shortcut Door Panel
Shadows Door Timer Inside
Shadows Door Timer Outside
Shadows Environmental Avoid 8
Shadows Follow 5
Shadows Lower Avoid 3
Shadows Lower Avoid 5
Keep Hedge Maze 1
Keep Pressure Plates 1
Keep Hedge Maze 2
Keep Hedge Maze 3
Keep Hedge Maze 4
Keep Pressure Plates 2
Keep Pressure Plates 3
Keep Pressure Plates 4
Keep Shortcut to Shadows Panel
Keep Tower Shortcut to Keep Panel
Monastery Shortcut Door Panel
Monastery Door Open Left
Monastery Door Open Right
Monastery Rhombic Avoid 3
Town Cargo Box Panel
Town Full Dot Grid Shapers 5
Town Tinted Door Panel
Town Door to Church Stars Panel
Town Maze Stair Control
Town Windmill Door Panel
Town Sound Room Left
Town Sound Room Right
Town Symmetry Squares 5 + Dots
Town Church Lattice
Town Hexagonal Reflection
Town Shapers & Dots & Eraser
Windmill Door to Front of Theater Panel
Theater Door to Cargo Box Left Panel
Theater Door to Cargo Box Right Panel
Jungle Shortcut to River Panel
Jungle Popup Wall Control
River Rhombic Avoid to Monastery Garden
Bunker Bunker Entry Panel
Bunker Door to Bunker Proper Panel
Bunker Drawn Squares through Tinted Glass 3
Bunker Drop-Down Door Squares 2
Swamp Entry Panel
Swamp Platform Shapers 4
Swamp Platform Shortcut Right Panel
Swamp Blue Underwater Negative Shapers 5
Swamp Broken Shapers 4
Swamp Cyan Underwater Negative Shapers 5
Swamp Red Underwater Negative Shapers 4
Swamp More Rotated Shapers 4
Swamp More Rotated Shapers 4
Swamp Near Laser Shortcut Right Panel
Treehouse First Door Panel
Treehouse Second Door Panel
Treehouse Beyond Yellow Bridge Door Panel
Treehouse Bridge Control
Treehouse Left Orange Bridge 15
Treehouse Right Orange Bridge 12
Treehouse Laser House Door Timer Outside Control
Treehouse Laser House Door Timer Inside Control
Inside Mountain Moving Background 7
Inside Mountain Obscured Vision 5
Inside Mountain Physically Obstructed 3
Inside Mountain Angled Inside Trash 2
Inside Mountain Color Cycle 5
Inside Mountain Light Bridge Controller 2
Inside Mountain Light Bridge Controller 3
Inside Mountain Same Solution 6
Inside Mountain Giant Puzzle
Inside Mountain Door to Final Room Left
Inside Mountain Door to Final Room Right
Inside Mountain Bottom Layer Discard
Inside Mountain Rock Control
Inside Mountain Secret Area Entry Panel
Inside Mountain Caves Lone Pillar
Inside Mountain Caves Shortcut to Mountain Panel
Inside Mountain Caves Shortcut to Swamp Panel
Inside Mountain Caves Challenge Entry Panel
Challenge Door to Theater Walkway Panel
Theater Walkway Theater Shortcut Panel
Theater Walkway Desert Shortcut Panel
Theater Walkway Town Shortcut Panel

View File

@ -0,0 +1,212 @@
Items:
Outside Tutorial Optional Door
Outside Tutorial Outpost Entry Door
Outside Tutorial Outpost Exit Door
Glass Factory Entry Door
Glass Factory Back Wall
Symmetry Island Lower Door
Symmetry Island Upper Door
Orchard Middle Gate
Orchard Final Gate
Desert Door to Flood Light Room
Desert Door to Pond Room
Desert Door to Water Levels Room
Desert Door to Elevator Room
Quarry Main Entry 1
Quarry Main Entry 2
Quarry Door to Mill
Quarry Mill Side Door
Quarry Mill Rooftop Shortcut
Quarry Mill Stairs
Quarry Boathouse Boat Staircase
Quarry Boathouse First Barrier
Quarry Boathouse Shortcut
Shadows Timed Door
Shadows Laser Room Right Door
Shadows Laser Room Left Door
Shadows Barrier to Quarry
Shadows Barrier to Ledge
Keep Hedge Maze 1 Exit Door
Keep Pressure Plates 1 Exit Door
Keep Hedge Maze 2 Shortcut
Keep Hedge Maze 2 Exit Door
Keep Hedge Maze 3 Shortcut
Keep Hedge Maze 3 Exit Door
Keep Hedge Maze 4 Shortcut
Keep Hedge Maze 4 Exit Door
Keep Pressure Plates 2 Exit Door
Keep Pressure Plates 3 Exit Door
Keep Pressure Plates 4 Exit Door
Keep Shortcut to Shadows
Keep Tower Shortcut
Monastery Shortcut
Monastery Inner Door
Monastery Outer Door
Monastery Door to Garden
Town Cargo Box Door
Town Wooden Roof Staircase
Town Tinted Door to RGB House
Town Door to Church
Town Maze Staircase
Town Windmill Door
Town RGB House Staircase
Town Tower Blue Panels Door
Town Tower Lattice Door
Town Tower Environmental Set Door
Town Tower Wooden Roof Set Door
Theater Entry Door
Theater Exit Door Left
Theater Exit Door Right
Jungle Bamboo Shortcut to River
Jungle Popup Wall
River Shortcut to Monastery Garden
Bunker Bunker Entry Door
Bunker Tinted Glass Door
Bunker Door to Ultraviolet Room
Bunker Door to Elevator
Swamp Entry Door
Swamp Door to Broken Shapers
Swamp Platform Shortcut Door
Swamp Cyan Water Pump
Swamp Door to Rotated Shapers
Swamp Red Water Pump
Swamp Red Underwater Exit
Swamp Blue Water Pump
Swamp Purple Water Pump
Swamp Near Laser Shortcut
Treehouse First Door
Treehouse Second Door
Treehouse Beyond Yellow Bridge Door
Treehouse Drawbridge
Treehouse Timed Door to Laser House
Inside Mountain First Layer Exit Door
Inside Mountain Second Layer Staircase Near
Inside Mountain Second Layer Exit Door
Inside Mountain Second Layer Staircase Far
Inside Mountain Giant Puzzle Exit Door
Inside Mountain Door to Final Room
Inside Mountain Bottom Layer Rock
Inside Mountain Door to Secret Area
Caves Pillar Door
Caves Mountain Shortcut
Caves Swamp Shortcut
Challenge Entry Door
Challenge Door to Theater Walkway
Theater Walkway Door to Windmill Interior
Theater Walkway Door to Desert Elevator Room
Theater Walkway Door to Town
Desert Flood Room Flood Controls (Panel)
Quarry Mill Ramp Controls (Panel)
Quarry Mill Elevator Controls (Panel)
Quarry Boathouse Ramp Height Control (Panel)
Quarry Boathouse Ramp Horizontal Control (Panel)
Bunker Elevator Control (Panel)
Swamp Sliding Bridge (Panel)
Swamp Rotating Bridge (Panel)
Swamp Maze Control (Panel)
Boat
Added Locations:
Outside Tutorial Door to Outpost Panel
Outside Tutorial Exit Door from Outpost Panel
Glass Factory Entry Door Panel
Glass Factory Vertical Symmetry 5
Symmetry Island Door to Symmetry Island Lower Panel
Symmetry Island Door to Symmetry Island Upper Panel
Orchard Apple Tree 3
Orchard Apple Tree 5
Desert Door to Desert Flood Light Room Panel
Desert Artificial Light Reflection 3
Desert Door to Water Levels Room Panel
Desert Flood Reflection 6
Quarry Door to Quarry 1 Panel
Quarry Door to Quarry 2 Panel
Quarry Door to Mill Right
Quarry Door to Mill Left
Quarry Mill Ground Floor Shortcut Door Panel
Quarry Mill Door to Outside Quarry Stairs Panel
Quarry Mill Stair Control
Quarry Boathouse Shortcut Door Panel
Shadows Door Timer Inside
Shadows Door Timer Outside
Shadows Environmental Avoid 8
Shadows Follow 5
Shadows Lower Avoid 3
Shadows Lower Avoid 5
Keep Hedge Maze 1
Keep Pressure Plates 1
Keep Hedge Maze 2
Keep Hedge Maze 3
Keep Hedge Maze 4
Keep Pressure Plates 2
Keep Pressure Plates 3
Keep Pressure Plates 4
Keep Shortcut to Shadows Panel
Keep Tower Shortcut to Keep Panel
Monastery Shortcut Door Panel
Monastery Door Open Left
Monastery Door Open Right
Monastery Rhombic Avoid 3
Town Cargo Box Panel
Town Full Dot Grid Shapers 5
Town Tinted Door Panel
Town Door to Church Stars Panel
Town Maze Stair Control
Town Windmill Door Panel
Town Sound Room Left
Town Sound Room Right
Town Symmetry Squares 5 + Dots
Town Church Lattice
Town Hexagonal Reflection
Town Shapers & Dots & Eraser
Windmill Door to Front of Theater Panel
Theater Door to Cargo Box Left Panel
Theater Door to Cargo Box Right Panel
Jungle Shortcut to River Panel
Jungle Popup Wall Control
River Rhombic Avoid to Monastery Garden
Bunker Bunker Entry Panel
Bunker Door to Bunker Proper Panel
Bunker Drawn Squares through Tinted Glass 3
Bunker Drop-Down Door Squares 2
Swamp Entry Panel
Swamp Platform Shapers 4
Swamp Platform Shortcut Right Panel
Swamp Blue Underwater Negative Shapers 5
Swamp Broken Shapers 4
Swamp Cyan Underwater Negative Shapers 5
Swamp Red Underwater Negative Shapers 4
Swamp More Rotated Shapers 4
Swamp More Rotated Shapers 4
Swamp Near Laser Shortcut Right Panel
Treehouse First Door Panel
Treehouse Second Door Panel
Treehouse Beyond Yellow Bridge Door Panel
Treehouse Bridge Control
Treehouse Left Orange Bridge 15
Treehouse Right Orange Bridge 12
Treehouse Laser House Door Timer Outside Control
Treehouse Laser House Door Timer Inside Control
Inside Mountain Moving Background 7
Inside Mountain Obscured Vision 5
Inside Mountain Physically Obstructed 3
Inside Mountain Angled Inside Trash 2
Inside Mountain Color Cycle 5
Inside Mountain Light Bridge Controller 2
Inside Mountain Light Bridge Controller 3
Inside Mountain Same Solution 6
Inside Mountain Giant Puzzle
Inside Mountain Door to Final Room Left
Inside Mountain Door to Final Room Right
Inside Mountain Bottom Layer Discard
Inside Mountain Rock Control
Inside Mountain Secret Area Entry Panel
Inside Mountain Caves Lone Pillar
Inside Mountain Caves Shortcut to Mountain Panel
Inside Mountain Caves Shortcut to Swamp Panel
Inside Mountain Caves Challenge Entry Panel
Challenge Door to Theater Walkway Panel
Theater Walkway Theater Shortcut Panel
Theater Walkway Desert Shortcut Panel
Theater Walkway Town Shortcut Panel

View File

@ -0,0 +1,146 @@
Items:
Glass Factory Back Wall
Quarry Boathouse Boat Staircase
Outside Tutorial Outpost Doors
Glass Factory Entry Door
Symmetry Island Doors
Orchard Gates
Desert Doors
Quarry Main Entry
Quarry Door to Mill
Quarry Mill Shortcuts
Quarry Boathouse Barriers
Shadows Timed Door
Shadows Laser Room Door
Shadows Barriers
Keep Hedge Maze Doors
Keep Pressure Plates Doors
Keep Shortcuts
Monastery Entry Door
Monastery Shortcuts
Town Doors
Town Tower Doors
Theater Entry Door
Theater Exit Door
Jungle & River Shortcuts
Jungle Popup Wall
Bunker Doors
Swamp Doors
Swamp Near Laser Shortcut
Swamp Water Pumps
Treehouse Entry Doors
Treehouse Drawbridge
Treehouse Timed Door to Laser House
Inside Mountain First Layer Exit Door
Inside Mountain Second Layer Stairs & Doors
Inside Mountain Giant Puzzle Exit Door
Inside Mountain Door to Final Room
Inside Mountain Bottom Layer Doors to Caves
Caves Doors to Challenge
Caves Exits to Main Island
Challenge Door to Theater Walkway
Theater Walkway Doors
Added Locations:
Outside Tutorial Door to Outpost Panel
Outside Tutorial Exit Door from Outpost Panel
Glass Factory Entry Door Panel
Glass Factory Vertical Symmetry 5
Symmetry Island Door to Symmetry Island Lower Panel
Symmetry Island Door to Symmetry Island Upper Panel
Orchard Apple Tree 3
Orchard Apple Tree 5
Desert Door to Desert Flood Light Room Panel
Desert Artificial Light Reflection 3
Desert Door to Water Levels Room Panel
Desert Flood Reflection 6
Quarry Door to Quarry 1 Panel
Quarry Door to Quarry 2 Panel
Quarry Door to Mill Right
Quarry Door to Mill Left
Quarry Mill Ground Floor Shortcut Door Panel
Quarry Mill Door to Outside Quarry Stairs Panel
Quarry Mill Stair Control
Quarry Boathouse Shortcut Door Panel
Shadows Door Timer Inside
Shadows Door Timer Outside
Shadows Environmental Avoid 8
Shadows Follow 5
Shadows Lower Avoid 3
Shadows Lower Avoid 5
Keep Hedge Maze 1
Keep Pressure Plates 1
Keep Hedge Maze 2
Keep Hedge Maze 3
Keep Hedge Maze 4
Keep Pressure Plates 2
Keep Pressure Plates 3
Keep Pressure Plates 4
Keep Shortcut to Shadows Panel
Keep Tower Shortcut to Keep Panel
Monastery Shortcut Door Panel
Monastery Door Open Left
Monastery Door Open Right
Monastery Rhombic Avoid 3
Town Cargo Box Panel
Town Full Dot Grid Shapers 5
Town Tinted Door Panel
Town Door to Church Stars Panel
Town Maze Stair Control
Town Windmill Door Panel
Town Sound Room Left
Town Sound Room Right
Town Symmetry Squares 5 + Dots
Town Church Lattice
Town Hexagonal Reflection
Town Shapers & Dots & Eraser
Windmill Door to Front of Theater Panel
Theater Door to Cargo Box Left Panel
Theater Door to Cargo Box Right Panel
Jungle Shortcut to River Panel
Jungle Popup Wall Control
River Rhombic Avoid to Monastery Garden
Bunker Bunker Entry Panel
Bunker Door to Bunker Proper Panel
Bunker Drawn Squares through Tinted Glass 3
Bunker Drop-Down Door Squares 2
Swamp Entry Panel
Swamp Platform Shapers 4
Swamp Platform Shortcut Right Panel
Swamp Blue Underwater Negative Shapers 5
Swamp Broken Shapers 4
Swamp Cyan Underwater Negative Shapers 5
Swamp Red Underwater Negative Shapers 4
Swamp More Rotated Shapers 4
Swamp More Rotated Shapers 4
Swamp Near Laser Shortcut Right Panel
Treehouse First Door Panel
Treehouse Second Door Panel
Treehouse Beyond Yellow Bridge Door Panel
Treehouse Bridge Control
Treehouse Left Orange Bridge 15
Treehouse Right Orange Bridge 12
Treehouse Laser House Door Timer Outside Control
Treehouse Laser House Door Timer Inside Control
Inside Mountain Moving Background 7
Inside Mountain Obscured Vision 5
Inside Mountain Physically Obstructed 3
Inside Mountain Angled Inside Trash 2
Inside Mountain Color Cycle 5
Inside Mountain Light Bridge Controller 2
Inside Mountain Light Bridge Controller 3
Inside Mountain Same Solution 6
Inside Mountain Giant Puzzle
Inside Mountain Door to Final Room Left
Inside Mountain Door to Final Room Right
Inside Mountain Bottom Layer Discard
Inside Mountain Rock Control
Inside Mountain Secret Area Entry Panel
Inside Mountain Caves Lone Pillar
Inside Mountain Caves Shortcut to Mountain Panel
Inside Mountain Caves Shortcut to Swamp Panel
Inside Mountain Caves Challenge Entry Panel
Challenge Door to Theater Walkway Panel
Theater Walkway Theater Shortcut Panel
Theater Walkway Desert Shortcut Panel
Theater Walkway Town Shortcut Panel

View File

@ -0,0 +1,9 @@
Items:
Caves Exits to Main Island
Starting Inventory:
Caves Exits to Main Island
Remove Items:
Caves Mountain Shortcut
Caves Swamp Shortcut

View File

@ -0,0 +1,12 @@
Items:
Symmetry Laser
Desert Laser
Keep Laser
Shadows Laser
Quarry Laser
Town Laser
Swamp Laser
Jungle Laser
Bunker Laser
Monastery Laser
Treehouse Laser

View File

@ -0,0 +1,14 @@
Items:
Dots
Colored Dots
Sound Dots
Symmetry
Triangles
Eraser
Shapers
Rotated Shapers
Negative Shapers
Stars
Stars + Same Colored Symbol
Black/White Squares
Colored Squares

View File

@ -5,12 +5,11 @@ from .utils import define_new_region, parse_lambda
class StaticWitnessLogic:
ALL_SYMBOL_ITEMS = set()
ALL_DOOR_ITEMS = set()
ALL_DOOR_ITEMS_AS_DICT = dict()
ALL_USEFULS = set()
ALL_TRAPS = set()
ALL_BOOSTS = set()
ALL_DOOR_ITEM_IDS_BY_HEX = dict()
DOOR_NAMES_BY_HEX = dict()
ALL_DOOR_ITEMS = set()
CONNECTIONS_TO_SEVER_BY_DOOR_HEX = dict()
EVENT_PANELS_FROM_REGIONS = set()
@ -47,35 +46,23 @@ class StaticWitnessLogic:
if line == "Usefuls:":
current_set = self.ALL_USEFULS
continue
if line == "Doors:":
current_set = self.ALL_DOOR_ITEMS
continue
if line == "":
continue
line_split = line.split(" - ")
if current_set is not self.ALL_USEFULS:
current_set.add((line_split[1], int(line_split[0])))
else:
if current_set is self.ALL_USEFULS:
current_set.add((line_split[1], int(line_split[0]), line_split[2] == "True"))
elif current_set is self.ALL_DOOR_ITEMS:
new_door = (line_split[1], int(line_split[0]), frozenset(line_split[2].split(",")))
current_set.add(new_door)
self.ALL_DOOR_ITEMS_AS_DICT[line_split[1]] = new_door
else:
current_set.add((line_split[1], int(line_split[0])))
path = os.path.join(os.path.dirname(__file__), "Door_Shuffle.txt")
with open(path, "r", encoding="utf-8") as file:
for line in file.readlines():
line = line.strip()
line_split = line.split(" - ")
hex_set_split = line_split[1].split(",")
sever_list = line_split[2].split(",")
sever_set = {sever_panel for sever_panel in sever_list if sever_panel != "None"}
for door_hex in hex_set_split:
self.ALL_DOOR_ITEM_IDS_BY_HEX[door_hex] = int(line_split[0])
self.CONNECTIONS_TO_SEVER_BY_DOOR_HEX[door_hex] = sever_set
if len(line_split) > 3:
self.DOOR_NAMES_BY_HEX[door_hex] = line_split[3]
def read_logic_file(self):
"""
Reads the logic file and does the initial population of data structures
@ -84,10 +71,7 @@ class StaticWitnessLogic:
with open(path, "r", encoding="utf-8") as file:
current_region = dict()
discard_ids = 0
normal_panel_ids = 0
vault_ids = 0
laser_ids = 0
counter = 0
for line in file.readlines():
line = line.strip()
@ -95,7 +79,7 @@ class StaticWitnessLogic:
if line == "":
continue
if line[0] != "0":
if line[-1] == ":":
new_region_and_connections = define_new_region(line)
current_region = new_region_and_connections[0]
region_name = current_region["name"]
@ -105,12 +89,33 @@ class StaticWitnessLogic:
line_split = line.split(" - ")
location_id = line_split.pop(0)
check_name_full = line_split.pop(0)
check_hex = check_name_full[0:7]
check_name = check_name_full[9:-1]
required_panel_lambda = line_split.pop(0)
if location_id == "Door" or location_id == "Laser":
self.CHECKS_BY_HEX[check_hex] = {
"checkName": current_region["shortName"] + " " + check_name,
"checkHex": check_hex,
"region": current_region,
"id": None,
"panelType": location_id
}
self.CHECKS_BY_NAME[self.CHECKS_BY_HEX[check_hex]["checkName"]] = self.CHECKS_BY_HEX[check_hex]
self.STATIC_DEPENDENT_REQUIREMENTS_BY_HEX[check_hex] = {
"panels": parse_lambda(required_panel_lambda)
}
current_region["panels"].add(check_hex)
continue
required_item_lambda = line_split.pop(0)
laser_names = {
@ -123,53 +128,14 @@ class StaticWitnessLogic:
if "Discard" in check_name:
location_type = "Discard"
location_id = discard_ids
discard_ids += 1
elif is_vault_or_video or check_name == "Tutorial Gate Close":
location_type = "Vault"
location_id = vault_ids
vault_ids += 1
elif check_name in laser_names:
location_type = "Laser"
location_id = laser_ids
laser_ids += 1
else:
location_type = "General"
if check_hex == "0x012D7": # Compatibility
normal_panel_ids += 1
if check_hex == "0x17E07": # Compatibility
location_id = 112
elif check_hex == "0xFFF00":
location_id = 800
else:
location_id = normal_panel_ids
normal_panel_ids += 1
required_items = parse_lambda(required_item_lambda)
items_actually_in_the_game = {item[0] for item in self.ALL_SYMBOL_ITEMS}
required_items = set(
subset.intersection(items_actually_in_the_game)
for subset in required_items
)
doors_in_the_game = self.ALL_DOOR_ITEM_IDS_BY_HEX.keys()
if check_hex in doors_in_the_game:
door_name = current_region["shortName"] + " " + check_name + " Power On"
if check_hex in self.DOOR_NAMES_BY_HEX.keys():
door_name = self.DOOR_NAMES_BY_HEX[check_hex]
required_items = set(
subset.union(frozenset({door_name}))
for subset in required_items
)
self.ALL_DOOR_ITEMS.add(
(door_name, self.ALL_DOOR_ITEM_IDS_BY_HEX[check_hex])
)
required_items = frozenset(required_items)
@ -182,7 +148,7 @@ class StaticWitnessLogic:
"checkName": current_region["shortName"] + " " + check_name,
"checkHex": check_hex,
"region": current_region,
"idOffset": location_id,
"id": int(location_id),
"panelType": location_type
}

View File

@ -98,9 +98,39 @@ def get_adjustment_file(adjustment_file):
@cache_argsless
def get_disable_unrandomized_list():
return get_adjustment_file("Disable_Unrandomized.txt")
return get_adjustment_file("settings/Disable_Unrandomized.txt")
@cache_argsless
def get_early_utm_list():
return get_adjustment_file("Early_UTM.txt")
return get_adjustment_file("settings/Early_UTM.txt")
@cache_argsless
def get_symbol_shuffle_list():
return get_adjustment_file("settings/Symbol_Shuffle.txt")
@cache_argsless
def get_door_panel_shuffle_list():
return get_adjustment_file("settings/Door_Panel_Shuffle.txt")
@cache_argsless
def get_doors_simple_list():
return get_adjustment_file("settings/Doors_Simple.txt")
@cache_argsless
def get_doors_complex_list():
return get_adjustment_file("settings/Doors_Complex.txt")
@cache_argsless
def get_doors_max_list():
return get_adjustment_file("settings/Doors_Max.txt")
@cache_argsless
def get_laser_shuffle():
return get_adjustment_file("settings/Laser_Shuffle.txt")