Subnautica: revamp filler item pool

This commit is contained in:
Fabian Dill 2023-05-25 22:57:15 +02:00 committed by Fabian Dill
parent b077b2aeef
commit 532c4c068f
4 changed files with 203 additions and 396 deletions

View File

@ -13,11 +13,17 @@ if __name__ == "__main__":
sys.path.append(new_home) sys.path.append(new_home)
from worlds.subnautica.Locations import Vector, location_table from worlds.subnautica.Locations import Vector, location_table
from worlds.subnautica.Items import item_table, group_items from worlds.subnautica.Items import item_table, group_items, items_by_type
from NetUtils import encode from NetUtils import encode
export_folder = os.path.join(new_home, "Subnautica Export")
os.makedirs(export_folder, exist_ok=True)
def in_export_folder(path: str) -> str:
return os.path.join(export_folder, path)
payload = {location_id: location_data["position"] for location_id, location_data in location_table.items()} payload = {location_id: location_data["position"] for location_id, location_data in location_table.items()}
with open("locations.json", "w") as f: with open(in_export_folder("locations.json"), "w") as f:
json.dump(payload, f) json.dump(payload, f)
# copy-paste from Rules # copy-paste from Rules
@ -49,17 +55,22 @@ if __name__ == "__main__":
"751": [location_id for location_id, location_data "751": [location_id for location_id, location_data
in location_table.items() if far_away(location_data["position"])], in location_table.items() if far_away(location_data["position"])],
} }
with open("logic.json", "w") as f: with open(in_export_folder("logic.json"), "w") as f:
json.dump(payload, f) json.dump(payload, f)
itemcount = sum(item_data["count"] for item_data in item_table.values()) itemcount = sum(item_data.count for item_data in item_table.values())
assert itemcount == len(location_table), f"{itemcount} != {len(location_table)}" assert itemcount == len(location_table), f"{itemcount} != {len(location_table)}"
payload = {item_id: item_data["tech_type"] for item_id, item_data in item_table.items()} payload = {item_id: item_data.tech_type for item_id, item_data in item_table.items()}
import json import json
with open("items.json", "w") as f: with open(in_export_folder("items.json"), "w") as f:
json.dump(payload, f) json.dump(payload, f)
with open("group_items.json", "w") as f:
with open(in_export_folder("group_items.json"), "w") as f:
# encode to convert set to list
f.write(encode(group_items)) f.write(encode(group_items))
print(f"Subnautica exports dumped to {new_home}") with open(in_export_folder("item_types.json"), "w") as f:
json.dump(items_by_type, f)
print(f"Subnautica exports dumped to {in_export_folder('')}")

View File

@ -1,390 +1,154 @@
from BaseClasses import ItemClassification from BaseClasses import ItemClassification as IC
from typing import TypedDict, Dict, Set from typing import NamedTuple, Dict, Set, List
from enum import IntEnum
class ItemDict(TypedDict): class ItemType(IntEnum):
classification: ItemClassification technology = 1
resource = 2
group = 3
class ItemData(NamedTuple):
classification: IC
count: int count: int
name: str name: str
tech_type: str tech_type: str
type: ItemType = ItemType.technology
item_table: Dict[int, ItemDict] = { def make_resource_bundle_data(display_name: str, internal_name: str = "") -> ItemData:
35000: {'classification': ItemClassification.useful, if not internal_name:
'count': 1, internal_name = display_name
'name': 'Compass', return ItemData(IC.filler, 0, display_name, internal_name, ItemType.resource)
'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': 'Water Filtration Suit',
'tech_type': 'WaterFiltrationSuit'},
35008: {'classification': ItemClassification.progression,
'count': 1,
'name': 'Alien Containment',
'tech_type': 'BaseWaterPark'},
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': 4,
'name': 'Cyclops Bridge Fragment',
'tech_type': 'CyclopsBridgeFragment'},
35021: {'classification': ItemClassification.progression,
'count': 4,
'name': 'Cyclops Engine Fragment',
'tech_type': 'CyclopsEngineFragment'},
35022: {'classification': ItemClassification.progression,
'count': 4,
'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': 2,
'name': 'Light Stick Fragment',
'tech_type': 'TechlightFragment'},
35026: {'classification': ItemClassification.progression,
'count': 5,
'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': 6,
'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.progression,
'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': 4,
'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_skip_balancing,
'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',
'tech_type': 'FarmingTray'},
35047: {'classification': ItemClassification.filler,
'count': 1,
'name': 'Picture Frame',
'tech_type': 'PictureFrameFragment'},
35048: {'classification': ItemClassification.filler,
'count': 1,
'name': 'Bench',
'tech_type': 'Bench'},
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': 1,
'name': 'Observatory',
'tech_type': 'BaseObservatory'},
35053: {'classification': ItemClassification.progression,
'count': 1,
'name': 'Multipurpose Room',
'tech_type': 'BaseRoom'},
35054: {'classification': ItemClassification.useful,
'count': 1,
'name': 'Bulkhead',
'tech_type': 'BaseBulkhead'},
35055: {'classification': ItemClassification.filler,
'count': 1,
'name': 'Spotlight',
'tech_type': 'Spotlight'},
35056: {'classification': ItemClassification.filler,
'count': 1,
'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': 1,
'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': 1,
'name': 'Coffee Vending Machine',
'tech_type': 'CoffeeVendingMachine'},
35065: {'classification': ItemClassification.filler,
'count': 1,
'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_skip_balancing,
'count': 1,
'name': 'Neptune Gantry',
'tech_type': 'RocketBaseLadder'},
35077: {'classification': ItemClassification.progression_skip_balancing,
'count': 1,
'name': 'Neptune Boosters',
'tech_type': 'RocketStage1'},
35078: {'classification': ItemClassification.progression_skip_balancing,
'count': 1,
'name': 'Neptune Fuel Reserve',
'tech_type': 'RocketStage2'},
35079: {'classification': ItemClassification.progression_skip_balancing,
'count': 1,
'name': 'Neptune Cockpit',
'tech_type': 'RocketStage3'},
35080: {'classification': ItemClassification.filler,
'count': 1,
'name': 'Water Filtration Machine',
'tech_type': 'BaseFiltrationMachine'},
35081: {'classification': ItemClassification.progression,
'count': 1,
'name': 'Ultra High Capacity Tank',
'tech_type': 'HighCapacityTank'},
35082: {'classification': ItemClassification.progression,
'count': 1,
'name': 'Large Room',
'tech_type': 'BaseLargeRoom'},
# awarded with their rooms, keeping that as-is as they're cosmetic
35083: {'classification': ItemClassification.filler,
'count': 0,
'name': 'Large Room Glass Dome',
'tech_type': 'BaseLargeGlassDome'},
35084: {'classification': ItemClassification.filler,
'count': 0,
'name': 'Multipurpose Room Glass Dome',
'tech_type': 'BaseGlassDome'},
35085: {'classification': ItemClassification.filler,
'count': 0,
'name': 'Partition',
'tech_type': 'BasePartition'},
35086: {'classification': ItemClassification.filler,
'count': 0,
'name': 'Partition Door',
'tech_type': 'BasePartitionDoor'},
# new items that the mod implements
item_table: Dict[int, ItemData] = {
35000: ItemData(IC.useful, 1, "Compass", "Compass"),
35001: ItemData(IC.progression, 1, "Lightweight High Capacity Tank", "PlasteelTank"),
35002: ItemData(IC.progression, 1, "Vehicle Upgrade Console", "BaseUpgradeConsole"),
35003: ItemData(IC.progression, 1, "Ultra Glide Fins", "UltraGlideFins"),
35004: ItemData(IC.useful, 1, "Cyclops Sonar Upgrade", "CyclopsSonarModule"),
35005: ItemData(IC.useful, 1, "Reinforced Dive Suit", "ReinforcedDiveSuit"),
35006: ItemData(IC.useful, 1, "Cyclops Thermal Reactor Module", "CyclopsThermalReactorModule"),
35007: ItemData(IC.filler, 1, "Water Filtration Suit", "WaterFiltrationSuit"),
35008: ItemData(IC.progression, 1, "Alien Containment", "BaseWaterPark"),
35009: ItemData(IC.useful, 1, "Creature Decoy", "CyclopsDecoy"),
35010: ItemData(IC.useful, 1, "Cyclops Fire Suppression System", "CyclopsFireSuppressionModule"),
35011: ItemData(IC.useful, 1, "Swim Charge Fins", "SwimChargeFins"),
35012: ItemData(IC.useful, 1, "Repulsion Cannon", "RepulsionCannon"),
35013: ItemData(IC.useful, 1, "Cyclops Decoy Tube Upgrade", "CyclopsDecoyModule"),
35014: ItemData(IC.progression, 1, "Cyclops Shield Generator", "CyclopsShieldModule"),
35015: ItemData(IC.progression, 1, "Cyclops Depth Module MK1", "CyclopsHullModule1"),
35016: ItemData(IC.useful, 1, "Cyclops Docking Bay Repair Module", "CyclopsSeamothRepairModule"),
35017: ItemData(IC.useful, 2, "Battery Charger fragment", "BatteryChargerFragment"),
35018: ItemData(IC.filler, 2, "Beacon Fragment", "BeaconFragment"),
35019: ItemData(IC.useful, 2, "Bioreactor Fragment", "BaseBioReactorFragment"),
35020: ItemData(IC.progression, 4, "Cyclops Bridge Fragment", "CyclopsBridgeFragment"),
35021: ItemData(IC.progression, 4, "Cyclops Engine Fragment", "CyclopsEngineFragment"),
35022: ItemData(IC.progression, 4, "Cyclops Hull Fragment", "CyclopsHullFragment"),
35023: ItemData(IC.filler, 2, "Grav Trap Fragment", "GravSphereFragment"),
35024: ItemData(IC.progression, 3, "Laser Cutter Fragment", "LaserCutterFragment"),
35025: ItemData(IC.filler, 2, "Light Stick Fragment", "TechlightFragment"),
35026: ItemData(IC.progression, 5, "Mobile Vehicle Bay Fragment", "ConstructorFragment"),
35027: ItemData(IC.progression, 3, "Modification Station Fragment", "WorkbenchFragment"),
35028: ItemData(IC.progression, 2, "Moonpool Fragment", "MoonpoolFragment"),
35029: ItemData(IC.useful, 3, "Nuclear Reactor Fragment", "BaseNuclearReactorFragment"),
35030: ItemData(IC.useful, 2, "Power Cell Charger Fragment", "PowerCellChargerFragment"),
35031: ItemData(IC.filler, 1, "Power Transmitter Fragment", "PowerTransmitterFragment"),
35032: ItemData(IC.progression, 6, "Prawn Suit Fragment", "ExosuitFragment"),
35033: ItemData(IC.useful, 2, "Prawn Suit Drill Arm Fragment", "ExosuitDrillArmFragment"),
35034: ItemData(IC.useful, 2, "Prawn Suit Grappling Arm Fragment", "ExosuitGrapplingArmFragment"),
35035: ItemData(IC.useful, 2, "Prawn Suit Propulsion Cannon Fragment", "ExosuitPropulsionArmFragment"),
35036: ItemData(IC.useful, 2, "Prawn Suit Torpedo Arm Fragment", "ExosuitTorpedoArmFragment"),
35037: ItemData(IC.useful, 3, "Scanner Room Fragment", "BaseMapRoomFragment"),
35038: ItemData(IC.progression, 5, "Seamoth Fragment", "SeamothFragment"),
35039: ItemData(IC.progression, 2, "Stasis Rifle Fragment", "StasisRifleFragment"),
35040: ItemData(IC.useful, 2, "Thermal Plant Fragment", "ThermalPlantFragment"),
35041: ItemData(IC.progression, 4, "Seaglide Fragment", "SeaglideFragment"),
35042: ItemData(IC.progression, 1, "Radiation Suit", "RadiationSuit"),
35043: ItemData(IC.progression, 2, "Propulsion Cannon Fragment", "PropulsionCannonFragment"),
35044: ItemData(IC.progression_skip_balancing, 1, "Neptune Launch Platform", "RocketBase"),
35045: ItemData(IC.progression, 1, "Ion Power Cell", "PrecursorIonPowerCell"),
35046: ItemData(IC.filler, 2, "Exterior Growbed", "FarmingTray"),
35047: ItemData(IC.filler, 1, "Picture Frame", "PictureFrameFragment"),
35048: ItemData(IC.filler, 1, "Bench", "Bench"),
35049: ItemData(IC.filler, 1, "Basic Plant Pot", "PlanterPotFragment"),
35050: ItemData(IC.filler, 1, "Interior Growbed", "PlanterBoxFragment"),
35051: ItemData(IC.filler, 1, "Plant Shelf", "PlanterShelfFragment"),
35052: ItemData(IC.filler, 1, "Observatory", "BaseObservatory"),
35053: ItemData(IC.progression, 1, "Multipurpose Room", "BaseRoom"),
35054: ItemData(IC.useful, 1, "Bulkhead", "BaseBulkhead"),
35055: ItemData(IC.filler, 1, "Spotlight", "Spotlight"),
35056: ItemData(IC.filler, 1, "Desk", "StarshipDesk"),
35057: ItemData(IC.filler, 1, "Swivel Chair", "StarshipChair"),
35058: ItemData(IC.filler, 1, "Office Chair", "StarshipChair2"),
35059: ItemData(IC.filler, 1, "Command Chair", "StarshipChair3"),
35060: ItemData(IC.filler, 1, "Counter", "LabCounter"),
35061: ItemData(IC.filler, 1, "Single Bed", "NarrowBed"),
35062: ItemData(IC.filler, 1, "Basic Double Bed", "Bed1"),
35063: ItemData(IC.filler, 1, "Quilted Double Bed", "Bed2"),
35064: ItemData(IC.filler, 1, "Coffee Vending Machine", "CoffeeVendingMachine"),
35065: ItemData(IC.filler, 1, "Trash Can", "Trashcans"),
35066: ItemData(IC.filler, 1, "Floodlight", "Techlight"),
35067: ItemData(IC.filler, 1, "Bar Table", "BarTable"),
35068: ItemData(IC.filler, 1, "Vending Machine", "VendingMachine"),
35069: ItemData(IC.filler, 1, "Single Wall Shelf", "SingleWallShelf"),
35070: ItemData(IC.filler, 1, "Wall Shelves", "WallShelves"),
35071: ItemData(IC.filler, 1, "Round Plant Pot", "PlanterPot2"),
35072: ItemData(IC.filler, 1, "Chic Plant Pot", "PlanterPot3"),
35073: ItemData(IC.filler, 1, "Nuclear Waste Disposal", "LabTrashcan"),
35074: ItemData(IC.filler, 1, "Wall Planter", "BasePlanter"),
35075: ItemData(IC.progression, 1, "Ion Battery", "PrecursorIonBattery"),
35076: ItemData(IC.progression_skip_balancing, 1, "Neptune Gantry", "RocketBaseLadder"),
35077: ItemData(IC.progression_skip_balancing, 1, "Neptune Boosters", "RocketStage1"),
35078: ItemData(IC.progression_skip_balancing, 1, "Neptune Fuel Reserve", "RocketStage2"),
35079: ItemData(IC.progression_skip_balancing, 1, "Neptune Cockpit", "RocketStage3"),
35080: ItemData(IC.filler, 1, "Water Filtration Machine", "BaseFiltrationMachine"),
35081: ItemData(IC.progression, 1, "Ultra High Capacity Tank", "HighCapacityTank"),
35082: ItemData(IC.progression, 1, "Large Room", "BaseLargeRoom"),
# awarded with their rooms, keeping that as-is as they"re cosmetic
35083: ItemData(IC.filler, 0, "Large Room Glass Dome", "BaseLargeGlassDome"),
35084: ItemData(IC.filler, 0, "Multipurpose Room Glass Dome", "BaseGlassDome"),
35085: ItemData(IC.filler, 0, "Partition", "BasePartition"),
35086: ItemData(IC.filler, 0, "Partition Door", "BasePartitionDoor"),
# Bundles of items
# Awards all furniture as a bundle # Awards all furniture as a bundle
35100: {'classification': ItemClassification.filler, 35100: ItemData(IC.filler, 0, "Furniture", "AP_Furniture", ItemType.group),
'count': 0,
'name': 'Furniture',
'tech_type': 'Furniture'},
# Awards all farming blueprints as a bundle # Awards all farming blueprints as a bundle
35101: {'classification': ItemClassification.filler, 35101: ItemData(IC.filler, 0, "Farming", "AP_Farming", ItemType.group),
'count': 0,
'name': 'Farming', # Awards multiple resources as a bundle
'tech_type': 'Farming'}, 35102: ItemData(IC.filler, 0, "Resources Bundle", "AP_Resources", ItemType.group),
# resource bundles, as convenience/filler
# ores
35200: make_resource_bundle_data("Titanium"),
35201: make_resource_bundle_data("Copper Ore", "Copper"),
35202: make_resource_bundle_data("Silver Ore", "Silver"),
35203: make_resource_bundle_data("Gold"),
35204: make_resource_bundle_data("Lead"),
35205: make_resource_bundle_data("Diamond"),
35206: make_resource_bundle_data("Lithium"),
35207: make_resource_bundle_data("Ruby", "AluminumOxide"),
35208: make_resource_bundle_data("Nickel Ore", "Nickel"),
35209: make_resource_bundle_data("Crystalline Sulfur", "Sulphur"),
35210: make_resource_bundle_data("Salt Deposit", "Salt"),
35211: make_resource_bundle_data("Kyanite"),
35212: make_resource_bundle_data("Magnetite"),
35213: make_resource_bundle_data("Reactor Rod", "ReactorRod"),
} }
advancement_item_names: Set[str] = set()
non_advancement_item_names: Set[str] = set()
items_by_type: Dict[ItemType, List[int]] = {item_type: [] for item_type in ItemType}
for item_id, item_data in item_table.items(): for item_id, item_data in item_table.items():
item_name = item_data["name"] items_by_type[item_data.type].append(item_id)
if ItemClassification.progression in item_data["classification"]:
advancement_item_names.add(item_name)
else:
non_advancement_item_names.add(item_name)
group_items: Dict[int, Set[int]] = { group_items: Dict[int, Set[int]] = {
35100: {35025, 35047, 35048, 35056, 35057, 35058, 35059, 35060, 35061, 35062, 35063, 35064, 35065, 35067, 35068, 35100: {35025, 35047, 35048, 35056, 35057, 35058, 35059, 35060, 35061, 35062, 35063, 35064, 35065, 35067, 35068,
35069, 35070, 35073, 35074}, 35069, 35070, 35073, 35074},
35101: {35049, 35050, 35051, 35071, 35072, 35074} 35101: {35049, 35050, 35051, 35071, 35072, 35074},
35102: set(items_by_type[ItemType.resource]),
} }

View File

@ -2,7 +2,7 @@ from __future__ import annotations
import logging import logging
import itertools import itertools
from typing import List, Dict, Any from typing import List, Dict, Any, cast
from BaseClasses import Region, Entrance, Location, Item, Tutorial, ItemClassification from BaseClasses import Region, Entrance, Location, Item, Tutorial, ItemClassification
from worlds.AutoWorld import World, WebWorld from worlds.AutoWorld import World, WebWorld
@ -10,7 +10,7 @@ from . import Items
from . import Locations from . import Locations
from . import Creatures from . import Creatures
from . import Options from . import Options
from .Items import item_table, group_items from .Items import item_table, group_items, items_by_type, ItemType
from .Rules import set_rules from .Rules import set_rules
logger = logging.getLogger("Subnautica") logger = logging.getLogger("Subnautica")
@ -40,12 +40,12 @@ class SubnauticaWorld(World):
game = "Subnautica" game = "Subnautica"
web = SubnaticaWeb() web = SubnaticaWeb()
item_name_to_id = {data["name"]: item_id for item_id, data in Items.item_table.items()} item_name_to_id = {data.name: item_id for item_id, data in Items.item_table.items()}
location_name_to_id = all_locations location_name_to_id = all_locations
option_definitions = Options.options option_definitions = Options.options
data_version = 9 data_version = 10
required_client_version = (0, 4, 0) required_client_version = (0, 4, 1)
creatures_to_scan: List[str] creatures_to_scan: List[str]
@ -61,8 +61,8 @@ class SubnauticaWorld(World):
self.multiworld.creature_scans[self.player].value self.multiworld.creature_scans[self.player].value
) )
self.creatures_to_scan = self.multiworld.random.sample(creature_pool, self.creatures_to_scan = self.multiworld.random.sample(
self.multiworld.creature_scans[self.player].value) creature_pool, self.multiworld.creature_scans[self.player].value)
def create_regions(self): def create_regions(self):
self.multiworld.regions += [ self.multiworld.regions += [
@ -94,27 +94,46 @@ class SubnauticaWorld(World):
for item_id, item in item_table.items(): for item_id, item in item_table.items():
if item_id in grouped: if item_id in grouped:
extras += item["count"] extras += item.count
else: else:
for i in range(item["count"]): for i in range(item.count):
subnautica_item = self.create_item(item["name"]) subnautica_item = self.create_item(item.name)
if item["name"] == "Neptune Launch Platform": if item.name == "Neptune Launch Platform":
self.multiworld.get_location("Aurora - Captain Data Terminal", self.player).place_locked_item( self.multiworld.get_location("Aurora - Captain Data Terminal", self.player).place_locked_item(
subnautica_item) subnautica_item)
else: else:
pool.append(subnautica_item) pool.append(subnautica_item)
group_amount: int = 3 group_amount: int = 2
assert len(group_items) * group_amount <= extras assert len(group_items) * group_amount <= extras
for name in ("Furniture", "Farming"): for item_id in group_items:
name = item_table[item_id].name
for _ in range(group_amount): for _ in range(group_amount):
pool.append(self.create_item(name)) pool.append(self.create_item(name))
extras -= group_amount extras -= group_amount
for item_name in self.multiworld.random.choices( for item_name in self.multiworld.random.sample(
sorted(Items.advancement_item_names - {"Neptune Launch Platform"}), k=extras): # list of high-count important fragments as priority filler
[
"Cyclops Engine Fragment",
"Modification Station Fragment",
"Mobile Vehicle Bay Fragment",
"Seamoth Fragment",
"Cyclops Hull Fragment",
"Cyclops Bridge Fragment",
"Prawn Suit Fragment",
"Moonpool Fragment",
],
k=min(extras, 8)):
item = self.create_item(item_name) item = self.create_item(item_name)
pool.append(item) pool.append(item)
extras -= 1
# resource bundle filler
for _ in range(extras):
item = self.create_filler()
item = cast(SubnauticaItem, item)
pool.append(item)
self.multiworld.itempool += pool self.multiworld.itempool += pool
@ -138,7 +157,7 @@ class SubnauticaWorld(World):
item_id: int = self.item_name_to_id[name] item_id: int = self.item_name_to_id[name]
return SubnauticaItem(name, return SubnauticaItem(name,
item_table[item_id]["classification"], item_table[item_id].classification,
item_id, player=self.player) item_id, player=self.player)
def create_region(self, name: str, locations=None, exits=None): def create_region(self, name: str, locations=None, exits=None):
@ -153,6 +172,9 @@ class SubnauticaWorld(World):
ret.exits.append(Entrance(self.player, region_exit, ret)) ret.exits.append(Entrance(self.player, region_exit, ret))
return ret return ret
def get_filler_item_name(self) -> str:
return item_table[self.multiworld.random.choice(items_by_type[ItemType.resource])].name
class SubnauticaLocation(Location): class SubnauticaLocation(Location):
game: str = "Subnautica" game: str = "Subnautica"

View File

@ -8,8 +8,18 @@ class SubnauticaTest(unittest.TestCase):
def testIDRange(self): def testIDRange(self):
for name, id in subnautica.SubnauticaWorld.location_name_to_id.items(): for name, id in subnautica.SubnauticaWorld.location_name_to_id.items():
with self.subTest(item=name): with self.subTest(location=name):
if "Scan" in name: if "Scan" in name:
self.assertLess(self.scancutoff, id) self.assertLess(self.scancutoff, id)
else: else:
self.assertGreater(self.scancutoff, id) self.assertGreater(self.scancutoff, id)
def testGroupAssociation(self):
from worlds.subnautica import Items
for item_id, item_data in Items.item_table.items():
if item_data.type == Items.ItemType.group:
with self.subTest(item=item_data.name):
self.assertIn(item_id, Items.group_items)
for item_id in Items.group_items:
with self.subTest(item_id=item_id):
self.assertEqual(Items.item_table[item_id].type, Items.ItemType.group)