The Witness: The big dumb refactor (#3007)

This commit is contained in:
NewSoupVi
2024-04-12 00:27:42 +02:00
committed by GitHub
parent 5d4ed00452
commit 401a6d9a42
48 changed files with 1080 additions and 1041 deletions

View File

@@ -3,13 +3,16 @@ Defines the rules by which locations can be accessed,
depending on the items received
"""
from typing import TYPE_CHECKING, Callable, FrozenSet
from typing import TYPE_CHECKING, FrozenSet
from BaseClasses import CollectionState
from .player_logic import WitnessPlayerLogic
from worlds.generic.Rules import CollectionRule, set_rule
from . import WitnessPlayerRegions
from .data import static_logic as static_witness_logic
from .locations import WitnessPlayerLocations
from . import StaticWitnessLogic, WitnessRegions
from worlds.generic.Rules import set_rule
from .player_logic import WitnessPlayerLogic
if TYPE_CHECKING:
from . import WitnessWorld
@@ -30,17 +33,17 @@ laser_hexes = [
def _has_laser(laser_hex: str, world: "WitnessWorld", player: int,
redirect_required: bool) -> Callable[[CollectionState], bool]:
redirect_required: bool) -> CollectionRule:
if laser_hex == "0x012FB" and redirect_required:
return lambda state: (
_can_solve_panel(laser_hex, world, world.player, world.player_logic, world.locat)(state)
_can_solve_panel(laser_hex, world, world.player, world.player_logic, world.player_locations)(state)
and state.has("Desert Laser Redirection", player)
)
else:
return _can_solve_panel(laser_hex, world, world.player, world.player_logic, world.locat)
return _can_solve_panel(laser_hex, world, world.player, world.player_logic, world.player_locations)
def _has_lasers(amount: int, world: "WitnessWorld", redirect_required: bool) -> Callable[[CollectionState], bool]:
def _has_lasers(amount: int, world: "WitnessWorld", redirect_required: bool) -> CollectionRule:
laser_lambdas = []
for laser_hex in laser_hexes:
@@ -52,7 +55,7 @@ def _has_lasers(amount: int, world: "WitnessWorld", redirect_required: bool) ->
def _can_solve_panel(panel: str, world: "WitnessWorld", player: int, player_logic: WitnessPlayerLogic,
locat: WitnessPlayerLocations) -> Callable[[CollectionState], bool]:
player_locations: WitnessPlayerLocations) -> CollectionRule:
"""
Determines whether a panel can be solved
"""
@@ -60,15 +63,16 @@ def _can_solve_panel(panel: str, world: "WitnessWorld", player: int, player_logi
panel_obj = player_logic.REFERENCE_LOGIC.ENTITIES_BY_HEX[panel]
entity_name = panel_obj["checkName"]
if entity_name + " Solved" in locat.EVENT_LOCATION_TABLE:
if entity_name + " Solved" in player_locations.EVENT_LOCATION_TABLE:
return lambda state: state.has(player_logic.EVENT_ITEM_PAIRS[entity_name + " Solved"], player)
else:
return make_lambda(panel, world)
def _can_move_either_direction(state: CollectionState, source: str, target: str, regio: WitnessRegions) -> bool:
entrance_forward = regio.created_entrances[source, target]
entrance_backward = regio.created_entrances[target, source]
def _can_move_either_direction(state: CollectionState, source: str, target: str,
player_regions: WitnessPlayerRegions) -> bool:
entrance_forward = player_regions.created_entrances[source, target]
entrance_backward = player_regions.created_entrances[target, source]
return (
any(entrance.can_reach(state) for entrance in entrance_forward)
@@ -81,49 +85,49 @@ def _can_do_expert_pp2(state: CollectionState, world: "WitnessWorld") -> bool:
player = world.player
hedge_2_access = (
_can_move_either_direction(state, "Keep 2nd Maze", "Keep", world.regio)
_can_move_either_direction(state, "Keep 2nd Maze", "Keep", world.player_regions)
)
hedge_3_access = (
_can_move_either_direction(state, "Keep 3rd Maze", "Keep", world.regio)
or _can_move_either_direction(state, "Keep 3rd Maze", "Keep 2nd Maze", world.regio)
and hedge_2_access
_can_move_either_direction(state, "Keep 3rd Maze", "Keep", world.player_regions)
or _can_move_either_direction(state, "Keep 3rd Maze", "Keep 2nd Maze", world.player_regions)
and hedge_2_access
)
hedge_4_access = (
_can_move_either_direction(state, "Keep 4th Maze", "Keep", world.regio)
or _can_move_either_direction(state, "Keep 4th Maze", "Keep 3rd Maze", world.regio)
and hedge_3_access
_can_move_either_direction(state, "Keep 4th Maze", "Keep", world.player_regions)
or _can_move_either_direction(state, "Keep 4th Maze", "Keep 3rd Maze", world.player_regions)
and hedge_3_access
)
hedge_access = (
_can_move_either_direction(state, "Keep 4th Maze", "Keep Tower", world.regio)
and state.can_reach("Keep", "Region", player)
and hedge_4_access
_can_move_either_direction(state, "Keep 4th Maze", "Keep Tower", world.player_regions)
and state.can_reach("Keep", "Region", player)
and hedge_4_access
)
backwards_to_fourth = (
state.can_reach("Keep", "Region", player)
and _can_move_either_direction(state, "Keep 4th Pressure Plate", "Keep Tower", world.regio)
and (
_can_move_either_direction(state, "Keep", "Keep Tower", world.regio)
or hedge_access
)
state.can_reach("Keep", "Region", player)
and _can_move_either_direction(state, "Keep 4th Pressure Plate", "Keep Tower", world.player_regions)
and (
_can_move_either_direction(state, "Keep", "Keep Tower", world.player_regions)
or hedge_access
)
)
shadows_shortcut = (
state.can_reach("Main Island", "Region", player)
and _can_move_either_direction(state, "Keep 4th Pressure Plate", "Shadows", world.regio)
state.can_reach("Main Island", "Region", player)
and _can_move_either_direction(state, "Keep 4th Pressure Plate", "Shadows", world.player_regions)
)
backwards_access = (
_can_move_either_direction(state, "Keep 3rd Pressure Plate", "Keep 4th Pressure Plate", world.regio)
and (backwards_to_fourth or shadows_shortcut)
_can_move_either_direction(state, "Keep 3rd Pressure Plate", "Keep 4th Pressure Plate", world.player_regions)
and (backwards_to_fourth or shadows_shortcut)
)
front_access = (
_can_move_either_direction(state, "Keep 2nd Pressure Plate", "Keep", world.regio)
and state.can_reach("Keep", "Region", player)
_can_move_either_direction(state, "Keep 2nd Pressure Plate", "Keep", world.player_regions)
and state.can_reach("Keep", "Region", player)
)
return front_access and backwards_access
@@ -131,27 +135,27 @@ def _can_do_expert_pp2(state: CollectionState, world: "WitnessWorld") -> bool:
def _can_do_theater_to_tunnels(state: CollectionState, world: "WitnessWorld") -> bool:
direct_access = (
_can_move_either_direction(state, "Tunnels", "Windmill Interior", world.regio)
and _can_move_either_direction(state, "Theater", "Windmill Interior", world.regio)
_can_move_either_direction(state, "Tunnels", "Windmill Interior", world.player_regions)
and _can_move_either_direction(state, "Theater", "Windmill Interior", world.player_regions)
)
theater_from_town = (
_can_move_either_direction(state, "Town", "Windmill Interior", world.regio)
and _can_move_either_direction(state, "Theater", "Windmill Interior", world.regio)
or _can_move_either_direction(state, "Town", "Theater", world.regio)
_can_move_either_direction(state, "Town", "Windmill Interior", world.player_regions)
and _can_move_either_direction(state, "Theater", "Windmill Interior", world.player_regions)
or _can_move_either_direction(state, "Town", "Theater", world.player_regions)
)
tunnels_from_town = (
_can_move_either_direction(state, "Tunnels", "Windmill Interior", world.regio)
and _can_move_either_direction(state, "Town", "Windmill Interior", world.regio)
or _can_move_either_direction(state, "Tunnels", "Town", world.regio)
_can_move_either_direction(state, "Tunnels", "Windmill Interior", world.player_regions)
and _can_move_either_direction(state, "Town", "Windmill Interior", world.player_regions)
or _can_move_either_direction(state, "Tunnels", "Town", world.player_regions)
)
return direct_access or theater_from_town and tunnels_from_town
def _has_item(item: str, world: "WitnessWorld", player: int,
player_logic: WitnessPlayerLogic, locat: WitnessPlayerLocations) -> Callable[[CollectionState], bool]:
player_logic: WitnessPlayerLogic, player_locations: WitnessPlayerLocations) -> CollectionRule:
if item in player_logic.REFERENCE_LOGIC.ALL_REGIONS_BY_NAME:
return lambda state: state.can_reach(item, "Region", player)
if item == "7 Lasers":
@@ -171,21 +175,21 @@ def _has_item(item: str, world: "WitnessWorld", player: int,
elif item == "Theater to Tunnels":
return lambda state: _can_do_theater_to_tunnels(state, world)
if item in player_logic.USED_EVENT_NAMES_BY_HEX:
return _can_solve_panel(item, world, player, player_logic, locat)
return _can_solve_panel(item, world, player, player_logic, player_locations)
prog_item = StaticWitnessLogic.get_parent_progressive_item(item)
prog_item = static_witness_logic.get_parent_progressive_item(item)
return lambda state: state.has(prog_item, player, player_logic.MULTI_AMOUNTS[item])
def _meets_item_requirements(requirements: FrozenSet[FrozenSet[str]],
world: "WitnessWorld") -> Callable[[CollectionState], bool]:
world: "WitnessWorld") -> CollectionRule:
"""
Checks whether item and panel requirements are met for
a panel
"""
lambda_conversion = [
[_has_item(item, world, world.player, world.player_logic, world.locat) for item in subset]
[_has_item(item, world, world.player, world.player_logic, world.player_locations) for item in subset]
for subset in requirements
]
@@ -195,7 +199,7 @@ def _meets_item_requirements(requirements: FrozenSet[FrozenSet[str]],
)
def make_lambda(entity_hex: str, world: "WitnessWorld") -> Callable[[CollectionState], bool]:
def make_lambda(entity_hex: str, world: "WitnessWorld") -> CollectionRule:
"""
Lambdas are created in a for loop so values need to be captured
"""
@@ -204,15 +208,15 @@ def make_lambda(entity_hex: str, world: "WitnessWorld") -> Callable[[CollectionS
return _meets_item_requirements(entity_req, world)
def set_rules(world: "WitnessWorld"):
def set_rules(world: "WitnessWorld") -> None:
"""
Sets all rules for all locations
"""
for location in world.locat.CHECK_LOCATION_TABLE:
for location in world.player_locations.CHECK_LOCATION_TABLE:
real_location = location
if location in world.locat.EVENT_LOCATION_TABLE:
if location in world.player_locations.EVENT_LOCATION_TABLE:
real_location = location[:-7]
associated_entity = world.player_logic.REFERENCE_LOGIC.ENTITIES_BY_NAME[real_location]
@@ -220,8 +224,8 @@ def set_rules(world: "WitnessWorld"):
rule = make_lambda(entity_hex, world)
location = world.multiworld.get_location(location, world.player)
location = world.get_location(location)
set_rule(location, rule)
world.multiworld.completion_condition[world.player] = lambda state: state.has('Victory', world.player)
world.multiworld.completion_condition[world.player] = lambda state: state.has("Victory", world.player)