Merge branch 'main' into add_dark_souls_III

This commit is contained in:
Marechal-l
2022-07-15 20:15:48 +02:00
16 changed files with 1213 additions and 777 deletions

View File

@@ -363,7 +363,8 @@ def main(args, seed=None, baked_server_options: Optional[Dict[str, object]] = No
for location in world.get_filled_locations():
if type(location.address) == int:
assert location.item.code is not None, "item code None should be event, " \
"location.address should then also be None"
"location.address should then also be None. Location: " \
f" {location}"
locations_data[location.player][location.address] = \
location.item.code, location.item.player, location.item.flags
if location.name in world.start_location_hints[location.player]:

View File

@@ -11,6 +11,8 @@ sm64courses = ["Bob-omb Battlefield", "Whomp's Fortress", "Jolly Roger Bay", "Co
"Wet-Dry World",
"Tall, Tall Mountain", "Tiny-Huge Island", "Tick Tock Clock", "Rainbow Ride"]
# sm64paintings is list of strings for quick reference for Painting IDs (NOT warp node IDs!)
sm64paintings = ["BOB", "WF", "JRB", "CCM", "BBH", "HMC", "LLL", "SSL", "DDD", "SL", "WDW", "TTM", "THI Tiny", "THI Huge", "TTC", "RR"]
def create_regions(world: MultiWorld, player: int):
regSS = Region("Menu", RegionType.Generic, "Castle Area", player, world)

View File

@@ -1,40 +1,50 @@
from ..generic.Rules import add_rule
from .Regions import connect_regions, sm64courses
from .Regions import connect_regions, sm64courses, sm64paintings
def set_rules(world, player: int, area_connections):
courseshuffle = list(range(len(sm64courses)))
entrance_ids = list(range(len(sm64paintings)))
destination_courses = list(range(13)) + [12,13,14] # Two instances of Destination Course THI
if world.AreaRandomizer[player]:
world.random.shuffle(courseshuffle)
area_connections.update({index: value for index, value in enumerate(courseshuffle)})
world.random.shuffle(entrance_ids)
temp_assign = dict(zip(entrance_ids,destination_courses)) # Used for Rules only
connect_regions(world, player, "Menu", sm64courses[area_connections[0]])
connect_regions(world, player, "Menu", sm64courses[area_connections[1]], lambda state: state.has("Power Star", player, 1))
connect_regions(world, player, "Menu", sm64courses[area_connections[2]], lambda state: state.has("Power Star", player, 3))
connect_regions(world, player, "Menu", sm64courses[area_connections[3]], lambda state: state.has("Power Star", player, 3))
# Destination Format: LVL | AREA with LVL = Course ID, 0-indexed, AREA = Area as used in sm64 code
area_connections.update({entrance: (destination_course*10 + 1) for entrance, destination_course in temp_assign.items()})
for i in range(len(area_connections)):
if (int(area_connections[i]/10) == 12):
# Change first occurence of course 12 (THI) to Area 2 (THI Tiny)
area_connections[i] = 12*10 + 2
break
connect_regions(world, player, "Menu", sm64courses[temp_assign[0]])
connect_regions(world, player, "Menu", sm64courses[temp_assign[1]], lambda state: state.has("Power Star", player, 1))
connect_regions(world, player, "Menu", sm64courses[temp_assign[2]], lambda state: state.has("Power Star", player, 3))
connect_regions(world, player, "Menu", sm64courses[temp_assign[3]], lambda state: state.has("Power Star", player, 3))
connect_regions(world, player, "Menu", "Bowser in the Dark World", lambda state: state.has("Power Star", player, world.FirstBowserStarDoorCost[player].value))
connect_regions(world, player, "Menu", sm64courses[area_connections[4]], lambda state: state.has("Power Star", player, 12))
connect_regions(world, player, "Menu", sm64courses[temp_assign[4]], lambda state: state.has("Power Star", player, 12))
connect_regions(world, player, "Menu", "Basement", lambda state: state.has("Basement Key", player) or state.has("Progressive Key", player, 1))
connect_regions(world, player, "Basement", sm64courses[area_connections[5]])
connect_regions(world, player, "Basement", sm64courses[area_connections[6]])
connect_regions(world, player, "Basement", sm64courses[area_connections[7]])
connect_regions(world, player, "Basement", sm64courses[area_connections[8]], lambda state: state.has("Power Star", player, world.BasementStarDoorCost[player].value))
connect_regions(world, player, "Basement", sm64courses[temp_assign[5]])
connect_regions(world, player, "Basement", sm64courses[temp_assign[6]])
connect_regions(world, player, "Basement", sm64courses[temp_assign[7]])
connect_regions(world, player, "Basement", sm64courses[temp_assign[8]], lambda state: state.has("Power Star", player, world.BasementStarDoorCost[player].value))
connect_regions(world, player, "Basement", "Bowser in the Fire Sea", lambda state: state.has("Power Star", player, world.BasementStarDoorCost[player].value) and
state.can_reach("DDD: Board Bowser's Sub", 'Location', player))
connect_regions(world, player, "Menu", "Second Floor", lambda state: state.has("Second Floor Key", player) or state.has("Progressive Key", player, 2))
connect_regions(world, player, "Second Floor", sm64courses[area_connections[9]])
connect_regions(world, player, "Second Floor", sm64courses[area_connections[10]])
connect_regions(world, player, "Second Floor", sm64courses[area_connections[11]])
connect_regions(world, player, "Second Floor", sm64courses[area_connections[12]])
connect_regions(world, player, "Second Floor", sm64courses[temp_assign[9]])
connect_regions(world, player, "Second Floor", sm64courses[temp_assign[10]])
connect_regions(world, player, "Second Floor", sm64courses[temp_assign[11]])
connect_regions(world, player, "Second Floor", sm64courses[temp_assign[12]]) # THI Tiny
connect_regions(world, player, "Second Floor", sm64courses[temp_assign[13]]) # THI Huge
connect_regions(world, player, "Second Floor", "Third Floor", lambda state: state.has("Power Star", player, world.SecondFloorStarDoorCost[player].value))
connect_regions(world, player, "Third Floor", sm64courses[area_connections[13]])
connect_regions(world, player, "Third Floor", sm64courses[area_connections[14]])
connect_regions(world, player, "Third Floor", sm64courses[temp_assign[14]])
connect_regions(world, player, "Third Floor", sm64courses[temp_assign[15]])
#Special Rules for some Locations
add_rule(world.get_location("Tower of the Wing Cap Switch", player), lambda state: state.has("Power Star", player, 10))

View File

@@ -5,7 +5,7 @@ from .Items import item_table, cannon_item_table, SM64Item
from .Locations import location_table, SM64Location
from .Options import sm64_options
from .Rules import set_rules
from .Regions import create_regions, sm64courses
from .Regions import create_regions, sm64courses, sm64paintings
from BaseClasses import Item, Tutorial, ItemClassification
from ..AutoWorld import World, WebWorld
@@ -35,7 +35,7 @@ class SM64World(World):
location_name_to_id = location_table
data_version = 6
client_version = 2
required_client_version = (0,3,0)
forced_auto_forfeit = False
@@ -54,10 +54,10 @@ class SM64World(World):
set_rules(self.world, self.player, self.area_connections)
if self.topology_present:
# Write area_connections to spoiler log
for painting_id, course_id in self.area_connections.items():
for painting_id, destination in self.area_connections.items():
self.world.spoiler.set_entrance(
sm64courses[painting_id] + " Painting",
sm64courses[course_id],
sm64paintings[painting_id] + " Painting",
sm64courses[destination // 10],
'entrance', self.player)
def create_item(self, name: str) -> Item:
@@ -145,8 +145,8 @@ class SM64World(World):
def modify_multidata(self, multidata):
if self.topology_present:
er_hint_data = {}
for painting_id, course_id in self.area_connections.items():
region = self.world.get_region(sm64courses[course_id], self.player)
for painting_id, destination in self.area_connections.items():
region = self.world.get_region(sm64courses[destination // 10], self.player)
for location in region.locations:
er_hint_data[location.address] = sm64courses[painting_id]
er_hint_data[location.address] = sm64paintings[painting_id]
multidata['er_hint_data'][self.player] = er_hint_data

View File

@@ -1,5 +1,6 @@
from BaseClasses import MultiWorld
from ..AutoWorld import LogicMixin
from .Options import EnergyCore
from typing import Set
# TODO: Options may preset certain progress steps (i.e. P_ROCK_SKIP), set in generate_early?
@@ -8,9 +9,9 @@ from . import pyevermizer
# TODO: resolve/flatten/expand rules to get rid of recursion below where possible
# Logic.rules are all rules including locations, excluding those with no progress (i.e. locations that only drop items)
rules = [rule for rule in pyevermizer.get_logic() if len(rule.provides) > 0]
# Logic.items are all items excluding non-progression items and duplicates
# Logic.items are all items and extra items excluding non-progression items and duplicates
item_names: Set[str] = set()
items = [item for item in filter(lambda item: item.progression, pyevermizer.get_items())
items = [item for item in filter(lambda item: item.progression, pyevermizer.get_items() + pyevermizer.get_extra_items())
if item.name not in item_names and not item_names.add(item.name)]
@@ -47,4 +48,9 @@ class SecretOfEvermoreLogic(LogicMixin):
"""
Returns True if count of one of evermizer's progress steps is reached based on collected items. i.e. 2 * P_DE
"""
if progress == pyevermizer.P_ENERGY_CORE: # logic is shared between worlds, so we override in the call
w = world.worlds[player]
if w.energy_core == EnergyCore.option_fragments:
progress = pyevermizer.P_CORE_FRAGMENT
count = w.required_fragments
return self._soe_count(progress, world, player, count) >= count

View File

@@ -37,6 +37,32 @@ class Difficulty(EvermizerFlags, Choice):
flags = ['e', 'n', 'h', 'x']
class EnergyCore(EvermizerFlags, Choice):
"""How to obtain the Energy Core"""
display_name = "Energy Core"
option_vanilla = 0
option_shuffle = 1
option_fragments = 2
default = 1
flags = ['z', '', 'Z']
class RequiredFragments(Range):
"""Required fragment count for Energy Core = Fragments"""
display_name = "Required Fragments"
range_start = 1
range_end = 99
default = 10
class AvailableFragments(Range):
"""Placed fragment count for Energy Core = Fragments"""
display_name = "Available Fragments"
range_start = 1
range_end = 99
default = 11
class MoneyModifier(Range):
"""Money multiplier in %"""
display_name = "Money Modifier"
@@ -186,10 +212,15 @@ class TrapChanceOHKO(TrapChance):
class SoEProgressionBalancing(ProgressionBalancing):
default = 30
__doc__ = ProgressionBalancing.__doc__.replace(f"default {ProgressionBalancing.default}", f"default {default}")
special_range_names = {**ProgressionBalancing.special_range_names, "normal": default}
soe_options: typing.Dict[str, type(Option)] = {
"difficulty": Difficulty,
"energy_core": EnergyCore,
"required_fragments": RequiredFragments,
"available_fragments": AvailableFragments,
"money_modifier": MoneyModifier,
"exp_modifier": ExpModifier,
"fix_sequence": FixSequence,

View File

@@ -16,7 +16,7 @@ except ImportError:
from . import pyevermizer # as part of the source tree
from . import Logic # load logic mixin
from .Options import soe_options
from .Options import soe_options, EnergyCore, RequiredFragments, AvailableFragments
from .Patch import SoEDeltaPatch, get_base_rom_path
"""
@@ -52,7 +52,6 @@ Item grouping currently supports
* Ingredients - Matches all ingredient drops
* Alchemy - Matches all alchemy formulas
* Weapons - Matches all weapons but Bazooka, Bone Crusher, Neutron Blade
* Bazooka - Matches all bazookas (currently only one)
* Traps - Matches all traps
"""
@@ -63,12 +62,14 @@ _id_offset: typing.Dict[int, int] = {
pyevermizer.CHECK_GOURD: _id_base + 100, # gourds 64100..64399
pyevermizer.CHECK_NPC: _id_base + 400, # npc 64400..64499
# TODO: sniff 64500..64799
pyevermizer.CHECK_TRAP: _id_base + 900, # npc 64900..64999
pyevermizer.CHECK_EXTRA: _id_base + 800, # extra items 64800..64899
pyevermizer.CHECK_TRAP: _id_base + 900, # trap 64900..64999
}
# cache native evermizer items and locations
_items = pyevermizer.get_items()
_traps = pyevermizer.get_traps()
_extras = pyevermizer.get_extra_items() # items that are not placed by default
_locations = pyevermizer.get_locations()
# fix up texts for AP
for _loc in _locations:
@@ -104,7 +105,7 @@ def _get_location_mapping() -> typing.Tuple[typing.Dict[str, int], typing.Dict[i
def _get_item_mapping() -> typing.Tuple[typing.Dict[str, int], typing.Dict[int, pyevermizer.Item]]:
name_to_id = {}
id_to_raw = {}
for item in itertools.chain(_items, _traps):
for item in itertools.chain(_items, _extras, _traps):
if item.name in name_to_id:
continue
ap_id = _id_offset[item.type] + item.index
@@ -127,7 +128,6 @@ def _get_item_grouping() -> typing.Dict[str, typing.Set[str]]:
groups['Alchemy'] = set(item.name for item in _items if item.type == pyevermizer.CHECK_ALCHEMY)
groups['Weapons'] = {'Spider Claw', 'Horn Spear', 'Gladiator Sword', 'Bronze Axe', 'Bronze Spear', 'Crusader Sword',
'Lance (Weapon)', 'Knight Basher', 'Atom Smasher', 'Laser Lance'}
groups['Bazooka'] = {'Bazooka+Shells / Shining Armor / 5k Gold'}
groups['Traps'] = {trap.name for trap in _traps}
return groups
@@ -136,7 +136,8 @@ class SoEWebWorld(WebWorld):
theme = 'jungle'
tutorials = [Tutorial(
"Multiworld Setup Guide",
"A guide to playing Secret of Evermore randomizer. This guide covers single-player, multiworld and related software.",
"A guide to playing Secret of Evermore randomizer. This guide covers single-player, multiworld and related"
" software.",
"English",
"multiworld_en.md",
"multiworld/en",
@@ -153,9 +154,9 @@ class SoEWorld(World):
options = soe_options
topology_present = False
remote_items = False
data_version = 2
data_version = 3
web = SoEWebWorld()
required_client_version = (0, 2, 6)
required_client_version = (0, 3, 3)
item_name_to_id, item_id_to_raw = _get_item_mapping()
location_name_to_id, location_id_to_raw = _get_location_mapping()
@@ -165,6 +166,9 @@ class SoEWorld(World):
evermizer_seed: int
connect_name: str
energy_core: int
available_fragments: int
required_fragments: int
_halls_ne_chest_names: typing.List[str] = [loc.name for loc in _locations if 'Halls NE' in loc.name]
@@ -172,6 +176,14 @@ class SoEWorld(World):
self.connect_name_available_event = threading.Event()
super(SoEWorld, self).__init__(*args, **kwargs)
def generate_early(self) -> None:
# store option values that change logic
self.energy_core = self.world.energy_core[self.player].value
self.required_fragments = self.world.required_fragments[self.player].value
if self.required_fragments > self.world.available_fragments[self.player].value:
self.world.available_fragments[self.player].value = self.required_fragments
self.available_fragments = self.world.available_fragments[self.player].value
def create_event(self, event: str) -> Item:
return SoEItem(event, ItemClassification.progression, None, self.player)
@@ -182,6 +194,8 @@ class SoEWorld(World):
classification = ItemClassification.trap
elif item.progression:
classification = ItemClassification.progression
elif item.useful:
classification = ItemClassification.useful
else:
classification = ItemClassification.filler
@@ -208,9 +222,33 @@ class SoEWorld(World):
self.world.get_entrance('New Game', self.player).connect(self.world.get_region('Ingame', self.player))
def create_items(self):
# add items to the pool
items = list(map(lambda item: self.create_item(item), _items))
# add regular items to the pool
exclusions: typing.List[str] = []
if self.energy_core != EnergyCore.option_shuffle:
exclusions.append("Energy Core") # will be placed in generate_basic or replaced by a fragment below
items = list(map(lambda item: self.create_item(item), (item for item in _items if item.name not in exclusions)))
# remove one pair of wings that will be placed in generate_basic
items.remove(self.create_item("Wings"))
def is_ingredient(item):
for ingredient in _ingredients:
if _match_item_name(item, ingredient):
return True
return False
# add energy core fragments to the pool
ingredients = [n for n, item in enumerate(items) if is_ingredient(item)]
if self.energy_core == EnergyCore.option_fragments:
items.append(self.create_item("Energy Core Fragment")) # replaces the vanilla energy core
for _ in range(self.available_fragments - 1):
if len(ingredients) < 1:
break # out of ingredients to replace
r = self.world.random.choice(ingredients)
ingredients.remove(r)
items[r] = self.create_item("Energy Core Fragment")
# add traps to the pool
trap_count = self.world.trap_count[self.player].value
trap_chances = {}
trap_names = {}
@@ -232,13 +270,12 @@ class SoEWorld(World):
return self.create_item(trap_names[t])
v -= c
while trap_count > 0:
r = self.world.random.randrange(len(items))
for ingredient in _ingredients:
if _match_item_name(items[r], ingredient):
items[r] = create_trap()
trap_count -= 1
break
for _ in range(trap_count):
if len(ingredients) < 1:
break # out of ingredients to replace
r = self.world.random.choice(ingredients)
ingredients.remove(r)
items[r] = create_trap()
self.world.itempool += items
@@ -271,7 +308,10 @@ class SoEWorld(World):
wings_location = self.world.random.choice(self._halls_ne_chest_names)
wings_item = self.create_item('Wings')
self.world.get_location(wings_location, self.player).place_locked_item(wings_item)
self.world.itempool.remove(wings_item)
# place energy core at vanilla location for vanilla mode
if self.energy_core == EnergyCore.option_vanilla:
energy_core = self.create_item('Energy Core')
self.world.get_location('Energy Core #285', self.player).place_locked_item(energy_core)
# generate stuff for later
self.evermizer_seed = self.world.random.randint(0, 2 ** 16 - 1) # TODO: make this an option for "full" plando?
@@ -286,9 +326,12 @@ class SoEWorld(World):
try:
money = self.world.money_modifier[self.player].value
exp = self.world.exp_modifier[self.player].value
switches = []
switches: typing.List[str] = []
if self.world.death_link[self.player].value:
switches.append("--death-link")
if self.energy_core == EnergyCore.option_fragments:
switches.extend(('--available-fragments', str(self.available_fragments),
'--required-fragments', str(self.required_fragments)))
rom_file = get_base_rom_path()
out_base = output_path(output_directory, f'AP_{self.world.seed_name}_P{self.player}_'
f'{self.world.get_file_safe_player_name(self.player)}')

View File

@@ -1,14 +1,14 @@
https://github.com/black-sliver/pyevermizer/releases/download/v0.41.2/pyevermizer-0.41.2-cp38-cp38-win_amd64.whl#egg=pyevermizer; sys_platform == 'win32' and platform_machine == 'AMD64' and python_version == '3.8'
https://github.com/black-sliver/pyevermizer/releases/download/v0.41.2/pyevermizer-0.41.2-cp39-cp39-win_amd64.whl#egg=pyevermizer; sys_platform == 'win32' and platform_machine == 'AMD64' and python_version == '3.9'
https://github.com/black-sliver/pyevermizer/releases/download/v0.41.2/pyevermizer-0.41.2-cp310-cp310-win_amd64.whl#egg=pyevermizer; sys_platform == 'win32' and platform_machine == 'AMD64' and python_version == '3.10'
https://github.com/black-sliver/pyevermizer/releases/download/v0.41.2/pyevermizer-0.41.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl#egg=pyevermizer; sys_platform == 'linux' and platform_machine == 'x86_64' and python_version == '3.8'
https://github.com/black-sliver/pyevermizer/releases/download/v0.41.2/pyevermizer-0.41.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl#egg=pyevermizer; sys_platform == 'linux' and platform_machine == 'x86_64' and python_version == '3.9'
https://github.com/black-sliver/pyevermizer/releases/download/v0.41.2/pyevermizer-0.41.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl#egg=pyevermizer; sys_platform == 'linux' and platform_machine == 'x86_64' and python_version == '3.10'
https://github.com/black-sliver/pyevermizer/releases/download/v0.41.2/pyevermizer-0.41.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl#egg=pyevermizer; sys_platform == 'linux' and platform_machine == 'aarch64' and python_version == '3.8'
https://github.com/black-sliver/pyevermizer/releases/download/v0.41.2/pyevermizer-0.41.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl#egg=pyevermizer; sys_platform == 'linux' and platform_machine == 'aarch64' and python_version == '3.9'
https://github.com/black-sliver/pyevermizer/releases/download/v0.41.2/pyevermizer-0.41.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl#egg=pyevermizer; sys_platform == 'linux' and platform_machine == 'aarch64' and python_version == '3.10'
https://github.com/black-sliver/pyevermizer/releases/download/v0.41.2/pyevermizer-0.41.2-cp38-cp38-macosx_10_9_x86_64.whl#egg=pyevermizer; sys_platform == 'darwin' and python_version == '3.8'
#https://github.com/black-sliver/pyevermizer/releases/download/v0.41.2/pyevermizer-0.41.2-cp39-cp39-macosx_10_9_x86_64.whl#egg=pyevermizer; sys_platform == 'darwin' and python_version == '3.9'
https://github.com/black-sliver/pyevermizer/releases/download/v0.41.2/pyevermizer-0.41.2-cp39-cp39-macosx_10_9_universal2.whl#egg=pyevermizer; sys_platform == 'darwin' and python_version == '3.9'
https://github.com/black-sliver/pyevermizer/releases/download/v0.41.2/pyevermizer-0.41.2-cp310-cp310-macosx_10_9_universal2.whl#egg=pyevermizer; sys_platform == 'darwin' and python_version == '3.10'
#https://github.com/black-sliver/pyevermizer/releases/download/v0.41.2/pyevermizer-0.41.2.tar.gz#egg=pyevermizer; python_version == '3.11'
https://github.com/black-sliver/pyevermizer/releases/download/v0.41.3/pyevermizer-0.41.3-cp38-cp38-win_amd64.whl#egg=pyevermizer; sys_platform == 'win32' and platform_machine == 'AMD64' and python_version == '3.8'
https://github.com/black-sliver/pyevermizer/releases/download/v0.41.3/pyevermizer-0.41.3-cp39-cp39-win_amd64.whl#egg=pyevermizer; sys_platform == 'win32' and platform_machine == 'AMD64' and python_version == '3.9'
https://github.com/black-sliver/pyevermizer/releases/download/v0.41.3/pyevermizer-0.41.3-cp310-cp310-win_amd64.whl#egg=pyevermizer; sys_platform == 'win32' and platform_machine == 'AMD64' and python_version == '3.10'
https://github.com/black-sliver/pyevermizer/releases/download/v0.41.3/pyevermizer-0.41.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl#egg=pyevermizer; sys_platform == 'linux' and platform_machine == 'x86_64' and python_version == '3.8'
https://github.com/black-sliver/pyevermizer/releases/download/v0.41.3/pyevermizer-0.41.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl#egg=pyevermizer; sys_platform == 'linux' and platform_machine == 'x86_64' and python_version == '3.9'
https://github.com/black-sliver/pyevermizer/releases/download/v0.41.3/pyevermizer-0.41.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl#egg=pyevermizer; sys_platform == 'linux' and platform_machine == 'x86_64' and python_version == '3.10'
https://github.com/black-sliver/pyevermizer/releases/download/v0.41.3/pyevermizer-0.41.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl#egg=pyevermizer; sys_platform == 'linux' and platform_machine == 'aarch64' and python_version == '3.8'
https://github.com/black-sliver/pyevermizer/releases/download/v0.41.3/pyevermizer-0.41.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl#egg=pyevermizer; sys_platform == 'linux' and platform_machine == 'aarch64' and python_version == '3.9'
https://github.com/black-sliver/pyevermizer/releases/download/v0.41.3/pyevermizer-0.41.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl#egg=pyevermizer; sys_platform == 'linux' and platform_machine == 'aarch64' and python_version == '3.10'
https://github.com/black-sliver/pyevermizer/releases/download/v0.41.3/pyevermizer-0.41.3-cp38-cp38-macosx_10_9_x86_64.whl#egg=pyevermizer; sys_platform == 'darwin' and python_version == '3.8'
#https://github.com/black-sliver/pyevermizer/releases/download/v0.41.3/pyevermizer-0.41.3-cp39-cp39-macosx_10_9_x86_64.whl#egg=pyevermizer; sys_platform == 'darwin' and python_version == '3.9'
https://github.com/black-sliver/pyevermizer/releases/download/v0.41.3/pyevermizer-0.41.3-cp39-cp39-macosx_10_9_universal2.whl#egg=pyevermizer; sys_platform == 'darwin' and python_version == '3.9'
https://github.com/black-sliver/pyevermizer/releases/download/v0.41.3/pyevermizer-0.41.3-cp310-cp310-macosx_10_9_universal2.whl#egg=pyevermizer; sys_platform == 'darwin' and python_version == '3.10'
#https://github.com/black-sliver/pyevermizer/releases/download/v0.41.3/pyevermizer-0.41.3.tar.gz#egg=pyevermizer; python_version == '3.11'

View File

@@ -1,23 +1,353 @@
import json
import os
from BaseClasses import ItemClassification
from typing import TypedDict, Dict, Set
with open(os.path.join(os.path.dirname(__file__), 'items.json'), 'r') as file:
item_table = json.loads(file.read())
lookup_id_to_name = {}
lookup_name_to_item = {}
advancement_item_names = set()
non_advancement_item_names = set()
class ItemDict(TypedDict):
classification: ItemClassification
count: int
name: str
tech_type: str
for item in item_table:
item_name = item["name"]
lookup_id_to_name[item["id"]] = item_name
lookup_name_to_item[item_name] = item
if item["progression"]:
item_table: Dict[int, ItemDict] = {
35000: {'classification': ItemClassification.useful,
'count': 1,
'name': 'Compass',
'tech_type': 'Compass'},
35001: {'classification': ItemClassification.progression,
'count': 1,
'name': 'Lightweight High Capacity Tank',
'tech_type': 'PlasteelTank'},
35002: {'classification': ItemClassification.progression,
'count': 1,
'name': 'Vehicle Upgrade Console',
'tech_type': 'BaseUpgradeConsole'},
35003: {'classification': ItemClassification.progression,
'count': 1,
'name': 'Ultra Glide Fins',
'tech_type': 'UltraGlideFins'},
35004: {'classification': ItemClassification.useful,
'count': 1,
'name': 'Cyclops Sonar Upgrade',
'tech_type': 'CyclopsSonarModule'},
35005: {'classification': ItemClassification.useful,
'count': 1,
'name': 'Reinforced Dive Suit',
'tech_type': 'ReinforcedDiveSuit'},
35006: {'classification': ItemClassification.useful,
'count': 1,
'name': 'Cyclops Thermal Reactor Module',
'tech_type': 'CyclopsThermalReactorModule'},
35007: {'classification': ItemClassification.filler,
'count': 1,
'name': 'Stillsuit',
'tech_type': 'Stillsuit'},
35008: {'classification': ItemClassification.filler,
'count': 2,
'name': 'Alien Containment Fragment',
'tech_type': 'BaseWaterParkFragment'},
35009: {'classification': ItemClassification.useful,
'count': 1,
'name': 'Creature Decoy',
'tech_type': 'CyclopsDecoy'},
35010: {'classification': ItemClassification.useful,
'count': 1,
'name': 'Cyclops Fire Suppression System',
'tech_type': 'CyclopsFireSuppressionModule'},
35011: {'classification': ItemClassification.useful,
'count': 1,
'name': 'Swim Charge Fins',
'tech_type': 'SwimChargeFins'},
35012: {'classification': ItemClassification.useful,
'count': 1,
'name': 'Repulsion Cannon',
'tech_type': 'RepulsionCannon'},
35013: {'classification': ItemClassification.useful,
'count': 1,
'name': 'Cyclops Decoy Tube Upgrade',
'tech_type': 'CyclopsDecoyModule'},
35014: {'classification': ItemClassification.progression,
'count': 1,
'name': 'Cyclops Shield Generator',
'tech_type': 'CyclopsShieldModule'},
35015: {'classification': ItemClassification.progression,
'count': 1,
'name': 'Cyclops Depth Module MK1',
'tech_type': 'CyclopsHullModule1'},
35016: {'classification': ItemClassification.useful,
'count': 1,
'name': 'Cyclops Docking Bay Repair Module',
'tech_type': 'CyclopsSeamothRepairModule'},
35017: {'classification': ItemClassification.useful,
'count': 2,
'name': 'Battery Charger fragment',
'tech_type': 'BatteryChargerFragment'},
35018: {'classification': ItemClassification.filler,
'count': 2,
'name': 'Beacon Fragment',
'tech_type': 'BeaconFragment'},
35019: {'classification': ItemClassification.useful,
'count': 2,
'name': 'Bioreactor Fragment',
'tech_type': 'BaseBioReactorFragment'},
35020: {'classification': ItemClassification.progression,
'count': 3,
'name': 'Cyclops Bridge Fragment',
'tech_type': 'CyclopsBridgeFragment'},
35021: {'classification': ItemClassification.progression,
'count': 3,
'name': 'Cyclops Engine Fragment',
'tech_type': 'CyclopsEngineFragment'},
35022: {'classification': ItemClassification.progression,
'count': 3,
'name': 'Cyclops Hull Fragment',
'tech_type': 'CyclopsHullFragment'},
35023: {'classification': ItemClassification.filler,
'count': 2,
'name': 'Grav Trap Fragment',
'tech_type': 'GravSphereFragment'},
35024: {'classification': ItemClassification.progression,
'count': 3,
'name': 'Laser Cutter Fragment',
'tech_type': 'LaserCutterFragment'},
35025: {'classification': ItemClassification.filler,
'count': 1,
'name': 'Light Stick Fragment',
'tech_type': 'TechlightFragment'},
35026: {'classification': ItemClassification.progression,
'count': 3,
'name': 'Mobile Vehicle Bay Fragment',
'tech_type': 'ConstructorFragment'},
35027: {'classification': ItemClassification.progression,
'count': 3,
'name': 'Modification Station Fragment',
'tech_type': 'WorkbenchFragment'},
35028: {'classification': ItemClassification.progression,
'count': 2,
'name': 'Moonpool Fragment',
'tech_type': 'MoonpoolFragment'},
35029: {'classification': ItemClassification.useful,
'count': 3,
'name': 'Nuclear Reactor Fragment',
'tech_type': 'BaseNuclearReactorFragment'},
35030: {'classification': ItemClassification.useful,
'count': 2,
'name': 'Power Cell Charger Fragment',
'tech_type': 'PowerCellChargerFragment'},
35031: {'classification': ItemClassification.filler,
'count': 1,
'name': 'Power Transmitter Fragment',
'tech_type': 'PowerTransmitterFragment'},
35032: {'classification': ItemClassification.progression,
'count': 4,
'name': 'Prawn Suit Fragment',
'tech_type': 'ExosuitFragment'},
35033: {'classification': ItemClassification.useful,
'count': 2,
'name': 'Prawn Suit Drill Arm Fragment',
'tech_type': 'ExosuitDrillArmFragment'},
35034: {'classification': ItemClassification.useful,
'count': 2,
'name': 'Prawn Suit Grappling Arm Fragment',
'tech_type': 'ExosuitGrapplingArmFragment'},
35035: {'classification': ItemClassification.useful,
'count': 2,
'name': 'Prawn Suit Propulsion Cannon Fragment',
'tech_type': 'ExosuitPropulsionArmFragment'},
35036: {'classification': ItemClassification.useful,
'count': 2,
'name': 'Prawn Suit Torpedo Arm Fragment',
'tech_type': 'ExosuitTorpedoArmFragment'},
35037: {'classification': ItemClassification.useful,
'count': 3,
'name': 'Scanner Room Fragment',
'tech_type': 'BaseMapRoomFragment'},
35038: {'classification': ItemClassification.progression,
'count': 5,
'name': 'Seamoth Fragment',
'tech_type': 'SeamothFragment'},
35039: {'classification': ItemClassification.useful,
'count': 2,
'name': 'Stasis Rifle Fragment',
'tech_type': 'StasisRifleFragment'},
35040: {'classification': ItemClassification.useful,
'count': 2,
'name': 'Thermal Plant Fragment',
'tech_type': 'ThermalPlantFragment'},
35041: {'classification': ItemClassification.progression,
'count': 2,
'name': 'Seaglide Fragment',
'tech_type': 'SeaglideFragment'},
35042: {'classification': ItemClassification.progression,
'count': 1,
'name': 'Radiation Suit',
'tech_type': 'RadiationSuit'},
35043: {'classification': ItemClassification.progression,
'count': 2,
'name': 'Propulsion Cannon Fragment',
'tech_type': 'PropulsionCannonFragment'},
35044: {'classification': ItemClassification.progression,
'count': 1,
'name': 'Neptune Launch Platform',
'tech_type': 'RocketBase'},
35045: {'classification': ItemClassification.progression,
'count': 1,
'name': 'Ion Power Cell',
'tech_type': 'PrecursorIonPowerCell'},
35046: {'classification': ItemClassification.filler,
'count': 2,
'name': 'Exterior Growbed Fragment',
'tech_type': 'FarmingTrayFragment'},
35047: {'classification': ItemClassification.filler,
'count': 1,
'name': 'Picture Frame',
'tech_type': 'PictureFrameFragment'},
35048: {'classification': ItemClassification.filler,
'count': 2,
'name': 'Bench Fragment',
'tech_type': 'BenchFragment'},
35049: {'classification': ItemClassification.filler,
'count': 1,
'name': 'Basic Plant Pot',
'tech_type': 'PlanterPotFragment'},
35050: {'classification': ItemClassification.filler,
'count': 1,
'name': 'Interior Growbed',
'tech_type': 'PlanterBoxFragment'},
35051: {'classification': ItemClassification.filler,
'count': 1,
'name': 'Plant Shelf',
'tech_type': 'PlanterShelfFragment'},
35052: {'classification': ItemClassification.filler,
'count': 2,
'name': 'Observatory Fragment',
'tech_type': 'BaseObservatoryFragment'},
35053: {'classification': ItemClassification.filler,
'count': 2,
'name': 'Multipurpose Room Fragment',
'tech_type': 'BaseRoomFragment'},
35054: {'classification': ItemClassification.useful,
'count': 2,
'name': 'Bulkhead Fragment',
'tech_type': 'BaseBulkheadFragment'},
35055: {'classification': ItemClassification.filler,
'count': 1,
'name': 'Spotlight',
'tech_type': 'Spotlight'},
35056: {'classification': ItemClassification.filler,
'count': 2,
'name': 'Desk',
'tech_type': 'StarshipDesk'},
35057: {'classification': ItemClassification.filler,
'count': 1,
'name': 'Swivel Chair',
'tech_type': 'StarshipChair'},
35058: {'classification': ItemClassification.filler,
'count': 1,
'name': 'Office Chair',
'tech_type': 'StarshipChair2'},
35059: {'classification': ItemClassification.filler,
'count': 1,
'name': 'Command Chair',
'tech_type': 'StarshipChair3'},
35060: {'classification': ItemClassification.filler,
'count': 2,
'name': 'Counter',
'tech_type': 'LabCounter'},
35061: {'classification': ItemClassification.filler,
'count': 1,
'name': 'Single Bed',
'tech_type': 'NarrowBed'},
35062: {'classification': ItemClassification.filler,
'count': 1,
'name': 'Basic Double Bed',
'tech_type': 'Bed1'},
35063: {'classification': ItemClassification.filler,
'count': 1,
'name': 'Quilted Double Bed',
'tech_type': 'Bed2'},
35064: {'classification': ItemClassification.filler,
'count': 2,
'name': 'Coffee Vending Machine',
'tech_type': 'CoffeeVendingMachine'},
35065: {'classification': ItemClassification.filler,
'count': 2,
'name': 'Trash Can',
'tech_type': 'Trashcans'},
35066: {'classification': ItemClassification.filler,
'count': 1,
'name': 'Floodlight',
'tech_type': 'Techlight'},
35067: {'classification': ItemClassification.filler,
'count': 1,
'name': 'Bar Table',
'tech_type': 'BarTable'},
35068: {'classification': ItemClassification.filler,
'count': 1,
'name': 'Vending Machine',
'tech_type': 'VendingMachine'},
35069: {'classification': ItemClassification.filler,
'count': 1,
'name': 'Single Wall Shelf',
'tech_type': 'SingleWallShelf'},
35070: {'classification': ItemClassification.filler,
'count': 1,
'name': 'Wall Shelves',
'tech_type': 'WallShelves'},
35071: {'classification': ItemClassification.filler,
'count': 1,
'name': 'Round Plant Pot',
'tech_type': 'PlanterPot2'},
35072: {'classification': ItemClassification.filler,
'count': 1,
'name': 'Chic Plant Pot',
'tech_type': 'PlanterPot3'},
35073: {'classification': ItemClassification.filler,
'count': 1,
'name': 'Nuclear Waste Disposal',
'tech_type': 'LabTrashcan'},
35074: {'classification': ItemClassification.filler,
'count': 1,
'name': 'Wall Planter',
'tech_type': 'BasePlanter'},
35075: {'classification': ItemClassification.progression,
'count': 1,
'name': 'Ion Battery',
'tech_type': 'PrecursorIonBattery'},
35076: {'classification': ItemClassification.progression,
'count': 1,
'name': 'Neptune Gantry',
'tech_type': 'RocketBaseLadder'},
35077: {'classification': ItemClassification.progression,
'count': 1,
'name': 'Neptune Boosters',
'tech_type': 'RocketStage1'},
35078: {'classification': ItemClassification.progression,
'count': 1,
'name': 'Neptune Fuel Reserve',
'tech_type': 'RocketStage2'},
35079: {'classification': ItemClassification.progression,
'count': 1,
'name': 'Neptune Cockpit',
'tech_type': 'RocketStage3'},
35080: {'classification': ItemClassification.filler,
'count': 1,
'name': 'Water Filtration Machine',
'tech_type': 'BaseFiltrationMachine'}}
advancement_item_names: Set[str] = set()
non_advancement_item_names: Set[str] = set()
for item_id, item_data in item_table.items():
item_name = item_data["name"]
if ItemClassification.progression in item_data["classification"]:
advancement_item_names.add(item_name)
else:
non_advancement_item_names.add(item_name)
lookup_id_to_name[None] = "Victory"
if False: # turn to True to export for Subnautica mod
payload = {item_id: item_data["tech_type"] for item_id, item_data in item_table.items()}
import json
lookup_name_to_id = {name: id for id, name in lookup_id_to_name.items()}
with open("items.json", "w") as f:
json.dump(payload, f)

View File

@@ -1,12 +1,570 @@
import json
import os
from typing import Dict, TypedDict, List
with open(os.path.join(os.path.dirname(__file__), 'locations.json'), 'r') as file:
location_table = json.loads(file.read())
lookup_id_to_name = {}
for item in location_table:
lookup_id_to_name[item["id"]] = item["name"]
class Vector(TypedDict):
x: float
y: float
z: float
lookup_id_to_name[None] = "Neptune Launch"
lookup_name_to_id = {name: id for id, name in lookup_id_to_name.items()}
class LocationDict(TypedDict, total=False):
name: str
can_slip_through: bool
need_laser_cutter: bool
position: Vector
need_propulsion_cannon: bool
events: List[str] = ["Neptune Launch", "Disable Quarantine", "Full Infection", "Repair Aurora Drive"]
location_table: Dict[int, LocationDict] = {
33000: {'can_slip_through': False,
'name': 'Blood Kelp Trench Wreck - Outside Databox',
'need_laser_cutter': False,
'position': {'x': -1234.3, 'y': -349.7, 'z': -396.0}},
33001: {'can_slip_through': False,
'name': 'Blood Kelp Trench Wreck - Inside Databox',
'need_laser_cutter': False,
'position': {'x': -1208.0, 'y': -349.6, 'z': -383.0}},
33002: {'can_slip_through': False,
'name': 'Blood Kelp Trench Wreck - PDA',
'need_laser_cutter': False,
'position': {'x': -1210.6, 'y': -340.7, 'z': -393.4}},
33003: {'can_slip_through': False,
'name': 'Bulb Zone West Wreck - Outside Databox',
'need_laser_cutter': False,
'position': {'x': 903.8, 'y': -220.3, 'z': 590.9}},
33004: {'can_slip_through': False,
'name': 'Bulb Zone West Wreck - Under Databox',
'need_laser_cutter': False,
'position': {'x': 910.9, 'y': -201.8, 'z': 623.5}},
33005: {'can_slip_through': False,
'name': 'Bulb Zone West Wreck - Inside Databox',
'need_laser_cutter': True,
'position': {'x': 914.9, 'y': -202.1, 'z': 611.8}},
33006: {'can_slip_through': False,
'name': 'Bulb Zone West Wreck - PDA',
'need_laser_cutter': True,
'position': {'x': 912.6, 'y': -202.0, 'z': 609.5}},
33007: {'can_slip_through': False,
'name': 'Bulb Zone East Wreck - Databox',
'need_laser_cutter': False,
'position': {'x': 1327.1, 'y': -234.9, 'z': 575.8}},
33008: {'can_slip_through': False,
'name': 'Dunes North Wreck - Outside Databox',
'need_laser_cutter': False,
'position': {'x': -1407.7, 'y': -344.2, 'z': 721.5}},
33009: {'can_slip_through': False,
'name': 'Dunes North Wreck - Office Databox',
'need_laser_cutter': False,
'position': {'x': -1393.9, 'y': -329.7, 'z': 733.5}},
33010: {'can_slip_through': False,
'name': 'Dunes North Wreck - PDA',
'need_laser_cutter': False,
'position': {'x': -1396.3, 'y': -330.8, 'z': 730.0}},
33011: {'can_slip_through': False,
'name': 'Dunes North Wreck - Cargo Databox',
'need_laser_cutter': True,
'position': {'x': -1409.8, 'y': -332.4, 'z': 706.9}},
33012: {'can_slip_through': False,
'name': 'Dunes West Wreck - Databox',
'need_laser_cutter': False,
'position': {'x': -1626.2, 'y': -357.5, 'z': 99.5}},
33013: {'can_slip_through': False,
'name': 'Dunes East Wreck - Outside Databox',
'need_laser_cutter': False,
'position': {'x': -1196.3, 'y': -223.0, 'z': 12.5}},
33014: {'can_slip_through': False,
'name': 'Dunes East Wreck - Inside Databox',
'need_laser_cutter': False,
'position': {'x': -1206.4, 'y': -225.6, 'z': 4.0}},
33015: {'can_slip_through': False,
'name': 'Grand Reef North Wreck - Outside Databox',
'need_laser_cutter': False,
'position': {'x': -269.7, 'y': -262.8, 'z': -764.3}},
33016: {'can_slip_through': False,
'name': 'Grand Reef North Wreck - Elevator Databox',
'need_laser_cutter': True,
'position': {'x': -285.8, 'y': -240.2, 'z': -786.5}},
33017: {'can_slip_through': False,
'name': 'Grand Reef North Wreck - Bottom Databox',
'need_laser_cutter': False,
'position': {'x': -285.2, 'y': -262.4, 'z': -788.4}},
33018: {'can_slip_through': False,
'name': 'Grand Reef North Wreck - Hangar PDA',
'need_laser_cutter': False,
'position': {'x': -272.5, 'y': -254.7, 'z': -788.5}},
33019: {'can_slip_through': False,
'name': 'Grand Reef South Wreck - Trench Databox',
'need_laser_cutter': False,
'position': {'x': -850.9, 'y': -473.2, 'z': -1414.6}},
33020: {'can_slip_through': False,
'name': 'Grand Reef South Wreck - Comms Databox',
'need_laser_cutter': True,
'position': {'x': -889.4, 'y': -433.8, 'z': -1424.8}},
33021: {'can_slip_through': False,
'name': 'Grand Reef South Wreck - Outside Databox',
'need_laser_cutter': False,
'position': {'x': -862.4, 'y': -437.5, 'z': -1444.1}},
33022: {'can_slip_through': False,
'name': 'Grand Reef South Wreck - PDA',
'need_laser_cutter': False,
'position': {'x': -887.9, 'y': -446.0, 'z': -1422.7}},
33023: {'can_slip_through': False,
'name': 'Grassy Plateaus South Wreck - Databox',
'need_laser_cutter': False,
'position': {'x': -23.3, 'y': -105.8, 'z': -604.2}},
33024: {'can_slip_through': False,
'name': 'Grassy Plateaus South Wreck - PDA',
'need_laser_cutter': False,
'position': {'x': -27.3, 'y': -106.8, 'z': -607.2}},
33025: {'can_slip_through': True,
'name': 'Grassy Plateaus East Wreck - Breach Databox',
'need_laser_cutter': True,
'position': {'x': 313.9, 'y': -91.8, 'z': 432.6}},
33026: {'can_slip_through': True,
'name': 'Grassy Plateaus East Wreck - Hangar Databox',
'need_laser_cutter': True,
'position': {'x': 319.4, 'y': -104.3, 'z': 441.5}},
33027: {'can_slip_through': False,
'name': 'Grassy Plateaus West Wreck - Locker PDA',
'need_laser_cutter': False,
'position': {'x': -632.3, 'y': -75.0, 'z': -8.9}},
33028: {'can_slip_through': False,
'name': 'Grassy Plateaus West Wreck - Data Terminal',
'need_laser_cutter': False,
'position': {'x': -664.4, 'y': -97.8, 'z': -8.0}},
33029: {'can_slip_through': False,
'name': 'Grassy Plateaus West Wreck - Databox',
'need_laser_cutter': True,
'position': {'x': -421.4, 'y': -107.8, 'z': -266.5}},
33030: {'can_slip_through': False,
'name': 'Safe Shallows Wreck - PDA',
'need_laser_cutter': False,
'position': {'x': -44.0, 'y': -29.1, 'z': -403.6}},
33031: {'can_slip_through': False,
'name': 'Kelp Forest Wreck - Databox',
'need_laser_cutter': False,
'position': {'x': -317.6, 'y': -78.8, 'z': 247.4}},
33032: {'can_slip_through': False,
'name': 'Kelp Forest Wreck - PDA',
'need_laser_cutter': False,
'position': {'x': 63.2, 'y': -38.5, 'z': 382.9}},
33033: {'can_slip_through': False,
'name': 'Mountains West Wreck - Outside Databox',
'need_laser_cutter': False,
'position': {'x': 740.3, 'y': -389.2, 'z': 1179.8}},
33034: {'can_slip_through': False,
'name': 'Mountains West Wreck - Data Terminal',
'need_laser_cutter': True,
'position': {'x': 703.7, 'y': -365.9, 'z': 1199.3}},
33035: {'can_slip_through': False,
'name': 'Mountains West Wreck - Hangar Databox',
'need_laser_cutter': True,
'position': {'x': 698.2, 'y': -350.8, 'z': 1186.9}},
33036: {'can_slip_through': False,
'name': 'Mountains West Wreck - Office Databox',
'need_laser_cutter': False,
'position': {'x': 676.3, 'y': -343.6, 'z': 1204.6}},
33037: {'can_slip_through': False,
'name': 'Mountains East Wreck - Comms Databox',
'need_laser_cutter': False,
'position': {'x': 1068.5, 'y': -283.4, 'z': 1345.3}},
33038: {'can_slip_through': False,
'name': 'Mountains East Wreck - Outside Databox',
'need_laser_cutter': False,
'position': {'x': 1075.7, 'y': -288.9, 'z': 1321.8}},
33039: {'can_slip_through': False,
'name': 'Northwestern Mushroom Forest Wreck - Cargo Databox',
'need_laser_cutter': True,
'position': {'x': -655.1, 'y': -109.6, 'z': 791.0}},
33040: {'can_slip_through': False,
'name': 'Northwestern Mushroom Forest Wreck - Office Databox',
'need_laser_cutter': False,
'position': {'x': -663.4, 'y': -111.9, 'z': 777.9}},
33041: {'can_slip_through': False,
'name': 'Northwestern Mushroom Forest Wreck - PDA',
'need_laser_cutter': False,
'position': {'x': -662.2, 'y': -113.4, 'z': 777.7}},
33042: {'can_slip_through': False,
'name': "Sea Treader's Path Wreck - Outside Databox",
'need_laser_cutter': False,
'position': {'x': -1161.1, 'y': -191.7, 'z': -758.3}},
33043: {'can_slip_through': False,
'name': "Sea Treader's Path Wreck - Hangar Databox",
'need_laser_cutter': True,
'position': {'x': -1129.5, 'y': -155.2, 'z': -729.3}},
33044: {'can_slip_through': False,
'name': "Sea Treader's Path Wreck - Lobby Databox",
'need_laser_cutter': False,
'position': {'x': -1115.9, 'y': -175.3, 'z': -724.5}},
33045: {'can_slip_through': False,
'name': "Sea Treader's Path Wreck - PDA",
'need_laser_cutter': False,
'position': {'x': -1136.8, 'y': -157.0, 'z': -734.6}},
33046: {'can_slip_through': False,
'name': 'Sparse Reef Wreck - Locker Databox',
'need_laser_cutter': True,
'position': {'x': -789.8, 'y': -216.1, 'z': -711.0}},
33047: {'can_slip_through': False,
'name': 'Sparse Reef Wreck - Outside Databox',
'need_laser_cutter': False,
'position': {'x': -810.7, 'y': -209.3, 'z': -685.5}},
33048: {'can_slip_through': False,
'name': 'Sparse Reef Wreck - Lab Databox',
'need_laser_cutter': True,
'position': {'x': -795.5, 'y': -204.1, 'z': -774.7}},
33049: {'can_slip_through': False,
'name': 'Underwater Islands Wreck - Outside Databox',
'need_laser_cutter': False,
'position': {'x': -170.8, 'y': -187.6, 'z': 880.7}},
33050: {'can_slip_through': False,
'name': 'Underwater Islands Wreck - Hangar Databox',
'need_laser_cutter': True,
'position': {'x': -138.4, 'y': -193.6, 'z': 888.7}},
33051: {'can_slip_through': False,
'name': 'Underwater Islands Wreck - Data Terminal',
'need_laser_cutter': True,
'position': {'x': -130.7, 'y': -193.2, 'z': 883.3}},
33052: {'can_slip_through': False,
'name': 'Underwater Islands Wreck - Cable Databox',
'need_laser_cutter': False,
'position': {'x': -137.8, 'y': -193.4, 'z': 879.4}},
33053: {'can_slip_through': False,
'name': 'Underwater Islands Wreck - Pipes Databox 1',
'need_laser_cutter': False,
'need_propulsion_cannon': True,
'position': {'x': -124.4, 'y': -200.7, 'z': 853.0}},
33054: {'can_slip_through': False,
'name': 'Underwater Islands Wreck - Pipes Databox 2',
'need_laser_cutter': False,
'need_propulsion_cannon': True,
'position': {'x': -126.8, 'y': -201.1, 'z': 852.1}},
33055: {'can_slip_through': False,
'name': 'Degasi Seabase - Deep Grand Reef - Bedroom Databox',
'need_laser_cutter': False,
'position': {'x': -643.8, 'y': -509.9, 'z': -941.9}},
33056: {'can_slip_through': False,
'name': 'Degasi Seabase - Deep Grand Reef - Observatory Databox',
'need_laser_cutter': False,
'position': {'x': -635.1, 'y': -502.7, 'z': -951.4}},
33057: {'can_slip_through': False,
'name': 'Degasi Seabase - Deep Grand Reef - Bedroom PDA',
'need_laser_cutter': False,
'position': {'x': -645.8, 'y': -508.7, 'z': -943.0}},
33058: {'can_slip_through': False,
'name': 'Degasi Seabase - Deep Grand Reef - Outside PDA',
'need_laser_cutter': False,
'position': {'x': -630.5, 'y': -511.1, 'z': -936.1}},
33059: {'can_slip_through': False,
'name': 'Degasi Seabase - Deep Grand Reef - Observatory PDA',
'need_laser_cutter': False,
'position': {'x': -647.7, 'y': -502.6, 'z': -935.8}},
33060: {'can_slip_through': False,
'name': 'Degasi Seabase - Deep Grand Reef - Lab PDA',
'need_laser_cutter': False,
'position': {'x': -639.6, 'y': -505.9, 'z': -946.6}},
33061: {'can_slip_through': False,
'name': 'Floating Island - Lake PDA',
'need_laser_cutter': False,
'position': {'x': -707.2, 'y': 0.5, 'z': -1096.7}},
33062: {'can_slip_through': False,
'name': 'Degasi Seabase - Floating Island - Databox',
'need_laser_cutter': False,
'position': {'x': -765.7, 'y': 17.6, 'z': -1116.4}},
33063: {'can_slip_through': False,
'name': 'Degasi Seabase - Floating Island - Room PDA',
'need_laser_cutter': False,
'position': {'x': -754.9, 'y': 14.6, 'z': -1108.9}},
33064: {'can_slip_through': False,
'name': 'Degasi Seabase - Floating Island - Green Wall PDA',
'need_laser_cutter': False,
'position': {'x': -765.3, 'y': 14.1, 'z': -1115.0}},
33065: {'can_slip_through': False,
'name': 'Degasi Seabase - Floating Island - Corridor PDA',
'need_laser_cutter': False,
'position': {'x': -758.6, 'y': 14.1, 'z': -1111.3}},
33066: {'can_slip_through': False,
'name': 'Degasi Seabase - Floating Island - North Observatory PDA',
'need_laser_cutter': False,
'position': {'x': -805.4, 'y': 76.9, 'z': -1055.7}},
33067: {'can_slip_through': False,
'name': 'Degasi Seabase - Floating Island - South Observatory PDA',
'need_laser_cutter': False,
'position': {'x': -715.9, 'y': 75.4, 'z': -1168.8}},
33068: {'can_slip_through': False,
'name': 'Jellyshroom Cave - PDA',
'need_laser_cutter': False,
'position': {'x': -540.5, 'y': -250.8, 'z': -83.4}},
33069: {'can_slip_through': False,
'name': 'Degasi Seabase - Jellyshroom Cave - Bedroom Databox',
'need_laser_cutter': False,
'position': {'x': 110.6, 'y': -264.9, 'z': -369.0}},
33070: {'can_slip_through': False,
'name': 'Degasi Seabase - Jellyshroom Cave - Detached PDA',
'need_laser_cutter': False,
'position': {'x': 80.6, 'y': -268.6, 'z': -358.3}},
33071: {'can_slip_through': False,
'name': 'Degasi Seabase - Jellyshroom Cave - Office PDA',
'need_laser_cutter': False,
'position': {'x': 78.2, 'y': -265.0, 'z': -373.4}},
33072: {'can_slip_through': False,
'name': 'Degasi Seabase - Jellyshroom Cave - Locker PDA',
'need_laser_cutter': False,
'position': {'x': 85.1, 'y': -264.1, 'z': -372.8}},
33073: {'can_slip_through': False,
'name': 'Degasi Seabase - Jellyshroom Cave - Bedroom PDA',
'need_laser_cutter': False,
'position': {'x': 112.3, 'y': -264.9, 'z': -369.3}},
33074: {'can_slip_through': False,
'name': 'Degasi Seabase - Jellyshroom Cave - Observatory PDA',
'need_laser_cutter': False,
'position': {'x': 95.5, 'y': -258.9, 'z': -366.5}},
33075: {'can_slip_through': False,
'name': 'Lifepod 2 - Databox',
'need_laser_cutter': False,
'position': {'x': -483.6, 'y': -504.7, 'z': 1326.6}},
33076: {'can_slip_through': False,
'name': 'Lifepod 2 - PDA',
'need_laser_cutter': False,
'position': {'x': -481.4, 'y': -503.6, 'z': 1324.1}},
33077: {'can_slip_through': False,
'name': 'Lifepod 3 - Databox',
'need_laser_cutter': False,
'position': {'x': -34.2, 'y': -22.4, 'z': 410.5}},
33078: {'can_slip_through': False,
'name': 'Lifepod 3 - PDA',
'need_laser_cutter': False,
'position': {'x': -33.8, 'y': -22.5, 'z': 408.8}},
33079: {'can_slip_through': False,
'name': 'Lifepod 4 - Databox',
'need_laser_cutter': False,
'position': {'x': 712.4, 'y': -3.4, 'z': 160.8}},
33080: {'can_slip_through': False,
'name': 'Lifepod 4 - PDA',
'need_laser_cutter': False,
'position': {'x': 712.0, 'y': -3.5, 'z': 161.5}},
33081: {'can_slip_through': False,
'name': 'Lifepod 6 - Databox',
'need_laser_cutter': False,
'position': {'x': 358.7, 'y': -117.1, 'z': 306.8}},
33082: {'can_slip_through': False,
'name': 'Lifepod 6 - Inside PDA',
'need_laser_cutter': False,
'position': {'x': 361.8, 'y': -116.2, 'z': 309.5}},
33083: {'can_slip_through': False,
'name': 'Lifepod 6 - Outside PDA',
'need_laser_cutter': False,
'position': {'x': 359.9, 'y': -117.0, 'z': 312.1}},
33084: {'can_slip_through': False,
'name': 'Lifepod 7 - PDA',
'need_laser_cutter': False,
'position': {'x': -56.0, 'y': -182.0, 'z': -1039.0}},
33085: {'can_slip_through': False,
'name': 'Lifepod 12 - Databox',
'need_laser_cutter': False,
'position': {'x': 1119.5, 'y': -271.7, 'z': 561.7}},
33086: {'can_slip_through': False,
'name': 'Lifepod 12 - PDA',
'need_laser_cutter': False,
'position': {'x': 1116.1, 'y': -271.3, 'z': 566.9}},
33087: {'can_slip_through': False,
'name': 'Lifepod 13 - Databox',
'need_laser_cutter': False,
'position': {'x': -926.4, 'y': -185.2, 'z': 501.8}},
33088: {'can_slip_through': False,
'name': 'Lifepod 13 - PDA',
'need_laser_cutter': False,
'position': {'x': -926.8, 'y': -184.4, 'z': 506.6}},
33089: {'can_slip_through': False,
'name': 'Lifepod 17 - PDA',
'need_laser_cutter': False,
'position': {'x': -514.5, 'y': -98.1, 'z': -56.5}},
33090: {'can_slip_through': False,
'name': 'Lifepod 19 - Databox',
'need_laser_cutter': False,
'position': {'x': -809.8, 'y': -302.2, 'z': -876.9}},
33091: {'can_slip_through': False,
'name': 'Lifepod 19 - Outside PDA',
'need_laser_cutter': False,
'position': {'x': -806.1, 'y': -294.1, 'z': -866.0}},
33092: {'can_slip_through': False,
'name': 'Lifepod 19 - Inside PDA',
'need_laser_cutter': False,
'position': {'x': -810.5, 'y': -299.4, 'z': -873.1}},
33093: {'can_slip_through': False,
'name': 'Aurora Seamoth Bay - Upgrade Console',
'need_laser_cutter': False,
'need_propulsion_cannon': True,
'position': {'x': 903.5, 'y': -0.2, 'z': 16.1}},
33094: {'can_slip_through': False,
'name': 'Aurora Drive Room - Upgrade Console',
'need_laser_cutter': False,
'need_propulsion_cannon': True,
'position': {'x': 872.5, 'y': 2.7, 'z': -0.7}},
33095: {'can_slip_through': False,
'name': 'Aurora Prawn Suit Bay - Upgrade Console',
'need_laser_cutter': True,
'need_propulsion_cannon': True,
'position': {'x': 991.6, 'y': 3.2, 'z': -31.0}},
33096: {'can_slip_through': False,
'name': 'Aurora - Office PDA',
'need_laser_cutter': False,
'position': {'x': 952.1, 'y': 41.2, 'z': 113.9}},
33097: {'can_slip_through': False,
'name': 'Aurora - Corridor PDA',
'need_laser_cutter': False,
'position': {'x': 977.2, 'y': 39.1, 'z': 83.0}},
33098: {'can_slip_through': False,
'name': 'Aurora - Cargo Bay PDA',
'need_laser_cutter': False,
'need_propulsion_cannon': True,
'position': {'x': 954.9, 'y': 11.2, 'z': 3.4}},
33099: {'can_slip_through': False,
'name': 'Aurora - Seamoth Bay PDA',
'need_laser_cutter': False,
'need_propulsion_cannon': True,
'position': {'x': 907.1, 'y': -1.5, 'z': 15.3}},
33100: {'can_slip_through': False,
'name': 'Aurora - Medkit Locker PDA',
'need_laser_cutter': True,
'need_propulsion_cannon': True,
'position': {'x': 951.8, 'y': -2.3, 'z': -34.7}},
33101: {'can_slip_through': False,
'name': 'Aurora - Locker PDA',
'need_laser_cutter': True,
'need_propulsion_cannon': True,
'position': {'x': 952.0, 'y': -3.7, 'z': -23.4}},
33102: {'can_slip_through': False,
'name': 'Aurora - Canteen PDA',
'need_laser_cutter': True,
'need_propulsion_cannon': True,
'position': {'x': 986.5, 'y': 9.6, 'z': -48.6}},
33103: {'can_slip_through': False,
'name': 'Aurora - Cabin 4 PDA',
'need_laser_cutter': True,
'need_propulsion_cannon': True,
'position': {'x': 951.3, 'y': 11.2, 'z': -51.0}},
33104: {'can_slip_through': False,
'name': 'Aurora - Cabin 7 PDA',
'need_laser_cutter': True,
'need_propulsion_cannon': True,
'position': {'x': 967.1, 'y': 10.4, 'z': -47.4}},
33105: {'can_slip_through': False,
'name': 'Aurora - Cabin 1 PDA',
'need_laser_cutter': True,
'need_propulsion_cannon': True,
'position': {'x': 964.1, 'y': 11.1, 'z': -61.9}},
33106: {'can_slip_through': False,
'name': 'Aurora - Captain PDA',
'need_laser_cutter': True,
'need_propulsion_cannon': True,
'position': {'x': 971.2, 'y': 10.8, 'z': -70.4}},
33107: {'can_slip_through': False,
'name': 'Aurora - Ring PDA',
'need_laser_cutter': False,
'need_propulsion_cannon': True,
'position': {'x': 1033.6, 'y': -8.5, 'z': 16.2}},
33108: {'can_slip_through': False,
'name': 'Aurora - Lab PDA',
'need_laser_cutter': False,
'need_propulsion_cannon': True,
'position': {'x': 1032.5, 'y': -7.8, 'z': 32.4}},
33109: {'can_slip_through': False,
'name': 'Aurora - Office Data Terminal',
'need_laser_cutter': False,
'position': {'x': 945.8, 'y': 40.8, 'z': 115.1}},
33110: {'can_slip_through': False,
'name': 'Aurora - Captain Data Terminal',
'need_laser_cutter': True,
'need_propulsion_cannon': True,
'position': {'x': 974.8, 'y': 10.0, 'z': -77.0}},
33111: {'can_slip_through': False,
'name': 'Aurora - Battery Room Data Terminal',
'need_laser_cutter': True,
'need_propulsion_cannon': True,
'position': {'x': 1040.8, 'y': -11.4, 'z': -3.4}},
33112: {'can_slip_through': False,
'name': 'Aurora - Lab Data Terminal',
'need_laser_cutter': False,
'need_propulsion_cannon': True,
'position': {'x': 1029.5, 'y': -8.7, 'z': 35.9}},
33113: {'can_slip_through': False,
'name': "Quarantine Enforcement Platform's - Upper Alien Data "
'Terminal',
'need_laser_cutter': False,
'position': {'x': 432.2, 'y': 3.0, 'z': 1193.2}},
33114: {'can_slip_through': False,
'name': "Quarantine Enforcement Platform's - Mid Alien Data Terminal",
'need_laser_cutter': False,
'position': {'x': 474.4, 'y': -4.5, 'z': 1224.4}},
33115: {'can_slip_through': False,
'name': 'Dunes Sanctuary - Alien Data Terminal',
'need_laser_cutter': False,
'position': {'x': -1224.2, 'y': -400.4, 'z': 1057.9}},
33116: {'can_slip_through': False,
'name': 'Deep Sparse Reef Sanctuary - Alien Data Terminal',
'need_laser_cutter': False,
'position': {'x': -895.5, 'y': -311.6, 'z': -838.1}},
33117: {'can_slip_through': False,
'name': 'Northern Blood Kelp Zone Sanctuary - Alien Data Terminal',
'need_laser_cutter': False,
'position': {'x': -642.9, 'y': -563.5, 'z': 1485.5}},
33118: {'can_slip_through': False,
'name': 'Lost River Laboratory Cache - Alien Data Terminal',
'need_laser_cutter': False,
'position': {'x': -1112.3, 'y': -687.3, 'z': -695.5}},
33119: {'can_slip_through': False,
'name': 'Disease Research Facility - Upper Alien Data Terminal',
'need_laser_cutter': False,
'position': {'x': -280.2, 'y': -804.3, 'z': 305.1}},
33120: {'can_slip_through': False,
'name': 'Disease Research Facility - Mid Alien Data Terminal',
'need_laser_cutter': False,
'position': {'x': -267.9, 'y': -806.6, 'z': 250.0}},
33121: {'can_slip_through': False,
'name': 'Disease Research Facility - Lower Alien Data Terminal',
'need_laser_cutter': False,
'position': {'x': -286.2, 'y': -815.6, 'z': 297.8}},
33122: {'can_slip_through': False,
'name': 'Alien Thermal Plant - Entrance Alien Data Terminal',
'need_laser_cutter': False,
'position': {'x': -71.3, 'y': -1227.2, 'z': 104.8}},
33123: {'can_slip_through': False,
'name': 'Alien Thermal Plant - Green Alien Data Terminal',
'need_laser_cutter': False,
'position': {'x': -38.7, 'y': -1226.6, 'z': 111.8}},
33124: {'can_slip_through': False,
'name': 'Alien Thermal Plant - Yellow Alien Data Terminal',
'need_laser_cutter': False,
'position': {'x': -30.4, 'y': -1220.3, 'z': 111.8}},
33125: {'can_slip_through': False,
'name': "Primary Containment Facility's Antechamber - Alien Data "
'Terminal',
'need_laser_cutter': False,
'position': {'x': 245.8, 'y': -1430.6, 'z': -311.5}},
33126: {'can_slip_through': False,
'name': "Primary Containment Facility's Egg Laboratory - Alien Data "
'Terminal',
'need_laser_cutter': False,
'position': {'x': 165.5, 'y': -1442.4, 'z': -385.8}},
33127: {'can_slip_through': False,
'name': "Primary Containment Facility's Pipe Room - Alien Data "
'Terminal',
'need_laser_cutter': False,
'position': {'x': 348.7, 'y': -1443.5, 'z': -291.9}},
33128: {'can_slip_through': False,
'name': 'Grassy Plateaus West Wreck - Beam PDA',
'need_laser_cutter': True,
'position': {'x': -641.8, 'y': -111.3, 'z': -19.7}},
33129: {'can_slip_through': False,
'name': 'Floating Island - Cave Entrance PDA',
'need_laser_cutter': False,
'position': {'x': -748.9, 'y': 14.4, 'z': -1179.5}}}
if False: # turn to True to export for Subnautica mod
payload = {location_id: location_data["position"] for location_id, location_data in location_table.items()}
import json
with open("locations.json", "w") as f:
json.dump(payload, f)

View File

@@ -2,13 +2,36 @@ from Options import Choice
class ItemPool(Choice):
"""Valuable item pool moves all not progression relevant items to starting inventory and
creates random duplicates of important items in their place."""
"""Valuable item pool leaves all filler items in their vanilla locations and
creates random duplicates of important items into freed spots."""
display_name = "Item Pool"
option_standard = 0
option_valuable = 1
class Goal(Choice):
"""Goal to complete.
Launch: Leave the planet.
Free: Disable quarantine.
Infected: Reach maximum infection level.
Drive: Repair the Aurora's Drive Core"""
auto_display_name = True
display_name = "Goal"
option_launch = 0
option_free = 1
option_infected = 2
option_drive = 3
def get_event_name(self) -> str:
return {
self.option_launch: "Neptune Launch",
self.option_infected: "Full Infection",
self.option_free: "Disable Quarantine",
self.option_drive: "Repair Aurora Drive"
}[self.value]
options = {
"item_pool": ItemPool
"item_pool": ItemPool,
"goal": Goal,
}

View File

@@ -1,8 +0,0 @@
def create_regions(world, player: int):
from . import create_region
from .Locations import lookup_name_to_id as location_lookup_name_to_id
world.regions += [
create_region(world, player, 'Menu', None, ['Lifepod 5']),
create_region(world, player, 'Planet 4546B', [location for location in location_lookup_name_to_id])
]

View File

@@ -1,6 +1,5 @@
from ..generic.Rules import set_rule
from .Locations import location_table
import logging
from worlds.generic.Rules import set_rule
from .Locations import location_table, LocationDict
import math
@@ -197,32 +196,32 @@ def get_max_depth(state, player):
get_prawn_max_depth(state, player))
def can_access_location(state, player, loc):
pos_x = loc.get("position").get("x")
pos_y = loc.get("position").get("y")
pos_z = loc.get("position").get("z")
depth = -pos_y # y-up
map_center_dist = math.sqrt(pos_x ** 2 + pos_z ** 2)
aurora_dist = math.sqrt((pos_x - 1038.0) ** 2 + (pos_y - -3.4) ** 2 + (pos_z - -163.1) ** 2)
need_radiation_suit = aurora_dist < 950
def can_access_location(state, player: int, loc: LocationDict):
need_laser_cutter = loc.get("need_laser_cutter", False)
need_propulsion_cannon = loc.get("need_propulsion_cannon", False)
if need_laser_cutter and not has_laser_cutter(state, player):
return False
if need_radiation_suit and not state.has("Radiation Suit", player):
need_propulsion_cannon = loc.get("need_propulsion_cannon", False)
if need_propulsion_cannon and not has_propulsion_cannon(state, player):
return False
if need_propulsion_cannon and not has_propulsion_cannon(state, player):
pos = loc["position"]
pos_x = pos["x"]
pos_y = pos["y"]
pos_z = pos["z"]
aurora_dist = math.sqrt((pos_x - 1038.0) ** 2 + (pos_y - -3.4) ** 2 + (pos_z - -163.1) ** 2)
need_radiation_suit = aurora_dist < 950
if need_radiation_suit and not state.has("Radiation Suit", player):
return False
# Seaglide doesn't unlock anything specific, but just allows for faster movement.
# Otherwise the game is painfully slow.
map_center_dist = math.sqrt(pos_x ** 2 + pos_z ** 2)
if (map_center_dist > 800 or pos_y < -200) and not has_seaglide(state, player):
return False
depth = -pos_y # y-up
return get_max_depth(state, player) >= depth
@@ -230,21 +229,33 @@ def set_location_rule(world, player, loc):
set_rule(world.get_location(loc["name"], player), lambda state: can_access_location(state, player, loc))
def set_rules(world, player):
for loc in location_table:
def set_rules(subnautica_world):
player = subnautica_world.player
world = subnautica_world.world
for loc in location_table.values():
set_location_rule(world, player, loc)
# Victory location
set_rule(world.get_location("Neptune Launch", player), lambda state: \
get_max_depth(state, player) >= 1444 and \
has_mobile_vehicle_bay(state, player) and \
state.has('Neptune Launch Platform', player) and \
state.has('Neptune Gantry', player) and \
state.has('Neptune Boosters', player) and \
state.has('Neptune Fuel Reserve', player) and \
state.has('Neptune Cockpit', player) and \
state.has('Ion Power Cell', player) and \
state.has('Ion Battery', player) and \
# Victory locations
set_rule(world.get_location("Neptune Launch", player), lambda state:
get_max_depth(state, player) >= 1444 and
has_mobile_vehicle_bay(state, player) and
state.has("Neptune Launch Platform", player) and
state.has("Neptune Gantry", player) and
state.has("Neptune Boosters", player) and
state.has("Neptune Fuel Reserve", player) and
state.has("Neptune Cockpit", player) and
state.has("Ion Power Cell", player) and
state.has("Ion Battery", player) and
has_cyclops_shield(state, player))
world.completion_condition[player] = lambda state: state.has('Victory', player)
set_rule(world.get_location("Disable Quarantine", player), lambda state:
get_max_depth(state, player) >= 1444)
set_rule(world.get_location("Full Infection", player), lambda state:
get_max_depth(state, player) >= 900)
room = world.get_location("Aurora Drive Room - Upgrade Console", player)
set_rule(world.get_location("Repair Aurora Drive", player), lambda state: room.can_reach(state))
world.completion_condition[player] = lambda state: state.has("Victory", player)

View File

@@ -1,18 +1,16 @@
import logging
from typing import List, Dict, Any
from BaseClasses import Region, Entrance, Location, Item, Tutorial, ItemClassification, RegionType
from worlds.AutoWorld import World, WebWorld
from . import Items
from . import Locations
from . import Options
from .Items import item_table
from .Rules import set_rules
logger = logging.getLogger("Subnautica")
from .Locations import lookup_name_to_id as locations_lookup_name_to_id
from .Items import item_table, lookup_name_to_item, advancement_item_names
from .Items import lookup_name_to_id as items_lookup_name_to_id
from .Regions import create_regions
from .Rules import set_rules
from .Options import options
from BaseClasses import Region, Entrance, Location, MultiWorld, Item, Tutorial, ItemClassification, RegionType
from ..AutoWorld import World, WebWorld
class SubnaticaWeb(WebWorld):
tutorials = [Tutorial(
@@ -34,34 +32,51 @@ class SubnauticaWorld(World):
game: str = "Subnautica"
web = SubnaticaWeb()
item_name_to_id = items_lookup_name_to_id
location_name_to_id = locations_lookup_name_to_id
options = options
item_name_to_id = {data["name"]: item_id for item_id, data in Items.item_table.items()}
location_name_to_id = {data["name"]: loc_id for loc_id, data in Locations.location_table.items()}
options = Options.options
data_version = 2
required_client_version = (0, 1, 9)
required_client_version = (0, 3, 3)
prefill_items: List[Item]
def generate_early(self) -> None:
self.prefill_items = [
self.create_item("Seaglide Fragment"),
self.create_item("Seaglide Fragment")
]
def create_regions(self):
self.world.regions += [
self.create_region("Menu", None, ["Lifepod 5"]),
self.create_region("Planet 4546B",
Locations.events + [location["name"] for location in Locations.location_table.values()])
]
# refer to Rules.py
set_rules = set_rules
def generate_basic(self):
# Link regions
self.world.get_entrance('Lifepod 5', self.player).connect(self.world.get_region('Planet 4546B', self.player))
self.world.get_entrance("Lifepod 5", self.player).connect(self.world.get_region("Planet 4546B", self.player))
# Generate item pool
pool = []
neptune_launch_platform = None
extras = 0
valuable = self.world.item_pool[self.player] == "valuable"
for item in item_table:
valuable = self.world.item_pool[self.player] == Options.ItemPool.option_valuable
for item in item_table.values():
for i in range(item["count"]):
subnautica_item = self.create_item(item["name"])
if item["name"] == "Neptune Launch Platform":
neptune_launch_platform = subnautica_item
elif valuable and not item["progression"]:
self.world.push_precollected(subnautica_item)
elif valuable and ItemClassification.filler == item["classification"]:
extras += 1
else:
pool.append(subnautica_item)
for item_name in self.world.random.choices(sorted(advancement_item_names - {"Neptune Launch Platform"}),
for item_name in self.world.random.choices(sorted(Items.advancement_item_names - {"Neptune Launch Platform"}),
k=extras):
item = self.create_item(item_name)
item.classification = ItemClassification.filler # as it's an extra, just fast-fill it somewhere
@@ -72,39 +87,57 @@ class SubnauticaWorld(World):
# Victory item
self.world.get_location("Aurora - Captain Data Terminal", self.player).place_locked_item(
neptune_launch_platform)
self.world.get_location("Neptune Launch", self.player).place_locked_item(
SubnauticaItem("Victory", ItemClassification.progression, None, player=self.player))
for event in Locations.events:
self.world.get_location(event, self.player).place_locked_item(
SubnauticaItem(event, ItemClassification.progression, None, player=self.player))
# make the goal event the victory "item"
self.world.get_location(self.world.goal[self.player].get_event_name(), self.player).item.name = "Victory"
def set_rules(self):
set_rules(self.world, self.player)
def fill_slot_data(self) -> Dict[str, Any]:
goal: Options.Goal = self.world.goal[self.player]
item_pool: Options.ItemPool = self.world.item_pool[self.player]
vanilla_tech: List[str] = []
if item_pool == Options.ItemPool.option_valuable:
for item in Items.item_table.values():
if item["classification"] == ItemClassification.filler:
vanilla_tech.append(item["tech_type"])
def create_regions(self):
create_regions(self.world, self.player)
slot_data: Dict[str, Any] = {
"goal": goal.current_key,
"vanilla_tech": vanilla_tech,
}
def fill_slot_data(self):
slot_data = {}
return slot_data
def create_item(self, name: str) -> Item:
item = lookup_name_to_item[name]
item_id: int = self.item_name_to_id[name]
return SubnauticaItem(name,
ItemClassification.progression if item["progression"] else ItemClassification.filler,
item["id"], player=self.player)
item_table[item_id]["classification"],
item_id, player=self.player)
def create_region(self, name: str, locations=None, exits=None):
ret = Region(name, RegionType.Generic, name, self.player)
ret.world = self.world
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
def create_region(world: MultiWorld, player: int, name: str, locations=None, exits=None):
ret = Region(name, RegionType.Generic, name, player)
ret.world = world
if locations:
for location in locations:
loc_id = locations_lookup_name_to_id.get(location, 0)
location = SubnauticaLocation(player, location, loc_id, ret)
ret.locations.append(location)
if exits:
for exit in exits:
ret.exits.append(Entrance(player, exit, ret))
def get_pre_fill_items(self) -> List[Item]:
return self.prefill_items
return ret
def pre_fill(self) -> None:
reachable = self.world.get_reachable_locations(player=self.player)
self.world.random.shuffle(reachable)
items = self.prefill_items.copy()
for item in items:
reachable.pop().place_locked_item(item)
class SubnauticaLocation(Location):
@@ -112,4 +145,4 @@ class SubnauticaLocation(Location):
class SubnauticaItem(Item):
game = "Subnautica"
game: str = "Subnautica"

View File

@@ -1,83 +0,0 @@
[
{ "id": 35000, "count": 1, "progression": false, "tech_type": "Compass", "name": "Compass" },
{ "id": 35001, "count": 1, "progression": true, "tech_type": "PlasteelTank", "name": "Lightweight High Capacity Tank" },
{ "id": 35002, "count": 1, "progression": true, "tech_type": "BaseUpgradeConsole", "name": "Vehicle Upgrade Console" },
{ "id": 35003, "count": 1, "progression": true, "tech_type": "UltraGlideFins", "name": "Ultra Glide Fins" },
{ "id": 35004, "count": 1, "progression": false, "tech_type": "CyclopsSonarModule", "name": "Cyclops Sonar Upgrade" },
{ "id": 35005, "count": 1, "progression": false, "tech_type": "ReinforcedDiveSuit", "name": "Reinforced Dive Suit" },
{ "id": 35006, "count": 1, "progression": false, "tech_type": "CyclopsThermalReactorModule", "name": "Cyclops Thermal Reactor Module" },
{ "id": 35007, "count": 1, "progression": false, "tech_type": "Stillsuit", "name": "Stillsuit" },
{ "id": 35008, "count": 2, "progression": false, "tech_type": "BaseWaterParkFragment", "name": "Alien Containment Fragment" },
{ "id": 35009, "count": 1, "progression": false, "tech_type": "CyclopsDecoy", "name": "Creature Decoy" },
{ "id": 35010, "count": 1, "progression": false, "tech_type": "CyclopsFireSuppressionModule", "name": "Cyclops Fire Suppression System" },
{ "id": 35011, "count": 1, "progression": false, "tech_type": "SwimChargeFins", "name": "Swim Charge Fins" },
{ "id": 35012, "count": 1, "progression": false, "tech_type": "RepulsionCannon", "name": "Repulsion Cannon" },
{ "id": 35013, "count": 1, "progression": false, "tech_type": "CyclopsDecoyModule", "name": "Cyclops Decoy Tube Upgrade" },
{ "id": 35014, "count": 1, "progression": true, "tech_type": "CyclopsShieldModule", "name": "Cyclops Shield Generator" },
{ "id": 35015, "count": 1, "progression": true, "tech_type": "CyclopsHullModule1", "name": "Cyclops Depth Module MK1" },
{ "id": 35016, "count": 1, "progression": false, "tech_type": "CyclopsSeamothRepairModule", "name": "Cyclops Docking Bay Repair Module" },
{ "id": 35017, "count": 2, "progression": false, "tech_type": "BatteryChargerFragment", "name": "Battery Charger fragment" },
{ "id": 35018, "count": 2, "progression": false, "tech_type": "BeaconFragment", "name": "Beacon Fragment" },
{ "id": 35019, "count": 2, "progression": false, "tech_type": "BaseBioReactorFragment", "name": "Bioreactor Fragment" },
{ "id": 35020, "count": 3, "progression": true, "tech_type": "CyclopsBridgeFragment", "name": "Cyclops Bridge Fragment" },
{ "id": 35021, "count": 3, "progression": true, "tech_type": "CyclopsEngineFragment", "name": "Cyclops Engine Fragment" },
{ "id": 35022, "count": 3, "progression": true, "tech_type": "CyclopsHullFragment", "name": "Cyclops Hull Fragment" },
{ "id": 35023, "count": 2, "progression": false, "tech_type": "GravSphereFragment", "name": "Grav Trap Fragment" },
{ "id": 35024, "count": 3, "progression": true, "tech_type": "LaserCutterFragment", "name": "Laser Cutter Fragment" },
{ "id": 35025, "count": 1, "progression": false, "tech_type": "TechlightFragment", "name": "Light Stick Fragment" },
{ "id": 35026, "count": 3, "progression": true, "tech_type": "ConstructorFragment", "name": "Mobile Vehicle Bay Fragment" },
{ "id": 35027, "count": 3, "progression": true, "tech_type": "WorkbenchFragment", "name": "Modification Station Fragment" },
{ "id": 35028, "count": 2, "progression": true, "tech_type": "MoonpoolFragment", "name": "Moonpool Fragment" },
{ "id": 35029, "count": 3, "progression": false, "tech_type": "BaseNuclearReactorFragment", "name": "Nuclear Reactor Fragment" },
{ "id": 35030, "count": 2, "progression": false, "tech_type": "PowerCellChargerFragment", "name": "Power Cell Charger Fragment" },
{ "id": 35031, "count": 1, "progression": false, "tech_type": "PowerTransmitterFragment", "name": "Power Transmitter Fragment" },
{ "id": 35032, "count": 4, "progression": true, "tech_type": "ExosuitFragment", "name": "Prawn Suit Fragment" },
{ "id": 35033, "count": 2, "progression": false, "tech_type": "ExosuitDrillArmFragment", "name": "Prawn Suit Drill Arm Fragment" },
{ "id": 35034, "count": 2, "progression": false, "tech_type": "ExosuitGrapplingArmFragment", "name": "Prawn Suit Grappling Arm Fragment" },
{ "id": 35035, "count": 2, "progression": false, "tech_type": "ExosuitPropulsionArmFragment", "name": "Prawn Suit Propulsion Cannon Fragment" },
{ "id": 35036, "count": 2, "progression": false, "tech_type": "ExosuitTorpedoArmFragment", "name": "Prawn Suit Torpedo Arm Fragment" },
{ "id": 35037, "count": 3, "progression": false, "tech_type": "BaseMapRoomFragment", "name": "Scanner Room Fragment" },
{ "id": 35038, "count": 5, "progression": true, "tech_type": "SeamothFragment", "name": "Seamoth Fragment" },
{ "id": 35039, "count": 2, "progression": false, "tech_type": "StasisRifleFragment", "name": "Stasis Rifle Fragment" },
{ "id": 35040, "count": 2, "progression": false, "tech_type": "ThermalPlantFragment", "name": "Thermal Plant Fragment" },
{ "id": 35041, "count": 4, "progression": true, "tech_type": "SeaglideFragment", "name": "Seaglide Fragment" },
{ "id": 35042, "count": 1, "progression": true, "tech_type": "RadiationSuit", "name": "Radiation Suit" },
{ "id": 35043, "count": 2, "progression": true, "tech_type": "PropulsionCannonFragment", "name": "Propulsion Cannon Fragment" },
{ "id": 35044, "count": 1, "progression": true, "tech_type": "RocketBase", "name": "Neptune Launch Platform" },
{ "id": 35045, "count": 1, "progression": true, "tech_type": "PrecursorIonPowerCell", "name": "Ion Power Cell" },
{ "id": 35046, "count": 2, "progression": false, "tech_type": "FarmingTrayFragment", "name": "Exterior Growbed Fragment" },
{ "id": 35047, "count": 1, "progression": false, "tech_type": "PictureFrameFragment", "name": "Picture Frame" },
{ "id": 35048, "count": 2, "progression": false, "tech_type": "BenchFragment", "name": "Bench Fragment" },
{ "id": 35049, "count": 1, "progression": false, "tech_type": "PlanterPotFragment", "name": "Basic Plant Pot" },
{ "id": 35050, "count": 1, "progression": false, "tech_type": "PlanterBoxFragment", "name": "Interior Growbed" },
{ "id": 35051, "count": 1, "progression": false, "tech_type": "PlanterShelfFragment", "name": "Plant Shelf" },
{ "id": 35052, "count": 2, "progression": false, "tech_type": "BaseObservatoryFragment", "name": "Observatory Fragment" },
{ "id": 35053, "count": 2, "progression": false, "tech_type": "BaseRoomFragment", "name": "Multipurpose Room Fragment" },
{ "id": 35054, "count": 2, "progression": false, "tech_type": "BaseBulkheadFragment", "name": "Bulkhead Fragment" },
{ "id": 35055, "count": 1, "progression": false, "tech_type": "Spotlight", "name": "Spotlight" },
{ "id": 35056, "count": 2, "progression": false, "tech_type": "StarshipDesk", "name": "Desk" },
{ "id": 35057, "count": 1, "progression": false, "tech_type": "StarshipChair", "name": "Swivel Chair" },
{ "id": 35058, "count": 1, "progression": false, "tech_type": "StarshipChair2", "name": "Office Chair" },
{ "id": 35059, "count": 1, "progression": false, "tech_type": "StarshipChair3", "name": "Command Chair" },
{ "id": 35060, "count": 2, "progression": false, "tech_type": "LabCounter", "name": "Counter" },
{ "id": 35061, "count": 1, "progression": false, "tech_type": "NarrowBed", "name": "Single Bed" },
{ "id": 35062, "count": 1, "progression": false, "tech_type": "Bed1", "name": "Basic Double Bed" },
{ "id": 35063, "count": 1, "progression": false, "tech_type": "Bed2", "name": "Quilted Double Bed" },
{ "id": 35064, "count": 2, "progression": false, "tech_type": "CoffeeVendingMachine", "name": "Coffee Vending Machine" },
{ "id": 35065, "count": 2, "progression": false, "tech_type": "Trashcans", "name": "Trash Can" },
{ "id": 35066, "count": 1, "progression": false, "tech_type": "Techlight", "name": "Floodlight" },
{ "id": 35067, "count": 1, "progression": false, "tech_type": "BarTable", "name": "Bar Table" },
{ "id": 35068, "count": 1, "progression": false, "tech_type": "VendingMachine", "name": "Vending Machine" },
{ "id": 35069, "count": 1, "progression": false, "tech_type": "SingleWallShelf", "name": "Single Wall Shelf" },
{ "id": 35070, "count": 1, "progression": false, "tech_type": "WallShelves", "name": "Wall Shelves" },
{ "id": 35071, "count": 1, "progression": false, "tech_type": "PlanterPot2", "name": "Round Plant Pot" },
{ "id": 35072, "count": 1, "progression": false, "tech_type": "PlanterPot3", "name": "Chic Plant Pot" },
{ "id": 35073, "count": 1, "progression": false, "tech_type": "LabTrashcan", "name": "Nuclear Waste Disposal" },
{ "id": 35074, "count": 1, "progression": false, "tech_type": "BasePlanter", "name": "Wall Planter" },
{ "id": 35075, "count": 1, "progression": true, "tech_type": "PrecursorIonBattery", "name": "Ion Battery" },
{ "id": 35076, "count": 1, "progression": true, "tech_type": "RocketBaseLadder", "name": "Neptune Gantry" },
{ "id": 35077, "count": 1, "progression": true, "tech_type": "RocketStage1", "name": "Neptune Boosters" },
{ "id": 35078, "count": 1, "progression": true, "tech_type": "RocketStage2", "name": "Neptune Fuel Reserve" },
{ "id": 35079, "count": 1, "progression": true, "tech_type": "RocketStage3", "name": "Neptune Cockpit" },
{ "id": 35080, "count": 1, "progression": false, "tech_type": "BaseFiltrationMachine", "name": "Water Filtration Machine" }
]

View File

@@ -1,521 +0,0 @@
[
{ "id": 33000, "position": { "x": -1234.3, "y": -349.7, "z": -396.0},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Blood Kelp Trench Wreck - Outside Databox" },
{ "id": 33001, "position": { "x": -1208.0, "y": -349.6, "z": -383.0},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Blood Kelp Trench Wreck - Inside Databox" },
{ "id": 33002, "position": { "x": -1210.6, "y": -340.7, "z": -393.4},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Blood Kelp Trench Wreck - PDA" },
{ "id": 33003, "position": { "x": 903.8, "y": -220.3, "z": 590.9},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Bulb Zone West Wreck - Outside Databox" },
{ "id": 33004, "position": { "x": 910.9, "y": -201.8, "z": 623.5},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Bulb Zone West Wreck - Under Databox" },
{ "id": 33005, "position": { "x": 914.9, "y": -202.1, "z": 611.8},
"need_laser_cutter": true, "can_slip_through": false,
"name": "Bulb Zone West Wreck - Inside Databox" },
{ "id": 33006, "position": { "x": 912.6, "y": -202.0, "z": 609.5},
"need_laser_cutter": true, "can_slip_through": false,
"name": "Bulb Zone West Wreck - PDA" },
{ "id": 33007, "position": { "x": 1327.1, "y": -234.9, "z": 575.8},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Bulb Zone East Wreck - Databox" },
{ "id": 33008, "position": { "x": -1407.7, "y": -344.2, "z": 721.5},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Dunes North Wreck - Outside Databox" },
{ "id": 33009, "position": { "x": -1393.9, "y": -329.7, "z": 733.5},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Dunes North Wreck - Office Databox" },
{ "id": 33010, "position": { "x": -1396.3, "y": -330.8, "z": 730.0},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Dunes North Wreck - PDA" },
{ "id": 33011, "position": { "x": -1409.8, "y": -332.4, "z": 706.9},
"need_laser_cutter": true, "can_slip_through": false,
"name": "Dunes North Wreck - Cargo Databox" },
{ "id": 33012, "position": { "x": -1626.2, "y": -357.5, "z": 99.5},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Dunes West Wreck - Databox" },
{ "id": 33013, "position": { "x": -1196.3, "y": -223.0, "z": 12.5},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Dunes East Wreck - Outside Databox" },
{ "id": 33014, "position": { "x": -1206.4, "y": -225.6, "z": 4.0},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Dunes East Wreck - Inside Databox" },
{ "id": 33015, "position": { "x": -269.7, "y": -262.8, "z": -764.3},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Grand Reef North Wreck - Outside Databox" },
{ "id": 33016, "position": { "x": -285.8, "y": -240.2, "z": -786.5},
"need_laser_cutter": true, "can_slip_through": false,
"name": "Grand Reef North Wreck - Elevator Databox" },
{ "id": 33017, "position": { "x": -285.2, "y": -262.4, "z": -788.4},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Grand Reef North Wreck - Bottom Databox" },
{ "id": 33018, "position": { "x": -272.5, "y": -254.7, "z": -788.5},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Grand Reef North Wreck - Hangar PDA" },
{ "id": 33019, "position": { "x": -850.9, "y": -473.2, "z": -1414.6},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Grand Reef South Wreck - Trench Databox" },
{ "id": 33020, "position": { "x": -889.4, "y": -433.8, "z": -1424.8},
"need_laser_cutter": true, "can_slip_through": false,
"name": "Grand Reef South Wreck - Comms Databox" },
{ "id": 33021, "position": { "x": -862.4, "y": -437.5, "z": -1444.1},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Grand Reef South Wreck - Outside Databox" },
{ "id": 33022, "position": { "x": -887.9, "y": -446.0, "z": -1422.7},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Grand Reef South Wreck - PDA" },
{ "id": 33023, "position": { "x": -23.3, "y": -105.8, "z": -604.2},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Grassy Plateaus South Wreck - Databox" },
{ "id": 33024, "position": { "x": -27.3, "y": -106.8, "z": -607.2},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Grassy Plateaus South Wreck - PDA" },
{ "id": 33025, "position": { "x": 313.9, "y": -91.8, "z": 432.6},
"need_laser_cutter": true, "can_slip_through": true,
"name": "Grassy Plateaus East Wreck - Breach Databox" },
{ "id": 33026, "position": { "x": 319.4, "y": -104.3, "z": 441.5},
"need_laser_cutter": true, "can_slip_through": true,
"name": "Grassy Plateaus East Wreck - Hangar Databox" },
{ "id": 33027, "position": { "x": -632.3, "y": -75.0, "z": -8.9},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Grassy Plateaus West Wreck - Locker PDA" },
{ "id": 33028, "position": { "x": -664.4, "y": -97.8, "z": -8.0},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Grassy Plateaus West Wreck - Data Terminal" },
{ "id": 33029, "position": { "x": -421.4, "y": -107.8, "z": -266.5},
"need_laser_cutter": true, "can_slip_through": false,
"name": "Grassy Plateaus West Wreck - Databox" },
{ "id": 33030, "position": { "x": -44.0, "y": -29.1, "z": -403.6},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Safe Shallows Wreck - PDA" },
{ "id": 33031, "position": { "x": -317.1, "y": -79.0, "z": 248.5},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Kelp Forest Wreck - Databox" },
{ "id": 33032, "position": { "x": 63.2, "y": -38.5, "z": 382.9},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Kelp Forest Wreck - PDA" },
{ "id": 33033, "position": { "x": 740.3, "y": -389.2, "z": 1179.8},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Mountains West Wreck - Outside Databox" },
{ "id": 33034, "position": { "x": 703.7, "y": -365.9, "z": 1199.3},
"need_laser_cutter": true, "can_slip_through": false,
"name": "Mountains West Wreck - Data Terminal" },
{ "id": 33035, "position": { "x": 698.2, "y": -350.8, "z": 1186.9},
"need_laser_cutter": true, "can_slip_through": false,
"name": "Mountains West Wreck - Hangar Databox" },
{ "id": 33036, "position": { "x": 676.3, "y": -343.6, "z": 1204.6},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Mountains West Wreck - Office Databox" },
{ "id": 33037, "position": { "x": 1068.5, "y": -283.4, "z": 1345.3},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Mountains East Wreck - Comms Databox" },
{ "id": 33038, "position": { "x": 1075.7, "y": -288.9, "z": 1321.8},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Mountains East Wreck - Outside Databox" },
{ "id": 33039, "position": { "x": -655.1, "y": -109.6, "z": 791.0},
"need_laser_cutter": true, "can_slip_through": false,
"name": "Northwestern Mushroom Forest Wreck - Cargo Databox" },
{ "id": 33040, "position": { "x": -663.4, "y": -111.9, "z": 777.9},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Northwestern Mushroom Forest Wreck - Office Databox" },
{ "id": 33041, "position": { "x": -662.2, "y": -113.4, "z": 777.7},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Northwestern Mushroom Forest Wreck - PDA" },
{ "id": 33042, "position": { "x": -1161.1, "y": -191.7, "z": -758.3},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Sea Treader's Path Wreck - Outside Databox" },
{ "id": 33043, "position": { "x": -1129.5, "y": -155.2, "z": -729.3},
"need_laser_cutter": true, "can_slip_through": false,
"name": "Sea Treader's Path Wreck - Hangar Databox" },
{ "id": 33044, "position": { "x": -1115.9, "y": -175.3, "z": -724.5},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Sea Treader's Path Wreck - Lobby Databox" },
{ "id": 33045, "position": { "x": -1136.8, "y": -157.0, "z": -734.6},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Sea Treader's Path Wreck - PDA" },
{ "id": 33046, "position": { "x": -789.8, "y": -216.1, "z": -711.0},
"need_laser_cutter": true, "can_slip_through": false,
"name": "Sparse Reef Wreck - Locker Databox" },
{ "id": 33047, "position": { "x": -810.7, "y": -209.3, "z": -685.5},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Sparse Reef Wreck - Outside Databox" },
{ "id": 33048, "position": { "x": -795.5, "y": -204.1, "z": -774.7},
"need_laser_cutter": true, "can_slip_through": false,
"name": "Sparse Reef Wreck - Lab Databox" },
{ "id": 33049, "position": { "x": -170.8, "y": -187.6, "z": 880.7},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Underwater Islands Wreck - Outside Databox" },
{ "id": 33050, "position": { "x": -138.4, "y": -193.6, "z": 888.7},
"need_laser_cutter": true, "can_slip_through": false,
"name": "Underwater Islands Wreck - Hangar Databox" },
{ "id": 33051, "position": { "x": -130.7, "y": -193.2, "z": 883.3},
"need_laser_cutter": true, "can_slip_through": false,
"name": "Underwater Islands Wreck - Data Terminal" },
{ "id": 33052, "position": { "x": -137.8, "y": -193.4, "z": 879.4},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Underwater Islands Wreck - Cable Databox" },
{ "id": 33053, "position": { "x": -124.4, "y": -200.7, "z": 853.0},
"need_laser_cutter": false, "can_slip_through": false, "need_propulsion_cannon": true,
"name": "Underwater Islands Wreck - Pipes Databox 1" },
{ "id": 33054, "position": { "x": -126.8, "y": -201.1, "z": 852.1},
"need_laser_cutter": false, "can_slip_through": false, "need_propulsion_cannon": true,
"name": "Underwater Islands Wreck - Pipes Databox 2" },
{ "id": 33055, "position": { "x": -643.8, "y": -509.9, "z": -941.9},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Degasi Seabase - Deep Grand Reef - Bedroom Databox" },
{ "id": 33056, "position": { "x": -635.1, "y": -502.7, "z": -951.4},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Degasi Seabase - Deep Grand Reef - Observatory Databox" },
{ "id": 33057, "position": { "x": -645.8, "y": -508.7, "z": -943.0},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Degasi Seabase - Deep Grand Reef - Bedroom PDA" },
{ "id": 33058, "position": { "x": -630.5, "y": -511.1, "z": -936.1},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Degasi Seabase - Deep Grand Reef - Outside PDA" },
{ "id": 33059, "position": { "x": -647.7, "y": -502.6, "z": -935.8},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Degasi Seabase - Deep Grand Reef - Observatory PDA" },
{ "id": 33060, "position": { "x": -639.6, "y": -505.9, "z": -946.6},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Degasi Seabase - Deep Grand Reef - Lab PDA" },
{ "id": 33061, "position": { "x": -707.2, "y": 0.5, "z": -1096.7},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Floating Island - Lake PDA" },
{ "id": 33062, "position": { "x": -765.7, "y": 17.6, "z": -1116.4},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Degasi Seabase - Floating Island - Databox" },
{ "id": 33063, "position": { "x": -754.9, "y": 14.6, "z": -1108.9},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Degasi Seabase - Floating Island - Room PDA" },
{ "id": 33064, "position": { "x": -765.3, "y": 14.1, "z": -1115.0},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Degasi Seabase - Floating Island - Green Wall PDA" },
{ "id": 33065, "position": { "x": -758.6, "y": 14.1, "z": -1111.3},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Degasi Seabase - Floating Island - Corridor PDA" },
{ "id": 33066, "position": { "x": -805.4, "y": 76.9, "z": -1055.7},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Degasi Seabase - Floating Island - North Observatory PDA" },
{ "id": 33067, "position": { "x": -715.9, "y": 75.4, "z": -1168.8},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Degasi Seabase - Floating Island - South Observatory PDA" },
{ "id": 33068, "position": { "x": -540.5, "y": -250.8, "z": -83.4},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Jellyshroom Cave - PDA" },
{ "id": 33069, "position": { "x": 110.6, "y": -264.9, "z": -369.0},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Degasi Seabase - Jellyshroom Cave - Bedroom Databox" },
{ "id": 33070, "position": { "x": 80.6, "y": -268.6, "z": -358.3},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Degasi Seabase - Jellyshroom Cave - Detached PDA" },
{ "id": 33071, "position": { "x": 78.2, "y": -265.0, "z": -373.4},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Degasi Seabase - Jellyshroom Cave - Office PDA" },
{ "id": 33072, "position": { "x": 85.1, "y": -264.1, "z": -372.8},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Degasi Seabase - Jellyshroom Cave - Locker PDA" },
{ "id": 33073, "position": { "x": 112.3, "y": -264.9, "z": -369.3},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Degasi Seabase - Jellyshroom Cave - Bedroom PDA" },
{ "id": 33074, "position": { "x": 95.5, "y": -258.9, "z": -366.5},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Degasi Seabase - Jellyshroom Cave - Observatory PDA" },
{ "id": 33075, "position": { "x": -483.6, "y": -504.7, "z": 1326.6},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Lifepod 2 - Databox" },
{ "id": 33076, "position": { "x": -481.4, "y": -503.6, "z": 1324.1},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Lifepod 2 - PDA" },
{ "id": 33077, "position": { "x": -34.2, "y": -22.4, "z": 410.5},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Lifepod 3 - Databox" },
{ "id": 33078, "position": { "x": -33.8, "y": -22.5, "z": 408.8},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Lifepod 3 - PDA" },
{ "id": 33079, "position": { "x": 712.4, "y": -3.4, "z": 160.8},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Lifepod 4 - Databox" },
{ "id": 33080, "position": { "x": 712.0, "y": -3.5, "z": 161.5},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Lifepod 4 - PDA" },
{ "id": 33081, "position": { "x": 358.7, "y": -117.1, "z": 306.8},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Lifepod 6 - Databox" },
{ "id": 33082, "position": { "x": 361.8, "y": -116.2, "z": 309.5},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Lifepod 6 - Inside PDA" },
{ "id": 33083, "position": { "x": 359.9, "y": -117.0, "z": 312.1},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Lifepod 6 - Outside PDA" },
{ "id": 33084, "position": { "x": -56.0, "y": -182.0, "z": -1039.0},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Lifepod 7 - PDA" },
{ "id": 33085, "position": { "x": 1119.5, "y": -271.7, "z": 561.7},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Lifepod 12 - Databox" },
{ "id": 33086, "position": { "x": 1116.1, "y": -271.3, "z": 566.9},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Lifepod 12 - PDA" },
{ "id": 33087, "position": { "x": -926.4, "y": -185.2, "z": 501.8},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Lifepod 13 - Databox" },
{ "id": 33088, "position": { "x": -926.8, "y": -184.4, "z": 506.6},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Lifepod 13 - PDA" },
{ "id": 33089, "position": { "x": -514.5, "y": -98.1, "z": -56.5},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Lifepod 17 - PDA" },
{ "id": 33090, "position": { "x": -809.8, "y": -302.2, "z": -876.9},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Lifepod 19 - Databox" },
{ "id": 33091, "position": { "x": -806.1, "y": -294.1, "z": -866.0},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Lifepod 19 - Outside PDA" },
{ "id": 33092, "position": { "x": -810.5, "y": -299.4, "z": -873.1},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Lifepod 19 - Inside PDA" },
{ "id": 33093, "position": { "x": 903.5, "y": -0.2, "z": 16.1},
"need_laser_cutter": false, "can_slip_through": false, "need_propulsion_cannon": true,
"name": "Aurora Seamoth Bay - Upgrade Console" },
{ "id": 33094, "position": { "x": 872.5, "y": 2.7, "z": -0.7},
"need_laser_cutter": false, "can_slip_through": false, "need_propulsion_cannon": true,
"name": "Aurora Drive Room - Upgrade Console" },
{ "id": 33095, "position": { "x": 991.6, "y": 3.2, "z": -31.0},
"need_laser_cutter": true, "can_slip_through": false, "need_propulsion_cannon": true,
"name": "Aurora Prawn Suit Bay - Upgrade Console" },
{ "id": 33096, "position": { "x": 952.1, "y": 41.2, "z": 113.9},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Aurora - Office PDA" },
{ "id": 33097, "position": { "x": 977.2, "y": 39.1, "z": 83.0},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Aurora - Corridor PDA" },
{ "id": 33098, "position": { "x": 954.9, "y": 11.2, "z": 3.4},
"need_laser_cutter": false, "can_slip_through": false, "need_propulsion_cannon": true,
"name": "Aurora - Cargo Bay PDA" },
{ "id": 33099, "position": { "x": 907.1, "y": -1.5, "z": 15.3},
"need_laser_cutter": false, "can_slip_through": false, "need_propulsion_cannon": true,
"name": "Aurora - Seamoth Bay PDA" },
{ "id": 33100, "position": { "x": 951.8, "y": -2.3, "z": -34.7},
"need_laser_cutter": true, "can_slip_through": false, "need_propulsion_cannon": true,
"name": "Aurora - Medkit Locker PDA" },
{ "id": 33101, "position": { "x": 952.0, "y": -3.7, "z": -23.4},
"need_laser_cutter": true, "can_slip_through": false, "need_propulsion_cannon": true,
"name": "Aurora - Locker PDA" },
{ "id": 33102, "position": { "x": 986.5, "y": 9.6, "z": -48.6},
"need_laser_cutter": true, "can_slip_through": false, "need_propulsion_cannon": true,
"name": "Aurora - Canteen PDA" },
{ "id": 33103, "position": { "x": 951.3, "y": 11.2, "z": -51.0},
"need_laser_cutter": true, "can_slip_through": false, "need_propulsion_cannon": true,
"name": "Aurora - Cabin 4 PDA" },
{ "id": 33104, "position": { "x": 967.1, "y": 10.4, "z": -47.4},
"need_laser_cutter": true, "can_slip_through": false, "need_propulsion_cannon": true,
"name": "Aurora - Cabin 7 PDA" },
{ "id": 33105, "position": { "x": 964.1, "y": 11.1, "z": -61.9},
"need_laser_cutter": true, "can_slip_through": false, "need_propulsion_cannon": true,
"name": "Aurora - Cabin 1 PDA" },
{ "id": 33106, "position": { "x": 971.2, "y": 10.8, "z": -70.4},
"need_laser_cutter": true, "can_slip_through": false, "need_propulsion_cannon": true,
"name": "Aurora - Captain PDA" },
{ "id": 33107, "position": { "x": 1033.6, "y": -8.5, "z": 16.2},
"need_laser_cutter": false, "can_slip_through": false, "need_propulsion_cannon": true,
"name": "Aurora - Ring PDA" },
{ "id": 33108, "position": { "x": 1032.5, "y": -7.8, "z": 32.4},
"need_laser_cutter": false, "can_slip_through": false, "need_propulsion_cannon": true,
"name": "Aurora - Lab PDA" },
{ "id": 33109, "position": { "x": 945.8, "y": 40.8, "z": 115.1},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Aurora - Office Data Terminal" },
{ "id": 33110, "position": { "x": 974.8, "y": 10.0, "z": -77.0},
"need_laser_cutter": true, "can_slip_through": false, "need_propulsion_cannon": true,
"name": "Aurora - Captain Data Terminal" },
{ "id": 33111, "position": { "x": 1040.8, "y": -11.4, "z": -3.4},
"need_laser_cutter": true, "can_slip_through": false, "need_propulsion_cannon": true,
"name": "Aurora - Battery Room Data Terminal" },
{ "id": 33112, "position": { "x": 1029.5, "y": -8.7, "z": 35.9},
"need_laser_cutter": false, "can_slip_through": false, "need_propulsion_cannon": true,
"name": "Aurora - Lab Data Terminal" },
{ "id": 33113, "position": { "x": 432.2, "y": 3.0, "z": 1193.2},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Quarantine Enforcement Platform's - Upper Alien Data Terminal" },
{ "id": 33114, "position": { "x": 474.4, "y": -4.5, "z": 1224.4},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Quarantine Enforcement Platform's - Mid Alien Data Terminal" },
{ "id": 33115, "position": { "x": -1224.2, "y": -400.4, "z": 1057.9},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Dunes Sanctuary - Alien Data Terminal" },
{ "id": 33116, "position": { "x": -895.5, "y": -311.6, "z": -838.1},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Deep Sparse Reef Sanctuary - Alien Data Terminal" },
{ "id": 33117, "position": { "x": -642.9, "y": -563.5, "z": 1485.5},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Northern Blood Kelp Zone Sanctuary - Alien Data Terminal" },
{ "id": 33118, "position": { "x": -1112.3, "y": -687.3, "z": -695.5},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Lost River Laboratory Cache - Alien Data Terminal" },
{ "id": 33119, "position": { "x": -280.2, "y": -804.3, "z": 305.1},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Disease Research Facility - Upper Alien Data Terminal" },
{ "id": 33120, "position": { "x": -267.9, "y": -806.6, "z": 250.0},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Disease Research Facility - Mid Alien Data Terminal" },
{ "id": 33121, "position": { "x": -286.2, "y": -815.6, "z": 297.8},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Disease Research Facility - Lower Alien Data Terminal" },
{ "id": 33122, "position": { "x": -71.3, "y": -1227.2, "z": 104.8},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Alien Thermal Plant - Entrance Alien Data Terminal" },
{ "id": 33123, "position": { "x": -38.7, "y": -1226.6, "z": 111.8},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Alien Thermal Plant - Green Alien Data Terminal" },
{ "id": 33124, "position": { "x": -30.4, "y": -1220.3, "z": 111.8},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Alien Thermal Plant - Yellow Alien Data Terminal" },
{ "id": 33125, "position": { "x": 245.8, "y": -1430.6, "z": -311.5},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Primary Containment Facility's Antechamber - Alien Data Terminal" },
{ "id": 33126, "position": { "x": 165.5, "y": -1442.4, "z": -385.8},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Primary Containment Facility's Egg Laboratory - Alien Data Terminal" },
{ "id": 33127, "position": { "x": 348.7, "y": -1443.5, "z": -291.9},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Primary Containment Facility's Pipe Room - Alien Data Terminal" },
{ "id": 33128, "position": { "x": -641.8, "y": -111.3, "z": -19.7},
"need_laser_cutter": true, "can_slip_through": false,
"name": "Grassy Plateaus West Wreck - Beam PDA" },
{ "id": 33129, "position": { "x": -748.9, "y": 14.4, "z": -1179.5},
"need_laser_cutter": false, "can_slip_through": false,
"name": "Floating Island - Cave Entrance PDA" }
]