| 
									
										
										
										
											2021-10-03 17:22:47 +02:00
										 |  |  | import typing | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-28 14:54:10 -07:00
										 |  |  | from BaseClasses import LocationProgressType, MultiWorld | 
					
						
							| 
									
										
										
										
											2022-01-19 20:19:07 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-03 17:22:47 +02:00
										 |  |  | if typing.TYPE_CHECKING: | 
					
						
							|  |  |  |     import BaseClasses | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     CollectionRule = typing.Callable[[BaseClasses.CollectionState], bool] | 
					
						
							|  |  |  |     ItemRule = typing.Callable[[BaseClasses.Item], bool] | 
					
						
							|  |  |  | else: | 
					
						
							|  |  |  |     CollectionRule = typing.Callable[[object], bool] | 
					
						
							|  |  |  |     ItemRule = typing.Callable[[object], bool] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-15 07:41:11 -07:00
										 |  |  | def group_locality_rules(world): | 
					
						
							|  |  |  |     for group_id, group in world.groups.items(): | 
					
						
							|  |  |  |         if set(world.player_ids) == set(group["players"]): | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  |         if group["local_items"]: | 
					
						
							|  |  |  |             for location in world.get_locations(): | 
					
						
							|  |  |  |                 if location.player not in group["players"]: | 
					
						
							|  |  |  |                     forbid_items_for_player(location, group["local_items"], group_id) | 
					
						
							|  |  |  |         if group["non_local_items"]: | 
					
						
							|  |  |  |             for location in world.get_locations(): | 
					
						
							|  |  |  |                 if location.player in group["players"]: | 
					
						
							|  |  |  |                     forbid_items_for_player(location, group["non_local_items"], group_id) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-03 17:22:47 +02:00
										 |  |  | def locality_rules(world, player: int): | 
					
						
							| 
									
										
										
										
											2021-09-17 00:17:54 +02:00
										 |  |  |     if world.local_items[player].value: | 
					
						
							| 
									
										
										
										
											2021-02-24 00:36:37 +01:00
										 |  |  |         for location in world.get_locations(): | 
					
						
							|  |  |  |             if location.player != player: | 
					
						
							| 
									
										
										
										
											2021-09-17 00:17:54 +02:00
										 |  |  |                 forbid_items_for_player(location, world.local_items[player].value, player) | 
					
						
							|  |  |  |     if world.non_local_items[player].value: | 
					
						
							| 
									
										
										
										
											2021-02-24 00:36:37 +01:00
										 |  |  |         for location in world.get_locations(): | 
					
						
							|  |  |  |             if location.player == player: | 
					
						
							| 
									
										
										
										
											2021-09-17 00:17:54 +02:00
										 |  |  |                 forbid_items_for_player(location, world.non_local_items[player].value, player) | 
					
						
							| 
									
										
										
										
											2021-02-24 00:36:37 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-28 14:54:10 -07:00
										 |  |  | def exclusion_rules(world: MultiWorld, player: int, exclude_locations: typing.Set[str]) -> None: | 
					
						
							| 
									
										
										
										
											2021-09-17 00:17:54 +02:00
										 |  |  |     for loc_name in exclude_locations: | 
					
						
							| 
									
										
										
										
											2021-10-05 17:52:03 -05:00
										 |  |  |         try: | 
					
						
							|  |  |  |             location = world.get_location(loc_name, player) | 
					
						
							|  |  |  |         except KeyError as e:  # failed to find the given location. Check if it's a legitimate location | 
					
						
							|  |  |  |             if loc_name not in world.worlds[player].location_name_to_id: | 
					
						
							| 
									
										
										
										
											2021-10-05 17:55:15 -05:00
										 |  |  |                 raise Exception(f"Unable to exclude location {loc_name} in player {player}'s world.") from e | 
					
						
							| 
									
										
										
										
											2022-09-28 14:54:10 -07:00
										 |  |  |         else: | 
					
						
							| 
									
										
										
										
											2022-06-17 03:23:27 +02:00
										 |  |  |             add_item_rule(location, lambda i: not (i.advancement or i.useful)) | 
					
						
							| 
									
										
										
										
											2022-01-19 20:19:07 -07:00
										 |  |  |             location.progress_type = LocationProgressType.EXCLUDED | 
					
						
							| 
									
										
										
										
											2021-07-14 08:24:34 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-01 16:36:14 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-22 07:24:36 +02:00
										 |  |  | def set_rule(spot: typing.Union["BaseClasses.Location", "BaseClasses.Entrance"], rule: CollectionRule): | 
					
						
							| 
									
										
										
										
											2021-02-24 00:36:37 +01:00
										 |  |  |     spot.access_rule = rule | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-22 07:24:36 +02:00
										 |  |  | def add_rule(spot: typing.Union["BaseClasses.Location", "BaseClasses.Entrance"], rule: CollectionRule, combine='and'): | 
					
						
							| 
									
										
										
										
											2021-02-24 00:36:37 +01:00
										 |  |  |     old_rule = spot.access_rule | 
					
						
							|  |  |  |     if combine == 'or': | 
					
						
							|  |  |  |         spot.access_rule = lambda state: rule(state) or old_rule(state) | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         spot.access_rule = lambda state: rule(state) and old_rule(state) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-22 07:24:36 +02:00
										 |  |  | def forbid_item(location: "BaseClasses.Location", item: str, player: int): | 
					
						
							| 
									
										
										
										
											2021-02-24 00:36:37 +01:00
										 |  |  |     old_rule = location.item_rule | 
					
						
							|  |  |  |     location.item_rule = lambda i: (i.name != item or i.player != player) and old_rule(i) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-22 07:24:36 +02:00
										 |  |  | def forbid_items_for_player(location: "BaseClasses.Location", items: typing.Set[str], player: int): | 
					
						
							| 
									
										
										
										
											2021-02-24 00:36:37 +01:00
										 |  |  |     old_rule = location.item_rule | 
					
						
							|  |  |  |     location.item_rule = lambda i: (i.player != player or i.name not in items) and old_rule(i) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-22 07:24:36 +02:00
										 |  |  | def forbid_items(location: "BaseClasses.Location", items: typing.Set[str]): | 
					
						
							| 
									
										
										
										
											2021-02-24 00:36:37 +01:00
										 |  |  |     """unused, but kept as a debugging tool.""" | 
					
						
							|  |  |  |     old_rule = location.item_rule | 
					
						
							|  |  |  |     location.item_rule = lambda i: i.name not in items and old_rule(i) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-22 07:24:36 +02:00
										 |  |  | def add_item_rule(location: "BaseClasses.Location", rule: ItemRule): | 
					
						
							| 
									
										
										
										
											2021-02-24 00:36:37 +01:00
										 |  |  |     old_rule = location.item_rule | 
					
						
							|  |  |  |     location.item_rule = lambda item: rule(item) and old_rule(item) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-22 07:24:36 +02:00
										 |  |  | def item_in_locations(state: "BaseClasses.CollectionState", item: str, player: int, | 
					
						
							|  |  |  |                       locations: typing.Sequence["BaseClasses.Location"]) -> bool: | 
					
						
							| 
									
										
										
										
											2021-02-24 00:36:37 +01:00
										 |  |  |     for location in locations: | 
					
						
							|  |  |  |         if item_name(state, location[0], location[1]) == (item, player): | 
					
						
							|  |  |  |             return True | 
					
						
							|  |  |  |     return False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-22 07:24:36 +02:00
										 |  |  | def item_name(state: "BaseClasses.CollectionState", location: str, player: int) -> \ | 
					
						
							|  |  |  |         typing.Optional[typing.Tuple[str, int]]: | 
					
						
							| 
									
										
										
										
											2021-02-24 00:36:37 +01:00
										 |  |  |     location = state.world.get_location(location, player) | 
					
						
							|  |  |  |     if location.item is None: | 
					
						
							|  |  |  |         return None | 
					
						
							| 
									
										
										
										
											2021-10-03 17:22:47 +02:00
										 |  |  |     return location.item.name, location.item.player |