| 
									
										
										
										
											2023-02-05 13:51:03 -07:00
										 |  |  | from typing import Tuple | 
					
						
							| 
									
										
										
										
											2021-08-29 14:02:02 -04:00
										 |  |  | from BaseClasses import Location | 
					
						
							| 
									
										
										
										
											2022-08-20 18:09:35 -05:00
										 |  |  | from .Options import TotalLocations | 
					
						
							| 
									
										
										
										
											2023-02-05 13:51:03 -07:00
										 |  |  | from .Options import ChestsPerEnvironment | 
					
						
							|  |  |  | from .Options import ShrinesPerEnvironment | 
					
						
							|  |  |  | from .Options import ScavengersPerEnvironment | 
					
						
							|  |  |  | from .Options import ScannersPerEnvironment | 
					
						
							|  |  |  | from .Options import AltarsPerEnvironment | 
					
						
							|  |  |  | from .RoR2Environments import * | 
					
						
							| 
									
										
										
										
											2022-08-20 18:09:35 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-29 14:02:02 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | class RiskOfRainLocation(Location): | 
					
						
							|  |  |  |     game: str = "Risk of Rain 2" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-23 16:22:31 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-05 13:51:03 -07:00
										 |  |  | ror2_locations_start_id = 38000 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def get_classic_item_pickups(n: int) -> Dict[str, int]: | 
					
						
							|  |  |  |     """Get n ItemPickups, capped at the max value for TotalLocations""" | 
					
						
							|  |  |  |     n = max(n, 0) | 
					
						
							|  |  |  |     n = min(n, TotalLocations.range_end) | 
					
						
							|  |  |  |     return { f"ItemPickup{i+1}": ror2_locations_start_id+i for i in range(n) } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | item_pickups = get_classic_item_pickups(TotalLocations.range_end) | 
					
						
							|  |  |  | location_table = item_pickups | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def environment_abreviation(long_name:str) -> str: | 
					
						
							|  |  |  |     """convert long environment names to initials""" | 
					
						
							|  |  |  |     abrev = "" | 
					
						
							|  |  |  |     # go through every word finding a letter (or number) for an initial | 
					
						
							|  |  |  |     for word in long_name.split(): | 
					
						
							|  |  |  |         initial = word[0] | 
					
						
							|  |  |  |         for letter in word: | 
					
						
							|  |  |  |             if letter.isalnum(): | 
					
						
							|  |  |  |                 initial = letter | 
					
						
							|  |  |  |                 break | 
					
						
							|  |  |  |         abrev+= initial | 
					
						
							|  |  |  |     return abrev | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # highest numbered orderedstages (this is so we can treat the easily caculate the check ids based on the environment and location "offset") | 
					
						
							|  |  |  | highest_orderedstage: int= max(compress_dict_list_horizontal(environment_orderedstages_table).values()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ror2_locations_start_orderedstage = ror2_locations_start_id + TotalLocations.range_end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class orderedstage_location: | 
					
						
							|  |  |  |     """A class to behave like a struct for storing the offsets of location types in the allocated space per orderedstage environments.""" | 
					
						
							|  |  |  |     # TODO is there a better, more generic way to do this? | 
					
						
							|  |  |  |     offset_ChestsPerEnvironment     = 0 | 
					
						
							|  |  |  |     offset_ShrinesPerEnvironment    = offset_ChestsPerEnvironment       + ChestsPerEnvironment.range_end | 
					
						
							|  |  |  |     offset_ScavengersPerEnvironment = offset_ShrinesPerEnvironment      + ShrinesPerEnvironment.range_end | 
					
						
							|  |  |  |     offset_ScannersPerEnvironment   = offset_ScavengersPerEnvironment   + ScavengersPerEnvironment.range_end | 
					
						
							|  |  |  |     offset_AltarsPerEnvironment     = offset_ScannersPerEnvironment     + ScannersPerEnvironment.range_end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # total space allocated to the locations in a single orderedstage environment | 
					
						
							|  |  |  |     allocation = offset_AltarsPerEnvironment + AltarsPerEnvironment.range_end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def get_environment_locations(chests:int, shrines:int, scavengers:int, scanners:int, altars:int, environment: Tuple[str, int]) -> Dict[str, int]: | 
					
						
							|  |  |  |         """Get the locations within a specific environment""" | 
					
						
							|  |  |  |         environment_name = environment[0] | 
					
						
							|  |  |  |         environment_index = environment[1] | 
					
						
							|  |  |  |         locations = {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # due to this mapping, since environment ids are not consecutive, there are lots of "wasted" id numbers | 
					
						
							|  |  |  |         # TODO perhaps a hashing algorithm could be used to compress this range and save "wasted" ids | 
					
						
							|  |  |  |         environment_start_id = environment_index * orderedstage_location.allocation + ror2_locations_start_orderedstage | 
					
						
							|  |  |  |         for n in range(chests): | 
					
						
							|  |  |  |             locations.update({f"{environment_name}: Chest {n+1}":            n + orderedstage_location.offset_ChestsPerEnvironment       + environment_start_id}) | 
					
						
							|  |  |  |         for n in range(shrines): | 
					
						
							|  |  |  |             locations.update({f"{environment_name}: Shrine {n+1}":           n + orderedstage_location.offset_ShrinesPerEnvironment      + environment_start_id}) | 
					
						
							|  |  |  |         for n in range(scavengers): | 
					
						
							|  |  |  |             locations.update({f"{environment_name}: Scavenger {n+1}":        n + orderedstage_location.offset_ScavengersPerEnvironment   + environment_start_id}) | 
					
						
							|  |  |  |         for n in range(scanners): | 
					
						
							|  |  |  |             locations.update({f"{environment_name}: Radio Scanner {n+1}":    n + orderedstage_location.offset_ScannersPerEnvironment     + environment_start_id}) | 
					
						
							|  |  |  |         for n in range(altars): | 
					
						
							|  |  |  |             locations.update({f"{environment_name}: Newt Altar {n+1}":       n + orderedstage_location.offset_AltarsPerEnvironment       + environment_start_id}) | 
					
						
							|  |  |  |         return locations | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def get_locations(chests:int, shrines:int, scavengers:int, scanners:int, altars:int, dlc_sotv:bool) -> Dict[str, int]: | 
					
						
							|  |  |  |         """Get a dictionary of locations for the ordedstage environments with the locations from the parameters.""" | 
					
						
							|  |  |  |         locations = {} | 
					
						
							|  |  |  |         orderedstages = compress_dict_list_horizontal(environment_vanilla_orderedstages_table) | 
					
						
							|  |  |  |         if(dlc_sotv): orderedstages.update(compress_dict_list_horizontal(environment_sotv_orderedstages_table)) | 
					
						
							|  |  |  |         # for every environment, generate the respective locations | 
					
						
							|  |  |  |         for environment_name, environment_index in orderedstages.items(): | 
					
						
							|  |  |  |             # locations = locations | orderedstage_location.get_environment_locations( | 
					
						
							|  |  |  |             locations.update(orderedstage_location.get_environment_locations( | 
					
						
							|  |  |  |                 chests=chests, | 
					
						
							|  |  |  |                 shrines=shrines, | 
					
						
							|  |  |  |                 scavengers=scavengers, | 
					
						
							|  |  |  |                 scanners=scanners, | 
					
						
							|  |  |  |                 altars=altars, | 
					
						
							|  |  |  |                 environment=(environment_name, environment_index) | 
					
						
							|  |  |  |             )) | 
					
						
							|  |  |  |         return locations | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def getall_locations(dlc_sotv:bool=True) -> Dict[str, int]: | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Get all locations in ordered stages. | 
					
						
							|  |  |  |         Set dlc_sotv to true for the SOTV DLC to be included. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         # to get all locations, attempt using as many locations as possible | 
					
						
							|  |  |  |         return orderedstage_location.get_locations( | 
					
						
							|  |  |  |             chests=ChestsPerEnvironment.range_end, | 
					
						
							|  |  |  |             shrines=ShrinesPerEnvironment.range_end, | 
					
						
							|  |  |  |             scavengers=ScavengersPerEnvironment.range_end, | 
					
						
							|  |  |  |             scanners=ScannersPerEnvironment.range_end, | 
					
						
							|  |  |  |             altars=AltarsPerEnvironment.range_end, | 
					
						
							|  |  |  |             dlc_sotv=dlc_sotv | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ror2_location_post_orderedstage = ror2_locations_start_orderedstage + highest_orderedstage*orderedstage_location.allocation | 
					
						
							|  |  |  | location_table.update(orderedstage_location.getall_locations()) | 
					
						
							|  |  |  | # use the sotv dlc in the lookup table so that all ids can be looked up regardless of use | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | lookup_id_to_name: Dict[int, str] = {id: name for name, id in location_table.items()} |