The Witness: Hint distribution changes, added locations, misc fixes (#1785)
Changes:
* Hints should feel a lot less same-y now ("Priority hints" are no longer always hints in disguise)
* Keep Hedge Mazes 1-3 and Pressure Plates 1-3 are added as locations in all settings
* Desert Final Room Hexagonal & Desert Final Room Bent 3 are added as locations
* Entries in exclude_locations that are referring to panels are now sent through slot data. This means they can be pre-skipped on the client side.
Fixes:
* Logic error in the Stoneworks that led to more restrictive seeds than necessary
* Logic error for Theater Flowers EP that led to more restrictive seeds than necessary
* Fixed crash in plando when "item" is a dict with weights
* Spoiler log locations were in random order per region, now they are consistent
			
			
This commit is contained in:
		
							parent
							
								
									afe9e12ef4
								
							
						
					
					
						commit
						845502ad39
					
				| 
						 | 
					@ -264,7 +264,7 @@ Quarry Stoneworks Upper Floor (Quarry Stoneworks) - Quarry Stoneworks Middle Flo
 | 
				
			||||||
158141 - 0x014E9 (Upper Row 8) - 0x03686 - Colored Squares & Eraser
 | 
					158141 - 0x014E9 (Upper Row 8) - 0x03686 - Colored Squares & Eraser
 | 
				
			||||||
158142 - 0x03677 (Stair Control) - True - Colored Squares & Eraser
 | 
					158142 - 0x03677 (Stair Control) - True - Colored Squares & Eraser
 | 
				
			||||||
Door - 0x0368A (Stairs) - 0x03677
 | 
					Door - 0x0368A (Stairs) - 0x03677
 | 
				
			||||||
158143 - 0x3C125 (Control Room Left) - 0x0367C - Black/White Squares & Dots & Eraser
 | 
					158143 - 0x3C125 (Control Room Left) - 0x014E9 - Black/White Squares & Dots & Eraser
 | 
				
			||||||
158144 - 0x0367C (Control Room Right) - 0x014E9 - Colored Squares & Dots & Eraser
 | 
					158144 - 0x0367C (Control Room Right) - 0x014E9 - Colored Squares & Dots & Eraser
 | 
				
			||||||
159411 - 0x0069D (Ramp EP) - 0x03676 & 0x275FF - True
 | 
					159411 - 0x0069D (Ramp EP) - 0x03676 & 0x275FF - True
 | 
				
			||||||
159413 - 0x00614 (Lift EP) - 0x275FF & 0x03675 - True
 | 
					159413 - 0x00614 (Lift EP) - 0x275FF & 0x03675 - True
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -264,7 +264,7 @@ Quarry Stoneworks Upper Floor (Quarry Stoneworks) - Quarry Stoneworks Middle Flo
 | 
				
			||||||
158141 - 0x014E9 (Upper Row 8) - 0x03686 - Squares & Colored Squares & Eraser & Stars & Stars + Same Colored Symbol
 | 
					158141 - 0x014E9 (Upper Row 8) - 0x03686 - Squares & Colored Squares & Eraser & Stars & Stars + Same Colored Symbol
 | 
				
			||||||
158142 - 0x03677 (Stair Control) - True - Squares & Colored Squares & Eraser
 | 
					158142 - 0x03677 (Stair Control) - True - Squares & Colored Squares & Eraser
 | 
				
			||||||
Door - 0x0368A (Stairs) - 0x03677
 | 
					Door - 0x0368A (Stairs) - 0x03677
 | 
				
			||||||
158143 - 0x3C125 (Control Room Left) - 0x0367C - Squares & Black/White Squares & Dots & Full Dots & Eraser
 | 
					158143 - 0x3C125 (Control Room Left) - 0x014E9 - Squares & Black/White Squares & Dots & Full Dots & Eraser
 | 
				
			||||||
158144 - 0x0367C (Control Room Right) - 0x014E9 - Squares & Colored Squares & Triangles & Eraser & Stars & Stars + Same Colored Symbol
 | 
					158144 - 0x0367C (Control Room Right) - 0x014E9 - Squares & Colored Squares & Triangles & Eraser & Stars & Stars + Same Colored Symbol
 | 
				
			||||||
159411 - 0x0069D (Ramp EP) - 0x03676 & 0x275FF - True
 | 
					159411 - 0x0069D (Ramp EP) - 0x03676 & 0x275FF - True
 | 
				
			||||||
159413 - 0x00614 (Lift EP) - 0x275FF & 0x03675 - True
 | 
					159413 - 0x00614 (Lift EP) - 0x275FF & 0x03675 - True
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15,7 +15,7 @@ Tutorial (Tutorial) - Outside Tutorial - 0x03629:
 | 
				
			||||||
158006 - 0x0A3B2 (Back Right) - True - True
 | 
					158006 - 0x0A3B2 (Back Right) - True - True
 | 
				
			||||||
158007 - 0x03629 (Gate Open) - 0x002C2 & 0x0A3B5 & 0x0A3B2 - True
 | 
					158007 - 0x03629 (Gate Open) - 0x002C2 & 0x0A3B5 & 0x0A3B2 - True
 | 
				
			||||||
158008 - 0x03505 (Gate Close) - 0x2FAF6 & 0x03629 - True
 | 
					158008 - 0x03505 (Gate Close) - 0x2FAF6 & 0x03629 - True
 | 
				
			||||||
158009 - 0x0C335 (Pillar) - True - Triangles - True
 | 
					158009 - 0x0C335 (Pillar) - True - Triangles
 | 
				
			||||||
158010 - 0x0C373 (Patio Floor) - 0x0C335 - Dots
 | 
					158010 - 0x0C373 (Patio Floor) - 0x0C335 - Dots
 | 
				
			||||||
159512 - 0x33530 (Cloud EP) - True - True
 | 
					159512 - 0x33530 (Cloud EP) - True - True
 | 
				
			||||||
159513 - 0x33600 (Patio Flowers EP) - 0x0C373 - True
 | 
					159513 - 0x33600 (Patio Flowers EP) - 0x0C373 - True
 | 
				
			||||||
| 
						 | 
					@ -264,7 +264,7 @@ Quarry Stoneworks Upper Floor (Quarry Stoneworks) - Quarry Stoneworks Middle Flo
 | 
				
			||||||
158141 - 0x014E9 (Upper Row 8) - 0x03686 - Colored Squares & Eraser
 | 
					158141 - 0x014E9 (Upper Row 8) - 0x03686 - Colored Squares & Eraser
 | 
				
			||||||
158142 - 0x03677 (Stair Control) - True - Colored Squares & Eraser
 | 
					158142 - 0x03677 (Stair Control) - True - Colored Squares & Eraser
 | 
				
			||||||
Door - 0x0368A (Stairs) - 0x03677
 | 
					Door - 0x0368A (Stairs) - 0x03677
 | 
				
			||||||
158143 - 0x3C125 (Control Room Left) - 0x0367C - Black/White Squares & Dots & Eraser
 | 
					158143 - 0x3C125 (Control Room Left) - 0x014E9 - Black/White Squares & Dots & Eraser
 | 
				
			||||||
158144 - 0x0367C (Control Room Right) - 0x014E9 - Colored Squares & Dots & Eraser
 | 
					158144 - 0x0367C (Control Room Right) - 0x014E9 - Colored Squares & Dots & Eraser
 | 
				
			||||||
159411 - 0x0069D (Ramp EP) - 0x03676 & 0x275FF - True
 | 
					159411 - 0x0069D (Ramp EP) - 0x03676 & 0x275FF - True
 | 
				
			||||||
159413 - 0x00614 (Lift EP) - 0x275FF & 0x03675 - True
 | 
					159413 - 0x00614 (Lift EP) - 0x275FF & 0x03675 - True
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -62,11 +62,11 @@ class WitnessWorld(World):
 | 
				
			||||||
            'item_id_to_door_hexes': self.static_items.ITEM_ID_TO_DOOR_HEX_ALL,
 | 
					            'item_id_to_door_hexes': self.static_items.ITEM_ID_TO_DOOR_HEX_ALL,
 | 
				
			||||||
            'door_hexes_in_the_pool': self.items.DOORS,
 | 
					            'door_hexes_in_the_pool': self.items.DOORS,
 | 
				
			||||||
            'symbols_not_in_the_game': self.items.SYMBOLS_NOT_IN_THE_GAME,
 | 
					            'symbols_not_in_the_game': self.items.SYMBOLS_NOT_IN_THE_GAME,
 | 
				
			||||||
            'disabled_panels': self.player_logic.COMPLETELY_DISABLED_CHECKS,
 | 
					            'disabled_panels': list(self.player_logic.COMPLETELY_DISABLED_CHECKS),
 | 
				
			||||||
            'log_ids_to_hints': self.log_ids_to_hints,
 | 
					            'log_ids_to_hints': self.log_ids_to_hints,
 | 
				
			||||||
            'progressive_item_lists': self.items.MULTI_LISTS_BY_CODE,
 | 
					            'progressive_item_lists': self.items.MULTI_LISTS_BY_CODE,
 | 
				
			||||||
            'obelisk_side_id_to_EPs': self.static_logic.OBELISK_SIDE_ID_TO_EP_HEXES,
 | 
					            'obelisk_side_id_to_EPs': self.static_logic.OBELISK_SIDE_ID_TO_EP_HEXES,
 | 
				
			||||||
            'precompleted_puzzles': {int(h, 16) for h in self.player_logic.PRECOMPLETED_LOCATIONS},
 | 
					            'precompleted_puzzles': [int(h, 16) for h in self.player_logic.EXCLUDED_LOCATIONS],
 | 
				
			||||||
            'entity_to_name': self.static_logic.ENTITY_ID_TO_NAME,
 | 
					            'entity_to_name': self.static_logic.ENTITY_ID_TO_NAME,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -143,14 +143,19 @@ class WitnessWorld(World):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for v in self.multiworld.plando_items[self.player]:
 | 
					        for v in self.multiworld.plando_items[self.player]:
 | 
				
			||||||
            if v.get("from_pool", True):
 | 
					            if v.get("from_pool", True):
 | 
				
			||||||
                plandoed_items.update({self.items_by_name[i] for i in v.get("items", dict()).keys()
 | 
					                for item_key in {"item", "items"}:
 | 
				
			||||||
                                       if i in self.items_by_name})
 | 
					                    if item_key in v:
 | 
				
			||||||
                if "item" in v and v["item"] in self.items_by_name:
 | 
					                        if type(v[item_key]) is str:
 | 
				
			||||||
                    plandoed_items.add(self.items_by_name[v["item"]])
 | 
					                            plandoed_items.add(v[item_key])
 | 
				
			||||||
 | 
					                        elif type(v[item_key]) is dict:
 | 
				
			||||||
 | 
					                            plandoed_items.update(item for item, weight in v[item_key].items() if weight)
 | 
				
			||||||
 | 
					                        else:
 | 
				
			||||||
 | 
					                            # Other type of iterable
 | 
				
			||||||
 | 
					                            plandoed_items.update(v[item_key])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for symbol in self.items.GOOD_ITEMS:
 | 
					        for symbol in self.items.GOOD_ITEMS:
 | 
				
			||||||
            item = self.items_by_name[symbol]
 | 
					            item = self.items_by_name[symbol]
 | 
				
			||||||
            if item in pool and item not in plandoed_items:
 | 
					            if item in pool and symbol 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.
 | 
					                # 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.
 | 
					                # 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.
 | 
					                # I could also partially resolve lists myself, but this could introduce errors if not done carefully.
 | 
				
			||||||
| 
						 | 
					@ -255,7 +260,7 @@ class WitnessWorld(World):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            self.multiworld.per_slot_randoms[self.player].shuffle(audio_logs)
 | 
					            self.multiworld.per_slot_randoms[self.player].shuffle(audio_logs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            duplicates = len(audio_logs) // hint_amount
 | 
					            duplicates = min(3, len(audio_logs) // hint_amount)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            for _ in range(0, hint_amount):
 | 
					            for _ in range(0, hint_amount):
 | 
				
			||||||
                hint = generated_hints.pop(0)
 | 
					                hint = generated_hints.pop(0)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -96,31 +96,30 @@ joke_hints = [
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_always_hint_items(multiworld: MultiWorld, player: int):
 | 
					def get_always_hint_items(multiworld: MultiWorld, player: int):
 | 
				
			||||||
    priority = [
 | 
					    always = [
 | 
				
			||||||
        "Boat",
 | 
					        "Boat",
 | 
				
			||||||
        "Mountain Bottom Floor Final Room Entry (Door)",
 | 
					 | 
				
			||||||
        "Caves Mountain Shortcut (Door)",
 | 
					 | 
				
			||||||
        "Caves Swamp Shortcut (Door)",
 | 
					 | 
				
			||||||
        "Caves Exits to Main Island",
 | 
					        "Caves Exits to Main Island",
 | 
				
			||||||
        "Progressive Dots",
 | 
					        "Progressive Dots",
 | 
				
			||||||
    ]
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    difficulty = get_option_value(multiworld, player, "puzzle_randomization")
 | 
					    difficulty = get_option_value(multiworld, player, "puzzle_randomization")
 | 
				
			||||||
    discards = is_option_enabled(multiworld, player, "shuffle_discarded_panels")
 | 
					    discards = is_option_enabled(multiworld, player, "shuffle_discarded_panels")
 | 
				
			||||||
 | 
					    wincon = get_option_value(multiworld, player, "victory_condition")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if discards:
 | 
					    if discards:
 | 
				
			||||||
        if difficulty == 1:
 | 
					        if difficulty == 1:
 | 
				
			||||||
            priority.append("Arrows")
 | 
					            always.append("Arrows")
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            priority.append("Triangles")
 | 
					            always.append("Triangles")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return priority
 | 
					    if wincon == 0:
 | 
				
			||||||
 | 
					        always.append("Mountain Bottom Floor Final Room Entry (Door)")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return always
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_always_hint_locations(multiworld: MultiWorld, player: int):
 | 
					def get_always_hint_locations(multiworld: MultiWorld, player: int):
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
        "Swamp Purple Underwater",
 | 
					 | 
				
			||||||
        "Shipwreck Vault Box",
 | 
					 | 
				
			||||||
        "Challenge Vault Box",
 | 
					        "Challenge Vault Box",
 | 
				
			||||||
        "Mountain Bottom Floor Discard",
 | 
					        "Mountain Bottom Floor Discard",
 | 
				
			||||||
        "Theater Eclipse EP",
 | 
					        "Theater Eclipse EP",
 | 
				
			||||||
| 
						 | 
					@ -131,6 +130,8 @@ def get_always_hint_locations(multiworld: MultiWorld, player: int):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_priority_hint_items(multiworld: MultiWorld, player: int):
 | 
					def get_priority_hint_items(multiworld: MultiWorld, player: int):
 | 
				
			||||||
    priority = {
 | 
					    priority = {
 | 
				
			||||||
 | 
					        "Caves Mountain Shortcut (Door)",
 | 
				
			||||||
 | 
					        "Caves Swamp Shortcut (Door)",
 | 
				
			||||||
        "Negative Shapers",
 | 
					        "Negative Shapers",
 | 
				
			||||||
        "Sound Dots",
 | 
					        "Sound Dots",
 | 
				
			||||||
        "Colored Dots",
 | 
					        "Colored Dots",
 | 
				
			||||||
| 
						 | 
					@ -157,16 +158,18 @@ def get_priority_hint_items(multiworld: MultiWorld, player: int):
 | 
				
			||||||
        if get_option_value(multiworld, player, "doors") >= 2:
 | 
					        if get_option_value(multiworld, player, "doors") >= 2:
 | 
				
			||||||
            priority.add("Desert Laser")
 | 
					            priority.add("Desert Laser")
 | 
				
			||||||
            lasers.remove("Desert Laser")
 | 
					            lasers.remove("Desert Laser")
 | 
				
			||||||
            priority.update(multiworld.per_slot_randoms[player].sample(lasers, 2))
 | 
					            priority.update(multiworld.per_slot_randoms[player].sample(lasers, 5))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            priority.update(multiworld.per_slot_randoms[player].sample(lasers, 3))
 | 
					            priority.update(multiworld.per_slot_randoms[player].sample(lasers, 6))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return priority
 | 
					    return priority
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_priority_hint_locations(multiworld: MultiWorld, player: int):
 | 
					def get_priority_hint_locations(multiworld: MultiWorld, player: int):
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
 | 
					        "Swamp Purple Underwater",
 | 
				
			||||||
 | 
					        "Shipwreck Vault Box",
 | 
				
			||||||
        "Town RGB Room Left",
 | 
					        "Town RGB Room Left",
 | 
				
			||||||
        "Town RGB Room Right",
 | 
					        "Town RGB Room Right",
 | 
				
			||||||
        "Treehouse Green Bridge 7",
 | 
					        "Treehouse Green Bridge 7",
 | 
				
			||||||
| 
						 | 
					@ -264,7 +267,8 @@ def make_hints(multiworld: MultiWorld, player: int, hint_amount: int):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    multiworld.per_slot_randoms[player].shuffle(hints)  # shuffle always hint order in case of low hint amount
 | 
					    multiworld.per_slot_randoms[player].shuffle(hints)  # shuffle always hint order in case of low hint amount
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    next_random_hint_is_item = multiworld.per_slot_randoms[player].randint(0, 2)
 | 
					    remaining_hints = hint_amount - len(hints)
 | 
				
			||||||
 | 
					    priority_hint_amount = int(max(0.0, min(len(priority_hint_pairs) / 2, remaining_hints / 2)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    prog_items_in_this_world = sorted(list(prog_items_in_this_world))
 | 
					    prog_items_in_this_world = sorted(list(prog_items_in_this_world))
 | 
				
			||||||
    locations_in_this_world = sorted(list(loc_in_this_world))
 | 
					    locations_in_this_world = sorted(list(loc_in_this_world))
 | 
				
			||||||
| 
						 | 
					@ -272,18 +276,21 @@ def make_hints(multiworld: MultiWorld, player: int, hint_amount: int):
 | 
				
			||||||
    multiworld.per_slot_randoms[player].shuffle(prog_items_in_this_world)
 | 
					    multiworld.per_slot_randoms[player].shuffle(prog_items_in_this_world)
 | 
				
			||||||
    multiworld.per_slot_randoms[player].shuffle(locations_in_this_world)
 | 
					    multiworld.per_slot_randoms[player].shuffle(locations_in_this_world)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    while len(hints) < hint_amount:
 | 
					    priority_hint_list = list(priority_hint_pairs.items())
 | 
				
			||||||
        if priority_hint_pairs:
 | 
					    multiworld.per_slot_randoms[player].shuffle(priority_hint_list)
 | 
				
			||||||
            loc = multiworld.per_slot_randoms[player].choice(list(priority_hint_pairs.keys()))
 | 
					    for _ in range(0, priority_hint_amount):
 | 
				
			||||||
            item = priority_hint_pairs[loc]
 | 
					        next_priority_hint = priority_hint_list.pop()
 | 
				
			||||||
            del priority_hint_pairs[loc]
 | 
					        loc = next_priority_hint[0]
 | 
				
			||||||
 | 
					        item = next_priority_hint[1]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if item[1]:
 | 
					        if item[1]:
 | 
				
			||||||
            hints.append((f"{item[0]} can be found at {loc}.", item[2]))
 | 
					            hints.append((f"{item[0]} can be found at {loc}.", item[2]))
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            hints.append((f"{loc} contains {item[0]}.", item[2]))
 | 
					            hints.append((f"{loc} contains {item[0]}.", item[2]))
 | 
				
			||||||
            continue
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    next_random_hint_is_item = multiworld.per_slot_randoms[player].randint(0, 2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    while len(hints) < hint_amount:
 | 
				
			||||||
        if next_random_hint_is_item:
 | 
					        if next_random_hint_is_item:
 | 
				
			||||||
            if not prog_items_in_this_world:
 | 
					            if not prog_items_in_this_world:
 | 
				
			||||||
                next_random_hint_is_item = not next_random_hint_is_item
 | 
					                next_random_hint_is_item = not next_random_hint_is_item
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -143,11 +143,11 @@ class WitnessPlayerItems:
 | 
				
			||||||
        self.PROGRESSION_TABLE = dict()
 | 
					        self.PROGRESSION_TABLE = dict()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.ITEM_ID_TO_DOOR_HEX = dict()
 | 
					        self.ITEM_ID_TO_DOOR_HEX = dict()
 | 
				
			||||||
        self.DOORS = set()
 | 
					        self.DOORS = list()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.PROG_ITEM_AMOUNTS = defaultdict(lambda: 1)
 | 
					        self.PROG_ITEM_AMOUNTS = defaultdict(lambda: 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.SYMBOLS_NOT_IN_THE_GAME = set()
 | 
					        self.SYMBOLS_NOT_IN_THE_GAME = list()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.EXTRA_AMOUNTS = {
 | 
					        self.EXTRA_AMOUNTS = {
 | 
				
			||||||
            "Functioning Brain": 1,
 | 
					            "Functioning Brain": 1,
 | 
				
			||||||
| 
						 | 
					@ -162,7 +162,7 @@ class WitnessPlayerItems:
 | 
				
			||||||
            if item[0] not in logic.PROG_ITEMS_ACTUALLY_IN_THE_GAME:
 | 
					            if item[0] not in logic.PROG_ITEMS_ACTUALLY_IN_THE_GAME:
 | 
				
			||||||
                del self.ITEM_TABLE[item[0]]
 | 
					                del self.ITEM_TABLE[item[0]]
 | 
				
			||||||
                if item in StaticWitnessLogic.ALL_SYMBOL_ITEMS:
 | 
					                if item in StaticWitnessLogic.ALL_SYMBOL_ITEMS:
 | 
				
			||||||
                    self.SYMBOLS_NOT_IN_THE_GAME.add(StaticWitnessItems.ALL_ITEM_TABLE[item[0]].code)
 | 
					                    self.SYMBOLS_NOT_IN_THE_GAME.append(StaticWitnessItems.ALL_ITEM_TABLE[item[0]].code)
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                if item[0] in StaticWitnessLogic.PROGRESSIVE_TO_ITEMS:
 | 
					                if item[0] in StaticWitnessLogic.PROGRESSIVE_TO_ITEMS:
 | 
				
			||||||
                    self.PROG_ITEM_AMOUNTS[item[0]] = len(logic.MULTI_LISTS[item[0]])
 | 
					                    self.PROG_ITEM_AMOUNTS[item[0]] = len(logic.MULTI_LISTS[item[0]])
 | 
				
			||||||
| 
						 | 
					@ -178,7 +178,7 @@ class WitnessPlayerItems:
 | 
				
			||||||
        for entity_hex, items in logic.DOOR_ITEMS_BY_ID.items():
 | 
					        for entity_hex, items in logic.DOOR_ITEMS_BY_ID.items():
 | 
				
			||||||
            entity_hex_int = int(entity_hex, 16)
 | 
					            entity_hex_int = int(entity_hex, 16)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            self.DOORS.add(entity_hex_int)
 | 
					            self.DOORS.append(entity_hex_int)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            for item in items:
 | 
					            for item in items:
 | 
				
			||||||
                item_id = StaticWitnessItems.ALL_ITEM_TABLE[item].code
 | 
					                item_id = StaticWitnessItems.ALL_ITEM_TABLE[item].code
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -43,6 +43,8 @@ class StaticWitnessLocations:
 | 
				
			||||||
        "Desert Light Room 3",
 | 
					        "Desert Light Room 3",
 | 
				
			||||||
        "Desert Pond Room 5",
 | 
					        "Desert Pond Room 5",
 | 
				
			||||||
        "Desert Flood Room 6",
 | 
					        "Desert Flood Room 6",
 | 
				
			||||||
 | 
					        "Desert Final Hexagonal",
 | 
				
			||||||
 | 
					        "Desert Final Bent 3",
 | 
				
			||||||
        "Desert Laser Panel",
 | 
					        "Desert Laser Panel",
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        "Quarry Stoneworks Lower Row 6",
 | 
					        "Quarry Stoneworks Lower Row 6",
 | 
				
			||||||
| 
						 | 
					@ -61,7 +63,13 @@ class StaticWitnessLocations:
 | 
				
			||||||
        "Shadows Near 5",
 | 
					        "Shadows Near 5",
 | 
				
			||||||
        "Shadows Laser Panel",
 | 
					        "Shadows Laser Panel",
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        "Keep Hedge Maze 1",
 | 
				
			||||||
 | 
					        "Keep Hedge Maze 2",
 | 
				
			||||||
 | 
					        "Keep Hedge Maze 3",
 | 
				
			||||||
        "Keep Hedge Maze 4",
 | 
					        "Keep Hedge Maze 4",
 | 
				
			||||||
 | 
					        "Keep Pressure Plates 1",
 | 
				
			||||||
 | 
					        "Keep Pressure Plates 2",
 | 
				
			||||||
 | 
					        "Keep Pressure Plates 3",
 | 
				
			||||||
        "Keep Pressure Plates 4",
 | 
					        "Keep Pressure Plates 4",
 | 
				
			||||||
        "Keep Discard",
 | 
					        "Keep Discard",
 | 
				
			||||||
        "Keep Laser Panel Hedges",
 | 
					        "Keep Laser Panel Hedges",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -296,7 +296,6 @@ class WitnessPlayerLogic:
 | 
				
			||||||
        elif get_option_value(world, player, "shuffle_EPs") == 1:  # Individual EPs
 | 
					        elif get_option_value(world, player, "shuffle_EPs") == 1:  # Individual EPs
 | 
				
			||||||
            adjustment_linesets_in_order.append(["Disabled Locations:"] + get_ep_obelisks()[1:])
 | 
					            adjustment_linesets_in_order.append(["Disabled Locations:"] + get_ep_obelisks()[1:])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        else:  # Obelisk Sides
 | 
					 | 
				
			||||||
        yaml_disabled_eps = []
 | 
					        yaml_disabled_eps = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for yaml_disabled_location in self.YAML_DISABLED_LOCATIONS:
 | 
					        for yaml_disabled_location in self.YAML_DISABLED_LOCATIONS:
 | 
				
			||||||
| 
						 | 
					@ -305,11 +304,12 @@ class WitnessPlayerLogic:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            loc_obj = StaticWitnessLogic.CHECKS_BY_NAME[yaml_disabled_location]
 | 
					            loc_obj = StaticWitnessLogic.CHECKS_BY_NAME[yaml_disabled_location]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if loc_obj["panelType"] != "EP":
 | 
					            if loc_obj["panelType"] == "EP" and get_option_value(world, player, "shuffle_EPs") == 2:
 | 
				
			||||||
                    continue
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                yaml_disabled_eps.append(loc_obj["checkHex"])
 | 
					                yaml_disabled_eps.append(loc_obj["checkHex"])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if loc_obj["panelType"] in {"EP", "General"}:
 | 
				
			||||||
 | 
					                self.EXCLUDED_LOCATIONS.add(loc_obj["checkHex"])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        adjustment_linesets_in_order.append(["Precompleted Locations:"] + yaml_disabled_eps)
 | 
					        adjustment_linesets_in_order.append(["Precompleted Locations:"] + yaml_disabled_eps)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for adjustment_lineset in adjustment_linesets_in_order:
 | 
					        for adjustment_lineset in adjustment_linesets_in_order:
 | 
				
			||||||
| 
						 | 
					@ -430,6 +430,7 @@ class WitnessPlayerLogic:
 | 
				
			||||||
        self.ALWAYS_EVENT_HEX_CODES = set()
 | 
					        self.ALWAYS_EVENT_HEX_CODES = set()
 | 
				
			||||||
        self.COMPLETELY_DISABLED_CHECKS = set()
 | 
					        self.COMPLETELY_DISABLED_CHECKS = set()
 | 
				
			||||||
        self.PRECOMPLETED_LOCATIONS = set()
 | 
					        self.PRECOMPLETED_LOCATIONS = set()
 | 
				
			||||||
 | 
					        self.EXCLUDED_LOCATIONS = set()
 | 
				
			||||||
        self.ADDED_CHECKS = set()
 | 
					        self.ADDED_CHECKS = set()
 | 
				
			||||||
        self.VICTORY_LOCATION = "0x0356B"
 | 
					        self.VICTORY_LOCATION = "0x0356B"
 | 
				
			||||||
        self.EVENT_ITEM_NAMES = {
 | 
					        self.EVENT_ITEM_NAMES = {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -141,14 +141,19 @@ class WitnessLogic(LogicMixin):
 | 
				
			||||||
                        and self.can_reach("Windmill Interior to Theater", "Entrance", player)
 | 
					                        and self.can_reach("Windmill Interior to Theater", "Entrance", player)
 | 
				
			||||||
                    )
 | 
					                    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    exit_to_town = self.can_reach("Theater to Town", "Entrance", player)
 | 
					                    theater_from_town = (
 | 
				
			||||||
                    entrance_to_town = (
 | 
					 | 
				
			||||||
                        self.can_reach("Town to Windmill Interior", "Entrance", player)
 | 
					                        self.can_reach("Town to Windmill Interior", "Entrance", player)
 | 
				
			||||||
                        and self.can_reach("Windmill Interior to Theater", "Entrance", player)
 | 
					                        and self.can_reach("Windmill Interior to Theater", "Entrance", player)
 | 
				
			||||||
 | 
					                        or self.can_reach("Theater to Town", "Entrance", player)
 | 
				
			||||||
                    )
 | 
					                    )
 | 
				
			||||||
                    tunnels_to_town = self.can_reach("Tunnels to Town", "Entrance", player)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    if not (direct_access or (exit_to_town or entrance_to_town) and tunnels_to_town):
 | 
					                    tunnels_from_town = (
 | 
				
			||||||
 | 
					                        self.can_reach("Tunnels to Windmill Interior", "Entrance", player)
 | 
				
			||||||
 | 
					                        and self.can_reach("Town to Windmill Interior", "Entrance", player)
 | 
				
			||||||
 | 
					                        or self.can_reach("Tunnels to Town", "Entrance", player)
 | 
				
			||||||
 | 
					                    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if not (direct_access or theater_from_town and tunnels_from_town):
 | 
				
			||||||
                        valid_option = False
 | 
					                        valid_option = False
 | 
				
			||||||
                        break
 | 
					                        break
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -84,8 +84,6 @@ Disabled Locations:
 | 
				
			||||||
0x0070F (Second Row 2)
 | 
					0x0070F (Second Row 2)
 | 
				
			||||||
0x0087D (Second Row 3)
 | 
					0x0087D (Second Row 3)
 | 
				
			||||||
0x002C7 (Second Row 4)
 | 
					0x002C7 (Second Row 4)
 | 
				
			||||||
0x15ADD (River Outside Vault)
 | 
					 | 
				
			||||||
0x03702 (River Vault Box)
 | 
					 | 
				
			||||||
0x17CAA (Monastery Shortcut Panel)
 | 
					0x17CAA (Monastery Shortcut Panel)
 | 
				
			||||||
0x0C2A4 (Bunker Entry)
 | 
					0x0C2A4 (Bunker Entry)
 | 
				
			||||||
0x17C79 (Tinted Glass Door)
 | 
					0x17C79 (Tinted Glass Door)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -57,7 +57,7 @@ class StaticWitnessLogicObj:
 | 
				
			||||||
                        "panels": parse_lambda(required_panel_lambda)
 | 
					                        "panels": parse_lambda(required_panel_lambda)
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    current_region["panels"].add(check_hex)
 | 
					                    current_region["panels"].append(check_hex)
 | 
				
			||||||
                    continue
 | 
					                    continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                required_item_lambda = line_split.pop(0)
 | 
					                required_item_lambda = line_split.pop(0)
 | 
				
			||||||
| 
						 | 
					@ -117,7 +117,7 @@ class StaticWitnessLogicObj:
 | 
				
			||||||
                self.CHECKS_BY_NAME[self.CHECKS_BY_HEX[check_hex]["checkName"]] = self.CHECKS_BY_HEX[check_hex]
 | 
					                self.CHECKS_BY_NAME[self.CHECKS_BY_HEX[check_hex]["checkName"]] = self.CHECKS_BY_HEX[check_hex]
 | 
				
			||||||
                self.STATIC_DEPENDENT_REQUIREMENTS_BY_HEX[check_hex] = requirement
 | 
					                self.STATIC_DEPENDENT_REQUIREMENTS_BY_HEX[check_hex] = requirement
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                current_region["panels"].add(check_hex)
 | 
					                current_region["panels"].append(check_hex)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __init__(self, file_path="WitnessLogic.txt"):
 | 
					    def __init__(self, file_path="WitnessLogic.txt"):
 | 
				
			||||||
        # All regions with a list of panels in them and the connections to other regions, before logic adjustments
 | 
					        # All regions with a list of panels in them and the connections to other regions, before logic adjustments
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -106,7 +106,7 @@ def define_new_region(region_string):
 | 
				
			||||||
    region_obj = {
 | 
					    region_obj = {
 | 
				
			||||||
        "name": region_name,
 | 
					        "name": region_name,
 | 
				
			||||||
        "shortName": region_name_simple,
 | 
					        "shortName": region_name_simple,
 | 
				
			||||||
        "panels": set()
 | 
					        "panels": list()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return region_obj, options
 | 
					    return region_obj, options
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue