mirror of
https://github.com/MarioSpore/Grinch-AP.git
synced 2025-10-21 20:21:32 -06:00
The Witness: Automatic Postgame & Disabled Panels Calculation (#2698)
* Refactor postgame code to be more readable * Change all references to options to strings * oops * Fix some outdated code related to yaml-disabled EPs * Small fixes to short/longbox stuff (thanks Medic) * comment * fix duplicate * Removed triplicate lmfao * Better comment * added another 'unfun' postgame consideration * comment * more option strings * oops * Remove an unnecessary comparison * another string missed * New classification changes (Credit: Exempt-Medic) * Don't need to pass world * Comments * Replace it with another magic system because why not at this point :DDDDDD * oops * Oops * Another was missed * Make events conditions. Disable_Non_Randomized will no longer just 'have all events' * What the fuck? Has this just always been broken? * Don't have boolean function with 'not' in the name * Another useful classification * slight code refactor * Funny haha booleans * This would create a really bad merge error * I can't believe this actually kind of works * And here's the punchline. + some bugfixes * Comment dat code * Comments galore * LMAO OOPS * so nice I did it twice * debug x2 * Careful * Add more comments * That comment is a bit unnecessary now * Fix overriding region connections * Correct a comment * Correct again * Rename variable * Idk I guess this is in this branch now * More tweaking of postgame & comments * This is commit just exists to fix that grammar error * I think I can just fucking delete this now??? * Forgot to reset something here * Delete dead codepath * Obelisk Keys were getting yote erroneously * More comments * Fix duplicate connections * Oopsington III * performance improvements & cleanup * More rules cleanup and performance improvements * Oh cool I can do this huh * Okay but this is even more swag tho * Lazy eval * remove some implicit checks * Is this too magical yet * more guard magic * Maaaaaaaagiccccccccc * Laaaaaaaaaaaaaaaazzzzzzyyyyyyyyyyy * Make it docstring * Newline bc I like that better * this is a little spooky lol * lol * Wait * spoO * Better variable name and comment * Improved comment again * better API * oops I deleted a deepcopy * lol help * Help??? * player_regionsns lmao * Add some comments * Make doors disabled properly again. I hope this works * Don't disable lasers * Omega oops * Make Floor 2 Exit not exist * Make a fix that's warps compatible * I think this was an oversight, I tested a seed and it seems to have the same result * This is definitely less Violet than before * Does this feel more violet lol * Exception if a laser gets disabled, cleanup * Ruff * >:( * consistent utils import * Make autopostgame more reviewable (hopefully) * more reviewability * WitnessRule * replace another instance of it * lint * style * comment * found the bug * Move comment * Get rid of cache and ugly allow_victory * comments and lint
This commit is contained in:
@@ -3,13 +3,14 @@ Defines Region for The Witness, assigns locations to them,
|
||||
and connects them with the proper requirements
|
||||
"""
|
||||
from collections import defaultdict
|
||||
from typing import TYPE_CHECKING, Dict, FrozenSet, List, Tuple
|
||||
from typing import TYPE_CHECKING, Dict, List, Set, Tuple
|
||||
|
||||
from BaseClasses import Entrance, Region
|
||||
|
||||
from worlds.generic.Rules import CollectionRule
|
||||
|
||||
from .data import static_logic as static_witness_logic
|
||||
from .data.utils import WitnessRule, optimize_witness_rule
|
||||
from .locations import WitnessPlayerLocations, static_witness_locations
|
||||
from .player_logic import WitnessPlayerLogic
|
||||
|
||||
@@ -24,7 +25,7 @@ class WitnessPlayerRegions:
|
||||
logic = None
|
||||
|
||||
@staticmethod
|
||||
def make_lambda(item_requirement: FrozenSet[FrozenSet[str]], world: "WitnessWorld") -> CollectionRule:
|
||||
def make_lambda(item_requirement: WitnessRule, world: "WitnessWorld") -> CollectionRule:
|
||||
from .rules import _meets_item_requirements
|
||||
|
||||
"""
|
||||
@@ -34,8 +35,8 @@ class WitnessPlayerRegions:
|
||||
|
||||
return _meets_item_requirements(item_requirement, world)
|
||||
|
||||
def connect_if_possible(self, world: "WitnessWorld", source: str, target: str, req: FrozenSet[FrozenSet[str]],
|
||||
regions_by_name: Dict[str, Region], backwards: bool = False):
|
||||
def connect_if_possible(self, world: "WitnessWorld", source: str, target: str, req: WitnessRule,
|
||||
regions_by_name: Dict[str, Region]):
|
||||
"""
|
||||
connect two regions and set the corresponding requirement
|
||||
"""
|
||||
@@ -43,10 +44,6 @@ class WitnessPlayerRegions:
|
||||
# Remove any possibilities where being in the target region would be required anyway.
|
||||
real_requirement = frozenset({option for option in req if target not in option})
|
||||
|
||||
# There are some connections that should only be done one way. If this is a backwards connection, check for that
|
||||
if backwards:
|
||||
real_requirement = frozenset({option for option in real_requirement if "TrueOneWay" not in option})
|
||||
|
||||
# Dissolve any "True" or "TrueOneWay"
|
||||
real_requirement = frozenset({option - {"True", "TrueOneWay"} for option in real_requirement})
|
||||
|
||||
@@ -56,12 +53,12 @@ class WitnessPlayerRegions:
|
||||
|
||||
# We don't need to check for the accessibility of the source region.
|
||||
final_requirement = frozenset({option - frozenset({source}) for option in real_requirement})
|
||||
final_requirement = optimize_witness_rule(final_requirement)
|
||||
|
||||
source_region = regions_by_name[source]
|
||||
target_region = regions_by_name[target]
|
||||
|
||||
backwards = " Backwards" if backwards else ""
|
||||
connection_name = source + " to " + target + backwards
|
||||
connection_name = source + " to " + target
|
||||
|
||||
connection = Entrance(
|
||||
world.player,
|
||||
@@ -74,7 +71,8 @@ class WitnessPlayerRegions:
|
||||
source_region.exits.append(connection)
|
||||
connection.connect(target_region)
|
||||
|
||||
self.created_entrances[source, target].append(connection)
|
||||
self.two_way_entrance_register[source, target].append(connection)
|
||||
self.two_way_entrance_register[target, source].append(connection)
|
||||
|
||||
# Register any necessary indirect connections
|
||||
mentioned_regions = {
|
||||
@@ -94,14 +92,19 @@ class WitnessPlayerRegions:
|
||||
all_locations = set()
|
||||
regions_by_name = dict()
|
||||
|
||||
for region_name, region in self.reference_logic.ALL_REGIONS_BY_NAME.items():
|
||||
regions_to_create = {
|
||||
k: v for k, v in self.reference_logic.ALL_REGIONS_BY_NAME.items()
|
||||
if k not in player_logic.UNREACHABLE_REGIONS
|
||||
}
|
||||
|
||||
for region_name, region in regions_to_create.items():
|
||||
locations_for_this_region = [
|
||||
self.reference_logic.ENTITIES_BY_HEX[panel]["checkName"] for panel in region["panels"]
|
||||
self.reference_logic.ENTITIES_BY_HEX[panel]["checkName"] for panel in region["entities"]
|
||||
if self.reference_logic.ENTITIES_BY_HEX[panel]["checkName"]
|
||||
in self.player_locations.CHECK_LOCATION_TABLE
|
||||
]
|
||||
locations_for_this_region += [
|
||||
static_witness_locations.get_event_name(panel) for panel in region["panels"]
|
||||
static_witness_locations.get_event_name(panel) for panel in region["entities"]
|
||||
if static_witness_locations.get_event_name(panel) in self.player_locations.EVENT_LOCATION_TABLE
|
||||
]
|
||||
|
||||
@@ -111,31 +114,13 @@ class WitnessPlayerRegions:
|
||||
|
||||
regions_by_name[region_name] = new_region
|
||||
|
||||
for region_name, region in self.reference_logic.ALL_REGIONS_BY_NAME.items():
|
||||
self.created_region_names = set(regions_by_name)
|
||||
|
||||
world.multiworld.regions += regions_by_name.values()
|
||||
|
||||
for region_name, region in regions_to_create.items():
|
||||
for connection in player_logic.CONNECTIONS_BY_REGION_NAME[region_name]:
|
||||
self.connect_if_possible(world, region_name, connection[0], connection[1], regions_by_name)
|
||||
self.connect_if_possible(world, connection[0], region_name, connection[1], regions_by_name, True)
|
||||
|
||||
# find regions that are completely disconnected from the start node and remove them
|
||||
regions_to_check = {"Menu"}
|
||||
reachable_regions = {"Menu"}
|
||||
|
||||
while regions_to_check:
|
||||
next_region = regions_to_check.pop()
|
||||
region_obj = regions_by_name[next_region]
|
||||
|
||||
for exit in region_obj.exits:
|
||||
target = exit.connected_region
|
||||
|
||||
if target.name in reachable_regions:
|
||||
continue
|
||||
|
||||
regions_to_check.add(target.name)
|
||||
reachable_regions.add(target.name)
|
||||
|
||||
self.created_regions = {k: v for k, v in regions_by_name.items() if k in reachable_regions}
|
||||
|
||||
world.multiworld.regions += self.created_regions.values()
|
||||
|
||||
def __init__(self, player_locations: WitnessPlayerLocations, world: "WitnessWorld") -> None:
|
||||
difficulty = world.options.puzzle_randomization
|
||||
@@ -148,5 +133,5 @@ class WitnessPlayerRegions:
|
||||
self.reference_logic = static_witness_logic.vanilla
|
||||
|
||||
self.player_locations = player_locations
|
||||
self.created_entrances: Dict[Tuple[str, str], List[Entrance]] = defaultdict(lambda: [])
|
||||
self.created_regions: Dict[str, Region] = dict()
|
||||
self.two_way_entrance_register: Dict[Tuple[str, str], List[Entrance]] = defaultdict(lambda: [])
|
||||
self.created_region_names: Set[str] = set()
|
||||
|
Reference in New Issue
Block a user