The Witness: The Secret Feature (#4370)

* Secret Feature

* Fixes

* Fixes and unit tests

* renaming some variables

* Fix the thing

* unit test for elevator egg

* Docstring

* reword

* Fix duplicate locations I think?

* Remove debug thing

* Add the tests back lol

* Make it so that you can exclude an egg to disable it

* Improve hint text for easter eggs

* Update worlds/witness/options.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Update worlds/witness/player_logic.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Update worlds/witness/options.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Update worlds/witness/player_logic.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Update worlds/witness/rules.py

Co-authored-by: Scipio Wright <scipiowright@gmail.com>

* Update test_easter_egg_shuffle.py

* This was actually not necessary, since this is the Egg requirements, nothing to do with location names

* Move one of them

* Improve logic

* Lol

* Moar

* Adjust unit tests

* option docstring adjustment

* Recommend door shuffle

* Don't overlap IDs

* Option description idk

* Change the way the difficulties work to reward playing higher modes

* Fix merge

* add some stuff to generate_data_file (this file is not imported during gen, don't review it :D)

* oop

* space

* This can be earlier than I thought, apparently.

* buffer

* Comment

* Make sure the option is VERY visible

* Some mypy stuff

* apparently ruff wants this

* .

* durinig

* Update options.py

* Explain the additional effects of each difficulty

* Fix logic of flood room secret

* Add Southern Peninsula Area

* oop

---------

Co-authored-by: Scipio Wright <scipiowright@gmail.com>
This commit is contained in:
NewSoupVi
2025-03-08 01:44:06 +01:00
committed by GitHub
parent bc61221ec6
commit 08b3b3ecf5
18 changed files with 651 additions and 73 deletions

View File

@@ -5,7 +5,7 @@ import dataclasses
from logging import error, warning from logging import error, warning
from typing import Any, Dict, List, Optional, cast from typing import Any, Dict, List, Optional, cast
from BaseClasses import CollectionState, Entrance, Location, Region, Tutorial from BaseClasses import CollectionState, Entrance, Location, LocationProgressType, Region, Tutorial
from Options import OptionError, PerGameCommonOptions, Toggle from Options import OptionError, PerGameCommonOptions, Toggle
from worlds.AutoWorld import WebWorld, World from worlds.AutoWorld import WebWorld, World
@@ -380,6 +380,10 @@ class WitnessWorld(World):
if isinstance(item_name, dict): if isinstance(item_name, dict):
item_name = next(iter(item_name)) item_name = next(iter(item_name))
# Easter Egg events with arbitrary sizes
if item_name.startswith("+") and "Easter Egg" in item_name:
return WitnessItem.make_egg_event(item_name, self.player)
# this conditional is purely for unit tests, which need to be able to create an item before generate_early # this conditional is purely for unit tests, which need to be able to create an item before generate_early
item_data: ItemData item_data: ItemData
if hasattr(self, "player_items") and self.player_items and item_name in self.player_items.item_data: if hasattr(self, "player_items") and self.player_items and item_name in self.player_items.item_data:
@@ -389,6 +393,18 @@ class WitnessWorld(World):
return WitnessItem(item_name, item_data.classification, item_data.ap_code, player=self.player) return WitnessItem(item_name, item_data.classification, item_data.ap_code, player=self.player)
def collect(self, state: "CollectionState", item: WitnessItem) -> bool:
changed = super().collect(state, item)
if changed and item.eggs:
state.prog_items[self.player]["Egg"] += item.eggs
return changed
def remove(self, state: "CollectionState", item: WitnessItem) -> bool:
changed = super().remove(state, item)
if changed and item.eggs:
state.prog_items[self.player]["Egg"] -= item.eggs
return changed
def get_filler_item_name(self) -> str: def get_filler_item_name(self) -> str:
return "Speed Boost" return "Speed Boost"
@@ -398,11 +414,9 @@ class WitnessLocation(Location):
Archipelago Location for The Witness Archipelago Location for The Witness
""" """
game: str = "The Witness" game: str = "The Witness"
entity_hex: int = -1
def __init__(self, player: int, name: str, address: Optional[int], parent: Region, ch_hex: int = -1) -> None: def __init__(self, player: int, name: str, address: Optional[int], parent: Region) -> None:
super().__init__(player, name, address, parent) super().__init__(player, name, address, parent)
self.entity_hex = ch_hex
def create_region(world: WitnessWorld, name: str, player_locations: WitnessPlayerLocations, def create_region(world: WitnessWorld, name: str, player_locations: WitnessPlayerLocations,
@@ -416,14 +430,13 @@ def create_region(world: WitnessWorld, name: str, player_locations: WitnessPlaye
for location in region_locations: for location in region_locations:
loc_id = player_locations.CHECK_LOCATION_TABLE[location] loc_id = player_locations.CHECK_LOCATION_TABLE[location]
entity_hex = -1 location_obj = WitnessLocation(world.player, location, loc_id, ret)
if location in static_witness_logic.ENTITIES_BY_NAME: if location in static_witness_logic.ENTITIES_BY_NAME:
entity_hex = int( entity_hex = static_witness_logic.ENTITIES_BY_NAME[location]["entity_hex"]
static_witness_logic.ENTITIES_BY_NAME[location]["entity_hex"], 0
) if entity_hex in world.player_logic.EXCLUDED_ENTITIES:
location_obj = WitnessLocation( location_obj.progress_type = LocationProgressType.EXCLUDED
world.player, location, loc_id, ret, entity_hex
)
ret.locations.append(location_obj) ret.locations.append(location_obj)
if exits: if exits:

View File

@@ -206,7 +206,7 @@ Door - 0x0A24B (Flood Room Entry) - 0x0A249
159043 - 0x0A14C (Pond Room Near Reflection EP) - True - True 159043 - 0x0A14C (Pond Room Near Reflection EP) - True - True
159044 - 0x0A14D (Pond Room Far Reflection EP) - True - True 159044 - 0x0A14D (Pond Room Far Reflection EP) - True - True
Desert Flood Room (Desert) - Desert Elevator Room - 0x0C316: Desert Flood Room (Desert) - Desert Elevator Room - 0x0C316 - Desert Flood Room Underwater - 0x1C260:
158097 - 0x1C2DF (Reduce Water Level Far Left) - True - True 158097 - 0x1C2DF (Reduce Water Level Far Left) - True - True
158098 - 0x1831E (Reduce Water Level Far Right) - True - True 158098 - 0x1831E (Reduce Water Level Far Right) - True - True
158099 - 0x1C260 (Reduce Water Level Near Left) - True - True 158099 - 0x1C260 (Reduce Water Level Near Left) - True - True
@@ -224,6 +224,8 @@ Desert Flood Room (Desert) - Desert Elevator Room - 0x0C316:
Door - 0x0C316 (Elevator Room Entry) - 0x18076 Door - 0x0C316 (Elevator Room Entry) - 0x18076
159034 - 0x337F8 (Flood Room EP) - 0x1C2DF - True 159034 - 0x337F8 (Flood Room EP) - 0x1C2DF - True
Desert Flood Room Underwater (Desert):
Desert Elevator Room (Desert) - Desert Behind Elevator - 0x01317: Desert Elevator Room (Desert) - Desert Behind Elevator - 0x01317:
158111 - 0x17C31 (Elevator Room Transparent) - True - True 158111 - 0x17C31 (Elevator Room Transparent) - True - True
158113 - 0x012D7 (Elevator Room Hexagonal) - 0x17C31 & 0x0A015 - True 158113 - 0x012D7 (Elevator Room Hexagonal) - 0x17C31 & 0x0A015 - True
@@ -501,7 +503,7 @@ Laser - 0x17C65 (Laser) - 0x17CA4
159121 - 0x03BE3 (Garden Right EP) - True - True 159121 - 0x03BE3 (Garden Right EP) - True - True
159122 - 0x0A409 (Wall EP) - True - True 159122 - 0x0A409 (Wall EP) - True - True
Inside Monastery (Monastery): Inside Monastery (Monastery) - Monastery North Shutters - 0x09D9B:
158213 - 0x09D9B (Shutters Control) - True - Dots 158213 - 0x09D9B (Shutters Control) - True - Dots
158214 - 0x193A7 (Inside 1) - 0x00037 - True 158214 - 0x193A7 (Inside 1) - 0x00037 - True
158215 - 0x193AA (Inside 2) - 0x193A7 - True 158215 - 0x193AA (Inside 2) - 0x193A7 - True
@@ -513,6 +515,8 @@ Inside Monastery (Monastery):
Monastery Garden (Monastery): Monastery Garden (Monastery):
Monastery North Shutters (Monastery):
==Town== ==Town==
Town Obelisk (Town) - Entry - True: Town Obelisk (Town) - Entry - True:
@@ -637,9 +641,13 @@ Door - 0x3CCDF (Exit Right) - 0x33AB2
159556 - 0x33A2A (Door EP) - 0x03553 - True 159556 - 0x33A2A (Door EP) - 0x03553 - True
159558 - 0x33B06 (Church EP) - 0x0354E - True 159558 - 0x33B06 (Church EP) - 0x0354E - True
==Southern Peninsula==
Southern Peninsula (Southern Peninsula) - Main Island - True:
==Jungle== ==Jungle==
Jungle (Jungle) - Main Island - True - The Ocean - 0x17CDF: Jungle (Jungle) - Main Island - True - The Ocean - 0x17CDF - Jungle Under Popup Wall - 0x1475B:
158251 - 0x17CDF (Shore Boat Spawn) - True - Boat 158251 - 0x17CDF (Shore Boat Spawn) - True - Boat
158609 - 0x17F9B (Discard) - True - Triangles 158609 - 0x17F9B (Discard) - True - Triangles
158252 - 0x002C4 (First Row 1) - True - True 158252 - 0x002C4 (First Row 1) - True - True
@@ -670,6 +678,8 @@ Door - 0x3873B (Laser Shortcut) - 0x337FA
159350 - 0x035CB (Bamboo CCW EP) - True - True 159350 - 0x035CB (Bamboo CCW EP) - True - True
159351 - 0x035CF (Bamboo CW EP) - True - True 159351 - 0x035CF (Bamboo CW EP) - True - True
Jungle Under Popup Wall (Jungle):
Outside Jungle River (Jungle) - Main Island - True - Monastery Garden - 0x0CF2A - Jungle Vault - 0x15287: Outside Jungle River (Jungle) - Main Island - True - Monastery Garden - 0x0CF2A - Jungle Vault - 0x15287:
158267 - 0x17CAA (Monastery Garden Shortcut Panel) - True - True 158267 - 0x17CAA (Monastery Garden Shortcut Panel) - True - True
Door - 0x0CF2A (Monastery Garden Shortcut) - 0x17CAA Door - 0x0CF2A (Monastery Garden Shortcut) - 0x17CAA
@@ -712,9 +722,11 @@ Bunker Ultraviolet Room (Bunker) - Bunker Elevator Section - 0x0A08D:
158285 - 0x17E67 (UV Room 2) - 0x17E63 & 0x34BC6 - Colored Squares & Black/White Squares 158285 - 0x17E67 (UV Room 2) - 0x17E63 & 0x34BC6 - Colored Squares & Black/White Squares
Door - 0x0A08D (Elevator Room Entry) - 0x17E67 Door - 0x0A08D (Elevator Room Entry) - 0x17E67
Bunker Elevator Section (Bunker) - Bunker Elevator - TrueOneWay: Bunker Elevator Section (Bunker) - Bunker Elevator - TrueOneWay - Bunker Under Elevator - 0x0A079 | Bunker Green Room | Bunker Cyan Room | Bunker Laser Platform:
159311 - 0x035F5 (Tinted Door EP) - 0x17C79 - True 159311 - 0x035F5 (Tinted Door EP) - 0x17C79 - True
Bunker Under Elevator (Bunker):
Bunker Elevator (Bunker) - Bunker Elevator Section - 0x0A079 - Bunker Cyan Room - 0x0A079 - Bunker Green Room - 0x0A079 - Bunker Laser Platform - 0x0A079 - Outside Bunker - 0x0A079: Bunker Elevator (Bunker) - Bunker Elevator Section - 0x0A079 - Bunker Cyan Room - 0x0A079 - Bunker Green Room - 0x0A079 - Bunker Laser Platform - 0x0A079 - Outside Bunker - 0x0A079:
158286 - 0x0A079 (Elevator Control) - True - Colored Squares & Black/White Squares 158286 - 0x0A079 (Elevator Control) - True - Colored Squares & Black/White Squares
@@ -1005,7 +1017,7 @@ Mountaintop (Mountaintop) - Mountain Floor 1 - 0x17C34:
Mountain Floor 1 (Mountain Floor 1) - Mountain Floor 1 Bridge - 0x09E39: Mountain Floor 1 (Mountain Floor 1) - Mountain Floor 1 Bridge - 0x09E39:
158408 - 0x09E39 (Light Bridge Controller) - True - Black/White Squares & Colored Squares & Eraser 158408 - 0x09E39 (Light Bridge Controller) - True - Black/White Squares & Colored Squares & Eraser
Mountain Floor 1 Bridge (Mountain Floor 1) - Mountain Floor 1 At Door - TrueOneWay: Mountain Floor 1 Bridge (Mountain Floor 1) - Mountain Floor 1 At Door - TrueOneWay - Mountain Floor 1 Trash Pillar - TrueOneWay - Mountain Floor 1 Back Section - TrueOneWay:
158409 - 0x09E7A (Right Row 1) - True - Black/White Squares & Dots 158409 - 0x09E7A (Right Row 1) - True - Black/White Squares & Dots
158410 - 0x09E71 (Right Row 2) - 0x09E7A - Black/White Squares & Dots 158410 - 0x09E71 (Right Row 2) - 0x09E7A - Black/White Squares & Dots
158411 - 0x09E72 (Right Row 3) - 0x09E71 - Black/White Squares & Shapers & Dots 158411 - 0x09E72 (Right Row 3) - 0x09E71 - Black/White Squares & Shapers & Dots
@@ -1018,11 +1030,15 @@ Mountain Floor 1 Bridge (Mountain Floor 1) - Mountain Floor 1 At Door - TrueOneW
158418 - 0x09E6C (Left Row 5) - 0x09E79 - Stars & Black/White Squares & Stars + Same Colored Symbol 158418 - 0x09E6C (Left Row 5) - 0x09E79 - Stars & Black/White Squares & Stars + Same Colored Symbol
158419 - 0x09E6F (Left Row 6) - 0x09E6C - Stars & Rotated Shapers & Shapers 158419 - 0x09E6F (Left Row 6) - 0x09E6C - Stars & Rotated Shapers & Shapers
158420 - 0x09E6B (Left Row 7) - 0x09E6F - Stars & Dots 158420 - 0x09E6B (Left Row 7) - 0x09E6F - Stars & Dots
158424 - 0x09EAD (Trash Pillar 1) - True - Black/White Squares & Shapers
158425 - 0x09EAF (Trash Pillar 2) - 0x09EAD - Black/White Squares & Shaper
Mountain Floor 1 Trash Pillar (Mountain Floor 1):
Mountain Floor 1 Back Section (Mountain Floor 1):
158421 - 0x33AF5 (Back Row 1) - True - Black/White Squares & Symmetry 158421 - 0x33AF5 (Back Row 1) - True - Black/White Squares & Symmetry
158422 - 0x33AF7 (Back Row 2) - 0x33AF5 - Black/White Squares & Stars 158422 - 0x33AF7 (Back Row 2) - 0x33AF5 - Black/White Squares & Stars
158423 - 0x09F6E (Back Row 3) - 0x33AF7 - Symmetry & Dots 158423 - 0x09F6E (Back Row 3) - 0x33AF7 - Symmetry & Dots
158424 - 0x09EAD (Trash Pillar 1) - True - Black/White Squares & Shapers
158425 - 0x09EAF (Trash Pillar 2) - 0x09EAD - Black/White Squares & Shapers
Mountain Floor 1 At Door (Mountain Floor 1) - Mountain Floor 2 - 0x09E54: Mountain Floor 1 At Door (Mountain Floor 1) - Mountain Floor 2 - 0x09E54:
Door - 0x09E54 (Exit) - 0x09EAF & 0x09F6E & 0x09E6B & 0x09E7B Door - 0x09E54 (Exit) - 0x09EAF & 0x09F6E & 0x09E6B & 0x09E7B
@@ -1098,14 +1114,16 @@ Elevator (Mountain Bottom Floor):
Mountain Pink Bridge EP (Mountain Floor 2): Mountain Pink Bridge EP (Mountain Floor 2):
159312 - 0x09D63 (Pink Bridge EP) - 0x09E39 - True 159312 - 0x09D63 (Pink Bridge EP) - 0x09E39 - True
Mountain Path to Caves (Mountain Bottom Floor) - Caves - 0x2D77D: Mountain Path to Caves (Mountain Bottom Floor) - Caves - 0x2D77D - Caves Entry Door - TrueOneWay:
158447 - 0x00FF8 (Caves Entry Panel) - True - Triangles & Black/White Squares 158447 - 0x00FF8 (Caves Entry Panel) - True - Triangles & Black/White Squares
Door - 0x2D77D (Caves Entry) - 0x00FF8 Door - 0x2D77D (Caves Entry) - 0x00FF8
158448 - 0x334E1 (Rock Control) - True - True 158448 - 0x334E1 (Rock Control) - True - True
==Caves== ==Caves==
Caves (Caves) - Main Island - 0x2D73F | 0x2D859 - Caves Path to Challenge - 0x019A5: Caves Entry Door (Caves):
Caves (Caves) - Main Island - 0x2D73F | 0x2D859 - Caves Path to Challenge - 0x019A5 - Caves Entry Door - TrueOneWay:
158451 - 0x335AB (Elevator Inside Control) - True - Dots & Black/White Squares 158451 - 0x335AB (Elevator Inside Control) - True - Dots & Black/White Squares
158452 - 0x335AC (Elevator Upper Outside Control) - 0x335AB - Black/White Squares 158452 - 0x335AC (Elevator Upper Outside Control) - 0x335AB - Black/White Squares
158453 - 0x3369D (Elevator Lower Outside Control) - 0x335AB - Black/White Squares & Dots 158453 - 0x3369D (Elevator Lower Outside Control) - 0x335AB - Black/White Squares & Dots
@@ -1219,3 +1237,7 @@ The Ocean (Boat) - Main Island - TrueOneWay - Swamp Near Boat - TrueOneWay - Tre
159521 - 0x33879 (Tutorial Reflection EP) - True - True 159521 - 0x33879 (Tutorial Reflection EP) - True - True
159522 - 0x03C19 (Tutorial Moss EP) - True - True 159522 - 0x03C19 (Tutorial Moss EP) - True - True
159531 - 0x035C9 (Cargo Box EP) - 0x0A0C9 - True 159531 - 0x035C9 (Cargo Box EP) - 0x0A0C9 - True
==Easter Eggs==
Easter Eggs (Easter Eggs) - Entry - True:

View File

@@ -206,7 +206,7 @@ Door - 0x0A24B (Flood Room Entry) - 0x0A249
159043 - 0x0A14C (Pond Room Near Reflection EP) - True - True 159043 - 0x0A14C (Pond Room Near Reflection EP) - True - True
159044 - 0x0A14D (Pond Room Far Reflection EP) - True - True 159044 - 0x0A14D (Pond Room Far Reflection EP) - True - True
Desert Flood Room (Desert) - Desert Elevator Room - 0x0C316: Desert Flood Room (Desert) - Desert Elevator Room - 0x0C316 - Desert Flood Room Underwater - 0x1C260:
158097 - 0x1C2DF (Reduce Water Level Far Left) - True - True 158097 - 0x1C2DF (Reduce Water Level Far Left) - True - True
158098 - 0x1831E (Reduce Water Level Far Right) - True - True 158098 - 0x1831E (Reduce Water Level Far Right) - True - True
158099 - 0x1C260 (Reduce Water Level Near Left) - True - True 158099 - 0x1C260 (Reduce Water Level Near Left) - True - True
@@ -224,6 +224,8 @@ Desert Flood Room (Desert) - Desert Elevator Room - 0x0C316:
Door - 0x0C316 (Elevator Room Entry) - 0x18076 Door - 0x0C316 (Elevator Room Entry) - 0x18076
159034 - 0x337F8 (Flood Room EP) - 0x1C2DF - True 159034 - 0x337F8 (Flood Room EP) - 0x1C2DF - True
Desert Flood Room Underwater (Desert):
Desert Elevator Room (Desert) - Desert Behind Elevator - 0x01317: Desert Elevator Room (Desert) - Desert Behind Elevator - 0x01317:
158111 - 0x17C31 (Elevator Room Transparent) - True - True 158111 - 0x17C31 (Elevator Room Transparent) - True - True
158113 - 0x012D7 (Elevator Room Hexagonal) - 0x17C31 & 0x0A015 - True 158113 - 0x012D7 (Elevator Room Hexagonal) - 0x17C31 & 0x0A015 - True
@@ -501,7 +503,7 @@ Laser - 0x17C65 (Laser) - 0x17CA4
159121 - 0x03BE3 (Garden Right EP) - True - True 159121 - 0x03BE3 (Garden Right EP) - True - True
159122 - 0x0A409 (Wall EP) - True - True 159122 - 0x0A409 (Wall EP) - True - True
Inside Monastery (Monastery): Inside Monastery (Monastery) - Monastery North Shutters - 0x09D9B:
158213 - 0x09D9B (Shutters Control) - True - Dots 158213 - 0x09D9B (Shutters Control) - True - Dots
158214 - 0x193A7 (Inside 1) - 0x00037 - True 158214 - 0x193A7 (Inside 1) - 0x00037 - True
158215 - 0x193AA (Inside 2) - 0x193A7 - True 158215 - 0x193AA (Inside 2) - 0x193A7 - True
@@ -513,6 +515,8 @@ Inside Monastery (Monastery):
Monastery Garden (Monastery): Monastery Garden (Monastery):
Monastery North Shutters (Monastery):
==Town== ==Town==
Town Obelisk (Town) - Entry - True: Town Obelisk (Town) - Entry - True:
@@ -637,9 +641,13 @@ Door - 0x3CCDF (Exit Right) - 0x33AB2
159556 - 0x33A2A (Door EP) - 0x03553 - True 159556 - 0x33A2A (Door EP) - 0x03553 - True
159558 - 0x33B06 (Church EP) - 0x0354E - True 159558 - 0x33B06 (Church EP) - 0x0354E - True
==Southern Peninsula==
Southern Peninsula (Southern Peninsula) - Main Island - True:
==Jungle== ==Jungle==
Jungle (Jungle) - Main Island - True - The Ocean - 0x17CDF: Jungle (Jungle) - Main Island - True - The Ocean - 0x17CDF - Jungle Under Popup Wall - 0x1475B:
158251 - 0x17CDF (Shore Boat Spawn) - True - Boat 158251 - 0x17CDF (Shore Boat Spawn) - True - Boat
158609 - 0x17F9B (Discard) - True - Arrows 158609 - 0x17F9B (Discard) - True - Arrows
158252 - 0x002C4 (First Row 1) - True - True 158252 - 0x002C4 (First Row 1) - True - True
@@ -670,6 +678,8 @@ Door - 0x3873B (Laser Shortcut) - 0x337FA
159350 - 0x035CB (Bamboo CCW EP) - True - True 159350 - 0x035CB (Bamboo CCW EP) - True - True
159351 - 0x035CF (Bamboo CW EP) - True - True 159351 - 0x035CF (Bamboo CW EP) - True - True
Jungle Under Popup Wall (Jungle):
Outside Jungle River (Jungle) - Main Island - True - Monastery Garden - 0x0CF2A - Jungle Vault - 0x15287: Outside Jungle River (Jungle) - Main Island - True - Monastery Garden - 0x0CF2A - Jungle Vault - 0x15287:
158267 - 0x17CAA (Monastery Garden Shortcut Panel) - True - True 158267 - 0x17CAA (Monastery Garden Shortcut Panel) - True - True
Door - 0x0CF2A (Monastery Garden Shortcut) - 0x17CAA Door - 0x0CF2A (Monastery Garden Shortcut) - 0x17CAA
@@ -712,9 +722,11 @@ Bunker Ultraviolet Room (Bunker) - Bunker Elevator Section - 0x0A08D:
158285 - 0x17E67 (UV Room 2) - 0x17E63 & 0x34BC6 - Squares & Colored Squares & Black/White Squares 158285 - 0x17E67 (UV Room 2) - 0x17E63 & 0x34BC6 - Squares & Colored Squares & Black/White Squares
Door - 0x0A08D (Elevator Room Entry) - 0x17E67 Door - 0x0A08D (Elevator Room Entry) - 0x17E67
Bunker Elevator Section (Bunker) - Bunker Elevator - TrueOneWay: Bunker Elevator Section (Bunker) - Bunker Elevator - TrueOneWay - Bunker Under Elevator - 0x0A079 | Bunker Green Room | Bunker Cyan Room | Bunker Laser Platform:
159311 - 0x035F5 (Tinted Door EP) - 0x17C79 - True 159311 - 0x035F5 (Tinted Door EP) - 0x17C79 - True
Bunker Under Elevator (Bunker):
Bunker Elevator (Bunker) - Bunker Elevator Section - 0x0A079 - Bunker Cyan Room - 0x0A079 - Bunker Green Room - 0x0A079 - Bunker Laser Platform - 0x0A079 - Outside Bunker - 0x0A079: Bunker Elevator (Bunker) - Bunker Elevator Section - 0x0A079 - Bunker Cyan Room - 0x0A079 - Bunker Green Room - 0x0A079 - Bunker Laser Platform - 0x0A079 - Outside Bunker - 0x0A079:
158286 - 0x0A079 (Elevator Control) - True - Colored Squares & Black/White Squares 158286 - 0x0A079 (Elevator Control) - True - Colored Squares & Black/White Squares
@@ -1005,7 +1017,7 @@ Mountaintop (Mountaintop) - Mountain Floor 1 - 0x17C34:
Mountain Floor 1 (Mountain Floor 1) - Mountain Floor 1 Bridge - 0x09E39: Mountain Floor 1 (Mountain Floor 1) - Mountain Floor 1 Bridge - 0x09E39:
158408 - 0x09E39 (Light Bridge Controller) - True - Eraser & Triangles 158408 - 0x09E39 (Light Bridge Controller) - True - Eraser & Triangles
Mountain Floor 1 Bridge (Mountain Floor 1) - Mountain Floor 1 At Door - TrueOneWay: Mountain Floor 1 Bridge (Mountain Floor 1) - Mountain Floor 1 At Door - TrueOneWay - Mountain Floor 1 Trash Pillar - TrueOneWay - Mountain Floor 1 Back Section - TrueOneWay:
158409 - 0x09E7A (Right Row 1) - True - Black/White Squares & Dots & Stars & Stars + Same Colored Symbol 158409 - 0x09E7A (Right Row 1) - True - Black/White Squares & Dots & Stars & Stars + Same Colored Symbol
158410 - 0x09E71 (Right Row 2) - 0x09E7A - Black/White Squares & Triangles 158410 - 0x09E71 (Right Row 2) - 0x09E7A - Black/White Squares & Triangles
158411 - 0x09E72 (Right Row 3) - 0x09E71 - Black/White Squares & Shapers & Stars & Stars + Same Colored Symbol 158411 - 0x09E72 (Right Row 3) - 0x09E71 - Black/White Squares & Shapers & Stars & Stars + Same Colored Symbol
@@ -1018,11 +1030,15 @@ Mountain Floor 1 Bridge (Mountain Floor 1) - Mountain Floor 1 At Door - TrueOneW
158418 - 0x09E6C (Left Row 5) - 0x09E79 - Stars & Shapers & Negative Shapers & Stars + Same Colored Symbol 158418 - 0x09E6C (Left Row 5) - 0x09E79 - Stars & Shapers & Negative Shapers & Stars + Same Colored Symbol
158419 - 0x09E6F (Left Row 6) - 0x09E6C - Symmetry & Stars & Colored Squares & Black/White Squares & Stars + Same Colored Symbol & Symmetry & Eraser 158419 - 0x09E6F (Left Row 6) - 0x09E6C - Symmetry & Stars & Colored Squares & Black/White Squares & Stars + Same Colored Symbol & Symmetry & Eraser
158420 - 0x09E6B (Left Row 7) - 0x09E6F - Symmetry & Dots & Full Dots & Triangles 158420 - 0x09E6B (Left Row 7) - 0x09E6F - Symmetry & Dots & Full Dots & Triangles
158424 - 0x09EAD (Trash Pillar 1) - True - Rotated Shapers & Stars
158425 - 0x09EAF (Trash Pillar 2) - 0x09EAD - Rotated Shapers & Triangles
Mountain Floor 1 Trash Pillar (Mountain Floor 1):
Mountain Floor 1 Back Section (Mountain Floor 1):
158421 - 0x33AF5 (Back Row 1) - True - Symmetry & Black/White Squares & Triangles 158421 - 0x33AF5 (Back Row 1) - True - Symmetry & Black/White Squares & Triangles
158422 - 0x33AF7 (Back Row 2) - 0x33AF5 - Symmetry & Stars & Triangles & Stars + Same Colored Symbol 158422 - 0x33AF7 (Back Row 2) - 0x33AF5 - Symmetry & Stars & Triangles & Stars + Same Colored Symbol
158423 - 0x09F6E (Back Row 3) - 0x33AF7 - Symmetry & Stars & Shapers & Stars + Same Colored Symbol 158423 - 0x09F6E (Back Row 3) - 0x33AF7 - Symmetry & Stars & Shapers & Stars + Same Colored Symbol
158424 - 0x09EAD (Trash Pillar 1) - True - Rotated Shapers & Stars
158425 - 0x09EAF (Trash Pillar 2) - 0x09EAD - Rotated Shapers & Triangles
Mountain Floor 1 At Door (Mountain Floor 1) - Mountain Floor 2 - 0x09E54: Mountain Floor 1 At Door (Mountain Floor 1) - Mountain Floor 2 - 0x09E54:
Door - 0x09E54 (Exit) - 0x09EAF & 0x09F6E & 0x09E6B & 0x09E7B Door - 0x09E54 (Exit) - 0x09EAF & 0x09F6E & 0x09E6B & 0x09E7B
@@ -1098,14 +1114,16 @@ Elevator (Mountain Bottom Floor):
Mountain Pink Bridge EP (Mountain Floor 2): Mountain Pink Bridge EP (Mountain Floor 2):
159312 - 0x09D63 (Pink Bridge EP) - 0x09E39 - True 159312 - 0x09D63 (Pink Bridge EP) - 0x09E39 - True
Mountain Path to Caves (Mountain Bottom Floor) - Caves - 0x2D77D: Mountain Path to Caves (Mountain Bottom Floor) - Caves - 0x2D77D - Caves Entry Door - TrueOneWay:
158447 - 0x00FF8 (Caves Entry Panel) - True - Arrows & Black/White Squares 158447 - 0x00FF8 (Caves Entry Panel) - True - Arrows & Black/White Squares
Door - 0x2D77D (Caves Entry) - 0x00FF8 Door - 0x2D77D (Caves Entry) - 0x00FF8
158448 - 0x334E1 (Rock Control) - True - True 158448 - 0x334E1 (Rock Control) - True - True
==Caves== ==Caves==
Caves (Caves) - Main Island - 0x2D73F | 0x2D859 - Caves Path to Challenge - 0x019A5: Caves Entry Door (Caves):
Caves (Caves) - Main Island - 0x2D73F | 0x2D859 - Caves Path to Challenge - 0x019A5 - Caves Entry Door - TrueOneWay:
158451 - 0x335AB (Elevator Inside Control) - True - Dots & Squares & Black/White Squares 158451 - 0x335AB (Elevator Inside Control) - True - Dots & Squares & Black/White Squares
158452 - 0x335AC (Elevator Upper Outside Control) - 0x335AB - Squares & Black/White Squares 158452 - 0x335AC (Elevator Upper Outside Control) - 0x335AB - Squares & Black/White Squares
158453 - 0x3369D (Elevator Lower Outside Control) - 0x335AB - Squares & Black/White Squares & Dots 158453 - 0x3369D (Elevator Lower Outside Control) - 0x335AB - Squares & Black/White Squares & Dots
@@ -1219,3 +1237,7 @@ The Ocean (Boat) - Main Island - TrueOneWay - Swamp Near Boat - TrueOneWay - Tre
159521 - 0x33879 (Tutorial Reflection EP) - True - True 159521 - 0x33879 (Tutorial Reflection EP) - True - True
159522 - 0x03C19 (Tutorial Moss EP) - True - True 159522 - 0x03C19 (Tutorial Moss EP) - True - True
159531 - 0x035C9 (Cargo Box EP) - 0x0A0C9 - True 159531 - 0x035C9 (Cargo Box EP) - 0x0A0C9 - True
==Easter Eggs==
Easter Eggs (Easter Eggs) - Entry - True:

View File

@@ -206,7 +206,7 @@ Door - 0x0A24B (Flood Room Entry) - 0x0A249
159043 - 0x0A14C (Pond Room Near Reflection EP) - True - True 159043 - 0x0A14C (Pond Room Near Reflection EP) - True - True
159044 - 0x0A14D (Pond Room Far Reflection EP) - True - True 159044 - 0x0A14D (Pond Room Far Reflection EP) - True - True
Desert Flood Room (Desert) - Desert Elevator Room - 0x0C316: Desert Flood Room (Desert) - Desert Elevator Room - 0x0C316 - Desert Flood Room Underwater - 0x1C260:
158097 - 0x1C2DF (Reduce Water Level Far Left) - True - True 158097 - 0x1C2DF (Reduce Water Level Far Left) - True - True
158098 - 0x1831E (Reduce Water Level Far Right) - True - True 158098 - 0x1831E (Reduce Water Level Far Right) - True - True
158099 - 0x1C260 (Reduce Water Level Near Left) - True - True 158099 - 0x1C260 (Reduce Water Level Near Left) - True - True
@@ -224,6 +224,8 @@ Desert Flood Room (Desert) - Desert Elevator Room - 0x0C316:
Door - 0x0C316 (Elevator Room Entry) - 0x18076 Door - 0x0C316 (Elevator Room Entry) - 0x18076
159034 - 0x337F8 (Flood Room EP) - 0x1C2DF - True 159034 - 0x337F8 (Flood Room EP) - 0x1C2DF - True
Desert Flood Room Underwater (Desert):
Desert Elevator Room (Desert) - Desert Behind Elevator - 0x01317: Desert Elevator Room (Desert) - Desert Behind Elevator - 0x01317:
158111 - 0x17C31 (Elevator Room Transparent) - True - True 158111 - 0x17C31 (Elevator Room Transparent) - True - True
158113 - 0x012D7 (Elevator Room Hexagonal) - 0x17C31 & 0x0A015 - True 158113 - 0x012D7 (Elevator Room Hexagonal) - 0x17C31 & 0x0A015 - True
@@ -501,7 +503,7 @@ Laser - 0x17C65 (Laser) - 0x17CA4
159121 - 0x03BE3 (Garden Right EP) - True - True 159121 - 0x03BE3 (Garden Right EP) - True - True
159122 - 0x0A409 (Wall EP) - True - True 159122 - 0x0A409 (Wall EP) - True - True
Inside Monastery (Monastery): Inside Monastery (Monastery) - Monastery North Shutters - 0x09D9B:
158213 - 0x09D9B (Shutters Control) - True - Dots 158213 - 0x09D9B (Shutters Control) - True - Dots
158214 - 0x193A7 (Inside 1) - 0x00037 - True 158214 - 0x193A7 (Inside 1) - 0x00037 - True
158215 - 0x193AA (Inside 2) - 0x193A7 - True 158215 - 0x193AA (Inside 2) - 0x193A7 - True
@@ -513,6 +515,8 @@ Inside Monastery (Monastery):
Monastery Garden (Monastery): Monastery Garden (Monastery):
Monastery North Shutters (Monastery):
==Town== ==Town==
Town Obelisk (Town) - Entry - True: Town Obelisk (Town) - Entry - True:
@@ -637,9 +641,13 @@ Door - 0x3CCDF (Exit Right) - 0x33AB2
159556 - 0x33A2A (Door EP) - 0x03553 - True 159556 - 0x33A2A (Door EP) - 0x03553 - True
159558 - 0x33B06 (Church EP) - 0x0354E - True 159558 - 0x33B06 (Church EP) - 0x0354E - True
==Southern Peninsula==
Southern Peninsula (Southern Peninsula) - Main Island - True:
==Jungle== ==Jungle==
Jungle (Jungle) - Main Island - True - The Ocean - 0x17CDF: Jungle (Jungle) - Main Island - True - The Ocean - 0x17CDF - Jungle Under Popup Wall - 0x1475B:
158251 - 0x17CDF (Shore Boat Spawn) - True - Boat 158251 - 0x17CDF (Shore Boat Spawn) - True - Boat
158609 - 0x17F9B (Discard) - True - Triangles 158609 - 0x17F9B (Discard) - True - Triangles
158252 - 0x002C4 (First Row 1) - True - True 158252 - 0x002C4 (First Row 1) - True - True
@@ -670,6 +678,8 @@ Door - 0x3873B (Laser Shortcut) - 0x337FA
159350 - 0x035CB (Bamboo CCW EP) - True - True 159350 - 0x035CB (Bamboo CCW EP) - True - True
159351 - 0x035CF (Bamboo CW EP) - True - True 159351 - 0x035CF (Bamboo CW EP) - True - True
Jungle Under Popup Wall (Jungle):
Outside Jungle River (Jungle) - Main Island - True - Monastery Garden - 0x0CF2A - Jungle Vault - 0x15287: Outside Jungle River (Jungle) - Main Island - True - Monastery Garden - 0x0CF2A - Jungle Vault - 0x15287:
158267 - 0x17CAA (Monastery Garden Shortcut Panel) - True - True 158267 - 0x17CAA (Monastery Garden Shortcut Panel) - True - True
Door - 0x0CF2A (Monastery Garden Shortcut) - 0x17CAA Door - 0x0CF2A (Monastery Garden Shortcut) - 0x17CAA
@@ -712,9 +722,11 @@ Bunker Ultraviolet Room (Bunker) - Bunker Elevator Section - 0x0A08D:
158285 - 0x17E67 (UV Room 2) - 0x17E63 & 0x34BC6 - Colored Squares & Black/White Squares 158285 - 0x17E67 (UV Room 2) - 0x17E63 & 0x34BC6 - Colored Squares & Black/White Squares
Door - 0x0A08D (Elevator Room Entry) - 0x17E67 Door - 0x0A08D (Elevator Room Entry) - 0x17E67
Bunker Elevator Section (Bunker) - Bunker Elevator - TrueOneWay: Bunker Elevator Section (Bunker) - Bunker Elevator - TrueOneWay - Bunker Under Elevator - 0x0A079 | Bunker Green Room | Bunker Cyan Room | Bunker Laser Platform:
159311 - 0x035F5 (Tinted Door EP) - 0x17C79 - True 159311 - 0x035F5 (Tinted Door EP) - 0x17C79 - True
Bunker Under Elevator (Bunker):
Bunker Elevator (Bunker) - Bunker Elevator Section - 0x0A079 - Bunker Cyan Room - 0x0A079 - Bunker Green Room - 0x0A079 - Bunker Laser Platform - 0x0A079 - Outside Bunker - 0x0A079: Bunker Elevator (Bunker) - Bunker Elevator Section - 0x0A079 - Bunker Cyan Room - 0x0A079 - Bunker Green Room - 0x0A079 - Bunker Laser Platform - 0x0A079 - Outside Bunker - 0x0A079:
158286 - 0x0A079 (Elevator Control) - True - Colored Squares & Black/White Squares 158286 - 0x0A079 (Elevator Control) - True - Colored Squares & Black/White Squares
@@ -1005,7 +1017,7 @@ Mountaintop (Mountaintop) - Mountain Floor 1 - 0x17C34:
Mountain Floor 1 (Mountain Floor 1) - Mountain Floor 1 Bridge - 0x09E39: Mountain Floor 1 (Mountain Floor 1) - Mountain Floor 1 Bridge - 0x09E39:
158408 - 0x09E39 (Light Bridge Controller) - True - Black/White Squares & Rotated Shapers 158408 - 0x09E39 (Light Bridge Controller) - True - Black/White Squares & Rotated Shapers
Mountain Floor 1 Bridge (Mountain Floor 1) - Mountain Floor 1 At Door - TrueOneWay: Mountain Floor 1 Bridge (Mountain Floor 1) - Mountain Floor 1 At Door - TrueOneWay - Mountain Floor 1 Trash Pillar - TrueOneWay - Mountain Floor 1 Back Section - TrueOneWay:
158409 - 0x09E7A (Right Row 1) - True - Black/White Squares & Dots 158409 - 0x09E7A (Right Row 1) - True - Black/White Squares & Dots
158410 - 0x09E71 (Right Row 2) - 0x09E7A - Black/White Squares & Dots 158410 - 0x09E71 (Right Row 2) - 0x09E7A - Black/White Squares & Dots
158411 - 0x09E72 (Right Row 3) - 0x09E71 - Black/White Squares & Shapers 158411 - 0x09E72 (Right Row 3) - 0x09E71 - Black/White Squares & Shapers
@@ -1018,11 +1030,15 @@ Mountain Floor 1 Bridge (Mountain Floor 1) - Mountain Floor 1 At Door - TrueOneW
158418 - 0x09E6C (Left Row 5) - 0x09E79 - Stars & Black/White Squares 158418 - 0x09E6C (Left Row 5) - 0x09E79 - Stars & Black/White Squares
158419 - 0x09E6F (Left Row 6) - 0x09E6C - Shapers & Dots 158419 - 0x09E6F (Left Row 6) - 0x09E6C - Shapers & Dots
158420 - 0x09E6B (Left Row 7) - 0x09E6F - Dots 158420 - 0x09E6B (Left Row 7) - 0x09E6F - Dots
158424 - 0x09EAD (Trash Pillar 1) - True - Black/White Squares & Shapers
158425 - 0x09EAF (Trash Pillar 2) - 0x09EAD - Black/White Squares & Shapers
Mountain Floor 1 Trash Pillar (Mountain Floor 1):
Mountain Floor 1 Back Section (Mountain Floor 1):
158421 - 0x33AF5 (Back Row 1) - True - Black/White Squares & Symmetry 158421 - 0x33AF5 (Back Row 1) - True - Black/White Squares & Symmetry
158422 - 0x33AF7 (Back Row 2) - 0x33AF5 - Black/White Squares 158422 - 0x33AF7 (Back Row 2) - 0x33AF5 - Black/White Squares
158423 - 0x09F6E (Back Row 3) - 0x33AF7 - Symmetry & Dots 158423 - 0x09F6E (Back Row 3) - 0x33AF7 - Symmetry & Dots
158424 - 0x09EAD (Trash Pillar 1) - True - Black/White Squares & Shapers
158425 - 0x09EAF (Trash Pillar 2) - 0x09EAD - Black/White Squares & Shapers
Mountain Floor 1 At Door (Mountain Floor 1) - Mountain Floor 2 - 0x09E54: Mountain Floor 1 At Door (Mountain Floor 1) - Mountain Floor 2 - 0x09E54:
Door - 0x09E54 (Exit) - 0x09EAF & 0x09F6E & 0x09E6B & 0x09E7B Door - 0x09E54 (Exit) - 0x09EAF & 0x09F6E & 0x09E6B & 0x09E7B
@@ -1098,14 +1114,16 @@ Elevator (Mountain Bottom Floor):
Mountain Pink Bridge EP (Mountain Floor 2): Mountain Pink Bridge EP (Mountain Floor 2):
159312 - 0x09D63 (Pink Bridge EP) - 0x09E39 - True 159312 - 0x09D63 (Pink Bridge EP) - 0x09E39 - True
Mountain Path to Caves (Mountain Bottom Floor) - Caves - 0x2D77D: Mountain Path to Caves (Mountain Bottom Floor) - Caves - 0x2D77D - Caves Entry Door - TrueOneWay:
158447 - 0x00FF8 (Caves Entry Panel) - True - Black/White Squares 158447 - 0x00FF8 (Caves Entry Panel) - True - Black/White Squares
Door - 0x2D77D (Caves Entry) - 0x00FF8 Door - 0x2D77D (Caves Entry) - 0x00FF8
158448 - 0x334E1 (Rock Control) - True - True 158448 - 0x334E1 (Rock Control) - True - True
==Caves== ==Caves==
Caves (Caves) - Main Island - 0x2D73F | 0x2D859 - Caves Path to Challenge - 0x019A5: Caves Entry Door (Caves):
Caves (Caves) - Main Island - 0x2D73F | 0x2D859 - Caves Path to Challenge - 0x019A5 - Caves Entry Door - TrueOneWay:
158451 - 0x335AB (Elevator Inside Control) - True - Dots & Black/White Squares 158451 - 0x335AB (Elevator Inside Control) - True - Dots & Black/White Squares
158452 - 0x335AC (Elevator Upper Outside Control) - 0x335AB - Black/White Squares 158452 - 0x335AC (Elevator Upper Outside Control) - 0x335AB - Black/White Squares
158453 - 0x3369D (Elevator Lower Outside Control) - 0x335AB - Black/White Squares & Dots 158453 - 0x3369D (Elevator Lower Outside Control) - 0x335AB - Black/White Squares & Dots
@@ -1219,3 +1237,7 @@ The Ocean (Boat) - Main Island - TrueOneWay - Swamp Near Boat - TrueOneWay - Tre
159521 - 0x33879 (Tutorial Reflection EP) - True - True 159521 - 0x33879 (Tutorial Reflection EP) - True - True
159522 - 0x03C19 (Tutorial Moss EP) - True - True 159522 - 0x03C19 (Tutorial Moss EP) - True - True
159531 - 0x035C9 (Cargo Box EP) - 0x0A0C9 - True 159531 - 0x035C9 (Cargo Box EP) - 0x0A0C9 - True
==Easter Eggs==
Easter Eggs (Easter Eggs) - Entry - True:

View File

@@ -206,7 +206,7 @@ Door - 0x0A24B (Flood Room Entry) - 0x0A249
159043 - 0x0A14C (Pond Room Near Reflection EP) - True - True 159043 - 0x0A14C (Pond Room Near Reflection EP) - True - True
159044 - 0x0A14D (Pond Room Far Reflection EP) - True - True 159044 - 0x0A14D (Pond Room Far Reflection EP) - True - True
Desert Flood Room (Desert) - Desert Elevator Room - 0x0C316: Desert Flood Room (Desert) - Desert Elevator Room - 0x0C316 - Desert Flood Room Underwater - 0x1C260:
158097 - 0x1C2DF (Reduce Water Level Far Left) - True - True 158097 - 0x1C2DF (Reduce Water Level Far Left) - True - True
158098 - 0x1831E (Reduce Water Level Far Right) - True - True 158098 - 0x1831E (Reduce Water Level Far Right) - True - True
158099 - 0x1C260 (Reduce Water Level Near Left) - True - True 158099 - 0x1C260 (Reduce Water Level Near Left) - True - True
@@ -224,6 +224,8 @@ Desert Flood Room (Desert) - Desert Elevator Room - 0x0C316:
Door - 0x0C316 (Elevator Room Entry) - 0x18076 Door - 0x0C316 (Elevator Room Entry) - 0x18076
159034 - 0x337F8 (Flood Room EP) - 0x1C2DF - True 159034 - 0x337F8 (Flood Room EP) - 0x1C2DF - True
Desert Flood Room Underwater (Desert):
Desert Elevator Room (Desert) - Desert Behind Elevator - 0x01317: Desert Elevator Room (Desert) - Desert Behind Elevator - 0x01317:
158111 - 0x17C31 (Elevator Room Transparent) - True - True 158111 - 0x17C31 (Elevator Room Transparent) - True - True
158113 - 0x012D7 (Elevator Room Hexagonal) - 0x17C31 & 0x0A015 - True 158113 - 0x012D7 (Elevator Room Hexagonal) - 0x17C31 & 0x0A015 - True
@@ -501,7 +503,7 @@ Laser - 0x17C65 (Laser) - 0x17CA4
159121 - 0x03BE3 (Garden Right EP) - True - True 159121 - 0x03BE3 (Garden Right EP) - True - True
159122 - 0x0A409 (Wall EP) - True - True 159122 - 0x0A409 (Wall EP) - True - True
Inside Monastery (Monastery): Inside Monastery (Monastery) - Monastery North Shutters - 0x09D9B:
158213 - 0x09D9B (Shutters Control) - True - Dots 158213 - 0x09D9B (Shutters Control) - True - Dots
158214 - 0x193A7 (Inside 1) - 0x00037 - True 158214 - 0x193A7 (Inside 1) - 0x00037 - True
158215 - 0x193AA (Inside 2) - 0x193A7 - True 158215 - 0x193AA (Inside 2) - 0x193A7 - True
@@ -513,6 +515,8 @@ Inside Monastery (Monastery):
Monastery Garden (Monastery): Monastery Garden (Monastery):
Monastery North Shutters (Monastery):
==Town== ==Town==
Town Obelisk (Town) - Entry - True: Town Obelisk (Town) - Entry - True:
@@ -637,9 +641,13 @@ Door - 0x3CCDF (Exit Right) - 0x33AB2
159556 - 0x33A2A (Door EP) - 0x03553 - True 159556 - 0x33A2A (Door EP) - 0x03553 - True
159558 - 0x33B06 (Church EP) - 0x0354E - True 159558 - 0x33B06 (Church EP) - 0x0354E - True
==Southern Peninsula==
Southern Peninsula (Southern Peninsula) - Main Island - True:
==Jungle== ==Jungle==
Jungle (Jungle) - Main Island - True - The Ocean - 0x17CDF: Jungle (Jungle) - Main Island - True - The Ocean - 0x17CDF - Jungle Under Popup Wall - 0x1475B:
158251 - 0x17CDF (Shore Boat Spawn) - True - Boat 158251 - 0x17CDF (Shore Boat Spawn) - True - Boat
158609 - 0x17F9B (Discard) - True - Arrows & Triangles 158609 - 0x17F9B (Discard) - True - Arrows & Triangles
158252 - 0x002C4 (First Row 1) - True - True 158252 - 0x002C4 (First Row 1) - True - True
@@ -670,6 +678,8 @@ Door - 0x3873B (Laser Shortcut) - 0x337FA
159350 - 0x035CB (Bamboo CCW EP) - True - True 159350 - 0x035CB (Bamboo CCW EP) - True - True
159351 - 0x035CF (Bamboo CW EP) - True - True 159351 - 0x035CF (Bamboo CW EP) - True - True
Jungle Under Popup Wall (Jungle):
Outside Jungle River (Jungle) - Main Island - True - Monastery Garden - 0x0CF2A - Jungle Vault - 0x15287: Outside Jungle River (Jungle) - Main Island - True - Monastery Garden - 0x0CF2A - Jungle Vault - 0x15287:
158267 - 0x17CAA (Monastery Garden Shortcut Panel) - True - True 158267 - 0x17CAA (Monastery Garden Shortcut Panel) - True - True
Door - 0x0CF2A (Monastery Garden Shortcut) - 0x17CAA Door - 0x0CF2A (Monastery Garden Shortcut) - 0x17CAA
@@ -712,9 +722,11 @@ Bunker Ultraviolet Room (Bunker) - Bunker Elevator Section - 0x0A08D:
158285 - 0x17E67 (UV Room 2) - 0x17E63 & 0x34BC6 - Colored Squares & Black/White Squares 158285 - 0x17E67 (UV Room 2) - 0x17E63 & 0x34BC6 - Colored Squares & Black/White Squares
Door - 0x0A08D (Elevator Room Entry) - 0x17E67 Door - 0x0A08D (Elevator Room Entry) - 0x17E67
Bunker Elevator Section (Bunker) - Bunker Elevator - TrueOneWay: Bunker Elevator Section (Bunker) - Bunker Elevator - TrueOneWay - Bunker Under Elevator - 0x0A079 | Bunker Green Room | Bunker Cyan Room | Bunker Laser Platform:
159311 - 0x035F5 (Tinted Door EP) - 0x17C79 - True 159311 - 0x035F5 (Tinted Door EP) - 0x17C79 - True
Bunker Under Elevator (Bunker):
Bunker Elevator (Bunker) - Bunker Elevator Section - 0x0A079 - Bunker Cyan Room - 0x0A079 - Bunker Green Room - 0x0A079 - Bunker Laser Platform - 0x0A079 - Outside Bunker - 0x0A079: Bunker Elevator (Bunker) - Bunker Elevator Section - 0x0A079 - Bunker Cyan Room - 0x0A079 - Bunker Green Room - 0x0A079 - Bunker Laser Platform - 0x0A079 - Outside Bunker - 0x0A079:
158286 - 0x0A079 (Elevator Control) - True - Colored Squares & Black/White Squares 158286 - 0x0A079 (Elevator Control) - True - Colored Squares & Black/White Squares
@@ -1005,7 +1017,7 @@ Mountaintop (Mountaintop) - Mountain Floor 1 - 0x17C34:
Mountain Floor 1 (Mountain Floor 1) - Mountain Floor 1 Bridge - 0x09E39: Mountain Floor 1 (Mountain Floor 1) - Mountain Floor 1 Bridge - 0x09E39:
158408 - 0x09E39 (Light Bridge Controller) - True - Black/White Squares & Colored Squares & Eraser 158408 - 0x09E39 (Light Bridge Controller) - True - Black/White Squares & Colored Squares & Eraser
Mountain Floor 1 Bridge (Mountain Floor 1) - Mountain Floor 1 At Door - TrueOneWay: Mountain Floor 1 Bridge (Mountain Floor 1) - Mountain Floor 1 At Door - TrueOneWay - Mountain Floor 1 Trash Pillar - TrueOneWay - Mountain Floor 1 Back Section - TrueOneWay:
158409 - 0x09E7A (Right Row 1) - True - Black/White Squares & Dots 158409 - 0x09E7A (Right Row 1) - True - Black/White Squares & Dots
158410 - 0x09E71 (Right Row 2) - 0x09E7A - Black/White Squares & Dots & Stars & Stars + Same Colored Symbol 158410 - 0x09E71 (Right Row 2) - 0x09E7A - Black/White Squares & Dots & Stars & Stars + Same Colored Symbol
158411 - 0x09E72 (Right Row 3) - 0x09E71 - Black/White Squares & Shapers & Stars & Stars + Same Colored Symbol 158411 - 0x09E72 (Right Row 3) - 0x09E71 - Black/White Squares & Shapers & Stars & Stars + Same Colored Symbol
@@ -1018,11 +1030,15 @@ Mountain Floor 1 Bridge (Mountain Floor 1) - Mountain Floor 1 At Door - TrueOneW
158418 - 0x09E6C (Left Row 5) - 0x09E79 - Arrows & Black/White Squares & Stars & Stars + Same Colored Symbol 158418 - 0x09E6C (Left Row 5) - 0x09E79 - Arrows & Black/White Squares & Stars & Stars + Same Colored Symbol
158419 - 0x09E6F (Left Row 6) - 0x09E6C - Arrows & Dots & Full Dots 158419 - 0x09E6F (Left Row 6) - 0x09E6C - Arrows & Dots & Full Dots
158420 - 0x09E6B (Left Row 7) - 0x09E6F - Arrows & Dots & Full Dots 158420 - 0x09E6B (Left Row 7) - 0x09E6F - Arrows & Dots & Full Dots
158424 - 0x09EAD (Trash Pillar 1) - True - Triangles & Arrows
158425 - 0x09EAF (Trash Pillar 2) - 0x09EAD - Triangles & Arrows
Mountain Floor 1 Trash Pillar (Mountain Floor 1):
Mountain Floor 1 Back Section (Mountain Floor 1):
158421 - 0x33AF5 (Back Row 1) - True - Symmetry & Triangles 158421 - 0x33AF5 (Back Row 1) - True - Symmetry & Triangles
158422 - 0x33AF7 (Back Row 2) - 0x33AF5 - Triangles 158422 - 0x33AF7 (Back Row 2) - 0x33AF5 - Triangles
158423 - 0x09F6E (Back Row 3) - 0x33AF7 - Symmetry & Triangles 158423 - 0x09F6E (Back Row 3) - 0x33AF7 - Symmetry & Triangles
158424 - 0x09EAD (Trash Pillar 1) - True - Triangles & Arrows
158425 - 0x09EAF (Trash Pillar 2) - 0x09EAD - Triangles & Arrows
Mountain Floor 1 At Door (Mountain Floor 1) - Mountain Floor 2 - 0x09E54: Mountain Floor 1 At Door (Mountain Floor 1) - Mountain Floor 2 - 0x09E54:
Door - 0x09E54 (Exit) - 0x09EAF & 0x09F6E & 0x09E6B & 0x09E7B Door - 0x09E54 (Exit) - 0x09EAF & 0x09F6E & 0x09E6B & 0x09E7B
@@ -1098,14 +1114,16 @@ Elevator (Mountain Bottom Floor):
Mountain Pink Bridge EP (Mountain Floor 2): Mountain Pink Bridge EP (Mountain Floor 2):
159312 - 0x09D63 (Pink Bridge EP) - 0x09E39 - True 159312 - 0x09D63 (Pink Bridge EP) - 0x09E39 - True
Mountain Path to Caves (Mountain Bottom Floor) - Caves - 0x2D77D: Mountain Path to Caves (Mountain Bottom Floor) - Caves - 0x2D77D - Caves Entry Door - TrueOneWay:
158447 - 0x00FF8 (Caves Entry Panel) - True - Black/White Squares & Arrows & Triangles 158447 - 0x00FF8 (Caves Entry Panel) - True - Black/White Squares & Arrows & Triangles
Door - 0x2D77D (Caves Entry) - 0x00FF8 Door - 0x2D77D (Caves Entry) - 0x00FF8
158448 - 0x334E1 (Rock Control) - True - True 158448 - 0x334E1 (Rock Control) - True - True
==Caves== ==Caves==
Caves (Caves) - Main Island - 0x2D73F | 0x2D859 - Caves Path to Challenge - 0x019A5: Caves Entry Door (Caves):
Caves (Caves) - Main Island - 0x2D73F | 0x2D859 - Caves Path to Challenge - 0x019A5 - Caves Entry Door - TrueOneWay:
158451 - 0x335AB (Elevator Inside Control) - True - Dots & Black/White Squares 158451 - 0x335AB (Elevator Inside Control) - True - Dots & Black/White Squares
158452 - 0x335AC (Elevator Upper Outside Control) - 0x335AB - Black/White Squares 158452 - 0x335AC (Elevator Upper Outside Control) - 0x335AB - Black/White Squares
158453 - 0x3369D (Elevator Lower Outside Control) - 0x335AB - Black/White Squares & Dots 158453 - 0x3369D (Elevator Lower Outside Control) - 0x335AB - Black/White Squares & Dots
@@ -1219,3 +1237,7 @@ The Ocean (Boat) - Main Island - TrueOneWay - Swamp Near Boat - TrueOneWay - Tre
159521 - 0x33879 (Tutorial Reflection EP) - True - True 159521 - 0x33879 (Tutorial Reflection EP) - True - True
159522 - 0x03C19 (Tutorial Moss EP) - True - True 159522 - 0x03C19 (Tutorial Moss EP) - True - True
159531 - 0x035C9 (Cargo Box EP) - 0x0A0C9 - True 159531 - 0x035C9 (Cargo Box EP) - 0x0A0C9 - True
==Easter Eggs==
Easter Eggs (Easter Eggs) - Entry - True:

View File

@@ -0,0 +1,75 @@
MAXIMUM_EASTER_EGG_CHECKS = 50
EASTER_EGGS = {
"Tutorial": 1,
"Outside Tutorial": 4,
"Outside Tutorial Path To Outpost": 1,
"Outside Tutorial Outpost": 1,
"Orchard Beyond First Gate": 1,
"Orchard End": 1,
"Inside Glass Factory": 2,
"Symmetry Island Lower": 2,
"Symmetry Island Upper": 1,
"Desert Outside": 6,
"Desert Vault": 1,
"Desert Pond Room": 2,
"Desert Flood Room Underwater": 1,
"Desert Elevator Room": 1,
"Outside Quarry": 2,
"Quarry": 5,
"Quarry Stoneworks Upper Floor": 2,
"Quarry Boathouse": 2,
"Shadows": 2,
"Shadows Ledge": 1,
"Shadows Laser Room": 1,
"Keep": 1,
"Keep 3rd Maze": 3,
"Keep 2nd Pressure Plate": 2,
"Keep 3rd Pressure Plate": 1,
"Keep 4th Pressure Plate": 1,
"Keep Tower": 2,
"Shipwreck": 5,
"Inside Monastery": 1,
"Monastery North Shutters": 1,
"Monastery Garden": 1,
"Town": 5,
"Town Wooden Rooftop": 1,
"Town RGB House": 2,
"Town Tower Top": 1,
"Windmill Interior": 2,
"Theater": 1,
"Southern Peninsula": 5,
"Jungle": 2,
"Jungle Under Popup Wall": 1,
"Jungle Vault": 1,
"Outside Bunker": 3,
"Bunker Glass Room": 1,
"Bunker Under Elevator": 1,
"Bunker Green Room": 1,
"Outside Swamp": 2,
"Swamp Entry Area": 1,
"Swamp Platform": 1,
"Swamp Cyan Underwater": 1,
"Swamp Near Boat": 1,
"Swamp Laser Area": 1,
"Treehouse Beach": 1,
"Treehouse Yellow Bridge": 1,
"Treehouse Junction": 2,
"Treehouse Second Purple Bridge": 1,
"Treehouse Green Bridge Left House": 1,
"Treehouse Laser Room Back Platform": 1,
"Treehouse Burned House": 1,
"Treehouse Drawbridge Platform": 1,
"Mountainside": 4,
"Mountaintop": 1,
"Mountain Floor 1 Trash Pillar": 1,
"Mountain Floor 1 Back Section": 1,
"Mountain Floor 2": 1,
"Mountain Bottom Floor Pillars Room": 1,
"Caves Entry Door": 1,
"Caves": 2,
"Caves Path to Challenge": 1,
"Challenge": 2,
"Tunnels": 2,
"The Ocean": 2,
}

View File

@@ -1,4 +1,4 @@
from collections import defaultdict from collections import Counter, defaultdict
from typing import Any, Dict, List, Optional, Set, Tuple from typing import Any, Dict, List, Optional, Set, Tuple
from Utils import cache_argsless from Utils import cache_argsless
@@ -11,6 +11,7 @@ from .item_definition_classes import (
ProgressiveItemDefinition, ProgressiveItemDefinition,
WeightedItemDefinition, WeightedItemDefinition,
) )
from .settings.easter_eggs import EASTER_EGGS
from .utils import ( from .utils import (
WitnessRule, WitnessRule,
define_new_region, define_new_region,
@@ -49,6 +50,70 @@ class StaticWitnessLogicObj:
self.reverse_connections() self.reverse_connections()
self.combine_connections() self.combine_connections()
def add_easter_eggs(self) -> None:
egg_counter = 0
area_counts: Dict[str, int] = Counter()
for region_name, entity_amount in EASTER_EGGS.items():
region_object = self.ALL_REGIONS_BY_NAME[region_name]
correct_area = region_object["area"]
for _ in range(entity_amount):
location_id = 160200 + egg_counter
entity_hex = hex(0xEE000 + egg_counter)
egg_counter += 1
area_counts[correct_area["name"]] += 1
full_entity_name = f"{correct_area['name']} Easter Egg {area_counts[correct_area['name']]}"
self.ENTITIES_BY_HEX[entity_hex] = {
"checkName": full_entity_name,
"entity_hex": entity_hex,
"region": region_object,
"id": int(location_id),
"entityType": "Easter Egg",
"locationType": "Easter Egg",
"area": correct_area,
"order": len(self.ENTITIES_BY_HEX),
}
self.ENTITIES_BY_NAME[self.ENTITIES_BY_HEX[entity_hex]["checkName"]] = self.ENTITIES_BY_HEX[entity_hex]
self.STATIC_DEPENDENT_REQUIREMENTS_BY_HEX[entity_hex] = {
"entities": frozenset({frozenset({})})
}
region_object["entities"].append(entity_hex)
region_object["physical_entities"].append(entity_hex)
easter_egg_region = self.ALL_REGIONS_BY_NAME["Easter Eggs"]
easter_egg_area = easter_egg_region["area"]
for i in range(sum(EASTER_EGGS.values())):
location_id = 160000 + i
entity_hex = hex(0xEE200 + i)
if i == 0:
continue
full_entity_name = f"{i + 1} Easter Eggs Collected"
self.ENTITIES_BY_HEX[entity_hex] = {
"checkName": full_entity_name,
"entity_hex": entity_hex,
"region": easter_egg_region,
"id": int(location_id),
"entityType": "Easter Egg Total",
"locationType": "Easter Egg Total",
"area": easter_egg_area,
"order": len(self.ENTITIES_BY_HEX),
}
self.ENTITIES_BY_NAME[self.ENTITIES_BY_HEX[entity_hex]["checkName"]] = self.ENTITIES_BY_HEX[entity_hex]
self.STATIC_DEPENDENT_REQUIREMENTS_BY_HEX[entity_hex] = {
"entities": frozenset({frozenset({})})
}
easter_egg_region["entities"].append(entity_hex)
easter_egg_region["physical_entities"].append(entity_hex)
def read_logic_file(self, lines: List[str]) -> None: def read_logic_file(self, lines: List[str]) -> None:
""" """
Reads the logic file and does the initial population of data structures Reads the logic file and does the initial population of data structures
@@ -66,7 +131,7 @@ class StaticWitnessLogicObj:
continue continue
if line[-1] == ":": if line[-1] == ":":
new_region_and_connections = define_new_region(line) new_region_and_connections = define_new_region(line, current_area)
current_region = new_region_and_connections[0] current_region = new_region_and_connections[0]
region_name = current_region["name"] region_name = current_region["name"]
self.ALL_REGIONS_BY_NAME[region_name] = current_region self.ALL_REGIONS_BY_NAME[region_name] = current_region
@@ -198,6 +263,8 @@ class StaticWitnessLogicObj:
current_region["entities"].append(entity_hex) current_region["entities"].append(entity_hex)
current_region["physical_entities"].append(entity_hex) current_region["physical_entities"].append(entity_hex)
self.add_easter_eggs()
def reverse_connection(self, source_region: str, connection: Tuple[str, Set[WitnessRule]]) -> None: def reverse_connection(self, source_region: str, connection: Tuple[str, Set[WitnessRule]]) -> None:
target = connection[0] target = connection[0]
traversal_options = connection[1] traversal_options = connection[1]

View File

@@ -1,3 +1,4 @@
from datetime import date
from math import floor from math import floor
from pkgutil import get_data from pkgutil import get_data
from random import Random from random import Random
@@ -61,7 +62,7 @@ def build_weighted_int_list(inputs: Collection[float], total: int) -> List[int]:
return rounded_output return rounded_output
def define_new_region(region_string: str) -> Tuple[Dict[str, Any], Set[Tuple[str, WitnessRule]]]: def define_new_region(region_string: str, area: dict[str, Any]) -> Tuple[Dict[str, Any], Set[Tuple[str, WitnessRule]]]:
""" """
Returns a region object by parsing a line in the logic file Returns a region object by parsing a line in the logic file
""" """
@@ -91,6 +92,7 @@ def define_new_region(region_string: str) -> Tuple[Dict[str, Any], Set[Tuple[str
"shortName": region_name_simple, "shortName": region_name_simple,
"entities": [], "entities": [],
"physical_entities": [], "physical_entities": [],
"area": area,
} }
return region_obj, options return region_obj, options
@@ -264,3 +266,15 @@ def logical_and_witness_rules(witness_rules: Iterable[WitnessRule]) -> WitnessRu
def logical_or_witness_rules(witness_rules: Iterable[WitnessRule]) -> WitnessRule: def logical_or_witness_rules(witness_rules: Iterable[WitnessRule]) -> WitnessRule:
return optimize_witness_rule(frozenset.union(*witness_rules)) return optimize_witness_rule(frozenset.union(*witness_rules))
def is_easter_time() -> bool:
# dateutils would have been nice here, because it has an easter() function.
# But adding it as a requirement seems heavier than necessary.
# Thus, we just take a range from the earliest to latest possible easter dates.
today = date.today()
earliest_easter_day = date(today.year, 3, 20) # Earliest possible is 3/22 + 2 day buffer for Good Friday
last_easter_day = date(today.year, 4, 26) # Latest possible is 4/25 + 1 day buffer for Easter Monday
return earliest_easter_day <= today <= last_easter_day

View File

@@ -43,3 +43,12 @@ if __name__ == "__main__":
) )
) )
datafile.write("\n};\n\n") datafile.write("\n};\n\n")
datafile.write("inline std::map<int, std::string> entityToName = {")
datafile.write(
"\n".join(
"\t{ " + entity_hex + ', "' + entity_object["checkName"] + '" },'
for entity_hex, entity_object in static_witness_logic.ENTITIES_BY_HEX.items()
)
)
datafile.write("\n};\n\n")

View File

@@ -241,7 +241,10 @@ def word_direct_hint(world: "WitnessWorld", hint: WitnessLocationHint) -> Witnes
area = chosen_group area = chosen_group
# local locations should only ever return a location group, as Witness defines groups for every location. # local locations should only ever return a location group, as Witness defines groups for every location.
hint_text = f"{item_name} can be found in the {area} area." if area == "Easter Eggs":
hint_text = f"{item_name} can be found by collecting Easter Eggs."
else:
hint_text = f"{item_name} can be found in the {area} area."
else: else:
player_name = world.multiworld.get_player_name(hint.location.player) player_name = world.multiworld.get_player_name(hint.location.player)
@@ -505,10 +508,13 @@ def word_area_hint(world: "WitnessWorld", hinted_area: str, area_items: List[Ite
area_progression_word = "Both" if total_progression == 2 else "All" area_progression_word = "Both" if total_progression == 2 else "All"
hint_string = f"In the {hinted_area} area, you will find " if hinted_area == "Easter Eggs":
hint_string = "Through collecting Easter Eggs, you will find "
else:
hint_string = f"In the {hinted_area} area, you will find "
hunt_panels = None hunt_panels = None
if world.options.victory_condition == "panel_hunt": if world.options.victory_condition == "panel_hunt" and hinted_area != "Easter Eggs":
hunt_panels = sum( hunt_panels = sum(
static_witness_logic.ENTITIES_BY_HEX[hunt_entity]["area"]["name"] == hinted_area static_witness_logic.ENTITIES_BY_HEX[hunt_entity]["area"]["name"] == hinted_area
for hunt_entity in world.player_logic.HUNT_ENTITIES for hunt_entity in world.player_logic.HUNT_ENTITIES

View File

@@ -19,7 +19,7 @@ class WitnessPlayerLocations:
def __init__(self, world: "WitnessWorld", player_logic: WitnessPlayerLogic) -> None: def __init__(self, world: "WitnessWorld", player_logic: WitnessPlayerLogic) -> None:
"""Defines locations AFTER logic changes due to options""" """Defines locations AFTER logic changes due to options"""
self.PANEL_TYPES_TO_SHUFFLE = {"General", "Good Boi"} self.PANEL_TYPES_TO_SHUFFLE = {"General", "Good Boi", "Easter Egg Total"}
self.CHECK_LOCATIONS = static_witness_locations.GENERAL_LOCATIONS.copy() self.CHECK_LOCATIONS = static_witness_locations.GENERAL_LOCATIONS.copy()
if world.options.shuffle_discarded_panels: if world.options.shuffle_discarded_panels:

View File

@@ -1,4 +1,6 @@
from dataclasses import dataclass from dataclasses import dataclass
from datetime import datetime
from typing import Tuple
from schema import And, Schema from schema import And, Schema
@@ -18,6 +20,7 @@ from Options import (
from .data import static_logic as static_witness_logic from .data import static_logic as static_witness_logic
from .data.item_definition_classes import ItemCategory, WeightedItemDefinition from .data.item_definition_classes import ItemCategory, WeightedItemDefinition
from .data.utils import is_easter_time
from .entity_hunt import ALL_HUNTABLE_PANELS from .entity_hunt import ALL_HUNTABLE_PANELS
@@ -142,6 +145,53 @@ class ShuffleEnvironmentalPuzzles(Choice):
option_obelisk_sides = 2 option_obelisk_sides = 2
class EasterEggHunt(Choice):
"""
Adds up to 120 Easter Eggs to the game, placed by NewSoupVi, Exempt-Medic, hatkirby, Scipio, and Rever.
These can be collected by simply clicking on them.
The difficulty options differ by how many Eggs you need to collect for each check and how many are logically required for each check.
- "Easy": 3 / 8
- "Normal": 3 / 6
- "Hard": 4 / 6
- "Very Hard": 4 / 5
- "Extreme": 4 / 4 (You are expected to collect every Easter Egg)
Checks that require more Eggs than logically available still exist, but are excluded.
For example, on "Easy", the "63 Eggs Collected" check can physically be obtained, but would logically require 125 Easter Eggs, which is impossible. Thus, it is excluded.
On "Easy", "Normal", and "Hard", you will start with an "Egg Radar" that you can activate using the Puzzle Skip key.
On every difficulty except "Extreme", there will be a message when you've collected all Easter Eggs in an area.
On "Easy", there will be an additional message after every Easter Egg telling you how many Easter Eggs are remaining in the area.
It is recommended that you play this mode together with Door Shuffle. Without it, more than half of the Easter Eggs will be in sphere 1.
"""
visibility = Visibility.all if is_easter_time() else Visibility.none
display_name = "Easter Egg Hunt"
option_off = 0
# Number represents the amount of eggs needed per check
option_easy = 1
option_normal = 2
option_hard = 3
option_very_hard = 4
option_extreme = 5
default = 2 if is_easter_time() else 0
def get_step_and_logical_step(self) -> Tuple[int, int]:
if self == "easy":
return 3, 8
if self == "normal":
return 3, 6
if self == "hard":
return 4, 6
if self == "very_hard":
return 4, 5
return 4, 4
class ShuffleDog(Choice): class ShuffleDog(Choice):
""" """
Adds petting the dog statue in Town into the location pool. Adds petting the dog statue in Town into the location pool.
@@ -504,6 +554,7 @@ class TheWitnessOptions(PerGameCommonOptions):
death_link_amnesty: DeathLinkAmnesty death_link_amnesty: DeathLinkAmnesty
puzzle_randomization_seed: PuzzleRandomizationSeed puzzle_randomization_seed: PuzzleRandomizationSeed
shuffle_dog: ShuffleDog shuffle_dog: ShuffleDog
easter_egg_hunt: EasterEggHunt
witness_option_groups = [ witness_option_groups = [
@@ -561,3 +612,13 @@ witness_option_groups = [
ShuffleDog, ShuffleDog,
]) ])
] ]
# Make sure that Easter Egg Hunt is VERY visible during easter time (when it's enabled by default)
if is_easter_time():
easter_special_option_group = OptionGroup("EASTER SPECIAL", [
EasterEggHunt,
])
witness_option_groups = [easter_special_option_group, *witness_option_groups]
else:
silly_options_group = next(group for group in witness_option_groups if group.name == "Silly Options")
silly_options_group.options.append(EasterEggHunt)

View File

@@ -31,6 +31,13 @@ class WitnessItem(Item):
Item from the game The Witness Item from the game The Witness
""" """
game: str = "The Witness" game: str = "The Witness"
eggs: int = 0
@classmethod
def make_egg_event(cls, item_name: str, player: int):
ret = cls(item_name, ItemClassification.progression, None, player)
ret.eggs = int(item_name[1:].split(" ", 1)[0])
return ret
class WitnessPlayerItems: class WitnessPlayerItems:

View File

@@ -24,7 +24,6 @@ from .data.item_definition_classes import DoorItemDefinition, ItemCategory, Prog
from .data.static_logic import StaticWitnessLogicObj from .data.static_logic import StaticWitnessLogicObj
from .data.utils import ( from .data.utils import (
WitnessRule, WitnessRule,
define_new_region,
get_boat, get_boat,
get_caves_except_path_to_challenge_exclusion_list, get_caves_except_path_to_challenge_exclusion_list,
get_complex_additional_panels, get_complex_additional_panels,
@@ -119,6 +118,8 @@ class WitnessPlayerLogic:
self.PRE_PICKED_HUNT_ENTITIES: Set[str] = set() self.PRE_PICKED_HUNT_ENTITIES: Set[str] = set()
self.HUNT_ENTITIES: Set[str] = set() self.HUNT_ENTITIES: Set[str] = set()
self.AVAILABLE_EASTER_EGGS: Set[str] = set()
self.AVAILABLE_EASTER_EGGS_PER_REGION: Dict[str, int] = {}
self.ALWAYS_EVENT_NAMES_BY_HEX = { self.ALWAYS_EVENT_NAMES_BY_HEX = {
"0x00509": "+1 Laser", "0x00509": "+1 Laser",
"0x012FB": "+1 Laser (Unredirected)", "0x012FB": "+1 Laser (Unredirected)",
@@ -154,6 +155,9 @@ class WitnessPlayerLogic:
picker = EntityHuntPicker(self, world, self.PRE_PICKED_HUNT_ENTITIES) picker = EntityHuntPicker(self, world, self.PRE_PICKED_HUNT_ENTITIES)
self.HUNT_ENTITIES = picker.pick_panel_hunt_panels(world.options.panel_hunt_total.value) self.HUNT_ENTITIES = picker.pick_panel_hunt_panels(world.options.panel_hunt_total.value)
if world.options.easter_egg_hunt:
self.finalize_easter_eggs(world)
# Finalize which items actually exist in the MultiWorld and which get grouped into progressive items. # Finalize which items actually exist in the MultiWorld and which get grouped into progressive items.
self.finalize_items() self.finalize_items()
@@ -241,6 +245,8 @@ class WitnessPlayerLogic:
if option_entity in {"7 Lasers", "11 Lasers", "7 Lasers + Redirect", "11 Lasers + Redirect", if option_entity in {"7 Lasers", "11 Lasers", "7 Lasers + Redirect", "11 Lasers + Redirect",
"PP2 Weirdness", "Theater to Tunnels", "Entity Hunt"}: "PP2 Weirdness", "Theater to Tunnels", "Entity Hunt"}:
new_items = frozenset({frozenset([option_entity])}) new_items = frozenset({frozenset([option_entity])})
elif "Eggs" in option_entity:
new_items = frozenset({frozenset([option_entity])})
elif option_entity in self.DISABLE_EVERYTHING_BEHIND: elif option_entity in self.DISABLE_EVERYTHING_BEHIND:
new_items = frozenset() new_items = frozenset()
else: else:
@@ -387,13 +393,6 @@ class WitnessPlayerLogic:
return return
if adj_type == "Region Changes":
new_region_and_options = define_new_region(line + ":")
self.CONNECTIONS_BY_REGION_NAME_THEORETICAL[new_region_and_options[0]["name"]] = new_region_and_options[1]
return
if adj_type == "New Connections": if adj_type == "New Connections":
line_split = line.split(" - ") line_split = line.split(" - ")
source_region = line_split[0] source_region = line_split[0]
@@ -533,6 +532,55 @@ class WitnessPlayerLogic:
return postgame_adjustments return postgame_adjustments
def set_easter_egg_requirements(self, world: "WitnessWorld") -> None:
eggs_per_check, logically_required_eggs_per_check = world.options.easter_egg_hunt.get_step_and_logical_step()
for entity_hex, entity_obj in static_witness_logic.ENTITIES_BY_HEX.items():
if entity_obj["entityType"] != "Easter Egg Total":
continue
direct_egg_count = int(entity_obj["checkName"].split(" ")[0])
if direct_egg_count % eggs_per_check:
self.COMPLETELY_DISABLED_ENTITIES.add(entity_hex)
requirement = direct_egg_count // eggs_per_check * logically_required_eggs_per_check
self.DEPENDENT_REQUIREMENTS_BY_HEX[entity_hex] = {
"entities": frozenset({frozenset({f"{requirement} Eggs"})})
}
def finalize_easter_eggs(self, world: "WitnessWorld") -> None:
self.AVAILABLE_EASTER_EGGS = {
entity_hex for entity_hex, entity_obj in static_witness_logic.ENTITIES_BY_HEX.items()
if entity_obj["entityType"] == "Easter Egg" and self.solvability_guaranteed(entity_hex)
}
max_eggs = len(self.AVAILABLE_EASTER_EGGS)
self.AVAILABLE_EASTER_EGGS_PER_REGION = defaultdict(int)
for entity_hex in self.AVAILABLE_EASTER_EGGS:
region_name = static_witness_logic.ENTITIES_BY_HEX[entity_hex]["region"]["name"]
self.AVAILABLE_EASTER_EGGS_PER_REGION[region_name] += 1
eggs_per_check, logically_required_eggs_per_check = world.options.easter_egg_hunt.get_step_and_logical_step()
for entity_hex, entity_obj in static_witness_logic.ENTITIES_BY_HEX.items():
if entity_obj["entityType"] != "Easter Egg Total":
continue
if entity_hex in self.COMPLETELY_DISABLED_ENTITIES:
continue
direct_egg_count = int(entity_obj["checkName"].split(" ", 1)[0])
logically_required_egg_count = direct_egg_count // eggs_per_check * logically_required_eggs_per_check
if direct_egg_count > max_eggs:
self.COMPLETELY_DISABLED_ENTITIES.add(entity_hex)
continue
self.ADDED_CHECKS.add(entity_obj["checkName"])
if logically_required_egg_count > max_eggs:
# Exclude and set logic to require every egg
self.EXCLUDED_ENTITIES.add(entity_hex)
self.REQUIREMENTS_BY_HEX[entity_hex] = frozenset({frozenset({f"{max_eggs} Eggs"})})
def make_options_adjustments(self, world: "WitnessWorld") -> None: def make_options_adjustments(self, world: "WitnessWorld") -> None:
"""Makes logic adjustments based on options""" """Makes logic adjustments based on options"""
adjustment_linesets_in_order = [] adjustment_linesets_in_order = []
@@ -641,6 +689,8 @@ class WitnessPlayerLogic:
adjustment_linesets_in_order.append([ adjustment_linesets_in_order.append([
"New Connections:", "New Connections:",
"Outside Bunker - Bunker Elevator - TrueOneWay", "Outside Bunker - Bunker Elevator - TrueOneWay",
"Bunker Elevator Section - Bunker Under Elevator - "
"0x0A079 | Bunker Green Room | Bunker Cyan Room | Bunker Laser Platform | Outside Bunker",
]) ])
if "Swamp Long Bridge" in world.options.elevators_come_to_you: if "Swamp Long Bridge" in world.options.elevators_come_to_you:
adjustment_linesets_in_order.append([ adjustment_linesets_in_order.append([
@@ -655,6 +705,14 @@ class WitnessPlayerLogic:
# "New Connections:" # "New Connections:"
# "Town Red Rooftop - Town Maze Rooftop - TrueOneWay" # "Town Red Rooftop - Town Maze Rooftop - TrueOneWay"
if world.options.easter_egg_hunt:
self.set_easter_egg_requirements(world)
else:
self.COMPLETELY_DISABLED_ENTITIES.update({
entity_hex for entity_hex, entity_obj in static_witness_logic.ENTITIES_BY_HEX.items()
if "Easter Egg" in entity_obj["entityType"]
})
if world.options.victory_condition == "panel_hunt": if world.options.victory_condition == "panel_hunt":
adjustment_linesets_in_order.append(get_entity_hunt()) adjustment_linesets_in_order.append(get_entity_hunt())
@@ -691,6 +749,9 @@ class WitnessPlayerLogic:
if loc_obj["entityType"] == "EP": if loc_obj["entityType"] == "EP":
self.COMPLETELY_DISABLED_ENTITIES.add(loc_obj["entity_hex"]) self.COMPLETELY_DISABLED_ENTITIES.add(loc_obj["entity_hex"])
if loc_obj["entityType"] == "Easter Egg":
self.COMPLETELY_DISABLED_ENTITIES.add(loc_obj["entity_hex"])
elif loc_obj["entityType"] == "Panel": elif loc_obj["entityType"] == "Panel":
self.EXCLUDED_ENTITIES.add(loc_obj["entity_hex"]) self.EXCLUDED_ENTITIES.add(loc_obj["entity_hex"])
@@ -937,6 +998,7 @@ class WitnessPlayerLogic:
doors = world.options.shuffle_doors doors = world.options.shuffle_doors
shortbox_req = world.options.mountain_lasers shortbox_req = world.options.mountain_lasers
longbox_req = world.options.challenge_lasers longbox_req = world.options.challenge_lasers
eggs_exist = world.options.easter_egg_hunt
swamp_bridge_comes_to_you = "Swamp Long Bridge" in world.options.elevators_come_to_you swamp_bridge_comes_to_you = "Swamp Long Bridge" in world.options.elevators_come_to_you
quarry_elevator_comes_to_you = "Quarry Elevator" in world.options.elevators_come_to_you quarry_elevator_comes_to_you = "Quarry Elevator" in world.options.elevators_come_to_you
@@ -953,17 +1015,17 @@ class WitnessPlayerLogic:
# It is easier to think about when these items *are* required, so we make that dict first # It is easier to think about when these items *are* required, so we make that dict first
# If the entity is disabled anyway, we don't need to consider that case # If the entity is disabled anyway, we don't need to consider that case
is_item_required_dict = { is_item_required_dict = {
"0x03750": eps_shuffled, # Monastery Garden Entry Door "0x03750": eps_shuffled or eggs_exist, # Monastery Garden Entry Door
"0x275FA": eps_shuffled, # Boathouse Hook Control "0x275FA": eps_shuffled, # Boathouse Hook Control
"0x17D02": eps_shuffled, # Windmill Turn Control "0x17D02": eps_shuffled, # Windmill Turn Control
"0x0368A": symbols_shuffled or door_panels, # Quarry Stoneworks Stairs Door "0x0368A": symbols_shuffled or door_panels, # Quarry Stoneworks Stairs Door
"0x3865F": symbols_shuffled or door_panels or eps_shuffled, # Quarry Boathouse 2nd Barrier "0x3865F": symbols_shuffled or door_panels or eps_shuffled, # Quarry Boathouse 2nd Barrier
"0x17CC4": quarry_elevator_comes_to_you or eps_shuffled, # Quarry Elevator Panel "0x17CC4": quarry_elevator_comes_to_you or eps_shuffled, # Quarry Elevator Panel
"0x17E2B": swamp_bridge_comes_to_you and boat_shuffled or eps_shuffled, # Swamp Long Bridge "0x17E2B": swamp_bridge_comes_to_you and boat_shuffled or eps_shuffled, # Swamp Long Bridge
"0x0CF2A": False, # Jungle Monastery Garden Shortcut "0x0CF2A": eggs_exist, # Jungle Monastery Garden Shortcut
"0x0364E": False, # Monastery Laser Shortcut Door "0x0364E": False, # Monastery Laser Shortcut Door
"0x03713": remote_doors, # Monastery Laser Shortcut Panel "0x03713": remote_doors, # Monastery Laser Shortcut Panel
"0x03313": False, # Orchard Second Gate "0x03313": eggs_exist, # Orchard Second Gate
"0x337FA": remote_doors, # Jungle Bamboo Laser Shortcut Panel "0x337FA": remote_doors, # Jungle Bamboo Laser Shortcut Panel
"0x3873B": False, # Jungle Bamboo Laser Shortcut Door "0x3873B": False, # Jungle Bamboo Laser Shortcut Door
"0x335AB": False, # Caves Elevator Controls "0x335AB": False, # Caves Elevator Controls
@@ -1026,4 +1088,9 @@ class WitnessPlayerLogic:
entity_name = entity_obj["checkName"] entity_name = entity_obj["checkName"]
self.EVENT_ITEM_PAIRS[entity_name + " (Panel Hunt)"] = ("+1 Panel Hunt", entity_hex) self.EVENT_ITEM_PAIRS[entity_name + " (Panel Hunt)"] = ("+1 Panel Hunt", entity_hex)
for region_name, easter_egg_count in self.AVAILABLE_EASTER_EGGS_PER_REGION.items():
plural = "s" if easter_egg_count != 1 else ""
event_name = f"+{easter_egg_count} Easter Egg{plural}"
self.EVENT_ITEM_PAIRS[f"{region_name} Easter Egg{plural}"] = (event_name, region_name)
return return

View File

@@ -117,12 +117,17 @@ class WitnessPlayerRegions:
event_locations_per_region = defaultdict(dict) event_locations_per_region = defaultdict(dict)
for event_location, event_item_and_entity in player_logic.EVENT_ITEM_PAIRS.items(): for event_location, event_item_and_entity in player_logic.EVENT_ITEM_PAIRS.items():
region = static_witness_logic.ENTITIES_BY_HEX[event_item_and_entity[1]]["region"] entity_or_region = event_item_and_entity[1]
if region is None: if entity_or_region in static_witness_logic.ALL_REGIONS_BY_NAME:
region_name = "Entry" region_name = entity_or_region
order = -1
else: else:
region_name = region["name"] region = static_witness_logic.ENTITIES_BY_HEX[event_item_and_entity[1]]["region"]
order = self.reference_logic.ENTITIES_BY_HEX[event_item_and_entity[1]]["order"] if region is None:
region_name = "Entry"
else:
region_name = region["name"]
order = self.reference_logic.ENTITIES_BY_HEX[entity_or_region]["order"]
event_locations_per_region[region_name][event_location] = order event_locations_per_region[region_name][event_location] = order
for region_name, region in regions_to_create.items(): for region_name, region in regions_to_create.items():

View File

@@ -2,7 +2,7 @@ line-length = 120
[lint] [lint]
select = ["C", "E", "F", "R", "W", "I", "N", "Q", "UP", "RUF", "ISC", "T20"] select = ["C", "E", "F", "R", "W", "I", "N", "Q", "UP", "RUF", "ISC", "T20"]
ignore = ["C9", "RUF012", "RUF100"] ignore = ["C9", "RUF012", "RUF021", "RUF100", "UP006", "UP035"]
[lint.per-file-ignores] [lint.per-file-ignores]
# The way options definitions work right now, I am forced to break line length requirements. # The way options definitions work right now, I am forced to break line length requirements.

View File

@@ -196,6 +196,8 @@ def _has_item(item: str, world: "WitnessWorld",
if item == "Entity Hunt": if item == "Entity Hunt":
# Right now, panel hunt is the only type of entity hunt. This may need to be changed later # Right now, panel hunt is the only type of entity hunt. This may need to be changed later
return _can_do_panel_hunt(world) return _can_do_panel_hunt(world)
if "Eggs" in item:
return SimpleItemRepresentation("Egg", int(item.split(" ")[0]))
if item == "PP2 Weirdness": if item == "PP2 Weirdness":
return lambda state: _can_do_expert_pp2(state, world) return lambda state: _can_do_expert_pp2(state, world)
if item == "Theater to Tunnels": if item == "Theater to Tunnels":
@@ -303,6 +305,11 @@ def make_lambda(entity_hex: str, world: "WitnessWorld") -> Optional[CollectionRu
return _meets_item_requirements(entity_req, world) return _meets_item_requirements(entity_req, world)
def make_region_lambda(region_name: str, world: "WitnessWorld") -> CollectionRule:
region = world.get_region(region_name)
return lambda state: region.can_reach(state)
def set_rules(world: "WitnessWorld") -> None: def set_rules(world: "WitnessWorld") -> None:
""" """
Sets all rules for all locations Sets all rules for all locations
@@ -312,8 +319,12 @@ def set_rules(world: "WitnessWorld") -> None:
real_location = location real_location = location
if location in world.player_locations.EVENT_LOCATION_TABLE: if location in world.player_locations.EVENT_LOCATION_TABLE:
entity_hex = world.player_logic.EVENT_ITEM_PAIRS[location][1] entity_hex_or_region_name = world.player_logic.EVENT_ITEM_PAIRS[location][1]
real_location = static_witness_logic.ENTITIES_BY_HEX[entity_hex]["checkName"] if entity_hex_or_region_name in static_witness_logic.ALL_REGIONS_BY_NAME:
set_rule(world.get_location(location), make_region_lambda(entity_hex_or_region_name, world))
continue
real_location = static_witness_logic.ENTITIES_BY_HEX[entity_hex_or_region_name]["checkName"]
associated_entity = world.player_logic.REFERENCE_LOGIC.ENTITIES_BY_NAME[real_location] associated_entity = world.player_logic.REFERENCE_LOGIC.ENTITIES_BY_NAME[real_location]
entity_hex = associated_entity["entity_hex"] entity_hex = associated_entity["entity_hex"]

View File

@@ -0,0 +1,155 @@
from typing import cast
from BaseClasses import LocationProgressType
from .. import WitnessWorld
from ..test import WitnessMultiworldTestBase
class TestEasterEggShuffle(WitnessMultiworldTestBase):
options_per_world = [
{
"easter_egg_hunt": "off",
},
{
"easter_egg_hunt": "easy",
},
{
"easter_egg_hunt": "normal",
},
{
"easter_egg_hunt": "hard",
},
{
"easter_egg_hunt": "very_hard",
},
{
"easter_egg_hunt": "extreme",
},
]
def test_easter_egg_hunt(self) -> None:
with self.subTest("Test that player without Easter Egg Hunt has no easter egg related locations"):
egg_locations = {location for location in self.multiworld.get_locations(1) if "Egg" in location.name}
self.assertFalse(egg_locations)
for player, eggs_per_check, logical_eggs_per_check in zip([2, 3, 4, 5, 6], [3, 3, 4, 4, 4], [8, 6, 6, 5, 4]):
world = cast(WitnessWorld, self.multiworld.worlds[player])
option_name = world.options.easter_egg_hunt
with self.subTest(f"Test that {option_name} Egg Hunt player starts with 0 eggs"):
self.assertEqual(self.multiworld.state.count("Egg", player), 0)
with self.subTest(f"Test that the correct Egg Collection locations exist for {option_name} player"):
first_egg_location = f"{eggs_per_check} Easter Eggs Collected"
one_less_location = f"{eggs_per_check - 1} Easter Eggs Collected"
one_more_location = f"{eggs_per_check + 1} Easter Eggs Collected"
self.assert_location_exists(first_egg_location, player)
self.assert_location_does_not_exist(one_less_location, player, strict_check=False)
self.assert_location_does_not_exist(one_more_location, player, strict_check=False)
one_too_few = logical_eggs_per_check - 1
with self.subTest(f'Test that "+{one_too_few} Easter Eggs" item adds 4 easter eggs'):
item = world.create_item(f"+{one_too_few} Easter Eggs")
self.multiworld.state.collect(item, prevent_sweep=True)
self.assertEqual(self.multiworld.state.count("Egg", player), one_too_few)
with self.subTest(
f"Test that {one_too_few} Easter Eggs are not enough for {option_name} player's first location"
):
self.assertFalse(self.multiworld.state.can_reach_location(first_egg_location, player))
with self.subTest(
f"Test that {logical_eggs_per_check} Easter Eggs are enough for {option_name} player's first location"
):
item = world.create_item("+1 Easter Egg")
self.multiworld.state.collect(item, prevent_sweep=True)
self.assertTrue(self.multiworld.state.can_reach_location(first_egg_location, player))
class TestEggRestrictions(WitnessMultiworldTestBase):
options_per_world = [
{
"shuffle_postgame": False,
},
{
"shuffle_postgame": True,
},
{
"shuffle_postgame": True,
"exclude_locations": frozenset({"Bunker Easter Egg 3"}),
}
]
common_options = {
"victory_condition": "mountain_box_short",
"shuffle_doors": "off",
"easter_egg_hunt": "very_hard",
"shuffle_vault_boxes": True,
}
def test_egg_restrictions(self) -> None:
with self.subTest("Test that locations beyond 108 Easter Eggs don't exist for a seed without Mountain"):
self.assert_location_exists("108 Easter Eggs Collected", 1)
self.assert_location_does_not_exist("112 Easter Eggs Collected", 1)
with self.subTest(
"Test that locations beyond 86 Easter Eggs, which would logically require more than 108 Eggs, are excluded"
):
egg_84_location = self.multiworld.get_location("84 Easter Eggs Collected", 1)
egg_88_location = self.multiworld.get_location("88 Easter Eggs Collected", 1)
self.assertNotEqual(egg_84_location.progress_type, LocationProgressType.EXCLUDED)
self.assertEqual(egg_88_location.progress_type, LocationProgressType.EXCLUDED)
with self.subTest("Test that in a seed with the whole game included, the 120 egg location exists"):
self.assert_location_exists("120 Easter Eggs Collected", 2)
with self.subTest(
"Test that locations beyond 96 Easter Eggs, which would logically require more than 120 Eggs, are excluded"
):
egg_96_location = self.multiworld.get_location("96 Easter Eggs Collected", 2)
egg_100_location = self.multiworld.get_location("100 Easter Eggs Collected", 2)
self.assertNotEqual(egg_96_location.progress_type, LocationProgressType.EXCLUDED)
self.assertEqual(egg_100_location.progress_type, LocationProgressType.EXCLUDED)
with self.subTest("Test that you can exclude and egg to disable it"):
self.assert_location_exists("116 Easter Eggs Collected", 3)
self.assert_location_does_not_exist("120 Easter Eggs Collected", 3)
class TestBunkerElevatorEgg(WitnessMultiworldTestBase):
options_per_world = [
{
"elevators_come_to_you": frozenset()
},
{
"elevators_come_to_you": frozenset({"Bunker Elevator"})
},
]
common_options = {
"easter_egg_hunt": "normal",
"shuffle_doors": "panels",
"shuffle_symbols": False,
}
def test_bunker_elevator_egg(self) -> None:
items_to_reach_bunker_elevator = [
"Bunker Entry (Panel)",
"Bunker Tinted Glass Door (Panel)",
"Bunker Drop-Down Door Controls (Panel)"
]
with self.subTest("Test that normally, the egg behind the elevator needs Elevator Control"):
self.assertFalse(self.multiworld.state.can_reach_location("Bunker Under Elevator Easter Egg", 1))
self.collect_by_name(items_to_reach_bunker_elevator, 1)
self.assertFalse(self.multiworld.state.can_reach_location("Bunker Under Elevator Easter Egg", 1))
self.collect_by_name(["Bunker Elevator Control (Panel)"], 1)
self.assertTrue(self.multiworld.state.can_reach_location("Bunker Under Elevator Easter Egg", 1))
with self.subTest("Test that with auto-elevators, the egg behind the elevator doesn't need Elevator Control"):
self.assertFalse(self.multiworld.state.can_reach_location("Bunker Under Elevator Easter Egg", 2))
self.collect_by_name(items_to_reach_bunker_elevator, 2)
self.assertTrue(self.multiworld.state.can_reach_location("Bunker Under Elevator Easter Egg", 2))