Witness: Bugfixes in response to beta tests (#1473)

* Make all Keep Pressure Plates logically required for the Laser Panel

* Added more Tutorial checks

* Added the remaining two Shipwreck Boat EPs to the exclude list for normal

* Improved itempool filling system, added warning if usefuls had to be eaten

* Moved creation of said warning string to utils

* Fixed logic bug causing broken seeds on Mountain Floor 2

* Hints system change

* Expert Logic Fix

* Fixed typo

* Better wording

* Added missing games to junk hints

* Made sure Entrance names are unique

* Fixed missing Obelisk Side

* Disable Non Randomized + EP Shuffle fix

* Fixed disable_non_randomized precompleted EPs being 'disabled' instead of 'precompleted'

* Fixed if/elif error

* Tutorial Gate Open local symbol item becomes local_early_item in expert instead

* Bump required client version. There is a beta client that sends 0.3.9.

* Removed print statement, oops

* Fixed itempool manipulation in pre_fill

* Replaced string concats with fstrings

* Improved make_warning_string function signature

Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>

* Improved performance on removing multiple items from multiworld itempool

* Comment

* Fixed errors with the code

* Made removal from itempool not fail unit test for multiple references

* Moved all item creation to create_items, got rid of itempool modifying system

* Colored Squares is no longer a good item, that's outdated

* Removed double if

* React to from_pool: false by removing a junk item

* Fixed warning if only Fnc Brain was removed

* Make use of string truthiness instead

* Made reading of plandoed items safer

---------

Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>
This commit is contained in:
NewSoupVi 2023-03-03 00:08:24 +01:00 committed by GitHub
parent 0cf8206660
commit 805f33c39e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 292 additions and 183 deletions

View File

@ -411,7 +411,7 @@ Keep Tower (Keep) - Keep - 0x04F8F:
158206 - 0x0361B (Tower Shortcut Panel) - True - True
Door - 0x04F8F (Tower Shortcut) - 0x0361B
158704 - 0x0360E (Laser Panel Hedges) - 0x01A0F & 0x019E7 & 0x019DC & 0x00139 - True
158705 - 0x03317 (Laser Panel Pressure Plates) - 0x01D3F - Shapers & Black/White Squares & Colored Squares & Stars & Stars + Same Colored Symbol & Dots
158705 - 0x03317 (Laser Panel Pressure Plates) - 0x033EA & 0x01BE9 & 0x01CD3 & 0x01D3F - Shapers & Black/White Squares & Colored Squares & Stars & Stars + Same Colored Symbol & Dots
Laser - 0x014BB (Laser) - 0x0360E | 0x03317
159240 - 0x033BE (Pressure Plates 1 EP) - 0x033EA - True
159241 - 0x033BF (Pressure Plates 2 EP) - 0x01BE9 - True
@ -909,7 +909,7 @@ Mountain Floor 2 (Mountain Floor 2) - Mountain Floor 2 Light Bridge Room Near -
158430 - 0x09FD8 (Near Row 5) - 0x09FD7 - Colored Squares & Symmetry & Colored Dots
Door - 0x09FFB (Staircase Near) - 0x09FD8
Mountain Floor 2 Blue Bridge (Mountain Floor 2) - Mountain Floor 2 Beyond Bridge - TrueOneWay - Mountain Floor 2 At Door - TrueOneWay:
Mountain Floor 2 Blue Bridge (Mountain Floor 2) - Mountain Floor 2 Beyond Bridge - TrueOneWay - Mountain Floor 2 At Door - 0x09ED8:
Mountain Floor 2 At Door (Mountain Floor 2) - Mountain Floor 2 Elevator Room - 0x09EDD:
Door - 0x09EDD (Elevator Room Entry) - 0x09ED8 & 0x09E86
@ -1113,8 +1113,9 @@ Obelisks (EPs) - Entry - True:
159735 - 0xFFE35 (River Obelisk Side 6) - 0x035CB & 0x035CF - True
159740 - 0xFFE40 (Quarry Obelisk Side 1) - 0x28A7B & 0x005F6 & 0x00859 & 0x17CB9 & 0x28A4A - True
159741 - 0xFFE41 (Quarry Obelisk Side 2) - 0x334B6 & 0x00614 & 0x0069D & 0x28A4C - True
159742 - 0xFFE42 (Quarry Obelisk Side 3) - 0x289CF & 0x289D1 & 0x33692 - True
159743 - 0xFFE43 (Quarry Obelisk Side 4) - 0x03E77 & 0x03E7C - True
159742 - 0xFFE42 (Quarry Obelisk Side 3) - 0x289CF & 0x289D1 - True
159743 - 0xFFE43 (Quarry Obelisk Side 4) - 0x33692 - True
159744 - 0xFFE44 (Quarry Obelisk Side 5) - 0x03E77 & 0x03E7C - True
159750 - 0xFFE50 (Town Obelisk Side 1) - 0x035C7 - True
159751 - 0xFFE51 (Town Obelisk Side 2) - 0x01848 & 0x03D06 & 0x33530 & 0x33600 & 0x28A2F & 0x28A37 & 0x334A3 & 0x3352F - True
159752 - 0xFFE52 (Town Obelisk Side 3) - 0x33857 & 0x33879 & 0x03C19 - True

View File

@ -270,7 +270,7 @@ Door - 0x0368A (Stairs) - 0x03677
159413 - 0x00614 (Lift EP) - 0x275FF & 0x03675 - True
Quarry Boathouse (Quarry Boathouse) - Quarry - True - Quarry Boathouse Upper Front - 0x03852 - Quarry Boathouse Behind Staircase - 0x2769B:
158146 - 0x034D4 (Intro Left) - True - Stars & Eraser
158146 - 0x034D4 (Intro Left) - True - Stars & Stars + Same Colored Symbol + Eraser
158147 - 0x021D5 (Intro Right) - True - Shapers & Eraser
158148 - 0x03852 (Ramp Height Control) - 0x034D4 & 0x021D5 - Rotated Shapers
158166 - 0x17CA6 (Boat Spawn) - True - Boat
@ -411,7 +411,7 @@ Keep Tower (Keep) - Keep - 0x04F8F:
158206 - 0x0361B (Tower Shortcut Panel) - True - True
Door - 0x04F8F (Tower Shortcut) - 0x0361B
158704 - 0x0360E (Laser Panel Hedges) - 0x01A0F & 0x019E7 & 0x019DC & 0x00139 - True
158705 - 0x03317 (Laser Panel Pressure Plates) - 0x01BE9 - Shapers & Rotated Shapers & Triangles & Stars & Stars + Same Colored Symbol & Colored Squares & Black/White Squares
158705 - 0x03317 (Laser Panel Pressure Plates) - 0x033EA & 0x01BE9 & 0x01CD3 & 0x01D3F - Shapers & Rotated Shapers & Triangles & Stars & Stars + Same Colored Symbol & Colored Squares & Black/White Squares
Laser - 0x014BB (Laser) - 0x0360E | 0x03317
159240 - 0x033BE (Pressure Plates 1 EP) - 0x033EA - True
159241 - 0x033BF (Pressure Plates 2 EP) - 0x01BE9 - True
@ -909,7 +909,7 @@ Mountain Floor 2 (Mountain Floor 2) - Mountain Floor 2 Light Bridge Room Near -
158430 - 0x09FD8 (Near Row 5) - 0x09FD7 - Stars & Stars + Same Colored Symbol & Rotated Shapers & Eraser
Door - 0x09FFB (Staircase Near) - 0x09FD8
Mountain Floor 2 Blue Bridge (Mountain Floor 2) - Mountain Floor 2 Beyond Bridge - TrueOneWay - Mountain Floor 2 At Door - TrueOneWay:
Mountain Floor 2 Blue Bridge (Mountain Floor 2) - Mountain Floor 2 Beyond Bridge - TrueOneWay - Mountain Floor 2 At Door - 0x09ED8:
Mountain Floor 2 At Door (Mountain Floor 2) - Mountain Floor 2 Elevator Room - 0x09EDD:
Door - 0x09EDD (Elevator Room Entry) - 0x09ED8 & 0x09E86
@ -1113,8 +1113,9 @@ Obelisks (EPs) - Entry - True:
159735 - 0xFFE35 (River Obelisk Side 6) - 0x035CB & 0x035CF - True
159740 - 0xFFE40 (Quarry Obelisk Side 1) - 0x28A7B & 0x005F6 & 0x00859 & 0x17CB9 & 0x28A4A - True
159741 - 0xFFE41 (Quarry Obelisk Side 2) - 0x334B6 & 0x00614 & 0x0069D & 0x28A4C - True
159742 - 0xFFE42 (Quarry Obelisk Side 3) - 0x289CF & 0x289D1 & 0x33692 - True
159743 - 0xFFE43 (Quarry Obelisk Side 4) - 0x03E77 & 0x03E7C - True
159742 - 0xFFE42 (Quarry Obelisk Side 3) - 0x289CF & 0x289D1 - True
159743 - 0xFFE43 (Quarry Obelisk Side 4) - 0x33692 - True
159744 - 0xFFE44 (Quarry Obelisk Side 5) - 0x03E77 & 0x03E7C - True
159750 - 0xFFE50 (Town Obelisk Side 1) - 0x035C7 - True
159751 - 0xFFE51 (Town Obelisk Side 2) - 0x01848 & 0x03D06 & 0x33530 & 0x33600 & 0x28A2F & 0x28A37 & 0x334A3 & 0x3352F - True
159752 - 0xFFE52 (Town Obelisk Side 3) - 0x33857 & 0x33879 & 0x03C19 - True

View File

@ -411,7 +411,7 @@ Keep Tower (Keep) - Keep - 0x04F8F:
158206 - 0x0361B (Tower Shortcut Panel) - True - True
Door - 0x04F8F (Tower Shortcut) - 0x0361B
158704 - 0x0360E (Laser Panel Hedges) - 0x01A0F & 0x019E7 & 0x019DC & 0x00139 - True
158705 - 0x03317 (Laser Panel Pressure Plates) - 0x01D3F - Shapers & Black/White Squares & Rotated Shapers
158705 - 0x03317 (Laser Panel Pressure Plates) - 0x033EA & 0x01BE9 & 0x01CD3 & 0x01D3F - Shapers & Black/White Squares & Rotated Shapers
Laser - 0x014BB (Laser) - 0x0360E | 0x03317
159240 - 0x033BE (Pressure Plates 1 EP) - 0x033EA - True
159241 - 0x033BF (Pressure Plates 2 EP) - 0x01BE9 - True
@ -909,7 +909,7 @@ Mountain Floor 2 (Mountain Floor 2) - Mountain Floor 2 Light Bridge Room Near -
158430 - 0x09FD8 (Near Row 5) - 0x09FD7 - Colored Squares & Symmetry
Door - 0x09FFB (Staircase Near) - 0x09FD8
Mountain Floor 2 Blue Bridge (Mountain Floor 2) - Mountain Floor 2 Beyond Bridge - TrueOneWay - Mountain Floor 2 At Door - TrueOneWay:
Mountain Floor 2 Blue Bridge (Mountain Floor 2) - Mountain Floor 2 Beyond Bridge - TrueOneWay - Mountain Floor 2 At Door - 0x09ED8:
Mountain Floor 2 At Door (Mountain Floor 2) - Mountain Floor 2 Elevator Room - 0x09EDD:
Door - 0x09EDD (Elevator Room Entry) - 0x09ED8 & 0x09E86
@ -1113,8 +1113,9 @@ Obelisks (EPs) - Entry - True:
159735 - 0xFFE35 (River Obelisk Side 6) - 0x035CB & 0x035CF - True
159740 - 0xFFE40 (Quarry Obelisk Side 1) - 0x28A7B & 0x005F6 & 0x00859 & 0x17CB9 & 0x28A4A - True
159741 - 0xFFE41 (Quarry Obelisk Side 2) - 0x334B6 & 0x00614 & 0x0069D & 0x28A4C - True
159742 - 0xFFE42 (Quarry Obelisk Side 3) - 0x289CF & 0x289D1 & 0x33692 - True
159743 - 0xFFE43 (Quarry Obelisk Side 4) - 0x03E77 & 0x03E7C - True
159742 - 0xFFE42 (Quarry Obelisk Side 3) - 0x289CF & 0x289D1 - True
159743 - 0xFFE43 (Quarry Obelisk Side 4) - 0x33692 - True
159744 - 0xFFE44 (Quarry Obelisk Side 5) - 0x03E77 & 0x03E7C - True
159750 - 0xFFE50 (Town Obelisk Side 1) - 0x035C7 - True
159751 - 0xFFE51 (Town Obelisk Side 2) - 0x01848 & 0x03D06 & 0x33530 & 0x33600 & 0x28A2F & 0x28A37 & 0x334A3 & 0x3352F - True
159752 - 0xFFE52 (Town Obelisk Side 3) - 0x33857 & 0x33879 & 0x03C19 - True

View File

@ -14,7 +14,7 @@ from .items import WitnessItem, StaticWitnessItems, WitnessPlayerItems
from .rules import set_rules
from .regions import WitnessRegions
from .Options import is_option_enabled, the_witness_options, get_option_value
from .utils import best_junk_to_add_based_on_weights, get_audio_logs
from .utils import best_junk_to_add_based_on_weights, get_audio_logs, make_warning_string
from logging import warning
@ -38,7 +38,7 @@ class WitnessWorld(World):
"""
game = "The Witness"
topology_present = False
data_version = 12
data_version = 13
static_logic = StaticWitnessLogic()
static_locat = StaticWitnessLocations()
@ -52,7 +52,7 @@ class WitnessWorld(World):
location_name_to_id = StaticWitnessLocations.ALL_LOCATIONS_TO_ID
item_name_groups = StaticWitnessItems.ITEM_NAME_GROUPS
required_client_version = (0, 3, 8)
required_client_version = (0, 3, 9)
def _get_slot_data(self):
return {
@ -93,13 +93,13 @@ class WitnessWorld(World):
self.items = WitnessPlayerItems(self.locat, self.multiworld, self.player, self.player_logic)
self.regio = WitnessRegions(self.locat)
def create_regions(self):
self.regio.create_regions(self.multiworld, self.player, self.player_logic)
def generate_basic(self):
self.log_ids_to_hints = dict()
self.junk_items_created = {key: 0 for key in self.items.JUNK_WEIGHTS.keys()}
def create_regions(self):
self.regio.create_regions(self.multiworld, self.player, self.player_logic)
def create_items(self):
# Generate item pool
pool = []
for item in self.items.ITEM_TABLE:
@ -109,22 +109,12 @@ class WitnessWorld(World):
pool.append(witness_item)
self.items_by_name[item] = witness_item
less_junk = 0
dog_check = self.multiworld.get_location(
"Town Pet the Dog", self.player
)
dog_check.place_locked_item(self.create_item("Puzzle Skip"))
less_junk += 1
for precol_item in self.multiworld.precollected_items[self.player]:
if precol_item.name in self.items_by_name: # if item is in the pool, remove 1 instance.
item_obj = self.items_by_name[precol_item.name]
if item_obj in pool:
pool.remove(item_obj) # remove one instance of this pre-collected item if it exists
pool.remove(item_obj) # remove one instance of this pre-collected item if it exists
for item in self.player_logic.STARTING_INVENTORY:
self.multiworld.push_precollected(self.items_by_name[item])
@ -132,15 +122,8 @@ class WitnessWorld(World):
for item in self.items.EXTRA_AMOUNTS:
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:
witness_item = self.create_item(item)
pool.append(witness_item)
# Put in junk items to fill the rest
junk_size = len(self.locat.CHECK_LOCATION_TABLE) - len(pool) - len(self.locat.EVENT_LOCATION_TABLE) - less_junk
for i in range(0, junk_size):
pool.append(self.create_item(self.get_filler_item_name()))
witness_item = self.create_item(item)
pool.append(witness_item)
# Tie Event Items to Event Locations (e.g. Laser Activations)
for event_location in self.locat.EVENT_LOCATION_TABLE:
@ -150,27 +133,108 @@ class WitnessWorld(World):
location_obj = self.multiworld.get_location(event_location, self.player)
location_obj.place_locked_item(item_obj)
self.multiworld.itempool += pool
# Find out how much empty space there is for junk items. -1 for the "Town Pet the Dog" check
itempool_difference = len(self.locat.CHECK_LOCATION_TABLE) - len(self.locat.EVENT_LOCATION_TABLE) - 1
itempool_difference -= len(pool)
def pre_fill(self):
# Put good item on first check if there are any of the designated "good items" in the pool
# Place two locked items: Good symbol on Tutorial Gate Open, and a Puzzle Skip on "Town Pet the Dog"
good_items_in_the_game = []
plandoed_items = set()
for v in self.multiworld.plando_items[self.player]:
if v.get("from_pool", True):
plandoed_items.update({self.items_by_name[i] for i in v.get("items", dict()).keys()
if i in self.items_by_name})
if "item" in v and v["item"] in self.items_by_name:
plandoed_items.add(self.items_by_name[v["item"]])
for symbol in self.items.GOOD_ITEMS:
item = self.items_by_name[symbol]
if item in self.multiworld.itempool: # Only do this if the item is still in item pool (e.g. after plando)
if item in pool and item not in plandoed_items:
# for now, any item that is mentioned in any plando option, even if it's a list of items, is ineligible.
# Hopefully, in the future, plando gets resolved before create_items.
# I could also partially resolve lists myself, but this could introduce errors if not done carefully.
good_items_in_the_game.append(symbol)
if good_items_in_the_game:
random_good_item = self.multiworld.random.choice(good_items_in_the_game)
first_check = self.multiworld.get_location(
"Tutorial Gate Open", self.player
)
item = self.items_by_name[random_good_item]
first_check.place_locked_item(item)
self.multiworld.itempool.remove(item)
if get_option_value(self.multiworld, self.player, "puzzle_randomization") == 1:
self.multiworld.local_early_items[self.player][random_good_item] = 1
else:
first_check = self.multiworld.get_location(
"Tutorial Gate Open", self.player
)
first_check.place_locked_item(item)
pool.remove(item)
dog_check = self.multiworld.get_location(
"Town Pet the Dog", self.player
)
dog_check.place_locked_item(self.create_item("Puzzle Skip"))
# Fill rest of item pool with junk if there is room
if itempool_difference > 0:
for i in range(0, itempool_difference):
self.multiworld.itempool.append(self.create_item(self.get_filler_item_name()))
# Remove junk, Functioning Brain, useful items (non-door), useful door items in that order until there is room
if itempool_difference < 0:
junk = [
item for item in pool
if item.classification in {ItemClassification.filler, ItemClassification.trap}
and item.name != "Functioning Brain"
]
f_brain = [item for item in pool if item.name == "Functioning Brain"]
usefuls = [
item for item in pool
if item.classification == ItemClassification.useful
and item.name not in StaticWitnessLogic.ALL_DOOR_ITEMS_AS_DICT
]
removable_doors = [
item for item in pool
if item.classification == ItemClassification.useful
and item.name in StaticWitnessLogic.ALL_DOOR_ITEMS_AS_DICT
]
self.multiworld.per_slot_randoms[self.player].shuffle(junk)
self.multiworld.per_slot_randoms[self.player].shuffle(usefuls)
self.multiworld.per_slot_randoms[self.player].shuffle(removable_doors)
removed_junk = False
removed_usefuls = False
removed_doors = False
for i in range(itempool_difference, 0):
if junk:
pool.remove(junk.pop())
removed_junk = True
elif f_brain:
pool.remove(f_brain.pop())
elif usefuls:
pool.remove(usefuls.pop())
removed_usefuls = True
elif removable_doors:
pool.remove(removable_doors.pop())
removed_doors = True
warn = make_warning_string(
removed_junk, removed_usefuls, removed_doors, not junk, not usefuls, not removable_doors
)
if warn:
warning(f"This Witness world has too few locations to place all its items."
f" In order to make space, {warn} had to be removed.")
# Finally, add the generated pool to the overall itempool
self.multiworld.itempool += pool
def set_rules(self):
set_rules(self.multiworld, self.player, self.player_logic, self.locat)

View File

@ -2,96 +2,96 @@ from BaseClasses import MultiWorld
from .Options import is_option_enabled, get_option_value
joke_hints = [
("Quaternions", "break", "my brain"),
("Eclipse", "has nothing", "but you should do it anyway"),
("", "Beep", ""),
("Putting in custom subtitles", "shouldn't have been", "as hard as it was..."),
("BK mode", "is right", "around the corner"),
("", "You can do it!", ""),
("", "I believe in you!", ""),
("The person playing", "is", "cute <3"),
("dash dot, dash dash dash", "dash, dot dot dot dot, dot dot", "dash dot, dash dash dot"),
("When you think about it,", "there are actually a lot of", "bubbles in a stream"),
("Never gonna give you up", "Never gonna let you down", "Never gonna run around and desert you"),
("Thanks to", "the Archipelago developers", "for making this possible."),
("Have you tried ChecksFinder?", "If you like puzzles,", "you might enjoy it!"),
("Have you tried Dark Souls III?", "A tough game like this", "feels better when friends are helping you!"),
("Have you tried Donkey Kong Country 3?", "A legendary game", "from a golden age of platformers!"),
("Have you tried Factorio?", "Alone in an unknown multiworld.", "Sound familiar?"),
("Have you tried Final Fantasy?", "Experience a classic game", "improved to fit modern standards!"),
("Have you tried Hollow Knight?", "Another independent hit", "revolutionising a genre!"),
("Have you tried A Link to the Past?", "The Archipelago game", "that started it all!"),
("Have you tried Meritous?", "You should know that obscure games", "are often groundbreaking!"),
("Have you tried Ocarine of Time?", "One of the biggest randomizers,", "big inspiration for this one's features!"),
("Have you tried Raft?", "Haven't you always wanted to explore", "the ocean surrounding this island?"),
("Have you tried Risk of Rain 2?", "I haven't either.", "But I hear it's incredible!"),
("Have you tried Rogue Legacy?", "After solving so many puzzles", "it's the perfect way to rest your brain."),
("Have you tried Secret of Evermore?", "I haven't either", "But I hear it's great!"),
("Have you tried Slay the Spire?", "Experience the thrill of combat", "without needing fast fingers!"),
("Have you tried SMZ3?", "Why play one incredible game", "when you can play 2 at once?"),
("Have you tried Starcraft 2?", "Use strategy and management", "to crush your enemies!"),
("Have you tried Super Mario 64?", "3-dimensional games like this", "owe everything to that game."),
("Have you tried Super Metroid?", "A classic game", "that started a whole genre."),
("Have you tried Timespinner?", "Everyone who plays it", "ends up loving it!"),
("Have you tried VVVVVV?", "Experience the essence of gaming", "distilled into its purest form!"),
("Have you tried The Witness?", "Oh. I guess you already have.", " Thanks for playing!"),
("Have you tried Super Mario World?", "I don't think I need to tell you", "that it is beloved by many."),
("Have you tried Overcooked 2?", "When you're done relaxing with puzzles,",
"use your energy to yell at your friends."),
("Have you tried Zillion?", "Me neither. But it looks fun.", "So, let's try something new together?"),
("Have you tried Hylics 2?", "Stop motion might just be", "the epitome of unique art styles."),
("Have you tried Pokemon Red&Blue?", "A cute pet collecting game", "that fascinated an entire generation."),
("Waiting to get your items?", "Try BK Sudoku!", "Make progress even while stuck."),
("One day I was fascinated", "by the subject of", "generation of waves by wind"),
("I don't like sandwiches", "Why would you think I like sandwiches?", "Have you ever seen me with a sandwich?"),
("Where are you right now?", "I'm at soup!", "What do you mean you're at soup?"),
("Remember to ask", "in the Archipelago Discord", "what the Functioning Brain does."),
("", "Don't use your puzzle skips", "you might need them later"),
("", "For an extra challenge", "Try playing blindfolded"),
("Go to the top of the mountain", "and see if you can see", "your house"),
("Yellow = Red + Green", "Cyan = Green + Blue", "Magenta = Red + Blue"),
("", "Maybe that panel really is unsolvable", ""),
("", "Did you make sure it was plugged in?", ""),
("", "Do not look into laser with remaining eye", ""),
("", "Try pressing Space to jump", ""),
("The Witness is a Doom clone.", "Just replace the demons", "with puzzles"),
("", "Test Hint please ignore", ""),
("Shapers can never be placed", "outside the panel boundaries", "even if subtracted."),
("", "The Keep laser panels use", "the same trick on both sides!"),
("Can't get past a door? Try going around.", "Can't go around? Try building a", "nether portal."),
("", "We've been trying to reach you", "about your car's extended warranty"),
("I hate this game. I hate this game.", "I hate this game.", "-chess player Bobby Fischer"),
("Dear Mario,", "Please come to the castle.", "I've baked a cake for you!"),
("Have you tried waking up?", "", "Yeah, me neither."),
("Why do they call it The Witness,", "when wit game the player view", "play of with the game."),
("", "THE WIND FISH IN NAME ONLY", "FOR IT IS NEITHER"),
("Like this game? Try The Wit.nes,", "Understand, INSIGHT, Taiji", "What the Witness?, and Tametsi."),
("", "In a race", "It's survival of the Witnesst"),
("", "This hint has been removed", "We apologize for your inconvenience."),
("", "O-----------", ""),
("Circle is draw", "Square is separate", "Line is win"),
("Circle is draw", "Star is pair", "Line is win"),
("Circle is draw", "Circle is copy", "Line is win"),
("Circle is draw", "Dot is eat", "Line is win"),
("Circle is start", "Walk is draw", "Line is win"),
("Circle is start", "Line is win", "Witness is you"),
("Can't find any items?", "Consider a relaxing boat trip", "around the island"),
("", "Don't forget to like, comment, and subscribe", ""),
("Ah crap, gimme a second.", "[papers rustling]", "Sorry, nothing."),
("", "Trying to get a hint?", "Too bad."),
("", "Here's a hint:", "Get good at the game."),
("", "I'm still not entirely sure", "what we're witnessing here."),
("Have you found a red page yet?", "No?", "Then have you found a blue page?"),
(
"And here we see the Witness player,",
"seeking answers where there are none-",
"Did someone turn on the loudspeaker?"
),
(
"Hints suggested by:",
"IHNN, Beaker, MrPokemon11, Ember, TheM8, NewSoupVi,",
"KF, Yoshi348, Berserker, BowlinJim, oddGarrett, Pink Switch."
),
"Quaternions break my brain",
"Eclipse has nothing, but you should do it anyway.",
"Beep",
"Putting in custom subtitles shouldn't have been as hard as it was...",
"BK mode is right around the corner.",
"You can do it!",
"I believe in you!",
"The person playing is cute. <3",
"dash dot, dash dash dash, dash, dot dot dot dot, dot dot, dash dot, dash dash dot",
"When you think about it, there are actually a lot of bubbles in a stream.",
"Never gonna give you up\nNever gonna let you down\nNever gonna run around and desert you",
"Thanks to the Archipelago developers for making this possible.",
"Have you tried ChecksFinder?\nIf you like puzzles, you might enjoy it!",
"Have you tried Dark Souls III?\nA tough game like this feels better when friends are helping you!",
"Have you tried Donkey Kong Country 3?\nA legendary game from a golden age of platformers!",
"Have you tried Factorio?\nAlone in an unknown multiworld. Sound familiar?",
"Have you tried Final Fantasy?\nExperience a classic game improved to fit modern standards!",
"Have you tried Hollow Knight?\nAnother independent hit revolutionising a genre!",
"Have you tried A Link to the Past?\nThe Archipelago game that started it all!",
"Have you tried Meritous?\nYou should know that obscure games are often groundbreaking!",
"Have you tried Ocarina of Time?\nOne of the biggest randomizers, big inspiration for this one's features!",
"Have you tried Raft?\nHaven't you always wanted to explore the ocean surrounding this island?",
"Have you tried Risk of Rain 2?\nI haven't either. But I hear it's incredible!",
"Have you tried Rogue Legacy?\nAfter solving so many puzzles it's the perfect way to rest your brain.",
"Have you tried Secret of Evermore?\nI haven't either But I hear it's great!",
"Have you tried Slay the Spire?\nExperience the thrill of combat without needing fast fingers!",
"Have you tried SMZ3?\nWhy play one incredible game when you can play 2 at once?",
"Have you tried Starcraft 2?\nUse strategy and management to crush your enemies!",
"Have you tried Super Mario 64?\n3-dimensional games like this owe everything to that game.",
"Have you tried Super Metroid?\nA classic game, yet still one of the best in the genre.",
"Have you tried Timespinner?\nEveryone who plays it ends up loving it!",
"Have you tried VVVVVV?\nExperience the essence of gaming distilled into its purest form!",
"Have you tried The Witness?\nOh. I guess you already have. Thanks for playing!",
"Have you tried Super Mario World?\nI don't think I need to tell you that it is beloved by many.",
"Have you tried Overcooked 2?\nWhen you're done relaxing with puzzles, use your energy to yell at your friends.",
"Have you tried Zillion?\nMe neither. But it looks fun. So, let's try something new together?",
"Have you tried Hylics 2?\nStop motion might just be the epitome of unique art styles.",
"Have you tried Pokemon Red&Blue?\nA cute pet collecting game that fascinated an entire generation.",
"Have you tried Lufia II?\nRoguelites are not just a 2010s phenomenon, turns out.",
"Have you tried Minecraft?\nI have recently learned this is a question that needs to be asked.",
"Have you tried Subnautica?\nIf you like this game's lonely atmosphere, I would suggest you try it.",
"Have you tried Sonic Adventure 2?\nIf the silence on this island is getting to you, "
"there aren't many games more energetic.",
"Waiting to get your items?\nTry BK Sudoku! Make progress even while stuck.",
"One day I was fascinated by the subject of generation of waves by wind.",
"I don't like sandwiches. Why would you think I like sandwiches? Have you ever seen me with a sandwich?",
"Where are you right now?\nI'm at soup!\nWhat do you mean you're at soup?",
"Remember to ask in the Archipelago Discord what the Functioning Brain does.",
"Don't use your puzzle skips, you might need them later.",
"For an extra challenge, try playing blindfolded.",
"Go to the top of the mountain and see if you can see your house.",
"Yellow = Red + Green\nCyan = Green + Blue\nMagenta = Red + Blue",
"Maybe that panel really is unsolvable.",
"Did you make sure it was plugged in?",
"Do not look into laser with remaining eye.",
"Try pressing Space to jump.",
"The Witness is a Doom clone.\nJust replace the demons with puzzles",
"Test Hint please ignore",
"Shapers can never be placed outside the panel boundaries, even if subtracted.",
"The Keep laser panels use the same trick on both sides!",
"Can't get past a door? Try going around. Can't go around? Try building a nether portal.",
"We've been trying to reach you about your car's extended warranty.",
"I hate this game. I hate this game. I hate this game.\n- Chess player Bobby Fischer",
"Dear Mario,\nPlease come to the castle. I've baked a cake for you!",
"Have you tried waking up?\nYeah, me neither.",
"Why do they call it The Witness, when wit game the player view play of with the game.",
"THE WIND FISH IN NAME ONLY, FOR IT IS NEITHER",
"Like this game?\nTry The Wit.nes, Understand, INSIGHT, Taiji What the Witness?, and Tametsi.",
"In a race, It's survival of the Witnesst.",
"This hint has been removed. We apologize for your inconvenience.",
"O-----------",
"Circle is draw\nSquare is separate\nLine is win",
"Circle is draw\nStar is pair\nLine is win",
"Circle is draw\nCircle is copy\nLine is win",
"Circle is draw\nDot is eat\nLine is win",
"Circle is start\nWalk is draw\nLine is win",
"Circle is start\nLine is win\nWitness is you",
"Can't find any items?\nConsider a relaxing boat trip around the island!",
"Don't forget to like, comment, and subscribe.",
"Ah crap, gimme a second.\n[papers rustling]\nSorry, nothing.",
"Trying to get a hint? Too bad.",
"Here's a hint: Get good at the game.",
"I'm still not entirely sure what we're witnessing here.",
"Have you found a red page yet? No? Then have you found a blue page?",
"And here we see the Witness player, seeking answers where there are none-\nDid someone turn on the loudspeaker?",
"Hints suggested by:\nIHNN, Beaker, MrPokemon11, Ember, TheM8, NewSoupVi,"
"KF, Yoshi348, Berserker, BowlinJim, oddGarrett, Pink Switch.",
]
@ -186,7 +186,7 @@ def make_hint_from_item(multiworld: MultiWorld, player: int, item: str):
if location_obj.player != player:
location_name += " (" + multiworld.get_player_name(location_obj.player) + ")"
return location_name, item, location_obj.address if(location_obj.player == player) else -1
return location_name, item, location_obj.address if (location_obj.player == player) else -1
def make_hint_from_location(multiworld: MultiWorld, player: int, location: str):
@ -196,7 +196,7 @@ def make_hint_from_location(multiworld: MultiWorld, player: int, location: str):
if item_obj.player != player:
item_name += " (" + multiworld.get_player_name(item_obj.player) + ")"
return location, item_name, location_obj.address if(location_obj.player == player) else -1
return location, item_name, location_obj.address if (location_obj.player == player) else -1
def make_hints(multiworld: MultiWorld, player: int, hint_amount: int):
@ -258,9 +258,9 @@ def make_hints(multiworld: MultiWorld, player: int, hint_amount: int):
for loc, item in always_hint_pairs.items():
if item[1]:
hints.append((item[0], "can be found at", loc, item[2]))
hints.append((f"{item[0]} can be found at {loc}.", item[2]))
else:
hints.append((loc, "contains", item[0], item[2]))
hints.append((f"{loc} contains {item[0]}.", item[2]))
multiworld.per_slot_randoms[player].shuffle(hints) # shuffle always hint order in case of low hint amount
@ -279,9 +279,9 @@ def make_hints(multiworld: MultiWorld, player: int, hint_amount: int):
del priority_hint_pairs[loc]
if item[1]:
hints.append((item[0], "can be found at", loc, item[2]))
hints.append((f"{item[0]} can be found at {loc}.", item[2]))
else:
hints.append((loc, "contains", item[0], item[2]))
hints.append((f"{loc} contains {item[0]}.", item[2]))
continue
if next_random_hint_is_item:
@ -290,10 +290,10 @@ def make_hints(multiworld: MultiWorld, player: int, hint_amount: int):
continue
hint = make_hint_from_item(multiworld, player, prog_items_in_this_world.pop())
hints.append((hint[1], "can be found at", hint[0], hint[2]))
hints.append((f"{hint[1]} can be found at {hint[0]}.", hint[2]))
else:
hint = make_hint_from_location(multiworld, player, locations_in_this_world.pop())
hints.append((hint[0], "contains", hint[1], hint[2]))
hints.append((f"{hint[0]} contains {hint[1]}.", hint[2]))
next_random_hint_is_item = not next_random_hint_is_item
@ -301,4 +301,4 @@ def make_hints(multiworld: MultiWorld, player: int, hint_amount: int):
def generate_joke_hints(multiworld: MultiWorld, player: int, amount: int):
return [(x, y, z, -1) for (x, y, z) in multiworld.per_slot_randoms[player].sample(joke_hints, amount)]
return [(x, -1) for x in multiworld.per_slot_randoms[player].sample(joke_hints, amount)]

View File

@ -205,13 +205,10 @@ class WitnessPlayerItems:
]
if is_option_enabled(multiworld, player, "shuffle_discarded_panels"):
if is_option_enabled(multiworld, player, "shuffle_discarded_panels"):
if get_option_value(multiworld, player, "puzzle_randomization") == 1:
self.GOOD_ITEMS.append("Arrows")
else:
self.GOOD_ITEMS.append("Triangles")
if not is_option_enabled(multiworld, player, "disable_non_randomized_puzzles"):
self.GOOD_ITEMS.append("Colored Squares")
if get_option_value(multiworld, player, "puzzle_randomization") == 1:
self.GOOD_ITEMS.append("Arrows")
else:
self.GOOD_ITEMS.append("Triangles")
self.GOOD_ITEMS = [
StaticWitnessLogic.ITEMS_TO_PROGRESSIVE.get(item, item) for item in self.GOOD_ITEMS

View File

@ -13,13 +13,10 @@ class StaticWitnessLocations:
"""
ID_START = 158000
EXTRA_LOCATIONS = {
GENERAL_LOCATIONS = {
"Tutorial Front Left",
"Tutorial Back Left",
"Tutorial Back Right",
}
GENERAL_LOCATIONS = {
"Tutorial Gate Open",
"Outside Tutorial Vault Box",
@ -302,6 +299,7 @@ class StaticWitnessLocations:
"Quarry Obelisk Side 2",
"Quarry Obelisk Side 3",
"Quarry Obelisk Side 4",
"Quarry Obelisk Side 5",
"Town Obelisk Side 1",
"Town Obelisk Side 2",
"Town Obelisk Side 3",
@ -338,6 +336,7 @@ class StaticWitnessLocations:
"Quarry Obelisk Side 2",
"Quarry Obelisk Side 3",
"Quarry Obelisk Side 4",
"Quarry Obelisk Side 5",
"Town Obelisk Side 1",
"Town Obelisk Side 2",
"Town Obelisk Side 3",

View File

@ -433,7 +433,6 @@ class WitnessPlayerLogic:
self.ADDED_CHECKS = set()
self.VICTORY_LOCATION = "0x0356B"
self.EVENT_ITEM_NAMES = {
"0x01A0F": "Keep Laser Panel (Hedge Mazes) Activates",
"0x09D9B": "Monastery Shutters Open",
"0x193A6": "Monastery Laser Panel Activates",
"0x00037": "Monastery Branch Panels Activate",
@ -442,8 +441,11 @@ class WitnessPlayerLogic:
"0x00139": "Keep Hedges 1 Knowledge",
"0x019DC": "Keep Hedges 2 Knowledge",
"0x019E7": "Keep Hedges 3 Knowledge",
"0x01D3F": "Keep Laser Panel (Pressure Plates) Activates",
"0x01BE9": "Keep Laser Panel (Pressure Plates) Activates - Expert",
"0x01A0F": "Keep Hedges 4 Knowledge",
"0x033EA": "Pressure Plates 1 Knowledge",
"0x01BE9": "Pressure Plates 2 Knowledge",
"0x01CD3": "Pressure Plates 3 Knowledge",
"0x01D3F": "Pressure Plates 4 Knowledge",
"0x09F7F": "Mountain Access",
"0x0367C": "Quarry Laser Stoneworks Requirement Met",
"0x009A1": "Swamp Between Bridges Far 1 Activates",
@ -492,11 +494,9 @@ class WitnessPlayerLogic:
"0x17D02": "Windmill Blades Spinning",
"0x0A0C9": "Cargo Box EP completable",
"0x09E39": "Pink Light Bridge Extended",
"0x01CD3": "Pressure Plates 3 EP available",
"0x17CC4": "Rails EP available",
"0x2896A": "Bridge Underside EP available",
"0x00064": "First Tunnel EP visible",
"0x033EA": "Pressure Plates 1 EP available",
"0x03553": "Tutorial Video EPs availble",
"0x17C79": "Bunker Door EP available",
"0x275FF": "Stoneworks Light EPs available",

View File

@ -27,20 +27,18 @@ class WitnessRegions:
)
def connect(self, world: MultiWorld, player: int, source: str, target: str, player_logic: WitnessPlayerLogic,
panel_hex_to_solve_set=frozenset({frozenset()})):
panel_hex_to_solve_set=frozenset({frozenset()}), backwards: bool = False):
"""
connect two regions and set the corresponding requirement
"""
source_region = world.get_region(source, player)
target_region = world.get_region(target, player)
#print(source_region)
#print(target_region)
#print("---")
backwards = " Backwards" if backwards else ""
connection = Entrance(
player,
source + " to " + target,
source + " to " + target + backwards,
source_region
)
@ -92,10 +90,18 @@ class WitnessRegions:
self.connect(world, player, region_name, connection[0], player_logic, frozenset({frozenset()}))
continue
backwards_connections = set()
for subset in connection[1]:
if all({panel in player_logic.DOOR_ITEMS_BY_ID for panel in subset}):
if all({reference_logic.CHECKS_BY_HEX[panel]["id"] is None for panel in subset}):
self.connect(world, player, connection[0], region_name, player_logic, frozenset({subset}))
backwards_connections.add(subset)
if backwards_connections:
self.connect(
world, player, connection[0], region_name, player_logic,
frozenset(backwards_connections), True
)
self.connect(world, player, region_name, connection[0], player_logic, connection[1])

View File

@ -114,15 +114,17 @@ Disabled Locations:
0x17CAA (River Garden Entry Panel)
0x034A7 (Left Shutter EP)
0x034AD (Middle Shutter EP)
0x034AF (Right Shutter EP)
0x339B6 (Eclipse EP) - 0x03549 - True
0x33A29 (Window EP) - 0x03553 - True
0x33A2A (Door EP) - 0x03553 - True
0x33B06 (Church EP) - 0x0354E - True
0x3352F (Gate EP)
0x33600 (Patio Flowers EP)
0x035F5 (Tinted Door EP)
0x000D3 (Green Room Flowers EP)
0x33A20 (Theater Flowers EP)
Precompleted Locations:
0x034A7
0x034AD
0x034AF
0x339B6
0x33A29
0x33A2A
0x33B06
0x3352F
0x33600
0x035F5
0x000D3
0x33A20
0x03BE2

View File

@ -9,4 +9,6 @@ Precompleted Locations:
0x33857
0x33879
0x016B2
0x036CE
0x036CE
0x03B25
0x28B2A

View File

@ -3,6 +3,42 @@ from Utils import cache_argsless
from itertools import accumulate
from typing import *
from fractions import Fraction
from collections import Counter
def make_warning_string(any_j: bool, any_u: bool, any_d: bool, all_j: bool, all_u: bool, all_d: bool) -> str:
warning_string = ""
if any_j:
if all_j:
warning_string += "all "
else:
warning_string += "some "
warning_string += "junk"
if any_u or any_d:
if warning_string:
warning_string += " and "
if all_u:
warning_string += "all "
else:
warning_string += "some "
warning_string += "usefuls"
if any_d:
warning_string += ", including "
if all_d:
warning_string += "all "
else:
warning_string += "some "
warning_string += "non-essential door items"
return warning_string
def best_junk_to_add_based_on_weights(weights: Dict[Any, Fraction], created_junk: Dict[Any, int]):