| 
									
										
										
										
											2023-03-23 21:21:11 +01:00
										 |  |  | from __future__ import annotations | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-17 12:07:45 -04:00
										 |  |  | import logging | 
					
						
							| 
									
										
										
										
											2023-03-23 21:21:11 +01:00
										 |  |  | import itertools | 
					
						
							| 
									
										
										
										
											2022-07-15 17:41:53 +02:00
										 |  |  | from typing import List, Dict, Any | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-13 18:06:43 -06:00
										 |  |  | from BaseClasses import Region, Entrance, Location, Item, Tutorial, ItemClassification | 
					
						
							| 
									
										
										
										
											2022-07-15 17:41:53 +02:00
										 |  |  | from worlds.AutoWorld import World, WebWorld | 
					
						
							|  |  |  | from . import Items | 
					
						
							|  |  |  | from . import Locations | 
					
						
							| 
									
										
										
										
											2022-07-16 16:45:40 +02:00
										 |  |  | from . import Creatures | 
					
						
							| 
									
										
										
										
											2022-07-15 17:41:53 +02:00
										 |  |  | from . import Options | 
					
						
							| 
									
										
										
										
											2023-03-23 21:21:11 +01:00
										 |  |  | from .Items import item_table, group_items | 
					
						
							| 
									
										
										
										
											2021-07-17 12:07:45 -04:00
										 |  |  | from .Rules import set_rules | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-15 17:41:53 +02:00
										 |  |  | logger = logging.getLogger("Subnautica") | 
					
						
							| 
									
										
										
										
											2022-05-11 13:05:53 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class SubnaticaWeb(WebWorld): | 
					
						
							|  |  |  |     tutorials = [Tutorial( | 
					
						
							|  |  |  |         "Multiworld Setup Guide", | 
					
						
							|  |  |  |         "A guide to setting up the Subnautica randomizer connected to an Archipelago Multiworld", | 
					
						
							|  |  |  |         "English", | 
					
						
							|  |  |  |         "setup_en.md", | 
					
						
							|  |  |  |         "setup/en", | 
					
						
							|  |  |  |         ["Berserker"] | 
					
						
							|  |  |  |     )] | 
					
						
							| 
									
										
										
										
											2021-07-17 12:07:45 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-16 16:45:40 +02:00
										 |  |  | all_locations = {data["name"]: loc_id for loc_id, data in Locations.location_table.items()} | 
					
						
							|  |  |  | all_locations.update(Creatures.creature_locations) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-17 12:07:45 -04:00
										 |  |  | class SubnauticaWorld(World): | 
					
						
							| 
									
										
										
										
											2021-08-31 17:28:46 -04:00
										 |  |  |     """
 | 
					
						
							|  |  |  |     Subnautica is an undersea exploration game. Stranded on an alien world, you become infected by | 
					
						
							|  |  |  |     an unknown bacteria. The planet's automatic quarantine will shoot you down if you try to leave. | 
					
						
							|  |  |  |     You must find a cure for yourself, build an escape rocket, and leave the planet. | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2023-02-16 00:40:19 +01:00
										 |  |  |     game = "Subnautica" | 
					
						
							| 
									
										
										
										
											2022-05-11 13:05:53 -05:00
										 |  |  |     web = SubnaticaWeb() | 
					
						
							| 
									
										
										
										
											2021-07-17 12:07:45 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-15 17:41:53 +02:00
										 |  |  |     item_name_to_id = {data["name"]: item_id for item_id, data in Items.item_table.items()} | 
					
						
							| 
									
										
										
										
											2022-07-16 16:45:40 +02:00
										 |  |  |     location_name_to_id = all_locations | 
					
						
							| 
									
										
										
										
											2022-08-15 16:46:59 -05:00
										 |  |  |     option_definitions = Options.options | 
					
						
							| 
									
										
										
										
											2021-07-17 12:07:45 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-26 09:48:41 +01:00
										 |  |  |     data_version = 9 | 
					
						
							| 
									
										
										
										
											2023-02-26 10:15:40 +01:00
										 |  |  |     required_client_version = (0, 3, 9) | 
					
						
							| 
									
										
										
										
											2022-07-15 17:41:53 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-16 16:45:40 +02:00
										 |  |  |     creatures_to_scan: List[str] | 
					
						
							| 
									
										
										
										
											2022-07-15 17:41:53 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def generate_early(self) -> None: | 
					
						
							| 
									
										
										
										
											2022-12-22 06:42:45 +01:00
										 |  |  |         if self.multiworld.early_seaglide[self.player]: | 
					
						
							| 
									
										
										
										
											2022-11-28 07:03:09 +01:00
										 |  |  |             self.multiworld.local_early_items[self.player]["Seaglide Fragment"] = 2 | 
					
						
							| 
									
										
										
										
											2022-10-27 03:00:24 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-31 21:41:21 -05:00
										 |  |  |         scan_option: Options.AggressiveScanLogic = self.multiworld.creature_scan_logic[self.player] | 
					
						
							| 
									
										
										
										
											2022-08-30 17:14:34 +02:00
										 |  |  |         creature_pool = scan_option.get_pool() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-31 21:41:21 -05:00
										 |  |  |         self.multiworld.creature_scans[self.player].value = min( | 
					
						
							| 
									
										
										
										
											2022-08-30 17:14:34 +02:00
										 |  |  |             len(creature_pool), | 
					
						
							| 
									
										
										
										
											2022-10-31 21:41:21 -05:00
										 |  |  |             self.multiworld.creature_scans[self.player].value | 
					
						
							| 
									
										
										
										
											2022-08-30 17:14:34 +02:00
										 |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-31 21:41:21 -05:00
										 |  |  |         self.creatures_to_scan = self.multiworld.random.sample(creature_pool, | 
					
						
							|  |  |  |                                                           self.multiworld.creature_scans[self.player].value) | 
					
						
							| 
									
										
										
										
											2022-07-15 17:41:53 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def create_regions(self): | 
					
						
							| 
									
										
										
										
											2022-10-31 21:41:21 -05:00
										 |  |  |         self.multiworld.regions += [ | 
					
						
							| 
									
										
										
										
											2022-07-15 17:41:53 +02:00
										 |  |  |             self.create_region("Menu", None, ["Lifepod 5"]), | 
					
						
							|  |  |  |             self.create_region("Planet 4546B", | 
					
						
							| 
									
										
										
										
											2022-07-16 16:45:40 +02:00
										 |  |  |                                Locations.events + | 
					
						
							|  |  |  |                                [location["name"] for location in Locations.location_table.values()] + | 
					
						
							|  |  |  |                                [creature+Creatures.suffix for creature in self.creatures_to_scan]) | 
					
						
							| 
									
										
										
										
											2022-07-15 17:41:53 +02:00
										 |  |  |         ] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-17 12:07:45 -04:00
										 |  |  |         # Link regions | 
					
						
							| 
									
										
										
										
											2022-10-31 21:41:21 -05:00
										 |  |  |         self.multiworld.get_entrance("Lifepod 5", self.player).connect(self.multiworld.get_region("Planet 4546B", self.player)) | 
					
						
							| 
									
										
										
										
											2021-07-17 12:07:45 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-16 20:22:14 +01:00
										 |  |  |         for event in Locations.events: | 
					
						
							|  |  |  |             self.multiworld.get_location(event, self.player).place_locked_item( | 
					
						
							|  |  |  |                 SubnauticaItem(event, ItemClassification.progression, None, player=self.player)) | 
					
						
							|  |  |  |         # make the goal event the victory "item" | 
					
						
							|  |  |  |         self.multiworld.get_location(self.multiworld.goal[self.player].get_event_name(), self.player).item.name = "Victory" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # refer to Rules.py | 
					
						
							|  |  |  |     set_rules = set_rules | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def create_items(self): | 
					
						
							| 
									
										
										
										
											2021-07-17 12:07:45 -04:00
										 |  |  |         # Generate item pool | 
					
						
							| 
									
										
										
										
											2023-03-23 21:21:11 +01:00
										 |  |  |         pool: List[SubnauticaItem] = [] | 
					
						
							| 
									
										
										
										
											2022-10-31 21:41:21 -05:00
										 |  |  |         extras = self.multiworld.creature_scans[self.player].value | 
					
						
							| 
									
										
										
										
											2023-03-23 21:21:11 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         grouped = set(itertools.chain.from_iterable(group_items.values())) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for item_id, item in item_table.items(): | 
					
						
							|  |  |  |             if item_id in grouped: | 
					
						
							|  |  |  |                 extras += item["count"] | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 for i in range(item["count"]): | 
					
						
							|  |  |  |                     subnautica_item = self.create_item(item["name"]) | 
					
						
							|  |  |  |                     if item["name"] == "Neptune Launch Platform": | 
					
						
							|  |  |  |                         self.multiworld.get_location("Aurora - Captain Data Terminal", self.player).place_locked_item( | 
					
						
							|  |  |  |                             subnautica_item) | 
					
						
							|  |  |  |                     else: | 
					
						
							|  |  |  |                         pool.append(subnautica_item) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         group_amount: int = 3 | 
					
						
							|  |  |  |         assert len(group_items) * group_amount <= extras | 
					
						
							|  |  |  |         for name in ("Furniture", "Farming"): | 
					
						
							|  |  |  |             for _ in range(group_amount): | 
					
						
							|  |  |  |                 pool.append(self.create_item(name)) | 
					
						
							|  |  |  |             extras -= group_amount | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for item_name in self.multiworld.random.choices( | 
					
						
							|  |  |  |                 sorted(Items.advancement_item_names -  {"Neptune Launch Platform"}), k=extras): | 
					
						
							| 
									
										
										
										
											2021-10-05 23:07:03 +02:00
										 |  |  |             item = self.create_item(item_name) | 
					
						
							|  |  |  |             pool.append(item) | 
					
						
							| 
									
										
										
										
											2021-09-17 04:32:36 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-31 21:41:21 -05:00
										 |  |  |         self.multiworld.itempool += pool | 
					
						
							| 
									
										
										
										
											2021-07-17 12:07:45 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-15 17:41:53 +02:00
										 |  |  |     def fill_slot_data(self) -> Dict[str, Any]: | 
					
						
							| 
									
										
										
										
											2022-10-31 21:41:21 -05:00
										 |  |  |         goal: Options.Goal = self.multiworld.goal[self.player] | 
					
						
							| 
									
										
										
										
											2023-02-16 00:40:19 +01:00
										 |  |  |         swim_rule: Options.SwimRule = self.multiworld.swim_rule[self.player] | 
					
						
							| 
									
										
										
										
											2022-07-15 17:41:53 +02:00
										 |  |  |         vanilla_tech: List[str] = [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         slot_data: Dict[str, Any] = { | 
					
						
							|  |  |  |             "goal": goal.current_key, | 
					
						
							| 
									
										
										
										
											2023-02-16 00:40:19 +01:00
										 |  |  |             "swim_rule": swim_rule.current_key, | 
					
						
							| 
									
										
										
										
											2022-07-15 17:41:53 +02:00
										 |  |  |             "vanilla_tech": vanilla_tech, | 
					
						
							| 
									
										
										
										
											2022-07-21 15:39:34 +02:00
										 |  |  |             "creatures_to_scan": self.creatures_to_scan, | 
					
						
							| 
									
										
										
										
											2022-10-31 21:41:21 -05:00
										 |  |  |             "death_link": self.multiworld.death_link[self.player].value, | 
					
						
							| 
									
										
										
										
											2022-07-15 17:41:53 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-07-17 12:07:45 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |         return slot_data | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-23 21:21:11 +01:00
										 |  |  |     def create_item(self, name: str) -> SubnauticaItem: | 
					
						
							| 
									
										
										
										
											2022-07-15 17:41:53 +02:00
										 |  |  |         item_id: int = self.item_name_to_id[name] | 
					
						
							| 
									
										
										
										
											2022-06-17 03:23:27 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-15 17:41:53 +02:00
										 |  |  |         return SubnauticaItem(name, | 
					
						
							|  |  |  |                               item_table[item_id]["classification"], | 
					
						
							|  |  |  |                               item_id, player=self.player) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def create_region(self, name: str, locations=None, exits=None): | 
					
						
							| 
									
										
										
										
											2023-02-13 18:06:43 -06:00
										 |  |  |         ret = Region(name, self.player, self.multiworld) | 
					
						
							| 
									
										
										
										
											2022-07-15 17:41:53 +02:00
										 |  |  |         if locations: | 
					
						
							|  |  |  |             for location in locations: | 
					
						
							|  |  |  |                 loc_id = self.location_name_to_id.get(location, None) | 
					
						
							|  |  |  |                 location = SubnauticaLocation(self.player, location, loc_id, ret) | 
					
						
							|  |  |  |                 ret.locations.append(location) | 
					
						
							|  |  |  |         if exits: | 
					
						
							|  |  |  |             for region_exit in exits: | 
					
						
							|  |  |  |                 ret.exits.append(Entrance(self.player, region_exit, ret)) | 
					
						
							|  |  |  |         return ret | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-17 12:07:45 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | class SubnauticaLocation(Location): | 
					
						
							|  |  |  |     game: str = "Subnautica" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class SubnauticaItem(Item): | 
					
						
							| 
									
										
										
										
											2022-07-15 17:41:53 +02:00
										 |  |  |     game: str = "Subnautica" |