| 
									
										
										
										
											2022-04-29 00:42:11 +02:00
										 |  |  | """
 | 
					
						
							|  |  |  | 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 | 
					
						
							| 
									
										
										
										
											2022-06-16 03:04:45 +02:00
										 |  |  | from .Options import is_option_enabled, get_option_value | 
					
						
							| 
									
										
										
										
											2022-04-29 00:42:11 +02:00
										 |  |  | 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 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-17 12:56:22 +02:00
										 |  |  |         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 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-29 00:42:11 +02:00
										 |  |  |         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)) | 
					
						
							| 
									
										
										
										
											2022-06-16 03:04:45 +02:00
										 |  |  |         lasers += int(self.has("Keep Laser Activation", player)) | 
					
						
							| 
									
										
										
										
											2022-04-29 00:42:11 +02:00
										 |  |  |         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 | 
					
						
							| 
									
										
										
										
											2022-07-17 12:56:22 +02:00
										 |  |  |         if (check_name + " Solved" not in locat.EVENT_LOCATION_TABLE | 
					
						
							|  |  |  |                 and not self._witness_meets_item_requirements(panel, world, player, player_logic, locat)): | 
					
						
							| 
									
										
										
										
											2022-04-29 00:42:11 +02:00
										 |  |  |             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": | 
					
						
							| 
									
										
										
										
											2022-06-16 03:04:45 +02:00
										 |  |  |                     if not self._witness_has_lasers(world, player, get_option_value(world, player, "mountain_lasers")): | 
					
						
							| 
									
										
										
										
											2022-04-29 00:42:11 +02:00
										 |  |  |                         valid_option = False | 
					
						
							|  |  |  |                         break | 
					
						
							|  |  |  |                 elif item == "11 Lasers": | 
					
						
							| 
									
										
										
										
											2022-06-16 03:04:45 +02:00
										 |  |  |                     if not self._witness_has_lasers(world, player, get_option_value(world, player, "challenge_lasers")): | 
					
						
							| 
									
										
										
										
											2022-04-29 00:42:11 +02:00
										 |  |  |                         valid_option = False | 
					
						
							|  |  |  |                         break | 
					
						
							| 
									
										
										
										
											2022-07-17 12:56:22 +02:00
										 |  |  |                 elif item in player_logic.EVENT_PANELS: | 
					
						
							|  |  |  |                     if not self._witness_can_solve_panel(item, world, player, player_logic, locat): | 
					
						
							|  |  |  |                         valid_option = False | 
					
						
							|  |  |  |                         break | 
					
						
							| 
									
										
										
										
											2022-04-29 00:42:11 +02:00
										 |  |  |                 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: | 
					
						
							| 
									
										
										
										
											2022-07-28 23:43:35 +02:00
										 |  |  |                 if not self._witness_can_solve_panel(panel, world, player, player_logic, locat): | 
					
						
							| 
									
										
										
										
											2022-04-29 00:42:11 +02:00
										 |  |  |                     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) |