Archipelago/worlds/witness/rules.py

157 lines
5.7 KiB
Python

"""
Defines the rules by which locations can be accessed,
depending on the items received
"""
# pylint: disable=E1101
from BaseClasses import MultiWorld
from .player_logic import WitnessPlayerLogic
from .Options import is_option_enabled, get_option_value
from .locations import WitnessPlayerLocations
from . import StaticWitnessLogic
from ..AutoWorld import LogicMixin
from ..generic.Rules import set_rule
class WitnessLogic(LogicMixin):
"""
Logic macros that get reused
"""
def _witness_has_lasers(self, world, player: int, amount: int) -> bool:
lasers = 0
if is_option_enabled(world, player, "shuffle_lasers"):
lasers += int(self.has("Symmetry Laser", player))
lasers += int(self.has("Desert Laser", player)
and self.has("Desert Laser Redirection", player))
lasers += int(self.has("Town Laser", player))
lasers += int(self.has("Monastery Laser", player))
lasers += int(self.has("Keep Laser", player))
lasers += int(self.has("Quarry Laser", player))
lasers += int(self.has("Treehouse Laser", player))
lasers += int(self.has("Jungle Laser", player))
lasers += int(self.has("Bunker Laser", player))
lasers += int(self.has("Swamp Laser", player))
lasers += int(self.has("Shadows Laser", player))
return lasers >= amount
lasers += int(self.has("Symmetry Laser Activation", player))
lasers += int(self.has("Desert Laser Activation", player)
and self.has("Desert Laser Redirection", player))
lasers += int(self.has("Town Laser Activation", player))
lasers += int(self.has("Monastery Laser Activation", player))
lasers += int(self.has("Keep Laser Activation", player))
lasers += int(self.has("Quarry Laser Activation", player))
lasers += int(self.has("Treehouse Laser Activation", player))
lasers += int(self.has("Jungle Laser Activation", player))
lasers += int(self.has("Bunker Laser Activation", player))
lasers += int(self.has("Swamp Laser Activation", player))
lasers += int(self.has("Shadows Laser Activation", player))
return lasers >= amount
def _witness_can_solve_panel(self, panel, world, player, player_logic: WitnessPlayerLogic, locat):
"""
Determines whether a panel can be solved
"""
panel_obj = StaticWitnessLogic.CHECKS_BY_HEX[panel]
check_name = panel_obj["checkName"]
if (check_name + " Solved" in locat.EVENT_LOCATION_TABLE
and not self.has(player_logic.EVENT_ITEM_PAIRS[check_name + " Solved"], player)):
return False
if (check_name + " Solved" not in locat.EVENT_LOCATION_TABLE
and not self._witness_meets_item_requirements(panel, world, player, player_logic, locat)):
return False
return True
def _witness_meets_item_requirements(self, panel, world, player, player_logic: WitnessPlayerLogic, locat):
"""
Checks whether item and panel requirements are met for
a panel
"""
panel_req = player_logic.REQUIREMENTS_BY_HEX[panel]
for option in panel_req:
if len(option) == 0:
return True
valid_option = True
for item in option:
if item == "7 Lasers":
if not self._witness_has_lasers(world, player, get_option_value(world, player, "mountain_lasers")):
valid_option = False
break
elif item == "11 Lasers":
if not self._witness_has_lasers(world, player, get_option_value(world, player, "challenge_lasers")):
valid_option = False
break
elif item in player_logic.EVENT_PANELS:
if not self._witness_can_solve_panel(item, world, player, player_logic, locat):
valid_option = False
break
elif not self.has(item, player):
valid_option = False
break
if valid_option:
return True
return False
def _witness_can_solve_panels(self, panel_hex_to_solve_set, world, player, player_logic: WitnessPlayerLogic, locat):
"""
Checks whether a set of panels can be solved.
"""
for option in panel_hex_to_solve_set:
if len(option) == 0:
return True
valid_option = True
for panel in option:
if not self._witness_can_solve_panel(panel, world, player, player_logic, locat):
valid_option = False
break
if valid_option:
return True
return False
def make_lambda(check_hex, world, player, player_logic, locat):
"""
Lambdas are created in a for loop so values need to be captured
"""
return lambda state: state._witness_meets_item_requirements(
check_hex, world, player, player_logic, locat
)
def set_rules(world: MultiWorld, player: int, player_logic: WitnessPlayerLogic, locat: WitnessPlayerLocations):
"""
Sets all rules for all locations
"""
for location in locat.CHECK_LOCATION_TABLE:
real_location = location
if location in locat.EVENT_LOCATION_TABLE:
real_location = location[:-7]
panel = StaticWitnessLogic.CHECKS_BY_NAME[real_location]
check_hex = panel["checkHex"]
rule = make_lambda(check_hex, world, player, player_logic, locat)
set_rule(world.get_location(location, player), rule)
world.completion_condition[player] = \
lambda state: state.has('Victory', player)