The Witness - 0.3.3 features and fixes (#617)

New option: "Early Secret Area" (Opens a door to the Challenge Area from the start of the game)
New option: Victory Conditions "Mountaintop Box Short" and "Mountaintop Box Long"
New options: Number of Lasers of Mountain, Number of Lasers for Challenge
New option & item: Add some number of "Puzzle Skips", which let you skip one puzzle in the game

Many logic fixes
This commit is contained in:
NewSoupVi 2022-06-16 03:04:45 +02:00 committed by GitHub
parent 0a63bd0fc6
commit 7d79cff66f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 410 additions and 125 deletions

View File

@ -1,5 +1,6 @@
Event Items: Event Items:
Shadows Laser Activation - 0x00021,0x17D28,0x17C71 Shadows Laser Activation - 0x00021,0x17D28,0x17C71
Keep Laser Activation - 0x03317
Bunker Laser Activation - 0x00061,0x17D01,0x17C42 Bunker Laser Activation - 0x00061,0x17D01,0x17C42
Monastery Laser Activation - 0x00A5B,0x17CE7,0x17FA9,0x17CA4 Monastery Laser Activation - 0x00A5B,0x17CE7,0x17FA9,0x17CA4
Town Tower 4th Door Opens - 0x17CFB,0x3C12B,0x00B8D,0x17CF7 Town Tower 4th Door Opens - 0x17CFB,0x3C12B,0x00B8D,0x17CF7
@ -26,7 +27,7 @@ Disabled Locations:
0x00055 (Orchard Apple Tree 3) 0x00055 (Orchard Apple Tree 3)
0x032F7 (Orchard Apple Tree 4) 0x032F7 (Orchard Apple Tree 4)
0x032FF (Orchard Apple Tree 5) 0x032FF (Orchard Apple Tree 5)
0x168B5 (Shadows Lower Avoid 1) 0x198B5 (Shadows Lower Avoid 1)
0x198BD (Shadows Lower Avoid 2) 0x198BD (Shadows Lower Avoid 2)
0x198BF (Shadows Lower Avoid 3) 0x198BF (Shadows Lower Avoid 3)
0x19771 (Shadows Lower Avoid 4) 0x19771 (Shadows Lower Avoid 4)
@ -53,6 +54,8 @@ Disabled Locations:
0x019E7 (Keep Hedge Maze 3) 0x019E7 (Keep Hedge Maze 3)
0x01A0F (Keep Hedge Maze 4) 0x01A0F (Keep Hedge Maze 4)
0x0360E (Laser Hedges) 0x0360E (Laser Hedges)
0x00B10 (Monastery Door Open Left)
0x00C92 (Monastery Door Open Right)
0x00290 (Monastery Rhombic Avoid 1) 0x00290 (Monastery Rhombic Avoid 1)
0x00038 (Monastery Rhombic Avoid 2) 0x00038 (Monastery Rhombic Avoid 2)
0x00037 (Monastery Rhombic Avoid 3) 0x00037 (Monastery Rhombic Avoid 3)

View File

@ -0,0 +1,30 @@
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

@ -0,0 +1,5 @@
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

@ -1,6 +1,6 @@
from typing import Dict from typing import Dict, Union
from BaseClasses import MultiWorld from BaseClasses import MultiWorld
from Options import Toggle, DefaultOnToggle, Option, Range from Options import Toggle, DefaultOnToggle, Option, Range, Choice
# class HardMode(Toggle): # class HardMode(Toggle):
@ -18,6 +18,23 @@ class DisableNonRandomizedPuzzles(DefaultOnToggle):
display_name = "Disable non randomized puzzles" display_name = "Disable non randomized puzzles"
class EarlySecretArea(Toggle):
"""The Mountainside shortcut to the Mountain Secret Area is open 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."""
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."""
display_name = "Shuffle Doors"
class ShuffleDiscardedPanels(Toggle): class ShuffleDiscardedPanels(Toggle):
"""Discarded Panels will have items on them. """Discarded Panels will have items on them.
Solving certain Discarded Panels may still be necessary!""" Solving certain Discarded Panels may still be necessary!"""
@ -40,10 +57,31 @@ class ShuffleHardLocations(Toggle):
display_name = "Shuffle Hard Locations" display_name = "Shuffle Hard Locations"
class ChallengeVictoryCondition(Toggle): class VictoryCondition(Choice):
"""The victory condition now becomes beating the Challenge area, """Change the victory condition from the original game's ending (elevator) to beating the Challenge
instead of the final elevator.""" or solving the mountaintop box, either using the short solution
display_name = "Victory on beating the Challenge" (7 lasers or whatever you've changed it to) or the long solution (11 lasers or whatever you've changed it to)."""
display_name = "Victory Condition"
option_elevator = 0
option_challenge = 1
option_mountain_box_short = 2
option_mountain_box_long = 3
class MountainLasers(Range):
"""Sets the amount of beams required to enter the final area."""
display_name = "Required Lasers for Mountain Entry"
range_start = 1
range_end = 7
default = 7
class ChallengeLasers(Range):
"""Sets the amount of beams required to enter the secret area through the Mountain Bottom Layer Discard."""
display_name = "Required Lasers for Challenge"
range_start = 1
range_end = 11
default = 11
class TrapPercentage(Range): class TrapPercentage(Range):
@ -54,16 +92,30 @@ class TrapPercentage(Range):
default = 20 default = 20
the_witness_options: Dict[str, Option] = { class PuzzleSkipAmount(Range):
"""Adds this number of Puzzle Skips into the pool, if there is room. Puzzle Skips let you skip one panel.
Works on most panels in the game - The only big exception is The Challenge."""
display_name = "Puzzle Skips"
range_start = 0
range_end = 20
default = 5
the_witness_options: Dict[str, type] = {
# "hard_mode": HardMode, # "hard_mode": HardMode,
# "unlock_symbols": UnlockSymbols,
"disable_non_randomized_puzzles": DisableNonRandomizedPuzzles, "disable_non_randomized_puzzles": DisableNonRandomizedPuzzles,
"shuffle_discarded_panels": ShuffleDiscardedPanels, "shuffle_discarded_panels": ShuffleDiscardedPanels,
"shuffle_vault_boxes": ShuffleVaultBoxes, "shuffle_vault_boxes": ShuffleVaultBoxes,
"shuffle_uncommon": ShuffleUncommonLocations, "shuffle_uncommon": ShuffleUncommonLocations,
"shuffle_hard": ShuffleHardLocations, "shuffle_hard": ShuffleHardLocations,
"challenge_victory": ChallengeVictoryCondition, "victory_condition": VictoryCondition,
"trap_percentage": TrapPercentage "trap_percentage": TrapPercentage,
"early_secret_area": EarlySecretArea,
# "shuffle_symbols": ShuffleSymbols,
# "shuffle_doors": ShuffleDoors,
"mountain_lasers": MountainLasers,
"challenge_lasers": ChallengeLasers,
"puzzle_skip_amount": PuzzleSkipAmount,
} }
@ -71,10 +123,12 @@ def is_option_enabled(world: MultiWorld, player: int, name: str) -> bool:
return get_option_value(world, player, name) > 0 return get_option_value(world, player, name) > 0
def get_option_value(world: MultiWorld, player: int, name: str) -> int: def get_option_value(world: MultiWorld, player: int, name: str) -> Union[bool, int]:
option = getattr(world, name, None) option = getattr(world, name, None)
if option is None: if option is None:
return 0 return 0
return int(option[player].value) if issubclass(the_witness_options[name], Toggle) or issubclass(the_witness_options[name], DefaultOnToggle):
return bool(option[player].value)
return option[player].value

View File

@ -13,6 +13,10 @@ Progression:
71 - Black/White Squares 71 - Black/White Squares
72 - Colored Squares 72 - Colored Squares
Usefuls:
101 - Functioning Brain
510 - Puzzle Skip
Boosts: Boosts:
500 - Speed Boost 500 - Speed Boost

View File

@ -11,7 +11,7 @@ Tutorial (Tutorial) - First Hallway - 0x00182:
0x03629 (Gate Open) - 0x002C2 & 0x0A3B5 & 0x0A3B2 - True 0x03629 (Gate Open) - 0x002C2 & 0x0A3B5 & 0x0A3B2 - True
0x03505 (Gate Close) - 0x2FAF6 - True 0x03505 (Gate Close) - 0x2FAF6 - True
0x0C335 (Pillar) - True - Triangles - True 0x0C335 (Pillar) - True - Triangles - True
0x0C373 (Patio Floor) - 0x0C335 - True 0x0C373 (Patio Floor) - 0x0C335 - Dots
Outside Tutorial (Outside Tutorial) - Tutorial - 0x03629: Outside Tutorial (Outside Tutorial) - Tutorial - 0x03629:
0x033D4 (Vault) - True - Dots & Squares & Black/White Squares 0x033D4 (Vault) - True - Dots & Squares & Black/White Squares
@ -52,10 +52,10 @@ Inside Glass Factory (Glass Factory) - Outside Glass Factory - 0x01A54:
0x00084 (Melting 1) - 0x00083 - Symmetry 0x00084 (Melting 1) - 0x00083 - Symmetry
0x00082 (Melting 2) - 0x00084 - Symmetry 0x00082 (Melting 2) - 0x00084 - Symmetry
0x0343A (Melting 3) - 0x00082 - Symmetry 0x0343A (Melting 3) - 0x00082 - Symmetry
0x17CC8 (Boat Spawn) - True - Boat 0x17CC8 (Boat Spawn) - 0x0005C - Boat
Outside Symmetry Island (Symmetry Island) - Main Island - True: Outside Symmetry Island (Symmetry Island) - Main Island - True:
0x000B0 (Door to Symmetry Island Lower) - True - Dots 0x000B0 (Door to Symmetry Island Lower) - 0x0343A - Dots
Symmetry Island Lower (Symmetry Island) - Outside Symmetry Island - 0x000B0: Symmetry Island Lower (Symmetry Island) - Outside Symmetry Island - 0x000B0:
0x00022 (Black Dots 1) - True - Symmetry & Dots 0x00022 (Black Dots 1) - True - Symmetry & Dots
@ -138,17 +138,16 @@ Desert Water Levels Room (Desert) - Desert Pond Room - 0x0A249:
0x1831D (Raise Water Level Far Right) - True - True 0x1831D (Raise Water Level Far Right) - True - True
0x1C2B1 (Raise Water Level Near Left) - True - True 0x1C2B1 (Raise Water Level Near Left) - True - True
0x1831B (Raise Water Level Near Right) - True - True 0x1831B (Raise Water Level Near Right) - True - True
0x04D18 (Flood Reflection 1) - True - Reflection 0x04D18 (Flood Reflection 1) - 0x1C260 & 0x1831C - Reflection
0x01205 (Flood Reflection 2) - 0x04D18 - Reflection 0x01205 (Flood Reflection 2) - 0x04D18 & 0x1C260 & 0x1831C - Reflection
0x181AB (Flood Reflection 3) - 0x01205 - Reflection 0x181AB (Flood Reflection 3) - 0x01205 & 0x1C260 & 0x1831C - Reflection
0x0117A (Flood Reflection 4) - 0x181AB - Reflection 0x0117A (Flood Reflection 4) - 0x181AB & 0x1C260 & 0x1831C - Reflection
0x17ECA (Flood Reflection 5) - 0x0117A - Reflection 0x17ECA (Flood Reflection 5) - 0x0117A & 0x1C260 & 0x1831C - Reflection
0x18076 (Flood Reflection 6) - 0x17ECA - Reflection 0x18076 (Flood Reflection 6) - 0x17ECA & 0x1C260 & 0x1831C - Reflection
Desert Elevator Room (Desert) - Desert Water Levels Room - 0x18076: Desert Elevator Room (Desert) - Desert Water Levels Room - 0x18076:
0x17C31 (Final Transparent Reflection) - True - Reflection 0x17C31 (Final Transparent Reflection) - True - Reflection
0x012D7 (Final Reflection) - 0x17C31 & 0x0A015 - Reflection 0x012D7 (Final Reflection) - 0x17C31 & 0x0A015 - Reflection
0x012D7 (Final Reflection) - 0x17C31 & 0x0A015 - Reflection
0x0A015 (Final Reflection Control) - 0x17C31 - True 0x0A015 (Final Reflection Control) - 0x17C31 - True
0x0A15C (Final Bent Reflection 1) - True - Reflection 0x0A15C (Final Bent Reflection 1) - True - Reflection
0x09FFF (Final Bent Reflection 2) - 0x0A15C - Reflection 0x09FFF (Final Bent Reflection 2) - 0x0A15C - Reflection
@ -187,8 +186,8 @@ Quarry Mill (Quarry Mill) - Quarry - 0x01E59 & 0x01E5A:
0x03686 (Eraser and Squares 7) - 0x3C12D - Squares & Colored Squares & Eraser 0x03686 (Eraser and Squares 7) - 0x3C12D - Squares & Colored Squares & Eraser
0x014E9 (Eraser and Squares 8) - 0x03686 - Squares & Colored Squares & Eraser 0x014E9 (Eraser and Squares 8) - 0x03686 - Squares & Colored Squares & Eraser
0x03677 (Stair Control) - 0x014E8 - Squares & Colored Squares & Eraser 0x03677 (Stair Control) - 0x014E8 - Squares & Colored Squares & Eraser
0x3C125 (Big Squares & Dots & and Eraser) - 0x0367C - Squares & Black/White Squares & Dots & Eraser 0x3C125 (Big Squares & Dots & Eraser) - 0x0367C - Squares & Black/White Squares & Dots & Eraser
0x0367C (Small Squares & Dots & and Eraser) - 0x014E9 - Squares & Colored Squares & Dots & Eraser 0x0367C (Small Squares & Dots & Eraser) - 0x014E9 - Squares & Colored Squares & Dots & Eraser
0x17CAC (Door to Outside Quarry Stairs) - True - True 0x17CAC (Door to Outside Quarry Stairs) - True - True
Quarry Boathouse (Quarry Boathouse) - Quarry - True: Quarry Boathouse (Quarry Boathouse) - Quarry - True:
@ -209,13 +208,13 @@ Quarry Boathouse (Quarry Boathouse) - Quarry - True:
0x09DB5 (Stars and Colored Eraser 5) - 0x021BB - Stars & Stars + Same Colored Symbol & Eraser 0x09DB5 (Stars and Colored Eraser 5) - 0x021BB - Stars & Stars + Same Colored Symbol & Eraser
0x09DB1 (Stars and Colored Eraser 6) - 0x09DB5 - Stars & Stars + Same Colored Symbol & Eraser 0x09DB1 (Stars and Colored Eraser 6) - 0x09DB5 - Stars & Stars + Same Colored Symbol & Eraser
0x3C124 (Stars and Colored Eraser 7) - 0x09DB1 - Stars & Stars + Same Colored Symbol & Eraser 0x3C124 (Stars and Colored Eraser 7) - 0x09DB1 - Stars & Stars + Same Colored Symbol & Eraser
0x09DB3 (Stars & Eraser & and Shapers 1) - 0x3C124 - Stars & Eraser & Shapers 0x09DB3 (Stars & Eraser & Shapers 1) - 0x3C124 - Stars & Eraser & Shapers
0x09DB4 (Stars & Eraser & and Shapers 2) - 0x09DB3 - Stars & Eraser & Shapers 0x09DB4 (Stars & Eraser & Shapers 2) - 0x09DB3 - Stars & Eraser & Shapers
0x275FA (Hook Control) - 0x03858 - Shapers & Eraser 0x275FA (Hook Control) - 0x03858 - Shapers & Eraser
0x17CA6 (Boat Spawn) - True - Boat 0x17CA6 (Boat Spawn) - True - Boat
0x0A3CB (Stars & Eraser & and Shapers 3) - 0x09DB4 - Stars & Eraser & Shapers 0x0A3CB (Stars & Eraser & Shapers 3) - 0x09DB4 - Stars & Eraser & Shapers
0x0A3CC (Stars & Eraser & and Shapers 4) - 0x0A3CB - Stars & Eraser & Shapers 0x0A3CC (Stars & Eraser & Shapers 4) - 0x0A3CB - Stars & Eraser & Shapers
0x0A3D0 (Stars & Eraser & and Shapers 5) - 0x0A3CC - Stars & Eraser & Shapers 0x0A3D0 (Stars & Eraser & Shapers 5) - 0x0A3CC - Stars & Eraser & Shapers
Shadows (Shadows) - Main Island - True - Keep Glass Plates - 0x09E49: Shadows (Shadows) - Main Island - True - Keep Glass Plates - 0x09E49:
0x334DB (Door Timer Outside) - True - True 0x334DB (Door Timer Outside) - True - True
@ -239,8 +238,8 @@ Shadows (Shadows) - Main Island - True - Keep Glass Plates - 0x09E49:
Shadows Ledge (Shadows) - Shadows - 0x334DB | 0x334DC | 0x0A8DC: Shadows Ledge (Shadows) - Shadows - 0x334DB | 0x334DC | 0x0A8DC:
0x334DC (Door Timer Inside) - True - True 0x334DC (Door Timer Inside) - True - True
0x168B5 (Lower Avoid 1) - True - Shadows Avoid 0x198B5 (Lower Avoid 1) - True - Shadows Avoid
0x198BD (Lower Avoid 2) - 0x168B5 - Shadows Avoid 0x198BD (Lower Avoid 2) - 0x198B5 - Shadows Avoid
0x198BF (Lower Avoid 3) - 0x198BD & 0x334DC - Shadows Avoid 0x198BF (Lower Avoid 3) - 0x198BD & 0x334DC - Shadows Avoid
0x19771 (Lower Avoid 4) - 0x198BF - Shadows Avoid 0x19771 (Lower Avoid 4) - 0x198BF - Shadows Avoid
0x0A8DC (Lower Avoid 5) - 0x19771 - Shadows Avoid 0x0A8DC (Lower Avoid 5) - 0x19771 - Shadows Avoid
@ -319,7 +318,7 @@ Town (Town) - Main Island - True - Theater - 0x0A168 | 0x33AB2:
0x28ABF (Full Dot Grid Shapers 3) - 0x28A33 - Shapers & Rotated Shapers & Dots 0x28ABF (Full Dot Grid Shapers 3) - 0x28A33 - Shapers & Rotated Shapers & Dots
0x28AC0 (Full Dot Grid Shapers 4) - 0x28ABF - Rotated Shapers & Dots 0x28AC0 (Full Dot Grid Shapers 4) - 0x28ABF - Rotated Shapers & Dots
0x28AC1 (Full Dot Grid Shapers 5) - 0x28AC0 - Rotated Shapers & Dots 0x28AC1 (Full Dot Grid Shapers 5) - 0x28AC0 - Rotated Shapers & Dots
0x28AD9 (Shapers & Dots & and Eraser) - 0x28AC1 - Rotated Shapers & Dots & Eraser 0x28AD9 (Shapers & Dots & Eraser) - 0x28AC1 - Rotated Shapers & Dots & Eraser
0x17F5F (Windmill Door) - True - Dots 0x17F5F (Windmill Door) - True - Dots
RGB House (Town) - Town - 0x28998: RGB House (Town) - Town - 0x28998:
@ -415,7 +414,7 @@ Swamp Entry Area (Swamp) - Outside Swamp - 0x0056E:
0x00985 (Combinable Shapers 6) - 0x00986 - Shapers 0x00985 (Combinable Shapers 6) - 0x00986 - Shapers
0x00987 (Combinable Shapers 7) - 0x00985 - Shapers 0x00987 (Combinable Shapers 7) - 0x00985 - Shapers
0x181A9 (Combinable Shapers 8) - 0x00987 - Shapers 0x181A9 (Combinable Shapers 8) - 0x00987 - Shapers
0x00609 (Slide Bridge) - 0x181A9 - Shapers 0x00609 (Sliding Bridge) - 0x181A9 - Shapers
Swamp Near Platform (Swamp) - Swamp Entry Area - 0x00609 | 0x18488: Swamp Near Platform (Swamp) - Swamp Entry Area - 0x00609 | 0x18488:
0x00999 (Broken Shapers 1) - 0x00990 - Broken Shapers 0x00999 (Broken Shapers 1) - 0x00990 - Broken Shapers
@ -447,24 +446,25 @@ Swamp Rotating Bridge Near Side (Swamp) - Swamp Near Platform - 0x009A1:
0x014D4 (Red Underwater Negative Shapers 3) - 0x00596 - Shapers & Negative Shapers 0x014D4 (Red Underwater Negative Shapers 3) - 0x00596 - Shapers & Negative Shapers
0x014D1 (Red Underwater Negative Shapers 4) - 0x00596 - Shapers & Negative Shapers 0x014D1 (Red Underwater Negative Shapers 4) - 0x00596 - Shapers & Negative Shapers
Swamp Near Boat (Swamp) - Swamp Rotating Bridge Near Side - 0x009A1 - Swamp Platform - 0x17C0D & 0x17C0E: Swamp Near Boat (Swamp) - Swamp Rotating Bridge Near Side - 0x0000A - Swamp Platform - 0x17C0D & 0x17C0E:
0x181F5 (Rotating Bridge) - True - Rotated Shapers, Shapers 0x181F5 (Rotating Bridge) - True - Rotated Shapers & Shapers
0x09DB8 (Boat Spawn) - True - Boat 0x09DB8 (Boat Spawn) - True - Boat
0x003B2 (More Rotated Shapers 1) - 0x0000A - Rotated Shapers 0x003B2 (More Rotated Shapers 1) - 0x0000A - Rotated Shapers
0x00A1E (More Rotated Shapers 2) - 0x003B2 - Rotated Shapers 0x00A1E (More Rotated Shapers 2) - 0x003B2 - Rotated Shapers
0x00C2E (More Rotated Shapers 3) - 0x00A1E - Rotated Shapers 0x00C2E (More Rotated Shapers 3) - 0x00A1E - Rotated Shapers
0x00E3A (More Rotated Shapers 4) - 0x00C2E - Rotated Shapers 0x00E3A (More Rotated Shapers 4) - 0x00C2E - Rotated Shapers
0x009A6 (Underwater Back Optional) - 0x00E3A - Shapers 0x009A6 (Underwater Back Optional) - 0x00E3A & 0x181F5 - Shapers
0x009AB (Blue Underwater Negative Shapers 1) - 0x00E3A - Shapers & Negative Shapers 0x009AB (Blue Underwater Negative Shapers 1) - 0x00E3A - Shapers & Negative Shapers
0x009AD (Blue Underwater Negative Shapers 2) - 0x009AB - Shapers & Negative Shapers 0x009AD (Blue Underwater Negative Shapers 2) - 0x009AB - Shapers & Negative Shapers
0x009AE (Blue Underwater Negetive Shapers 3) - 0x009AD - Shapers & Negative Shapers 0x009AE (Blue Underwater Negetive Shapers 3) - 0x009AD - Shapers & Negative Shapers
0x009AF (Blue Underwater Negative Shapers 4) - 0x009AE - Shapers & Negative Shapers 0x009AF (Blue Underwater Negative Shapers 4) - 0x009AE - Shapers & Negative Shapers
0x00006 (Blue Underwater Negative Shapers 5) - 0x009AF - Shapers & Negative Shapers & Broken Negative Shapers 0x00006 (Blue Underwater Negative Shapers 5) - 0x009AF - Shapers & Negative Shapers & Broken Negative Shapers
0x17E2B (Long Bridge Control) - True - Rotated Shapers 0x17E2B (Long Bridge Control) - True - Rotated Shapers & Shapers
Swamp Maze (Swamp) - Swamp Rotating Bridge Near Side - 0x00001 & 0x014D2 & 0x014D4 & 0x014D1 - Outside Swamp - 0x17C05 & 0x17C02: Swamp Maze (Swamp) - Swamp Rotating Bridge Near Side - 0x00001 & 0x014D2 & 0x014D4 & 0x014D1 - Outside Swamp - 0x17C05 & 0x17C02:
0x17C04 (Maze Control) - True - Shapers & Negative Shapers & Rotated Shapers & Environment 0x17C0A (Maze Control) - True - Shapers & Negative Shapers & Rotated Shapers & Environment
0x03615 (Laser) - 0x17C04 - True 0x17E07 (Maze Control Other Side) - True - Shapers & Negative Shapers & Rotated Shapers & Environment
0x03615 (Laser) - 0x17C0A & 0x17E07 - True
0x17C05 (Near Laser Shortcut Door Left) - True - Rotated Shapers 0x17C05 (Near Laser Shortcut Door Left) - True - Rotated Shapers
0x17C02 (Near Laser Shortcut Door Right) - 0x17C05 - Shapers & Negative Shapers & Rotated Shapers 0x17C02 (Near Laser Shortcut Door Right) - 0x17C05 - Shapers & Negative Shapers & Rotated Shapers
@ -543,7 +543,8 @@ Treehouse Bridge Platform (Treehouse) - Treehouse Beyond Yellow Bridge - 0x17DA2
Mountaintop (Mountaintop) - Main Island - True: Mountaintop (Mountaintop) - Main Island - True:
0x0042D (River Shape) - True - True 0x0042D (River Shape) - True - True
0x09F7F (Box Open) - 7 Lasers - True 0x09F7F (Box Short) - 7 Lasers - True
0xFFF00 (Box Long) - 11 Lasers & 0x17C34 - True
0x17C34 (Trap Door Triple Exit) - 0x09F7F - Stars & Squares & Black/White Squares & Stars + Same Colored Symbol 0x17C34 (Trap Door Triple Exit) - 0x09F7F - Stars & Squares & Black/White Squares & Stars + Same Colored Symbol
0x17C42 (Discard) - True - Triangles 0x17C42 (Discard) - True - Triangles
0x002A6 (Vault) - True - Symmetry & Colored Dots & Squares & Black/White Squares & Dots 0x002A6 (Vault) - True - Symmetry & Colored Dots & Squares & Black/White Squares & Dots
@ -577,7 +578,7 @@ Inside Mountain Second Layer (Inside Mountain) - Inside Mountain Top Layer Bridg
0x09FD6 (Color Cycle 3) - 0x09FD4 - Color Cycle & RGB & Stars & Squares & Colored Squares & Stars + Same Colored Symbol 0x09FD6 (Color Cycle 3) - 0x09FD4 - Color Cycle & RGB & Stars & Squares & Colored Squares & Stars + Same Colored Symbol
0x09FD7 (Color Cycle 4) - 0x09FD6 - Color Cycle & RGB & Stars & Squares & Colored Squares & Stars + Same Colored Symbol & Shapers & Colored Shapers 0x09FD7 (Color Cycle 4) - 0x09FD6 - Color Cycle & RGB & Stars & Squares & Colored Squares & Stars + Same Colored Symbol & Shapers & Colored Shapers
0x09FD8 (Color Cycle 5) - 0x09FD7 - Color Cycle & RGB & Squares & Colored Squares & Symmetry & Colored Dots 0x09FD8 (Color Cycle 5) - 0x09FD7 - Color Cycle & RGB & Squares & Colored Squares & Symmetry & Colored Dots
0x09E86 (Light Bridge Controller 2) - 0x09FD7 - Stars & Stars + Same Colored Symbol & Colored Rotated Shapers & Eraser & Two Lines 0x09E86 (Light Bridge Controller 2) - 0x09FD8 - Stars & Stars + Same Colored Symbol & Colored Rotated Shapers & Rotated Shapers & Eraser & Two Lines
Inside Mountain Second Layer Beyond Bridge (Inside Mountain) - Inside Mountain Second Layer - 0x09E86: Inside Mountain Second Layer Beyond Bridge (Inside Mountain) - Inside Mountain Second Layer - 0x09E86:
0x09FCC (Same Solution 1) - True - Dots & Same Solution 0x09FCC (Same Solution 1) - True - Dots & Same Solution
@ -586,7 +587,7 @@ Inside Mountain Second Layer Beyond Bridge (Inside Mountain) - Inside Mountain S
0x09FD0 (Same Solution 4) - 0x09FCF - Rotated Shapers & Same Solution 0x09FD0 (Same Solution 4) - 0x09FCF - Rotated Shapers & Same Solution
0x09FD1 (Same Solution 5) - 0x09FD0 - Stars & Squares & Colored Squares & Stars + Same Colored Symbol & Same Solution 0x09FD1 (Same Solution 5) - 0x09FD0 - Stars & Squares & Colored Squares & Stars + Same Colored Symbol & Same Solution
0x09FD2 (Same Solution 6) - 0x09FD1 - Shapers & Same Solution 0x09FD2 (Same Solution 6) - 0x09FD1 - Shapers & Same Solution
0x09ED8 (Light Bridge Controller 3) - 0x09FD2 - Stars & Stars + Same Colored Symbol & Colored Rotated Shapers & Eraser & Two Lines 0x09ED8 (Light Bridge Controller 3) - 0x09FD2 - Stars & Stars + Same Colored Symbol & Colored Rotated Shapers & Rotated Shapers & Eraser & Two Lines
Inside Mountain Second Layer Elevator (Inside Mountain) - Inside Mountain Second Layer - 0x09ED8 & 0x09E86: Inside Mountain Second Layer Elevator (Inside Mountain) - Inside Mountain Second Layer - 0x09ED8 & 0x09E86:
0x09EEB (Elevator Control Panel) - True - Dots 0x09EEB (Elevator Control Panel) - True - Dots
@ -600,10 +601,9 @@ Inside Mountain Third Layer (Inside Mountain) - Inside Mountain Second Layer Ele
0x09FDA (Giant Puzzle) - 0x09FC1 & 0x09F8E & 0x09F01 & 0x09EFF - Shapers & Symmetry 0x09FDA (Giant Puzzle) - 0x09FC1 & 0x09F8E & 0x09F01 & 0x09EFF - Shapers & Symmetry
Inside Mountain Bottom Layer (Inside Mountain) - Inside Mountain Third Layer - 0x09FDA - Inside Mountain Path to Secret Area - 0x334E1: Inside Mountain Bottom Layer (Inside Mountain) - Inside Mountain Third Layer - 0x09FDA - Inside Mountain Path to Secret Area - 0x334E1:
0x17FA2 (Bottom Layer Discard) - 11 Lasers & 0x09F7F - Triangles & Environment 0x17FA2 (Bottom Layer Discard) - 0xFFF00 - Triangles & Environment
0x01983 (Door to Final Room Left) - True - Shapers & Stars 0x01983 (Door to Final Room Left) - True - Shapers & Stars
0x01987 (Door to Final Room Right) - True - Squares & Colored Squares 0x01987 (Door to Final Room Right) - True - Squares & Colored Squares & Dots
Inside Mountain Path to Secret Area (Inside Mountain) - Inside Mountain Bottom Layer - 0x17FA2: Inside Mountain Path to Secret Area (Inside Mountain) - Inside Mountain Bottom Layer - 0x17FA2:
0x00FF8 (Door to Secret Area) - True - Triangles & Black/White Squares & Squares 0x00FF8 (Door to Secret Area) - True - Triangles & Black/White Squares & Squares
@ -636,17 +636,17 @@ Inside Mountain Secret Area (Inside Mountain Secret Area) - Inside Mountain Path
0x32962 (Rotated Broken Shapers) - True - Rotated Shapers & Broken Rotated Shapers 0x32962 (Rotated Broken Shapers) - True - Rotated Shapers & Broken Rotated Shapers
0x32966 (Stars and Squares) - True - Stars & Squares & Black/White Squares & Stars + Same Colored Symbol 0x32966 (Stars and Squares) - True - Stars & Squares & Black/White Squares & Stars + Same Colored Symbol
0x01A31 (Rainbow Squares) - True - Color Cycle & RGB & Squares & Colored Squares 0x01A31 (Rainbow Squares) - True - Color Cycle & RGB & Squares & Colored Squares
0x00B71 (Squares & Stars and Colored Eraser) - True - Colored Eraser & Squares & Colored Squares & Stars & Stars + Same Colored Symbol 0x00B71 (Squares & Stars and Colored Eraser) - True - Colored Eraser & Squares & Colored Squares & Stars & Stars + Same Colored Symbol & Eraser
0x09DD5 (Lone Pillar) - True - Pillar & Triangles 0x09DD5 (Lone Pillar) - True - Pillar & Triangles
0x0A16E (Door to Challenge) - 0x09DD5 - Stars & Shapers & Colored Shapers & Stars + Same Colored Symbol 0x0A16E (Door to Challenge) - 0x09DD5 - Stars & Shapers & Colored Shapers & Stars + Same Colored Symbol
0x288EA (Wooden Beam Shapers) - True - Environment & Shapers 0x288EA (Wooden Beam Shapers) - True - Environment & Shapers
0x288FC (Wooden Beam Squares and Shapers) - True - Environment & Squares & Black/White Squares & Shapers & Rotated Shapers 0x288FC (Wooden Beam Squares and Shapers) - True - Environment & Squares & Black/White Squares & Shapers & Rotated Shapers
0x289E7 (Wooden Beam Shapers and Squares) - True - Environment & Stars & Squares & Black/White Squares 0x289E7 (Wooden Beam Stars and Squares) - True - Environment & Stars & Squares & Black/White Squares
0x288AA (Wooden Beam Shapers and Stars) - True - Environment & Stars & Shapers 0x288AA (Wooden Beam Shapers and Stars) - True - Environment & Stars & Shapers
0x17FB9 (Upstairs Dot Grid Negative Shapers) - True - Shapers & Dots & Negative Shapers 0x17FB9 (Upstairs Dot Grid Negative Shapers) - True - Shapers & Dots & Negative Shapers
0x0A16B (Upstairs Dot Grid Squares) - True - Squares & Black/White Squares & Colored Squares & Dots 0x0A16B (Upstairs Dot Grid Gap Dots) - True - Dots
0x0A2CE (Upstairs Dot Grid Stars) - 0x0A16B - Stars & Dots 0x0A2CE (Upstairs Dot Grid Stars) - 0x0A16B - Stars & Dots
0x0A2D7 (Upstairs Dot Grid Triangles) - 0x0A2CE - Triangles & Dots 0x0A2D7 (Upstairs Dot Grid Stars & Squares) - 0x0A2CE - Dots & Black/White Squares & Stars + Same Colored Symbol & Stars
0x0A2DD (Upstairs Dot Grid Shapers) - 0x0A2D7 - Shapers & Dots 0x0A2DD (Upstairs Dot Grid Shapers) - 0x0A2D7 - Shapers & Dots
0x0A2EA (Upstairs Dot Grid Rotated Shapers) - 0x0A2DD - Rotated Shapers & Dots 0x0A2EA (Upstairs Dot Grid Rotated Shapers) - 0x0A2DD - Rotated Shapers & Dots
0x0008F (Upstairs Invisible Dots 1) - True - Dots & Invisible Dots 0x0008F (Upstairs Invisible Dots 1) - True - Dots & Invisible Dots
@ -662,7 +662,7 @@ Inside Mountain Secret Area (Inside Mountain Secret Area) - Inside Mountain Path
0x00029 (Upstairs Invisible Dot Symmetry 3) - 0x00028 - Dots & Invisible Dots & Symmetry 0x00029 (Upstairs Invisible Dot Symmetry 3) - 0x00028 - Dots & Invisible Dots & Symmetry
Challenge (Challenge) - Inside Mountain Secret Area - 0x0A16E: Challenge (Challenge) - Inside Mountain Secret Area - 0x0A16E:
0x0A332 (Start Timer) - True - True 0x0A332 (Start Timer) - 11 Lasers - True
0x0088E (Small Basic) - 0x0A332 - True 0x0088E (Small Basic) - 0x0A332 - True
0x00BAF (Big Basic) - 0x0088E - True 0x00BAF (Big Basic) - 0x0088E - True
0x00BF3 (Square) - 0x00BAF - Squares & Black/White Squares 0x00BF3 (Square) - 0x00BAF - Squares & Black/White Squares
@ -694,11 +694,11 @@ Final Room (Inside Mountain Final Room) - Inside Mountain Bottom Layer - 0x01983
0x0383A (Stars Pillar) - True - Stars & Pillar 0x0383A (Stars Pillar) - True - Stars & Pillar
0x09E56 (Stars and Dots Pillar) - 0x0383A - Stars & Dots & Pillar 0x09E56 (Stars and Dots Pillar) - 0x0383A - Stars & Dots & Pillar
0x09E5A (Dot Grid Pillar) - 0x09E56 - Dots & Pillar 0x09E5A (Dot Grid Pillar) - 0x09E56 - Dots & Pillar
0x33961 (Sparse Dots Pillar) - 0x09E5A - Dots & Pillar 0x33961 (Sparse Dots Pillar) - 0x09E5A - Dots & Symmetry & Pillar
0x0383D (Dot Maze Pillar) - True - Dots & Pillar 0x0383D (Dot Maze Pillar) - True - Dots & Pillar
0x0383F (Squares Pillar) - 0x0383D - Squares & Black/White Squares & Pillar 0x0383F (Squares Pillar) - 0x0383D - Squares & Black/White Squares & Pillar
0x03859 (Shapers Pillar) - 0x0383F - Shapers & Pillar 0x03859 (Shapers Pillar) - 0x0383F - Shapers & Pillar
0x339BB (Squares and Stars) - 0x03859 - Squares & Black/White Squares & Stars & Pillar 0x339BB (Squares and Stars) - 0x03859 - Squares & Black/White Squares & Stars & Symmetry & Pillar
Elevator (Inside Mountain Final Room) - Final Room - 0x339BB & 0x33961: Elevator (Inside Mountain Final Room) - Final Room - 0x339BB & 0x33961:
0x3D9A6 (Elevator Door Closer Left) - True - True 0x3D9A6 (Elevator Door Closer Left) - True - True
@ -709,4 +709,4 @@ Elevator (Inside Mountain Final Room) - Final Room - 0x339BB & 0x33961:
0x3D9A8 (Back Wall Right) - 0x3D9A6 | 0x3D9A7 - True 0x3D9A8 (Back Wall Right) - 0x3D9A6 | 0x3D9A7 - True
0x3D9A9 (Elevator Start) - 0x3D9AA | 0x3D9A8 - True 0x3D9A9 (Elevator Start) - 0x3D9AA | 0x3D9A8 - True
Boat (Boat) - Main Island - 0x17CDF | 0x17CC8 | 0x17CA6 | 0x09DB8 | 0x17C95 - Inside Glass Factory - 0x17CDF | 0x17CC8 | 0x17CA6 | 0x09DB8 | 0x17C95 - Quarry Boathouse - 0x17CDF | 0x17CC8 | 0x17CA6 | 0x09DB8 | 0x17C95 - Swamp Near Boat - 0x17CDF | 0x17CC8 | 0x17CA6 | 0x09DB8 | 0x17C95 - Treehouse Entry Area - 0x17CDF | 0x17CC8 | 0x17CA6 | 0x09DB8 | 0x17C95: Boat (Boat) - Main Island - 0x17CDF | 0x17CC8 & 0x0005C | 0x17CA6 | 0x09DB8 | 0x17C95 | 0x0A054 - Inside Glass Factory - 0x17CDF & 0x0005C | 0x17CC8 & 0x0005C | 0x17CA6 & 0x0005C | 0x09DB8 & 0x0005C | 0x17C95 & 0x0005C | 0x0A054 & 0x0005C - Quarry Boathouse - 0x17CA6 - Swamp Near Boat - 0x17CDF | 0x17CC8 & 0x0005C | 0x17CA6 | 0x09DB8 | 0x17C95 | 0x0A054 - Treehouse Entry Area - 0x17CDF | 0x17CC8 & 0x0005C | 0x17CA6 | 0x09DB8 | 0x17C95 | 0x0A054:

View File

@ -11,7 +11,7 @@ from .locations import WitnessPlayerLocations, StaticWitnessLocations
from .items import WitnessItem, StaticWitnessItems, WitnessPlayerItems from .items import WitnessItem, StaticWitnessItems, WitnessPlayerItems
from .rules import set_rules from .rules import set_rules
from .regions import WitnessRegions from .regions import WitnessRegions
from .Options import is_option_enabled, the_witness_options from .Options import is_option_enabled, the_witness_options, get_option_value
from .utils import best_junk_to_add_based_on_weights from .utils import best_junk_to_add_based_on_weights
@ -50,7 +50,9 @@ class WitnessWorld(World):
return { return {
'seed': self.world.random.randint(0, 1000000), 'seed': self.world.random.randint(0, 1000000),
'victory_location': int(self.player_logic.VICTORY_LOCATION, 16), 'victory_location': int(self.player_logic.VICTORY_LOCATION, 16),
'panelhex_to_id': self.locat.CHECK_PANELHEX_TO_ID '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
} }
def generate_early(self): def generate_early(self):
@ -67,11 +69,17 @@ class WitnessWorld(World):
items_by_name = dict() items_by_name = dict()
for item in self.items.ITEM_TABLE: for item in self.items.ITEM_TABLE:
witness_item = self.create_item(item) witness_item = self.create_item(item)
if item not in self.items.EVENT_ITEM_TABLE: if item in self.items.PROGRESSION_TABLE:
pool.append(witness_item) pool.append(witness_item)
items_by_name[item] = witness_item items_by_name[item] = witness_item
# Put good item on first check 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
if symbols:
random_good_item = self.world.random.choice(self.items.GOOD_ITEMS) random_good_item = self.world.random.choice(self.items.GOOD_ITEMS)
first_check = self.world.get_location( first_check = self.world.get_location(
"Tutorial Gate Open", self.player "Tutorial Gate Open", self.player
@ -79,8 +87,18 @@ class WitnessWorld(World):
first_check.place_locked_item(items_by_name[random_good_item]) first_check.place_locked_item(items_by_name[random_good_item])
pool.remove(items_by_name[random_good_item]) pool.remove(items_by_name[random_good_item])
less_junk = 1
for item in self.items.EXTRA_AMOUNTS:
witness_item = self.create_item(item)
for i in range(0, self.items.EXTRA_AMOUNTS[item]):
if len(pool) < len(self.locat.CHECK_LOCATION_TABLE) - len(self.locat.EVENT_LOCATION_TABLE) - less_junk:
pool.append(witness_item)
# Put in junk items to fill the rest # Put in junk items to fill the rest
junk_size = len(self.locat.CHECK_LOCATION_TABLE) - len(pool) - len(self.locat.EVENT_LOCATION_TABLE) - 1 junk_size = len(self.locat.CHECK_LOCATION_TABLE) - len(pool) - len(self.locat.EVENT_LOCATION_TABLE) - less_junk
print(junk_size)
for i in range(0, junk_size): for i in range(0, junk_size):
pool.append(self.create_item(self.get_filler_item_name())) pool.append(self.create_item(self.get_filler_item_name()))
@ -107,7 +125,7 @@ class WitnessWorld(World):
slot_data["hard_mode"] = False slot_data["hard_mode"] = False
for option_name in the_witness_options: for option_name in the_witness_options:
slot_data[option_name] = is_option_enabled( slot_data[option_name] = get_option_value(
self.world, self.player, option_name self.world, self.player, option_name
) )
@ -124,6 +142,8 @@ class WitnessWorld(World):
name, item.progression, item.code, player=self.player name, item.progression, item.code, player=self.player
) )
new_item.trap = item.trap new_item.trap = item.trap
if item.never_exclude:
new_item.never_exclude = True
return new_item return new_item
def get_filler_item_name(self) -> str: # Used by itemlinks def get_filler_item_name(self) -> str: # Used by itemlinks

View File

@ -6,7 +6,7 @@ from typing import Dict, NamedTuple, Optional
from BaseClasses import Item, MultiWorld from BaseClasses import Item, MultiWorld
from . import StaticWitnessLogic, WitnessPlayerLocations, WitnessPlayerLogic from . import StaticWitnessLogic, WitnessPlayerLocations, WitnessPlayerLogic
from .Options import get_option_value, is_option_enabled from .Options import get_option_value, is_option_enabled, the_witness_options
from fractions import Fraction from fractions import Fraction
@ -18,6 +18,7 @@ class ItemData(NamedTuple):
progression: bool progression: bool
event: bool = False event: bool = False
trap: bool = False trap: bool = False
never_exclude: bool = False
class WitnessItem(Item): class WitnessItem(Item):
@ -50,7 +51,7 @@ class StaticWitnessItems:
def __init__(self): def __init__(self):
item_tab = dict() item_tab = dict()
for item in StaticWitnessLogic.ALL_ITEMS: for item in StaticWitnessLogic.ALL_SYMBOL_ITEMS.union(StaticWitnessLogic.ALL_DOOR_ITEMS):
if item[0] == "11 Lasers" or item == "7 Lasers": if item[0] == "11 Lasers" or item == "7 Lasers":
continue continue
@ -64,6 +65,9 @@ class StaticWitnessItems:
for item in StaticWitnessLogic.ALL_BOOSTS: for item in StaticWitnessLogic.ALL_BOOSTS:
item_tab[item[0]] = ItemData(158000 + item[1], False, False) item_tab[item[0]] = ItemData(158000 + item[1], False, False)
for item in StaticWitnessLogic.ALL_USEFULS:
item_tab[item[0]] = ItemData(158000 + item[1], False, False, False, True)
item_tab = dict(sorted( item_tab = dict(sorted(
item_tab.items(), item_tab.items(),
key=lambda single_item: single_item[1].code key=lambda single_item: single_item[1].code
@ -83,7 +87,31 @@ class WitnessPlayerItems:
"""Adds event items after logic changes due to options""" """Adds event items after logic changes due to options"""
self.EVENT_ITEM_TABLE = dict() self.EVENT_ITEM_TABLE = dict()
self.ITEM_TABLE = copy.copy(StaticWitnessItems.ALL_ITEM_TABLE) self.ITEM_TABLE = copy.copy(StaticWitnessItems.ALL_ITEM_TABLE)
self.PROGRESSION_TABLE = dict()
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:
del self.ITEM_TABLE[item[0]]
else:
self.PROGRESSION_TABLE[item[0]] = self.ITEM_TABLE[item[0]]
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")
if doors and symbols:
self.GOOD_ITEMS = [
"Dots", "Black/White Squares", "Symmetry"
]
elif symbols:
self.GOOD_ITEMS = [ self.GOOD_ITEMS = [
"Dots", "Black/White Squares", "Stars", "Dots", "Black/White Squares", "Stars",
"Shapers", "Symmetry" "Shapers", "Symmetry"

View File

@ -19,6 +19,12 @@ class StaticWitnessLocations:
"Laser": 700, "Laser": 700,
} }
EXTRA_LOCATIONS = {
"Tutorial Front Left",
"Tutorial Back Left",
"Tutorial Back Right",
}
GENERAL_LOCATIONS = { GENERAL_LOCATIONS = {
"Tutorial Gate Open", "Tutorial Gate Open",
@ -50,11 +56,12 @@ class StaticWitnessLocations:
"Quarry Mill Eraser and Dots 6", "Quarry Mill Eraser and Dots 6",
"Quarry Mill Eraser and Squares 8", "Quarry Mill Eraser and Squares 8",
"Quarry Mill Small Squares & Dots & and Eraser", "Quarry Mill Small Squares & Dots & Eraser",
"Quarry Boathouse Intro Shapers", "Quarry Boathouse Intro Shapers",
"Quarry Boathouse Intro Stars",
"Quarry Boathouse Eraser and Shapers 5", "Quarry Boathouse Eraser and Shapers 5",
"Quarry Boathouse Stars & Eraser & and Shapers 2", "Quarry Boathouse Stars & Eraser & Shapers 2",
"Quarry Boathouse Stars & Eraser & and Shapers 5", "Quarry Boathouse Stars & Eraser & Shapers 5",
"Quarry Discard", "Quarry Discard",
"Quarry Laser", "Quarry Laser",
@ -82,7 +89,7 @@ class StaticWitnessLocations:
"Town Rooftop Discard", "Town Rooftop Discard",
"Town Symmetry Squares 5 + Dots", "Town Symmetry Squares 5 + Dots",
"Town Full Dot Grid Shapers 5", "Town Full Dot Grid Shapers 5",
"Town Shapers & Dots & and Eraser", "Town Shapers & Dots & Eraser",
"Town Laser", "Town Laser",
"Theater Discard", "Theater Discard",
@ -138,7 +145,7 @@ class StaticWitnessLocations:
UNCOMMON_LOCATIONS = { UNCOMMON_LOCATIONS = {
"Mountaintop River Shape", "Mountaintop River Shape",
"Tutorial Patio Floor", "Tutorial Patio Floor",
"Quarry Mill Big Squares & Dots & and Eraser", "Quarry Mill Big Squares & Dots & Eraser",
"Theater Tutorial Video", "Theater Tutorial Video",
"Theater Desert Video", "Theater Desert Video",
"Theater Jungle Video", "Theater Jungle Video",
@ -165,11 +172,11 @@ class StaticWitnessLocations:
"Inside Mountain Secret Area Lone Pillar", "Inside Mountain Secret Area Lone Pillar",
"Inside Mountain Secret Area Wooden Beam Shapers", "Inside Mountain Secret Area Wooden Beam Shapers",
"Inside Mountain Secret Area Wooden Beam Squares and Shapers", "Inside Mountain Secret Area Wooden Beam Squares and Shapers",
"Inside Mountain Secret Area Wooden Beam Shapers and Squares", "Inside Mountain Secret Area Wooden Beam Stars and Squares",
"Inside Mountain Secret Area Wooden Beam Shapers and Stars", "Inside Mountain Secret Area Wooden Beam Shapers and Stars",
"Inside Mountain Secret Area Upstairs Invisible Dots 8", "Inside Mountain Secret Area Upstairs Invisible Dots 8",
"Inside Mountain Secret Area Upstairs Invisible Dot Symmetry 3", "Inside Mountain Secret Area Upstairs Invisible Dot Symmetry 3",
"Inside Mountain Secret Area Upstairs Dot Grid Shapers", "Inside Mountain Secret Area Upstairs Dot Grid Negative Shapers",
"Inside Mountain Secret Area Upstairs Dot Grid Rotated Shapers", "Inside Mountain Secret Area Upstairs Dot Grid Rotated Shapers",
"Challenge Vault Box", "Challenge Vault Box",
@ -241,6 +248,13 @@ class WitnessPlayerLocations:
if is_option_enabled(world, player, "shuffle_hard"): if is_option_enabled(world, player, "shuffle_hard"):
self.CHECK_LOCATIONS = self.CHECK_LOCATIONS | StaticWitnessLocations.HARD_LOCATIONS 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 self.CHECK_LOCATIONS = self.CHECK_LOCATIONS | player_logic.ADDED_CHECKS
self.CHECK_LOCATIONS = self.CHECK_LOCATIONS - { self.CHECK_LOCATIONS = self.CHECK_LOCATIONS - {
@ -259,9 +273,6 @@ class WitnessPlayerLocations:
event_locations = { event_locations = {
p for p in player_logic.NECESSARY_EVENT_PANELS p for p in player_logic.NECESSARY_EVENT_PANELS
if StaticWitnessLogic.CHECKS_BY_HEX[p]["checkName"]
not in self.CHECK_LOCATIONS
or p in player_logic.ALWAYS_EVENT_HEX_CODES
} }
self.EVENT_LOCATION_TABLE = { self.EVENT_LOCATION_TABLE = {

View File

@ -18,13 +18,22 @@ When the world has parsed its options, a second function is called to finalize t
import copy import copy
from BaseClasses import MultiWorld from BaseClasses import MultiWorld
from .static_logic import StaticWitnessLogic from .static_logic import StaticWitnessLogic
from .utils import define_new_region, get_disable_unrandomized_list, parse_lambda from .utils import define_new_region, get_disable_unrandomized_list, parse_lambda, get_early_utm_list
from .Options import is_option_enabled from .Options import is_option_enabled, get_option_value, the_witness_options
class WitnessPlayerLogic: class WitnessPlayerLogic:
"""WITNESS LOGIC CLASS""" """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): def reduce_req_within_region(self, panel_hex):
""" """
Panels in this game often only turn on when other panels are solved. Panels in this game often only turn on when other panels are solved.
@ -34,13 +43,27 @@ class WitnessPlayerLogic:
Panels outside of the same region will still be checked manually. Panels outside of the same region will still be checked manually.
""" """
if self.DEPENDENT_REQUIREMENTS_BY_HEX[panel_hex]["panels"] == frozenset({frozenset()}): these_items = self.DEPENDENT_REQUIREMENTS_BY_HEX[panel_hex]["items"]
return self.DEPENDENT_REQUIREMENTS_BY_HEX[panel_hex]["items"]
real_items = {item[0] for item in self.PROG_ITEMS_ACTUALLY_IN_THE_GAME}
these_items = frozenset({
subset.intersection(real_items)
for subset in these_items
})
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() all_options = set()
these_items = self.DEPENDENT_REQUIREMENTS_BY_HEX[panel_hex]["items"]
these_panels = self.DEPENDENT_REQUIREMENTS_BY_HEX[panel_hex]["panels"]
check_obj = StaticWitnessLogic.CHECKS_BY_HEX[panel_hex] check_obj = StaticWitnessLogic.CHECKS_BY_HEX[panel_hex]
for option in these_panels: for option in these_panels:
@ -57,6 +80,9 @@ class WitnessPlayerLogic:
elif dep_obj["region"]["name"] != check_obj["region"]["name"]: elif dep_obj["region"]["name"] != check_obj["region"]["name"]:
new_items = frozenset({frozenset([option_panel])}) new_items = frozenset({frozenset([option_panel])})
self.EVENT_PANELS_FROM_PANELS.add(option_panel) self.EVENT_PANELS_FROM_PANELS.add(option_panel)
elif option_panel in self.ALWAYS_EVENT_NAMES_BY_HEX.keys():
new_items = frozenset({frozenset([option_panel])})
self.EVENT_PANELS_FROM_PANELS.add(option_panel)
else: else:
new_items = self.reduce_req_within_region(option_panel) new_items = self.reduce_req_within_region(option_panel)
@ -105,7 +131,7 @@ class WitnessPlayerLogic:
line_split = line.split(" - ") line_split = line.split(" - ")
required_items = parse_lambda(line_split[2]) required_items = parse_lambda(line_split[2])
items_actually_in_the_game = {item[0] for item in StaticWitnessLogic.ALL_ITEMS} items_actually_in_the_game = {item[0] for item in StaticWitnessLogic.ALL_SYMBOL_ITEMS}
required_items = frozenset( required_items = frozenset(
subset.intersection(items_actually_in_the_game) subset.intersection(items_actually_in_the_game)
for subset in required_items for subset in required_items
@ -121,7 +147,14 @@ class WitnessPlayerLogic:
return return
if adj_type == "Disabled Locations": if adj_type == "Disabled Locations":
self.COMPLETELY_DISABLED_CHECKS.add(line[:7]) panel_hex = line[:7]
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 return
@ -139,10 +172,14 @@ class WitnessPlayerLogic:
"""Makes logic adjustments based on options""" """Makes logic adjustments based on options"""
adjustment_linesets_in_order = [] adjustment_linesets_in_order = []
if is_option_enabled(world, player, "challenge_victory"): if get_option_value(world, player, "victory_condition") == 0:
self.VICTORY_LOCATION = "0x0356B"
else:
self.VICTORY_LOCATION = "0x3D9A9" self.VICTORY_LOCATION = "0x3D9A9"
elif get_option_value(world, player, "victory_condition") == 1:
self.VICTORY_LOCATION = "0x0356B"
elif get_option_value(world, player, "victory_condition") == 2:
self.VICTORY_LOCATION = "0x09F7F"
elif get_option_value(world, player, "victory_condition") == 3:
self.VICTORY_LOCATION = "0xFFF00"
self.COMPLETELY_DISABLED_CHECKS.add( self.COMPLETELY_DISABLED_CHECKS.add(
self.VICTORY_LOCATION self.VICTORY_LOCATION
@ -151,6 +188,20 @@ class WitnessPlayerLogic:
if is_option_enabled(world, player, "disable_non_randomized_puzzles"): if is_option_enabled(world, player, "disable_non_randomized_puzzles"):
adjustment_linesets_in_order.append(get_disable_unrandomized_list()) 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)
if is_option_enabled(world, player, "shuffle_doors"):
self.PROG_ITEMS_ACTUALLY_IN_THE_GAME.update(StaticWitnessLogic.ALL_DOOR_ITEMS)
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"
}
for adjustment_lineset in adjustment_linesets_in_order: for adjustment_lineset in adjustment_linesets_in_order:
current_adjustment_type = None current_adjustment_type = None
@ -182,6 +233,17 @@ class WitnessPlayerLogic:
pair = (name, self.EVENT_ITEM_NAMES[panel]) pair = (name, self.EVENT_ITEM_NAMES[panel])
return pair 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): def make_event_panel_lists(self):
""" """
Special event panel data structures Special event panel data structures
@ -197,7 +259,6 @@ class WitnessPlayerLogic:
self.ORIGINAL_EVENT_PANELS.update(self.EVENT_PANELS_FROM_PANELS) self.ORIGINAL_EVENT_PANELS.update(self.EVENT_PANELS_FROM_PANELS)
self.ORIGINAL_EVENT_PANELS.update(self.EVENT_PANELS_FROM_REGIONS) self.ORIGINAL_EVENT_PANELS.update(self.EVENT_PANELS_FROM_REGIONS)
self.NECESSARY_EVENT_PANELS.update(self.EVENT_PANELS_FROM_PANELS)
for panel in self.EVENT_PANELS_FROM_REGIONS: for panel in self.EVENT_PANELS_FROM_REGIONS:
for region_name, region in StaticWitnessLogic.ALL_REGIONS_BY_NAME.items(): for region_name, region in StaticWitnessLogic.ALL_REGIONS_BY_NAME.items():
@ -213,6 +274,15 @@ class WitnessPlayerLogic:
if panel not in region["panels"] | connected_r["panels"]: if panel not in region["panels"] | connected_r["panels"]:
self.NECESSARY_EVENT_PANELS.add(panel) self.NECESSARY_EVENT_PANELS.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)
for always_hex, always_item in self.ALWAYS_EVENT_NAMES_BY_HEX.items(): for always_hex, always_item in self.ALWAYS_EVENT_NAMES_BY_HEX.items():
self.ALWAYS_EVENT_HEX_CODES.add(always_hex) self.ALWAYS_EVENT_HEX_CODES.add(always_hex)
self.NECESSARY_EVENT_PANELS.add(always_hex) self.NECESSARY_EVENT_PANELS.add(always_hex)
@ -226,6 +296,10 @@ class WitnessPlayerLogic:
self.EVENT_PANELS_FROM_PANELS = set() self.EVENT_PANELS_FROM_PANELS = set()
self.EVENT_PANELS_FROM_REGIONS = set() 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.CONNECTIONS_BY_REGION_NAME = copy.copy(StaticWitnessLogic.STATIC_CONNECTIONS_BY_REGION_NAME) 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) self.DEPENDENT_REQUIREMENTS_BY_HEX = copy.copy(StaticWitnessLogic.STATIC_DEPENDENT_REQUIREMENTS_BY_HEX)
self.REQUIREMENTS_BY_HEX = dict() self.REQUIREMENTS_BY_HEX = dict()
@ -257,7 +331,9 @@ class WitnessPlayerLogic:
"0x09ED8": "Inside Mountain Second Layer Both Light Bridges Solved", "0x09ED8": "Inside Mountain Second Layer Both Light Bridges Solved",
"0x0A3D0": "Quarry Laser Boathouse Requirement Met", "0x0A3D0": "Quarry Laser Boathouse Requirement Met",
"0x00596": "Swamp Red Water Drains", "0x00596": "Swamp Red Water Drains",
"0x28B39": "Town Tower 4th Door Opens" "0x28B39": "Town Tower 4th Door Opens",
"0x0343A": "Door to Symmetry Island Powers On",
"0xFFF00": "Inside Mountain Bottom Layer Discard Turns On"
} }
self.ALWAYS_EVENT_NAMES_BY_HEX = { self.ALWAYS_EVENT_NAMES_BY_HEX = {
@ -266,8 +342,8 @@ class WitnessPlayerLogic:
"0x09F98": "Desert Laser Redirection", "0x09F98": "Desert Laser Redirection",
"0x03612": "Quarry Laser Activation", "0x03612": "Quarry Laser Activation",
"0x19650": "Shadows Laser Activation", "0x19650": "Shadows Laser Activation",
"0x0360E": "Keep Laser Hedges Activation", "0x0360E": "Keep Laser Activation",
"0x03317": "Keep Laser Pressure Plates Activation", "0x03317": "Keep Laser Activation",
"0x17CA4": "Monastery Laser Activation", "0x17CA4": "Monastery Laser Activation",
"0x032F5": "Town Laser Activation", "0x032F5": "Town Laser Activation",
"0x03616": "Jungle Laser Activation", "0x03616": "Jungle Laser Activation",
@ -280,6 +356,8 @@ class WitnessPlayerLogic:
"0x03481": "Tutorial Video Pattern Knowledge", "0x03481": "Tutorial Video Pattern Knowledge",
"0x03702": "Jungle Video Pattern Knowledge", "0x03702": "Jungle Video Pattern Knowledge",
"0x2FAF6": "Theater Walkway Video Pattern Knowledge", "0x2FAF6": "Theater Walkway Video Pattern Knowledge",
"0x09F7F": "Mountaintop Trap Door Turns On",
"0x17C34": "Mountain Access",
} }
self.make_options_adjustments(world, player) self.make_options_adjustments(world, player)

View File

@ -7,7 +7,7 @@ depending on the items received
from BaseClasses import MultiWorld from BaseClasses import MultiWorld
from .player_logic import WitnessPlayerLogic from .player_logic import WitnessPlayerLogic
from .Options import is_option_enabled from .Options import is_option_enabled, get_option_value
from .locations import WitnessPlayerLocations from .locations import WitnessPlayerLocations
from . import StaticWitnessLogic from . import StaticWitnessLogic
from ..AutoWorld import LogicMixin from ..AutoWorld import LogicMixin
@ -27,10 +27,7 @@ class WitnessLogic(LogicMixin):
and self.has("Desert Laser Redirection", player)) and self.has("Desert Laser Redirection", player))
lasers += int(self.has("Town Laser Activation", player)) lasers += int(self.has("Town Laser Activation", player))
lasers += int(self.has("Monastery Laser Activation", player)) lasers += int(self.has("Monastery Laser Activation", player))
lasers += int(self.has("Keep Laser Pressure Plates Activation", player) and ( lasers += int(self.has("Keep Laser Activation", player))
is_option_enabled(world, player, "disable_non_randomized_puzzles")
or self.has("Keep Laser Hedges Activation", player)
))
lasers += int(self.has("Quarry Laser Activation", player)) lasers += int(self.has("Quarry Laser Activation", player))
lasers += int(self.has("Treehouse Laser Activation", player)) lasers += int(self.has("Treehouse Laser Activation", player))
lasers += int(self.has("Jungle Laser Activation", player)) lasers += int(self.has("Jungle Laser Activation", player))
@ -57,7 +54,6 @@ class WitnessLogic(LogicMixin):
and check_name + " Solved" not in locat.EVENT_LOCATION_TABLE and check_name + " Solved" not in locat.EVENT_LOCATION_TABLE
and not self._witness_safe_manual_panel_check(panel, world, player, player_logic, locat)): and not self._witness_safe_manual_panel_check(panel, world, player, player_logic, locat)):
return False return False
return True return True
def _witness_meets_item_requirements(self, panel, world, player, player_logic: WitnessPlayerLogic, locat): def _witness_meets_item_requirements(self, panel, world, player, player_logic: WitnessPlayerLogic, locat):
@ -76,22 +72,15 @@ class WitnessLogic(LogicMixin):
for item in option: for item in option:
if item == "7 Lasers": if item == "7 Lasers":
if not self._witness_has_lasers(world, player, 7): if not self._witness_has_lasers(world, player, get_option_value(world, player, "mountain_lasers")):
valid_option = False valid_option = False
break break
elif item == "11 Lasers": elif item == "11 Lasers":
if not self._witness_has_lasers(world, player, 11): if not self._witness_has_lasers(world, player, get_option_value(world, player, "challenge_lasers")):
valid_option = False valid_option = False
break break
elif item in player_logic.NECESSARY_EVENT_PANELS: elif item in player_logic.ORIGINAL_EVENT_PANELS:
if StaticWitnessLogic.CHECKS_BY_HEX[item]["checkName"] + " Solved" in locat.EVENT_LOCATION_TABLE: valid_option = self._witness_can_solve_panel(item, world, player, player_logic, locat)
valid_option = self.has(player_logic.EVENT_ITEM_NAMES[item], player)
else:
valid_option = self.can_reach(
StaticWitnessLogic.CHECKS_BY_HEX[item]["checkName"], "Location", player
)
if not valid_option:
break
elif not self.has(item, player): elif not self.has(item, player):
valid_option = False valid_option = False
break break

View File

@ -4,9 +4,14 @@ from .utils import define_new_region, parse_lambda
class StaticWitnessLogic: class StaticWitnessLogic:
ALL_ITEMS = set() ALL_SYMBOL_ITEMS = set()
ALL_USEFULS = set()
ALL_TRAPS = set() ALL_TRAPS = set()
ALL_BOOSTS = 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() EVENT_PANELS_FROM_REGIONS = set()
@ -25,13 +30,13 @@ class StaticWitnessLogic:
path = os.path.join(os.path.dirname(__file__), "WitnessItems.txt") path = os.path.join(os.path.dirname(__file__), "WitnessItems.txt")
with open(path, "r", encoding="utf-8") as file: with open(path, "r", encoding="utf-8") as file:
current_set = self.ALL_ITEMS current_set = self.ALL_SYMBOL_ITEMS
for line in file.readlines(): for line in file.readlines():
line = line.strip() line = line.strip()
if line == "Progression:": if line == "Progression:":
current_set = self.ALL_ITEMS current_set = self.ALL_SYMBOL_ITEMS
continue continue
if line == "Boosts:": if line == "Boosts:":
current_set = self.ALL_BOOSTS current_set = self.ALL_BOOSTS
@ -39,6 +44,9 @@ class StaticWitnessLogic:
if line == "Traps:": if line == "Traps:":
current_set = self.ALL_TRAPS current_set = self.ALL_TRAPS
continue continue
if line == "Usefuls:":
current_set = self.ALL_USEFULS
continue
if line == "": if line == "":
continue continue
@ -46,13 +54,32 @@ class StaticWitnessLogic:
current_set.add((line_split[1], int(line_split[0]))) 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): def read_logic_file(self):
""" """
Reads the logic file and does the initial population of data structures Reads the logic file and does the initial population of data structures
""" """
path = os.path.join(os.path.dirname(__file__), "WitnessLogic.txt") path = os.path.join(os.path.dirname(__file__), "WitnessLogic.txt")
with open(path, "r", encoding="utf-8") as file: with open(path, "r", encoding="utf-8") as file:
current_region = "" current_region = dict()
discard_ids = 0 discard_ids = 0
normal_panel_ids = 0 normal_panel_ids = 0
@ -105,16 +132,44 @@ class StaticWitnessLogic:
laser_ids += 1 laser_ids += 1
else: else:
location_type = "General" 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 location_id = normal_panel_ids
normal_panel_ids += 1 normal_panel_ids += 1
required_items = parse_lambda(required_item_lambda) required_items = parse_lambda(required_item_lambda)
items_actually_in_the_game = {item[0] for item in self.ALL_ITEMS} items_actually_in_the_game = {item[0] for item in self.ALL_SYMBOL_ITEMS}
required_items = frozenset( required_items = set(
subset.intersection(items_actually_in_the_game) subset.intersection(items_actually_in_the_game)
for subset in required_items 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)
requirement = { requirement = {
"panels": parse_lambda(required_panel_lambda), "panels": parse_lambda(required_panel_lambda),
"items": required_items "items": required_items

View File

@ -89,10 +89,18 @@ def parse_lambda(lambda_string):
return lambda_set return lambda_set
@cache_argsless def get_adjustment_file(adjustment_file):
def get_disable_unrandomized_list():
adjustment_file = "Disable_Unrandomized.txt"
path = os.path.join(os.path.dirname(__file__), adjustment_file) path = os.path.join(os.path.dirname(__file__), adjustment_file)
with open(path) as f: with open(path) as f:
return [line.strip() for line in f.readlines()] return [line.strip() for line in f.readlines()]
@cache_argsless
def get_disable_unrandomized_list():
return get_adjustment_file("Disable_Unrandomized.txt")
@cache_argsless
def get_early_utm_list():
return get_adjustment_file("Early_UTM.txt")