| 
									
										
										
										
											2021-11-28 14:32:08 -07:00
										 |  |  | import json | 
					
						
							|  |  |  | from pathlib import Path | 
					
						
							|  |  |  | from typing import Dict, NamedTuple, List, Optional | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-13 18:06:43 -06:00
										 |  |  | from BaseClasses import Region, Location, MultiWorld | 
					
						
							| 
									
										
										
										
											2021-11-28 14:32:08 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | EventId: Optional[int] = None | 
					
						
							|  |  |  | CHAOS_TERMINATED_EVENT = 'Terminated Chaos' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class LocationData(NamedTuple): | 
					
						
							|  |  |  |     name: str | 
					
						
							|  |  |  |     address: int | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class FF1Locations: | 
					
						
							|  |  |  |     _location_table: List[LocationData] = [] | 
					
						
							|  |  |  |     _location_table_lookup: Dict[str, LocationData] = {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _populate_item_table_from_data(self): | 
					
						
							|  |  |  |         base_path = Path(__file__).parent | 
					
						
							|  |  |  |         file_path = (base_path / "data/locations.json").resolve() | 
					
						
							|  |  |  |         with open(file_path) as file: | 
					
						
							|  |  |  |             locations = json.load(file) | 
					
						
							|  |  |  |             # Hardcode progression and categories for now | 
					
						
							|  |  |  |             self._location_table = [LocationData(name, code) for name, code in locations.items()] | 
					
						
							|  |  |  |             self._location_table_lookup = {item.name: item for item in self._location_table} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _get_location_table(self) -> List[LocationData]: | 
					
						
							|  |  |  |         if not self._location_table or not self._location_table_lookup: | 
					
						
							|  |  |  |             self._populate_item_table_from_data() | 
					
						
							|  |  |  |         return self._location_table | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _get_location_table_lookup(self) -> Dict[str, LocationData]: | 
					
						
							|  |  |  |         if not self._location_table or not self._location_table_lookup: | 
					
						
							|  |  |  |             self._populate_item_table_from_data() | 
					
						
							|  |  |  |         return self._location_table_lookup | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def get_location_name_to_address_dict(self) -> Dict[str, int]: | 
					
						
							|  |  |  |         data = {name: location.address for name, location in self._get_location_table_lookup().items()} | 
					
						
							|  |  |  |         data[CHAOS_TERMINATED_EVENT] = EventId | 
					
						
							|  |  |  |         return data | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @staticmethod | 
					
						
							|  |  |  |     def create_menu_region(player: int, locations: Dict[str, int], | 
					
						
							| 
									
										
										
										
											2023-02-13 18:06:43 -06:00
										 |  |  |                            rules: Dict[str, List[List[str]]], world: MultiWorld) -> Region: | 
					
						
							|  |  |  |         menu_region = Region("Menu", player, world) | 
					
						
							| 
									
										
										
										
											2021-11-28 14:32:08 -07:00
										 |  |  |         for name, address in locations.items(): | 
					
						
							|  |  |  |             location = Location(player, name, address, menu_region) | 
					
						
							|  |  |  |             ## TODO REMOVE WHEN LOGIC FOR TOFR IS CORRECT | 
					
						
							|  |  |  |             if "ToFR" in name: | 
					
						
							|  |  |  |                 rules_list = [["Rod", "Cube", "Lute", "Key", "Chime", "Oxyale", | 
					
						
							|  |  |  |                                "Ship", "Canoe", "Floater", "Canal", | 
					
						
							|  |  |  |                                "Crown", "Crystal", "Herb", "Tnt", "Adamant", "Slab", "Ruby", "Bottle"]] | 
					
						
							|  |  |  |                 location.access_rule = generate_rule(rules_list, player) | 
					
						
							|  |  |  |             elif name in rules: | 
					
						
							|  |  |  |                 rules_list = rules[name] | 
					
						
							|  |  |  |                 location.access_rule = generate_rule(rules_list, player) | 
					
						
							|  |  |  |             menu_region.locations.append(location) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return menu_region | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def generate_rule(rules_list, player): | 
					
						
							|  |  |  |     def x(state): | 
					
						
							|  |  |  |         for rule in rules_list: | 
					
						
							|  |  |  |             current_state = True | 
					
						
							|  |  |  |             for item in rule: | 
					
						
							|  |  |  |                 if not state.has(item, player): | 
					
						
							|  |  |  |                     current_state = False | 
					
						
							|  |  |  |                     break | 
					
						
							|  |  |  |             if current_state: | 
					
						
							|  |  |  |                 return True | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  |     return x |