diff --git a/test/general/test_ids.py b/test/general/test_ids.py index e51a070c1f..b09170d1a9 100644 --- a/test/general/test_ids.py +++ b/test/general/test_ids.py @@ -52,8 +52,23 @@ class TestIDs(unittest.TestCase): def test_duplicate_location_ids(self): """Test that a game doesn't have location id overlap within its own datapackage""" for gamename, world_type in AutoWorldRegister.world_types.items(): + self.maxDiff = None + with self.subTest(game=gamename): - self.assertEqual(len(world_type.location_id_to_name), len(world_type.location_name_to_id)) + len_location_id_to_name = len(world_type.location_id_to_name) + len_location_name_to_id = len(world_type.location_name_to_id) + + if len_location_id_to_name != len_location_name_to_id: + self.assertCountEqual( + world_type.location_id_to_name.values(), + world_type.location_name_to_id.keys(), + "\nThese locations have overlapping ids with other locations in its own world") + self.assertCountEqual( + world_type.location_id_to_name.keys(), + world_type.location_name_to_id.values(), + "\nThese locations have overlapping names with other locations in its own world") + + self.assertEqual(len_location_id_to_name, len_location_name_to_id) def test_postgen_datapackage(self): """Generates a solo multiworld and checks that the datapackage is still valid""" diff --git a/test/general/test_reachability.py b/test/general/test_reachability.py index b45a2bdfc0..3210daeabe 100644 --- a/test/general/test_reachability.py +++ b/test/general/test_reachability.py @@ -52,7 +52,8 @@ class TestBase(unittest.TestCase): state = multiworld.get_all_state(False) for location in multiworld.get_locations(): with self.subTest("Location should be reached", location=location.name): - self.assertTrue(location.can_reach(state), f"{location.name} unreachable") + if not location.can_reach(state): + self.assertTrue(location.can_reach(state), f"{location.name} unreachable") for region in multiworld.get_regions(): if region.name in unreachable_regions: @@ -60,7 +61,8 @@ class TestBase(unittest.TestCase): self.assertFalse(region.can_reach(state)) else: with self.subTest("Region should be reached", region=region.name): - self.assertTrue(region.can_reach(state)) + if not region.can_reach(state): + self.assertTrue(region.can_reach(state)) with self.subTest("Completion Condition"): self.assertTrue(multiworld.can_beat_game(state)) diff --git a/worlds/satisfactory/CriticalPathCalculator.py b/worlds/satisfactory/CriticalPathCalculator.py new file mode 100644 index 0000000000..8cc40bbc58 --- /dev/null +++ b/worlds/satisfactory/CriticalPathCalculator.py @@ -0,0 +1,169 @@ +from random import Random +from typing import Optional +from collections.abc import Iterable +from .GameLogic import GameLogic, Recipe +from .Options import SatisfactoryOptions +from .Options import SatisfactoryOptions + +class CriticalPathCalculator: + logic: GameLogic + random: Random + options: SatisfactoryOptions + + required_parts: set[str] + required_buildings: set[str] + required_item_names: set[str] + required_power_level: int + + __potential_required_belt_speed: int + __potential_required_pipes: bool + __potential_required_radioactive: bool + + parts_to_exclude: set[str] + recipes_to_exclude: set[str] + buildings_to_exclude: set[str] + + def __init__(self, logic: GameLogic, random: Random, options: SatisfactoryOptions): + self.logic = logic + self.random = random + self.options = options + + self.required_parts = set() + self.required_buildings = set() + self.required_power_level: int = 1 + + self.__potential_required_belt_speed = 1 + self.__potential_required_pipes = False + + selected_power_infrastructure: dict[int, Recipe] = {} + + self.select_minimal_required_parts_for(self.logic.space_elevator_tiers[options.final_elevator_package-1].keys()) + + for tree in self.logic.man_trees.values(): + self.select_minimal_required_parts_for(tree.access_items) + + for node in tree.nodes: + if node.minimal_tier > options.final_elevator_package: + continue + + self.select_minimal_required_parts_for(node.unlock_cost.keys()) + + self.select_minimal_required_parts_for_building("MAM") + self.select_minimal_required_parts_for_building("AWESOME Sink") + self.select_minimal_required_parts_for_building("AWESOME Shop") + self.select_minimal_required_parts_for_building("Space Elevator") + self.select_minimal_required_parts_for_building("Conveyor Splitter") + self.select_minimal_required_parts_for_building("Conveyor Merger") + self.select_minimal_required_parts_for_building("Equipment Workshop") + self.select_minimal_required_parts_for_building("Foundation") + self.select_minimal_required_parts_for_building("Walls Orange") + self.select_minimal_required_parts_for_building("Power Storage") + self.select_minimal_required_parts_for_building("Miner Mk.2") + + if self.logic.recipes["Uranium"][0].minimal_tier <= options.final_elevator_package: + self.select_minimal_required_parts_for(("Hazmat Suit", "Iodine Infused Filter")) + + for i in range(1, self.__potential_required_belt_speed + 1): + self.select_minimal_required_parts_for_building(f"Conveyor Mk.{i}") + if self.__potential_required_pipes: + self.select_minimal_required_parts_for_building("Pipes Mk.1") + self.select_minimal_required_parts_for_building("Pipes Mk.2") + self.select_minimal_required_parts_for_building("Pipeline Pump Mk.1") + self.select_minimal_required_parts_for_building("Pipeline Pump Mk.2") + for i in range(1, self.required_power_level + 1): + power_recipe = random.choice(self.logic.requirement_per_powerlevel[i]) + selected_power_infrastructure[i] = power_recipe + self.select_minimal_required_parts_for(power_recipe.inputs) + self.select_minimal_required_parts_for_building(power_recipe.building) + + self.required_item_names = set( + recipe.name + for part in self.required_parts + for recipe in self.logic.recipes[part] + if recipe.minimal_tier <= self.options.final_elevator_package + ) + self.required_item_names.update("Building: "+ building for building in self.required_buildings) + + self.parts_to_exclude = set() + self.buildings_to_exclude = set() + self.recipes_to_exclude = set( + recipe.name + for part in self.logic.recipes + for recipe in self.logic.recipes[part] + if recipe.minimal_tier > self.options.final_elevator_package + ) + + excluded_count = len(self.recipes_to_exclude) + while True: + for part in self.logic.recipes: + if part in self.parts_to_exclude: + continue + + for recipe in self.logic.recipes[part]: + if recipe.name in self.recipes_to_exclude: + continue + + if recipe.inputs and any(input in self.parts_to_exclude for input in recipe.inputs): + self.recipes_to_exclude.add(recipe.name) + + if all(r.name in self.recipes_to_exclude for r in self.logic.recipes[part]): + self.parts_to_exclude.add(part) + + new_buildings_to_exclude = set( + building_name + for building_name, building in self.logic.buildings.items() + if building_name not in self.buildings_to_exclude + and building.inputs and any(input in self.parts_to_exclude for input in building.inputs) + ) + + self.recipes_to_exclude.update( + recipe_per_part.name + for building_to_exclude in new_buildings_to_exclude + for recipes_per_part in self.logic.recipes.values() + for recipe_per_part in recipes_per_part + if recipe_per_part.building == building_to_exclude + ) + + self.buildings_to_exclude.update(new_buildings_to_exclude) + + new_length = len(self.recipes_to_exclude) + if new_length == excluded_count: + break + excluded_count = new_length + + def select_minimal_required_parts_for_building(self, building: str) -> None: + self.select_minimal_required_parts_for(self.logic.buildings[building].inputs) + self.required_buildings.add(building) + + def select_minimal_required_parts_for(self, parts: Optional[Iterable[str]]) -> None: + if parts is None: + return + + for part in parts: + if part in self.required_parts: + continue + + self.required_parts.add(part) + + for recipe in self.logic.recipes[part]: + if recipe.minimal_tier > self.options.final_elevator_package: + continue + + self.__potential_required_belt_speed = \ + max(self.__potential_required_belt_speed, recipe.minimal_belt_speed) + + self.select_minimal_required_parts_for(recipe.inputs) + + if recipe.needs_pipes: + self.__potential_required_pipes = True + if recipe.is_radio_active: + self.__potential_required_radioactive = True + + if recipe.building: + self.select_minimal_required_parts_for(self.logic.buildings[recipe.building].inputs) + self.required_buildings.add(recipe.building) + + if self.logic.buildings[recipe.building].power_requirement: + self.required_power_level = \ + max(self.required_power_level, + self.logic.buildings[recipe.building].power_requirement) \ No newline at end of file diff --git a/worlds/satisfactory/GameLogic.py b/worlds/satisfactory/GameLogic.py index b7b71392d4..4e0537e527 100644 --- a/worlds/satisfactory/GameLogic.py +++ b/worlds/satisfactory/GameLogic.py @@ -1,4 +1,4 @@ -from typing import Tuple, Optional, Dict, Set, List +from typing import Optional from dataclasses import dataclass from enum import IntEnum @@ -11,7 +11,7 @@ class PowerInfrastructureLevel(IntEnum): def to_name(self): return "Power level: " + self.name -liquids: Set[str] = { +liquids: set[str] = { "Water", "Liquid Biofuel", "Crude Oil", @@ -29,7 +29,7 @@ liquids: Set[str] = { "Dark Matter Residue" } -radio_actives: Set[str] = { +radio_actives: set[str] = { "Uranium", "Encased Uranium Cell", "Uranium Fuel Rod" @@ -50,19 +50,20 @@ class Recipe(): """ name: str building: str - inputs: Tuple[str, ...] + inputs: tuple[str, ...] minimal_belt_speed: int handcraftable: bool implicitly_unlocked: bool """No explicit location/item is needed to unlock this recipe, you have access as soon as dependencies are met (ex. Water, Leaves, tutorial starting items)""" - additional_outputs: Tuple[str, ...] + additional_outputs: tuple[str, ...] + minimal_tier: int needs_pipes: bool is_radio_active: bool - def __init__(self, name: str, building: Optional[str] = None, inputs: Optional[Tuple[str, ...]] = None, + def __init__(self, name: str, building: Optional[str] = None, inputs: Optional[tuple[str, ...]] = None, minimal_belt_speed: int = 1, handcraftable: bool = False, implicitly_unlocked: bool = False, - additional_outputs: Optional[Tuple[str, ...]] = None): + additional_outputs: Optional[tuple[str, ...]] = None, minimal_tier: Optional[int] = 1): self.name = "Recipe: " + name self.building = building self.inputs = inputs @@ -70,8 +71,9 @@ class Recipe(): self.handcraftable = handcraftable self.implicitly_unlocked = implicitly_unlocked self.additional_outputs = additional_outputs + self.minimal_tier = minimal_tier - all_parts: List[str] = [name] + all_parts: list[str] = [name] if inputs: all_parts += inputs if additional_outputs: @@ -84,7 +86,7 @@ class Building(Recipe): power_requirement: Optional[PowerInfrastructureLevel] can_produce: bool - def __init__(self, name: str, inputs: Optional[Tuple[str, ...]] = None, + def __init__(self, name: str, inputs: Optional[tuple[str, ...]] = None, power_requirement: Optional[PowerInfrastructureLevel] = None, can_produce: bool = True, implicitly_unlocked: bool = False): super().__init__(name, None, inputs, handcraftable=True, implicitly_unlocked=implicitly_unlocked) @@ -96,23 +98,26 @@ class Building(Recipe): class MamNode(): name: str - unlock_cost: Dict[str, int] + unlock_cost: dict[str, int] """All game items must be submitted to purchase this MamNode""" - depends_on: Tuple[str, ...] + depends_on: tuple[str, ...] """At least one of these prerequisite MamNodes must be unlocked to purchase this MamNode""" + minimal_tier: Optional[int] - def __init__(self, name: str, unlock_cost: Dict[str, int], depends_on: Tuple[str, ...]): + def __init__(self, name: str, unlock_cost: dict[str, int], depends_on: tuple[str, ...], + minimal_tier: Optional[int] = 1): self.name = name self.unlock_cost = unlock_cost self.depends_on = depends_on + self.minimal_tier = minimal_tier class MamTree(): - access_items: Tuple[str, ...] + access_items: tuple[str, ...] """At least one of these game items must enter the player inventory for this MamTree to be available""" - nodes: Tuple[MamNode, ...] + nodes: tuple[MamNode, ...] - def __init__(self, access_items: Tuple[str, ...], nodes: Tuple[MamNode, ...]): + def __init__(self, access_items: tuple[str, ...], nodes: tuple[MamNode, ...]): self.access_items = access_items self.nodes = nodes @@ -129,7 +134,7 @@ class DropPodData: class GameLogic: - recipes: Dict[str, Tuple[Recipe, ...]] = { + recipes: dict[str, tuple[Recipe, ...]] = { # This Dict should only contain items that are used somewhere in a logic chain # Exploration Items @@ -186,15 +191,15 @@ class GameLogic: "Crude Oil": ( Recipe("Crude Oil", "Oil Extractor", implicitly_unlocked=True), ), "Bauxite": ( - Recipe("Bauxite", "Miner Mk.1", handcraftable=True, implicitly_unlocked=True), ), + Recipe("Bauxite", "Miner Mk.1", handcraftable=True, implicitly_unlocked=True, minimal_tier=2), ), "Nitrogen Gas": ( - Recipe("Nitrogen Gas", "Resource Well Pressurizer", implicitly_unlocked=True), ), + Recipe("Nitrogen Gas", "Resource Well Pressurizer", implicitly_unlocked=True, minimal_tier=2), ), "Uranium": ( - Recipe("Uranium", "Miner Mk.1", handcraftable=True, implicitly_unlocked=True), ), + Recipe("Uranium", "Miner Mk.1", handcraftable=True, implicitly_unlocked=True, minimal_tier=2), ), # Special Items "Uranium Waste": ( - Recipe("Uranium Waste", "Nuclear Power Plant", ("Uranium Fuel Rod", "Water"), implicitly_unlocked=True), ), + Recipe("Uranium Waste", "Nuclear Power Plant", ("Uranium Fuel Rod", "Water"), implicitly_unlocked=True, minimal_tier=2), ), #"Plutonium Waste": ( # Recipe("Plutonium Waste", "Nuclear Power Plant", ("Plutonium Fuel Rod", "Water"), implicitly_unlocked=True), ), @@ -253,7 +258,7 @@ class GameLogic: Recipe("Molded Steel Pipe", "Foundry", ("Steel Ingot", "Concrete"))), "Steel Beam": ( Recipe("Steel Beam", "Constructor", ("Steel Ingot", ), handcraftable=True), - Recipe("Aluminum Beam", "Constructor", ("Aluminum Ingot", )), + Recipe("Aluminum Beam", "Constructor", ("Aluminum Ingot", ), minimal_tier=2), Recipe("Molded Beam", "Foundry", ("Steel Ingot", "Concrete"), minimal_belt_speed=2)), "Heavy Oil Residue": ( Recipe("Heavy Oil Residue", "Refinery", ("Crude Oil", ), additional_outputs=("Polymer Resin", )), @@ -266,7 +271,7 @@ class GameLogic: Recipe("Heavy Oil Residue", "Refinery", ("Crude Oil", ), additional_outputs=("Heavy Oil Residue", ), minimal_belt_speed=3)), "Fuel": ( Recipe("Fuel", "Refinery", ("Crude Oil", ), additional_outputs=("Polymer Resin", )), - Recipe("Diluted Fuel", "Blender", ("Heavy Oil Residue", "Water")), + Recipe("Diluted Fuel", "Blender", ("Heavy Oil Residue", "Water"), minimal_tier=2), Recipe("Residual Fuel", "Refinery", ("Heavy Oil Residue", ))), "Concrete": ( Recipe("Concrete", "Constructor", ("Limestone", ), handcraftable=True, implicitly_unlocked=True), @@ -275,16 +280,16 @@ class GameLogic: Recipe("Wet Concrete", "Refinery", ("Limestone", "Water"), minimal_belt_speed=2)), "Silica": ( Recipe("Silica", "Constructor", ("Raw Quartz", ), handcraftable=True), - Recipe("Alumina Solution", "Refinery", ("Bauxite", "Water"), additional_outputs=("Alumina Solution", ), minimal_belt_speed=2), + Recipe("Alumina Solution", "Refinery", ("Bauxite", "Water"), additional_outputs=("Alumina Solution", ), minimal_belt_speed=2, minimal_tier=2), Recipe("Cheap Silica", "Assembler", ("Raw Quartz", "Limestone")), - Recipe("Distilled Silica", "Blender", ("Dissolved Silica", "Limestone", "Water"), additional_outputs=("Water", ))), + Recipe("Distilled Silica", "Blender", ("Dissolved Silica", "Limestone", "Water"), additional_outputs=("Water", ), minimal_tier=2)), "Dissolved Silica": ( - Recipe("Quartz Purification", "Refinery", ("Raw Quartz", "Nitric Acid"), additional_outputs=("Quartz Crystal", ), minimal_belt_speed=2), ), + Recipe("Quartz Purification", "Refinery", ("Raw Quartz", "Nitric Acid"), additional_outputs=("Quartz Crystal", ), minimal_belt_speed=2, minimal_tier=2), ), "Quartz Crystal": ( Recipe("Quartz Crystal", "Constructor", ("Raw Quartz", ), handcraftable=True), Recipe("Pure Quartz Crystal", "Refinery", ("Raw Quartz", "Water"), minimal_belt_speed=2), Recipe("Fused Quartz Crystal", "Foundry", ("Raw Quartz", "Coal"), minimal_belt_speed=2), - Recipe("Quartz Purification", "Refinery", ("Raw Quartz", "Nitric Acid"), additional_outputs=("Dissolved Silica", ), minimal_belt_speed=2)), + Recipe("Quartz Purification", "Refinery", ("Raw Quartz", "Nitric Acid"), additional_outputs=("Dissolved Silica", ), minimal_belt_speed=2, minimal_tier=2)), "Iron Ingot": ( Recipe("Iron Ingot", "Smelter", ("Iron Ore", ), handcraftable=True, implicitly_unlocked=True), Recipe("Pure Iron Ingot", "Refinery", ("Iron Ore", "Water"), minimal_belt_speed=2), @@ -351,61 +356,61 @@ class GameLogic: Recipe("Smart Plating", "Assembler", ("Reinforced Iron Plate", "Rotor")), Recipe("Plastic Smart Plating", "Manufacturer", ("Reinforced Iron Plate", "Rotor", "Plastic"))), "Versatile Framework": ( - Recipe("Versatile Framework", "Assembler", ("Modular Frame", "Steel Beam")), - Recipe("Flexible Framework", "Manufacturer", ("Modular Frame", "Steel Beam", "Rubber"))), + Recipe("Versatile Framework", "Assembler", ("Modular Frame", "Steel Beam"), minimal_tier=2), + Recipe("Flexible Framework", "Manufacturer", ("Modular Frame", "Steel Beam", "Rubber"), minimal_tier=2)), "Automated Wiring": ( - Recipe("Automated Wiring", "Assembler", ("Stator", "Cable")), - Recipe("Automated Speed Wiring", "Manufacturer", ("Stator", "Wire", "High-Speed Connector"), minimal_belt_speed=2)), + Recipe("Automated Wiring", "Assembler", ("Stator", "Cable"), minimal_tier=2), + Recipe("Automated Speed Wiring", "Manufacturer", ("Stator", "Wire", "High-Speed Connector"), minimal_belt_speed=2, minimal_tier=2)), "Modular Engine": ( - Recipe("Modular Engine", "Manufacturer", ("Motor", "Rubber", "Smart Plating")), ), + Recipe("Modular Engine", "Manufacturer", ("Motor", "Rubber", "Smart Plating"), minimal_tier=3), ), "Adaptive Control Unit": ( - Recipe("Adaptive Control Unit", "Manufacturer", ("Automated Wiring", "Circuit Board", "Heavy Modular Frame", "Computer")), ), + Recipe("Adaptive Control Unit", "Manufacturer", ("Automated Wiring", "Circuit Board", "Heavy Modular Frame", "Computer"), minimal_tier=3), ), "Portable Miner": ( Recipe("Portable Miner", "Equipment Workshop", ("Iron Rod", "Iron Plate"), handcraftable=True, minimal_belt_speed=0, implicitly_unlocked=True), - Recipe("Automated Miner", "Manufacturer", ("Steel Pipe", "Iron Plate")), ), + Recipe("Automated Miner", "Assembler", ("Steel Pipe", "Iron Plate")), ), "Alumina Solution": ( - Recipe("Alumina Solution", "Refinery", ("Bauxite", "Water"), additional_outputs=("Silica", ), minimal_belt_speed=2), - Recipe("Sloppy Alumina", "Refinery", ("Bauxite", "Water"), minimal_belt_speed=3)), + Recipe("Alumina Solution", "Refinery", ("Bauxite", "Water"), additional_outputs=("Silica", ), minimal_belt_speed=2, minimal_tier=2), + Recipe("Sloppy Alumina", "Refinery", ("Bauxite", "Water"), minimal_belt_speed=3, minimal_tier=2)), "Aluminum Scrap": ( - Recipe("Aluminum Scrap", "Refinery", ("Alumina Solution", "Coal"), additional_outputs=("Water", ), minimal_belt_speed=4), - Recipe("Electrode Aluminum Scrap", "Refinery", ("Alumina Solution", "Petroleum Coke"), additional_outputs=("Water", ), minimal_belt_speed=4), - Recipe("Instant Scrap", "Blender", ("Bauxite", "Coal", "Sulfuric Acid", "Water"), additional_outputs=("Water", ), minimal_belt_speed=3)), + Recipe("Aluminum Scrap", "Refinery", ("Alumina Solution", "Coal"), additional_outputs=("Water", ), minimal_belt_speed=4, minimal_tier=2), + Recipe("Electrode Aluminum Scrap", "Refinery", ("Alumina Solution", "Petroleum Coke"), additional_outputs=("Water", ), minimal_belt_speed=4, minimal_tier=2), + Recipe("Instant Scrap", "Blender", ("Bauxite", "Coal", "Sulfuric Acid", "Water"), additional_outputs=("Water", ), minimal_belt_speed=3, minimal_tier=2)), "Aluminum Ingot": ( - Recipe("Aluminum Ingot", "Foundry", ("Aluminum Scrap", "Silica"), minimal_belt_speed=2, handcraftable=True), - Recipe("Pure Aluminum Ingot", "Smelter", ("Aluminum Scrap", ))), + Recipe("Aluminum Ingot", "Foundry", ("Aluminum Scrap", "Silica"), minimal_belt_speed=2, handcraftable=True, minimal_tier=2), + Recipe("Pure Aluminum Ingot", "Smelter", ("Aluminum Scrap", ), minimal_tier=2)), "Alclad Aluminum Sheet": ( - Recipe("Alclad Aluminum Sheet", "Assembler", ("Aluminum Ingot", "Copper Ingot"), handcraftable=True), ), + Recipe("Alclad Aluminum Sheet", "Assembler", ("Aluminum Ingot", "Copper Ingot"), handcraftable=True, minimal_tier=2), ), "Aluminum Casing": ( - Recipe("Aluminum Casing", "Constructor", ("Alclad Aluminum Sheet", ), handcraftable=True), - Recipe("Alclad Casing", "Assembler", ("Aluminum Ingot", "Copper Ingot"))), + Recipe("Aluminum Casing", "Constructor", ("Alclad Aluminum Sheet", ), handcraftable=True, minimal_tier=2), + Recipe("Alclad Casing", "Assembler", ("Aluminum Ingot", "Copper Ingot"), minimal_tier=2)), "Heat Sink": ( - Recipe("Heat Sink", "Assembler", ("Alclad Aluminum Sheet", "Silica"), minimal_belt_speed=2, handcraftable=True), - Recipe("Heat Exchanger", "Assembler", ("Aluminum Casing", "Rubber"), minimal_belt_speed=3)), + Recipe("Heat Sink", "Assembler", ("Alclad Aluminum Sheet", "Silica"), minimal_belt_speed=2, handcraftable=True, minimal_tier=2), + Recipe("Heat Exchanger", "Assembler", ("Aluminum Casing", "Rubber"), minimal_belt_speed=3, minimal_tier=2)), "Nitric Acid": ( - Recipe("Nitric Acid", "Blender", ("Nitrogen Gas", "Water", "Iron Plate")), ), + Recipe("Nitric Acid", "Blender", ("Nitrogen Gas", "Water", "Iron Plate"), minimal_tier=2), ), "Fused Modular Frame": ( - Recipe("Fused Modular Frame", "Blender", ("Heavy Modular Frame", "Aluminum Casing", "Nitrogen Gas"), minimal_belt_speed=2), - Recipe("Heat-Fused Frame", "Blender", ("Heavy Modular Frame", "Aluminum Ingot", "Nitric Acid", "Fuel"), minimal_belt_speed=3)), + Recipe("Fused Modular Frame", "Blender", ("Heavy Modular Frame", "Aluminum Casing", "Nitrogen Gas"), minimal_belt_speed=2, minimal_tier=2), + Recipe("Heat-Fused Frame", "Blender", ("Heavy Modular Frame", "Aluminum Ingot", "Nitric Acid", "Fuel"), minimal_belt_speed=3, minimal_tier=2)), "Radio Control Unit": ( - Recipe("Radio Control Unit", "Manufacturer", ("Aluminum Casing", "Crystal Oscillator", "Computer"), handcraftable=True), - Recipe("Radio Connection Unit", "Manufacturer", ("Heat Sink", "High-Speed Connector", "Quartz Crystal")), - Recipe("Radio Control System", "Manufacturer", ("Crystal Oscillator", "Circuit Board", "Aluminum Casing", "Rubber"), minimal_belt_speed=2)), + Recipe("Radio Control Unit", "Manufacturer", ("Aluminum Casing", "Crystal Oscillator", "Computer"), handcraftable=True, minimal_tier=2), + Recipe("Radio Connection Unit", "Manufacturer", ("Heat Sink", "High-Speed Connector", "Quartz Crystal"), minimal_tier=2), + Recipe("Radio Control System", "Manufacturer", ("Crystal Oscillator", "Circuit Board", "Aluminum Casing", "Rubber"), minimal_belt_speed=2, minimal_tier=2)), "Pressure Conversion Cube": ( - Recipe("Pressure Conversion Cube", "Assembler", ("Fused Modular Frame", "Radio Control Unit"), handcraftable=True), ), + Recipe("Pressure Conversion Cube", "Assembler", ("Fused Modular Frame", "Radio Control Unit"), handcraftable=True, minimal_tier=2), ), "Cooling System": ( - Recipe("Cooling System", "Blender", ("Heat Sink", "Rubber", "Water", "Nitrogen Gas")), - Recipe("Cooling Device", "Blender", ("Heat Sink", "Motor", "Nitrogen Gas"))), + Recipe("Cooling System", "Blender", ("Heat Sink", "Rubber", "Water", "Nitrogen Gas"), minimal_tier=2), + Recipe("Cooling Device", "Blender", ("Heat Sink", "Motor", "Nitrogen Gas"), minimal_tier=2)), "Turbo Motor": ( - Recipe("Turbo Motor", "Manufacturer", ("Cooling System", "Radio Control Unit", "Motor", "Rubber"), handcraftable=True), - Recipe("Turbo Electric Motor", "Manufacturer", ("Motor", "Radio Control Unit", "Electromagnetic Control Rod", "Rotor")), - Recipe("Turbo Pressure Motor", "Manufacturer", ("Motor", "Pressure Conversion Cube", "Packaged Nitrogen Gas", "Stator"))), + Recipe("Turbo Motor", "Manufacturer", ("Cooling System", "Radio Control Unit", "Motor", "Rubber"), handcraftable=True, minimal_tier=2), + Recipe("Turbo Electric Motor", "Manufacturer", ("Motor", "Radio Control Unit", "Electromagnetic Control Rod", "Rotor"), minimal_tier=2), + Recipe("Turbo Pressure Motor", "Manufacturer", ("Motor", "Pressure Conversion Cube", "Packaged Nitrogen Gas", "Stator"), minimal_tier=2)), "Battery": ( - Recipe("Battery", "Blender", ("Sulfuric Acid", "Alumina Solution", "Aluminum Casing"), additional_outputs=("Water", )), - Recipe("Classic Battery", "Manufacturer", ("Sulfur", "Alclad Aluminum Sheet", "Plastic", "Wire"), minimal_belt_speed=2)), + Recipe("Battery", "Blender", ("Sulfuric Acid", "Alumina Solution", "Aluminum Casing"), additional_outputs=("Water", ), minimal_tier=2), + Recipe("Classic Battery", "Manufacturer", ("Sulfur", "Alclad Aluminum Sheet", "Plastic", "Wire"), minimal_belt_speed=2, minimal_tier=2)), "Supercomputer": ( Recipe("Supercomputer", "Manufacturer", ("Computer", "AI Limiter", "High-Speed Connector", "Plastic"), handcraftable=True), - Recipe("OC Supercomputer", "Assembler", ("Radio Control Unit", "Cooling System")), - Recipe("Super-State Computer", "Manufacturer", ("Computer", "Electromagnetic Control Rod", "Battery", "Wire"))), + Recipe("OC Supercomputer", "Assembler", ("Radio Control Unit", "Cooling System"), minimal_tier=2), + Recipe("Super-State Computer", "Manufacturer", ("Computer", "Electromagnetic Control Rod", "Battery", "Wire"), minimal_tier=2)), "Sulfuric Acid": ( Recipe("Sulfuric Acid", "Refinery", ("Sulfur", "Water")), ), "Encased Uranium Cell": ( @@ -428,19 +433,19 @@ class GameLogic: "Gas Filter": ( Recipe("Gas Filter", "Manufacturer", ("Coal", "Rubber", "Fabric"), handcraftable=True), ), "Iodine Infused Filter": ( - Recipe("Iodine Infused Filter", "Manufacturer", ("Gas Filter", "Quickwire", "Aluminum Casing"), handcraftable=True), ), + Recipe("Iodine Infused Filter", "Manufacturer", ("Gas Filter", "Quickwire", "Aluminum Casing"), handcraftable=True, minimal_tier=2), ), "Hazmat Suit": ( - Recipe("Hazmat Suit", "Equipment Workshop", ("Rubber", "Plastic", "Fabric", "Alclad Aluminum Sheet"), handcraftable=True, minimal_belt_speed=0), ), + Recipe("Hazmat Suit", "Equipment Workshop", ("Rubber", "Plastic", "Fabric", "Alclad Aluminum Sheet"), handcraftable=True, minimal_tier=2), ), "Assembly Director System": ( - Recipe("Assembly Director System", "Assembler", ("Adaptive Control Unit", "Supercomputer")), ), + Recipe("Assembly Director System", "Assembler", ("Adaptive Control Unit", "Supercomputer"), minimal_tier=4), ), "Magnetic Field Generator": ( - Recipe("Magnetic Field Generator", "Assembler", ("Versatile Framework", "Electromagnetic Control Rod")), ), + Recipe("Magnetic Field Generator", "Assembler", ("Versatile Framework", "Electromagnetic Control Rod"), minimal_tier=4), ), "Copper Powder": ( Recipe("Copper Powder", "Constructor", ("Copper Ingot", ), handcraftable=True), ), "Nuclear Pasta": ( - Recipe("Nuclear Pasta", "Particle Accelerator", ("Copper Powder", "Pressure Conversion Cube")), ), + Recipe("Nuclear Pasta", "Particle Accelerator", ("Copper Powder", "Pressure Conversion Cube"), minimal_tier=2), ), "Thermal Propulsion Rocket": ( - Recipe("Thermal Propulsion Rocket", "Manufacturer", ("Modular Engine", "Turbo Motor", "Cooling System", "Fused Modular Frame")), ), + Recipe("Thermal Propulsion Rocket", "Manufacturer", ("Modular Engine", "Turbo Motor", "Cooling System", "Fused Modular Frame"), minimal_tier=4), ), "Alien Protein": ( Recipe("Hatcher Protein", "Constructor", ("Hatcher Remains", ), handcraftable=True), Recipe("Hog Protein", "Constructor", ("Hog Remains", ), handcraftable=True), @@ -450,7 +455,7 @@ class GameLogic: Recipe("Biomass (Leaves)", "Constructor", ("Leaves", ), minimal_belt_speed=2, handcraftable=True, implicitly_unlocked=True), Recipe("Biomass (Wood)", "Constructor", ("Wood", ), minimal_belt_speed=4, handcraftable=True, implicitly_unlocked=True), Recipe("Biomass (Mycelia)", "Constructor", ("Mycelia", ), minimal_belt_speed=3, handcraftable=True), - Recipe("Biomass (Alien Protein)", "Constructor", ("Alien Protein", ), minimal_belt_speed=5, handcraftable=True)), + Recipe("Biomass (Alien Protein)", "Constructor", ("Alien Protein", ), minimal_belt_speed=4, handcraftable=True)), "Fabric": ( Recipe("Fabric", "Assembler", ("Biomass", "Mycelia"), handcraftable=True, minimal_belt_speed=2), Recipe("Polyester Fabric", "Refinery", ("Polymer Resin", "Water"))), @@ -463,7 +468,7 @@ class GameLogic: Recipe("Coated Iron Canister", "Assembler", ("Iron Plate", "Copper Sheet")), Recipe("Steel Canister", "Constructor", ("Steel Ingot", ))), "Empty Fluid Tank": ( - Recipe("Empty Fluid Tank", "Constructor", ("Aluminum Ingot", ), handcraftable=True), ), + Recipe("Empty Fluid Tank", "Constructor", ("Aluminum Ingot", ), handcraftable=True, minimal_tier=2), ), "Packaged Alumina Solution": ( Recipe("Packaged Alumina Solution", "Packager", ("Alumina Solution", "Empty Canister"), minimal_belt_speed=2), ), "Packaged Fuel": ( @@ -478,23 +483,23 @@ class GameLogic: "Packaged Nitrogen Gas": ( Recipe("Packaged Nitrogen Gas", "Packager", ("Nitrogen Gas", "Empty Fluid Tank")), ), "Packaged Oil": ( - Recipe("Packaged Oil", "Packager", ("Crude Oil", "Empty Fluid Tank")), ), + Recipe("Packaged Oil", "Packager", ("Crude Oil", "Empty Canister")), ), "Packaged Sulfuric Acid": ( - Recipe("Packaged Sulfuric Acid", "Packager", ("Sulfuric Acid", "Empty Fluid Tank")), ), + Recipe("Packaged Sulfuric Acid", "Packager", ("Sulfuric Acid", "Empty Canister")), ), "Packaged Turbofuel": ( - Recipe("Packaged Turbofuel", "Packager", ("Turbofuel", "Empty Fluid Tank")), ), + Recipe("Packaged Turbofuel", "Packager", ("Turbofuel", "Empty Canister")), ), "Packaged Water": ( - Recipe("Packaged Water", "Packager", ("Water", "Empty Fluid Tank")), ), + Recipe("Packaged Water", "Packager", ("Water", "Empty Canister")), ), "Turbofuel": ( Recipe("Turbofuel", "Refinery", ("Fuel", "Compacted Coal")), Recipe("Turbo Heavy Fuel", "Refinery", ("Heavy Oil Residue", "Compacted Coal")), - Recipe("Turbo Blend Fuel", "Blender", ("Fuel", "Heavy Oil Residue", "Sulfur", "Petroleum Coke"))), + Recipe("Turbo Blend Fuel", "Blender", ("Fuel", "Heavy Oil Residue", "Sulfur", "Petroleum Coke"), minimal_tier=2)), "Gas Mask": ( Recipe("Gas Mask", "Equipment Workshop", ("Rubber", "Plastic", "Fabric"), handcraftable=True, minimal_belt_speed=0), ), "Alien DNA Capsule": ( Recipe("Alien DNA Capsule", "Constructor", ("Alien Protein", ), handcraftable=True), ), "Black Powder": ( - Recipe("Black Powder", "Assembler", ("Coal", "Sulfur"), handcraftable=True), + Recipe("Black Powder", "Equipment Workshop", ("Coal", "Sulfur"), handcraftable=True), Recipe("Fine Black Powder", "Assembler", ("Sulfur", "Compacted Coal"))), "Smokeless Powder": ( Recipe("Smokeless Powder", "Refinery", ("Black Powder", "Heavy Oil Residue")), ), @@ -508,7 +513,7 @@ class GameLogic: Recipe("Power Shard (1)", "Constructor", ("Blue Power Slug", ), handcraftable=True), Recipe("Power Shard (2)", "Constructor", ("Yellow Power Slug", ), handcraftable=True), Recipe("Power Shard (5)", "Constructor", ("Purple Power Slug", ), handcraftable=True), - Recipe("Synthetic Power Shard", "Quantum Encoder", ("Dark Matter Residue", "Excited Photonic Matter", "Time Crystal", "Dark Matter Crystal", "Quartz Crystal"))), # 1.0 + Recipe("Synthetic Power Shard", "Quantum Encoder", ("Dark Matter Residue", "Excited Photonic Matter", "Time Crystal", "Dark Matter Crystal", "Quartz Crystal"), minimal_tier=4)), # 1.0 "Object Scanner": ( Recipe("Object Scanner", "Equipment Workshop", ("Reinforced Iron Plate", "Wire", "Screw"), handcraftable=True), ), "Xeno-Zapper": ( @@ -516,8 +521,8 @@ class GameLogic: #1.0 "Rocket Fuel": ( - Recipe("Rocket Fuel", "Blender", ("Turbofuel", "Nitric Acid"), additional_outputs=("Compacted Coal", )), - Recipe("Nitro Rocket Fuel", "Blender", ("Fuel", "Nitrogen Gas", "Sulfur", "Coal"), minimal_belt_speed=2, additional_outputs=("Compacted Coal", ))), + Recipe("Rocket Fuel", "Blender", ("Turbofuel", "Nitric Acid"), additional_outputs=("Compacted Coal", ), minimal_tier=2), + Recipe("Nitro Rocket Fuel", "Blender", ("Fuel", "Nitrogen Gas", "Sulfur", "Coal"), minimal_belt_speed=2, additional_outputs=("Compacted Coal", ), minimal_tier=2)), #"Ionized Fuel": ( # Recipe("Ionized Fuel", "Refinery", ("Rocket Fuel", "Power Shard"), additional_outputs=("Compacted Coal", )), ), "Packaged Rocket Fuel": ( @@ -554,9 +559,9 @@ class GameLogic: "Singularity Cell": ( Recipe("Singularity Cell", "Manufacturer", ("Nuclear Pasta", "Dark Matter Crystal", "Iron Plate", "Concrete"), minimal_belt_speed=3), ), "Biochemical Sculptor": ( - Recipe("Biochemical Sculptor", "Blender", ("Assembly Director System", "Ficsite Trigon", "Water")), ), + Recipe("Biochemical Sculptor", "Blender", ("Assembly Director System", "Ficsite Trigon", "Water"), minimal_tier=5), ), "Ballistic Warp Drive": ( - Recipe("Ballistic Warp Drive", "Manufacturer", ("Thermal Propulsion Rocket", "Singularity Cell", "Superposition Oscillator", "Dark Matter Crystal")), ), + Recipe("Ballistic Warp Drive", "Manufacturer", ("Thermal Propulsion Rocket", "Singularity Cell", "Superposition Oscillator", "Dark Matter Crystal"), minimal_tier=5), ), # All Quantum Encoder recipes have `Dark Matter Residue` set as an input, this hack makes the logic make sure you can get rid of it "Dark Matter Residue": ( @@ -569,20 +574,18 @@ class GameLogic: "Neural-Quantum Processor": ( Recipe("Neural-Quantum Processor", "Quantum Encoder", ("Dark Matter Residue", "Excited Photonic Matter", "Time Crystal", "Supercomputer", "Ficsite Trigon")), ), "AI Expansion Server": ( - Recipe("AI Expansion Server", "Quantum Encoder", ("Dark Matter Residue", "Excited Photonic Matter", "Magnetic Field Generator", "Neural-Quantum Processor", "Superposition Oscillator")), ), + Recipe("AI Expansion Server", "Quantum Encoder", ("Dark Matter Residue", "Excited Photonic Matter", "Magnetic Field Generator", "Neural-Quantum Processor", "Superposition Oscillator"), minimal_tier=5), ), ### #1.0 - - # TODO transport types aren't currently in logic } - buildings: Dict[str, Building] = { + buildings: dict[str, Building] = { "Constructor": Building("Constructor", ("Reinforced Iron Plate", "Cable"), PowerInfrastructureLevel.Basic, implicitly_unlocked=True), "Assembler": Building("Assembler", ("Reinforced Iron Plate", "Rotor", "Cable"), PowerInfrastructureLevel.Basic), "Manufacturer": Building("Manufacturer", ("Motor", "Heavy Modular Frame", "Cable", "Plastic"), PowerInfrastructureLevel.Advanced), "Packager": Building("Packager", ("Steel Beam", "Rubber", "Plastic"), PowerInfrastructureLevel.Basic), "Refinery": Building("Refinery", ("Motor", "Encased Industrial Beam", "Steel Pipe", "Copper Sheet"), PowerInfrastructureLevel.Automated), - "Blender": Building("Blender", ("Motor", "Heavy Modular Frame", "Aluminum Casing", "Radio Control Unit"), PowerInfrastructureLevel.Complex), + "Blender": Building("Blender", ("Motor", "Heavy Modular Frame", "Aluminum Casing", "Radio Control Unit"), PowerInfrastructureLevel.Advanced), "Particle Accelerator": Building("Particle Accelerator", ("Radio Control Unit", "Electromagnetic Control Rod", "Supercomputer", "Cooling System", "Fused Modular Frame", "Turbo Motor"), PowerInfrastructureLevel.Complex), "Biomass Burner": Building("Biomass Burner", ("Iron Plate", "Iron Rod", "Wire"), implicitly_unlocked=True), "Coal Generator": Building("Coal Generator", ("Reinforced Iron Plate", "Rotor", "Cable")), @@ -590,8 +593,8 @@ class GameLogic: "Geothermal Generator": Building("Geothermal Generator", ("Motor", "Modular Frame", "High-Speed Connector", "Copper Sheet", "Wire")), "Nuclear Power Plant": Building("Nuclear Power Plant", ("Concrete", "Heavy Modular Frame", "Supercomputer", "Cable", "Alclad Aluminum Sheet")), "Miner Mk.1": Building("Miner Mk.1", ("Iron Plate", "Concrete"), PowerInfrastructureLevel.Basic, implicitly_unlocked=True), - "Miner Mk.2": Building("Miner Mk.2", ("Encased Industrial Beam", "Steel Pipe", "Modular Frame"), PowerInfrastructureLevel.Automated), - "Miner Mk.3": Building("Miner Mk.3", ("Steel Pipe", "Supercomputer", "Fused Modular Frame", "Turbo Motor"), PowerInfrastructureLevel.Advanced), + "Miner Mk.2": Building("Miner Mk.2", ("Encased Industrial Beam", "Steel Pipe", "Modular Frame"), PowerInfrastructureLevel.Automated, can_produce=False), + "Miner Mk.3": Building("Miner Mk.3", ("Steel Pipe", "Supercomputer", "Fused Modular Frame", "Turbo Motor"), PowerInfrastructureLevel.Advanced, can_produce=False), "Oil Extractor": Building("Oil Extractor", ("Motor", "Encased Industrial Beam", "Cable")), "Water Extractor": Building("Water Extractor", ("Copper Sheet", "Reinforced Iron Plate", "Rotor")), "Smelter": Building("Smelter", ("Iron Rod", "Wire"), PowerInfrastructureLevel.Basic, implicitly_unlocked=True), @@ -629,13 +632,13 @@ class GameLogic: #1.0 } - handcraftable_recipes: Dict[str, List[Recipe]] = {} + handcraftable_recipes: dict[str, list[Recipe]] = {} for part, recipes_per_part in recipes.items(): for recipe in recipes_per_part: if recipe.handcraftable: handcraftable_recipes.setdefault(part, list()).append(recipe) - implicitly_unlocked_recipes: Dict[str, Recipe] = { + implicitly_unlocked_recipes: dict[str, Recipe] = { recipe.name: recipe for recipes_per_part in recipes.values() for recipe in recipes_per_part if recipe.implicitly_unlocked @@ -645,7 +648,7 @@ class GameLogic: for building in buildings.values() if building.implicitly_unlocked }) - requirement_per_powerlevel: Dict[PowerInfrastructureLevel, Tuple[Recipe, ...]] = { + requirement_per_powerlevel: dict[PowerInfrastructureLevel, tuple[Recipe, ...]] = { # no need to polute the logic by including higher level recipes based on previus recipes PowerInfrastructureLevel.Basic: ( Recipe("Biomass Power (Biomass)", "Biomass Burner", ("Biomass", ), implicitly_unlocked=True), @@ -675,7 +678,7 @@ class GameLogic: slots_per_milestone: int = 8 - hub_layout: Tuple[Tuple[Dict[str, int], ...], ...] = ( + hub_layout: tuple[tuple[dict[str, int], ...], ...] = ( # Regenerate via /Script/Engine.Blueprint'/Archipelago/Debug/CC_BuildHubData.CC_BuildHubData' ( # Tier 1 {"Concrete":200, "Iron Plate":100, "Iron Rod":100, }, # Schematic: Base Building (Schematic_1-1_C) @@ -741,7 +744,7 @@ class GameLogic: ) # Values from /Game/FactoryGame/Schematics/Progression/BP_GamePhaseManager.BP_GamePhaseManager - space_elevator_tiers: Tuple[Dict[str, int], ...] = ( + space_elevator_tiers: tuple[dict[str, int], ...] = ( { "Smart Plating": 50 }, { "Smart Plating": 500, "Versatile Framework": 500, "Automated Wiring": 100 }, { "Versatile Framework": 2500, "Modular Engine": 500, "Adaptive Control Unit": 100 }, @@ -751,7 +754,7 @@ class GameLogic: # Do not regenerate as format got changed # Regenerate via /Script/Engine.Blueprint'/Archipelago/Debug/CC_BuildMamData.CC_BuildMamData' - man_trees: Dict[str, MamTree] = { + man_trees: dict[str, MamTree] = { "Alien Organisms": MamTree(("Hog Remains", "Plasma Spitter Remains", "Stinger Remains", "Hatcher Remains"), ( # Alien Organisms (BPD_ResearchTree_AlienOrganisms_C) MamNode("Inflated Pocket Dimension", {"Alien Protein":3,"Cable":1000,}, depends_on=("Bio-Organic Properties", )), #(Research_AOrgans_3_C) MamNode("Hostile Organism Detection", {"Alien DNA Capsule":10,"Crystal Oscillator":5,"High-Speed Connector":5,}, depends_on=("Bio-Organic Properties", )), #(Research_AOrganisms_2_C) @@ -785,7 +788,7 @@ class GameLogic: MamNode("Alien Energy Harvesting", {"SAM Fluctuator":10,}, depends_on=("Somersloop Analysis", "SAM Fluctuator")), MamNode("Production Amplifier", {"Somersloop":1,"SAM Fluctuator":100,"Circuit Board":50,}, depends_on=("Alien Energy Harvesting",)), MamNode("Power Augmenter", {"Somersloop":1,"SAM Fluctuator":100,"Computer":50,}, depends_on=("Alien Energy Harvesting",)), - MamNode("Alien Power Matrix", {"Singularity Cell":50,"Power Shard":100,"SAM Fluctuator":500}, depends_on=("Power Augmenter",)), + MamNode("Alien Power Matrix", {"Singularity Cell":50,"Power Shard":100,"SAM Fluctuator":500}, depends_on=("Power Augmenter",), minimal_tier=4), )), # 1.0 "Caterium": MamTree(("Caterium Ore", ), ( # Caterium (BPD_ResearchTree_Caterium_C) @@ -831,7 +834,7 @@ class GameLogic: MamNode("Yellow Power Shards", {"Yellow Power Slug":1,"Rotor":25,"Cable":100,}, depends_on=("Blue Power Slugs", )), #(Research_PowerSlugs_4_C) MamNode("Purple Power Shards", {"Purple Power Slug":1,"Modular Frame":25,"Copper Sheet":100,}, depends_on=("Yellow Power Shards", )), #(Research_PowerSlugs_5_C) MamNode("Overclock Production", {"Power Shard":1,"Iron Plate":50,"Wire":50,}, depends_on=("Blue Power Slugs", )), #(Research_PowerSlugs_2_C) - MamNode("Synthetic Power Shards", {"Power Shard":10,"Time Crystal":100,"Quartz Crystal":200,}, depends_on=("Purple Power Shards", )), # 1.0 + MamNode("Synthetic Power Shards", {"Power Shard":10,"Time Crystal":100,"Quartz Crystal":200,}, depends_on=("Purple Power Shards", ), minimal_tier=4), # 1.0 )), "Quartz": MamTree(("Raw Quartz", ), ( # Quartz (BPD_ResearchTree_Quartz_C) MamNode("Crystal Oscillator", {"Quartz Crystal":100,"Reinforced Iron Plate":50,}, depends_on=("Quartz Crystals", )), #(Research_Quartz_2_C) @@ -857,16 +860,16 @@ class GameLogic: MamNode("Explosive Rebar", {"Smokeless Powder":200,"Iron Rebar":200,"Steel Beam":200,}, depends_on=("Smokeless Powder", )), #(Research_Sulfur_4_2_C) MamNode("Cluster Nobelisk", {"Smokeless Powder":100,"Nobelisk":200,}, depends_on=("Smokeless Powder", )), #(Research_Sulfur_4_C) MamNode("Experimental Power Generation", {"Sulfur":25,"Modular Frame":50,"Rotor":100,}, depends_on=("Sulfur", )), #(Research_Sulfur_ExperimentalPower_C) - MamNode("Turbo Rifle Ammo", {"Rifle Ammo":1000,"Packaged Turbofuel":50,"Aluminum Casing":100,}, depends_on=("The Rifle", )), #(Research_Sulfur_5_2_C) # 1.0 + MamNode("Turbo Rifle Ammo", {"Rifle Ammo":1000,"Packaged Turbofuel":50,"Aluminum Casing":100,}, depends_on=("The Rifle", ), minimal_tier=2), #(Research_Sulfur_5_2_C) # 1.0 MamNode("Turbo Fuel", {"Hard Drive":1,"Compacted Coal":15,"Packaged Fuel":50,}, depends_on=("Experimental Power Generation", )), #(Research_Sulfur_TurboFuel_C) MamNode("Expanded Toolbelt", {"Black Powder":100,"Encased Industrial Beam":50,}, depends_on=("Black Powder", )), #(Research_Sulfur_5_C) - MamNode("Nuclear Deterrent Development", {"Nobelisk":500,"Encased Uranium Cell":10,"AI Limiter":100,}, depends_on=("Cluster Nobelisk", )), #(Research_Sulfur_5_1_C) # 1.0 - MamNode("Rocket Fuel", {"Hard Drive":1,"Empty Fluid Tank":10,"Packaged Turbofuel":100,}, depends_on=("Turbo Fuel", )), # 1.0 - MamNode("Ionized Fuel", {"Hard Drive":1,"Power Shard":100,"Packaged Rocket Fuel":200,}, depends_on=("Turbo Fuel", )), # 1.0 + MamNode("Nuclear Deterrent Development", {"Nobelisk":500,"Encased Uranium Cell":10,"AI Limiter":100,}, depends_on=("Cluster Nobelisk", ), minimal_tier=2), #(Research_Sulfur_5_1_C) # 1.0 + MamNode("Rocket Fuel", {"Hard Drive":1,"Empty Fluid Tank":10,"Packaged Turbofuel":100,}, depends_on=("Turbo Fuel", ), minimal_tier=3), # 1.0 + MamNode("Ionized Fuel", {"Hard Drive":1,"Power Shard":100,"Packaged Rocket Fuel":200,}, depends_on=("Turbo Fuel", ), minimal_tier=4), # 1.0 )) } - drop_pods: List[DropPodData] = [ + drop_pods: list[DropPodData] = [ # Regenerate via /Script/Engine.Blueprint'/Archipelago/Debug/CC_BuildDropPodLocations.CC_BuildDropPodLocations' DropPodData(-29068, -22640, 17384, "Encased Industrial Beam", 0), # Unlocks with: 4 x Desc_SteelPlateReinforced_C DropPodData(-33340, 5176, 23519, "Crystal Oscillator", 0), # Unlocks with: 5 x Desc_CrystalOscillator_C diff --git a/worlds/satisfactory/ItemData.py b/worlds/satisfactory/ItemData.py index 2f8dd991e2..b62dd1acd4 100644 --- a/worlds/satisfactory/ItemData.py +++ b/worlds/satisfactory/ItemData.py @@ -1,40 +1,42 @@ -from enum import Enum -from typing import NamedTuple, Set +from enum import IntFlag +from typing import NamedTuple from BaseClasses import ItemClassification -class ItemGroups(str, Enum): - Parts = 1 - Equipment = 2 - Ammo = 3 - Recipe = 4 - Building = 5 - Trap = 6 - Lights = 7 - Foundations = 8 - Transport = 9 - Trains = 10 - ConveyorMk1 = 11 - ConveyorMk2 = 12 - ConveyorMk3 = 13 - ConveyorMk4 = 14 - ConveyorMk5 = 15 - ConveyorSupports = 16 - PipesMk1 = 17 - PipesMk2 = 18 - PipelineSupports = 19 - HyperTubes = 20 - Signs = 21 - Pilars = 22 - Beams = 23 - Walls = 24 - Upgrades = 25 - Vehicles = 26 - Customizer = 27 - ConveyorMk6 = 28 +class ItemGroups(IntFlag): + Parts = 1 << 1 + Equipment = 1 << 2 + Ammo = 1 << 3 + Recipe = 1 << 4 + Building = 1 << 5 + Trap = 1 << 6 + Lights = 1 << 7 + Foundations = 1 << 8 + Transport = 1 << 9 + Trains = 1 << 10 + ConveyorMk1 = 1 << 11 + ConveyorMk2 = 1 << 12 + ConveyorMk3 = 1 << 13 + ConveyorMk4 = 1 << 14 + ConveyorMk5 = 1 << 15 + ConveyorSupports = 1 << 16 + PipesMk1 = 1 << 17 + PipesMk2 = 1 << 18 + PipelineSupports = 1 << 19 + HyperTubes = 1 << 20 + Signs = 1 << 21 + Pilars = 1 << 22 + Beams = 1 << 23 + Walls = 1 << 24 + Upgrades = 1 << 25 + Vehicles = 1 << 26 + Customizer = 1 << 27 + ConveyorMk6 = 1 << 28 + AlwaysUseful = 1 << 29 + class ItemData(NamedTuple): """Represents an item in the pool, it could be a resource bundle, production recipe, trap, etc.""" - category: Set[ItemGroups] + category: ItemGroups code: int type: ItemClassification = ItemClassification.filler count: int = 1 diff --git a/worlds/satisfactory/Items.py b/worlds/satisfactory/Items.py index 4ac7bcbbc7..9a5e8d85cc 100644 --- a/worlds/satisfactory/Items.py +++ b/worlds/satisfactory/Items.py @@ -1,695 +1,861 @@ -import copy from random import Random -from typing import ClassVar, Dict, Set, List, TextIO, Tuple, Optional +from typing import ClassVar, Optional from BaseClasses import Item, ItemClassification as C, MultiWorld -from .GameLogic import GameLogic, Recipe +from .GameLogic import GameLogic from .Options import SatisfactoryOptions from .ItemData import ItemData, ItemGroups as G from .Options import SatisfactoryOptions -import logging - +from .CriticalPathCalculator import CriticalPathCalculator class Items: - item_data: ClassVar[Dict[str, ItemData]] = { + item_data: ClassVar[dict[str, ItemData]] = { # Resource Bundles - "Bundle: Adaptive Control Unit": ItemData(frozenset({G.Parts}), 1338000), - "Bundle: AI Limiter": ItemData(frozenset({G.Parts}), 1338001), - "Bundle: Alclad Aluminum Sheet": ItemData(frozenset({G.Parts}), 1338002), - "Bundle: Blue Power Slug": ItemData(frozenset({G.Parts}), 1338003), - "Bundle: Yellow Power Slug": ItemData(frozenset({G.Parts}), 1338004), - "Bundle: Alien Protein": ItemData(frozenset({G.Parts}), 1338005), - "Bundle: Purple Power Slug": ItemData(frozenset({G.Parts}), 1338006), - "Bundle: Aluminum Casing": ItemData(frozenset({G.Parts}), 1338007), - "Bundle: Aluminum Ingot": ItemData(frozenset({G.Parts}), 1338008), - "Bundle: Aluminum Scrap": ItemData(frozenset({G.Parts}), 1338009), - "Bundle: Assembly Director System": ItemData(frozenset({G.Parts}), 1338010), - "Bundle: Automated Wiring": ItemData(frozenset({G.Parts}), 1338011), - "Bundle: Battery": ItemData(frozenset({G.Parts}), 1338012), - "Bundle: Bauxite": ItemData(frozenset({G.Parts}), 1338013), - "Bundle: Neural-Quantum Processor": ItemData(frozenset({G.Parts}), 1338014), #1.0 - "Bundle: Biomass": ItemData(frozenset({G.Parts}), 1338015), - "Bundle: Black Powder": ItemData(frozenset({G.Parts}), 1338016), - "Bundle: Cable": ItemData(frozenset({G.Parts}), 1338017), - "Bundle: Caterium Ingot": ItemData(frozenset({G.Parts}), 1338018), - "Bundle: Caterium Ore": ItemData(frozenset({G.Parts}), 1338019), - "Bundle: Circuit Board": ItemData(frozenset({G.Parts}), 1338020), - "Bundle: Coal": ItemData(frozenset({G.Parts}), 1338021), - "Bundle: Singularity Cell": ItemData(frozenset({G.Parts}), 1338022), #1.0 - "Bundle: Compacted Coal": ItemData(frozenset({G.Parts}), 1338023), - "Bundle: Computer": ItemData(frozenset({G.Parts}), 1338024), - "Bundle: Concrete": ItemData(frozenset({G.Parts}), 1338025), - "Bundle: Cooling System": ItemData(frozenset({G.Parts}), 1338026), - "Bundle: Copper Ingot": ItemData(frozenset({G.Parts}), 1338027), - "Bundle: Copper Ore": ItemData(frozenset({G.Parts}), 1338028), - "Bundle: Copper Powder": ItemData(frozenset({G.Parts}), 1338029), - "Bundle: Copper Sheet": ItemData(frozenset({G.Parts}), 1338030), - "Bundle: Adequate Pioneering Statue": ItemData(frozenset({G.Parts}), 1338031), - "Bundle: Crystal Oscillator": ItemData(frozenset({G.Parts}), 1338032), - "Bundle: Electromagnetic Control Rod": ItemData(frozenset({G.Parts}), 1338033), - "Bundle: Empty Canister": ItemData(frozenset({G.Parts}), 1338034), - "Bundle: Empty Fluid Tank": ItemData(frozenset({G.Parts}), 1338035), - "Bundle: Encased Industrial Beam": ItemData(frozenset({G.Parts}), 1338036), - "Bundle: Encased Plutonium Cell": ItemData(frozenset({G.Trap}), 1338037, C.trap), - "Bundle: Encased Uranium Cell": ItemData(frozenset({G.Trap}), 1338038, C.trap), - "Bundle: Fabric": ItemData(frozenset({G.Parts}), 1338039), - "Bundle: FICSIT Coupon": ItemData(frozenset({G.Parts}), 1338040), - "Bundle: AI Expansion Server": ItemData(frozenset({G.Parts}), 1338041), #1.0 - "Bundle: Fused Modular Frame": ItemData(frozenset({G.Parts}), 1338042), - "Bundle: Hard Drive": ItemData(frozenset({G.Parts}), 1338043), - "Bundle: Heat Sink": ItemData(frozenset({G.Parts}), 1338044), - "Bundle: Heavy Modular Frame": ItemData(frozenset({G.Parts}), 1338045), - "Bundle: High-Speed Connector": ItemData(frozenset({G.Parts}), 1338046), - "Bundle: Satisfactory Pioneering Statue": ItemData(frozenset({G.Parts}), 1338047), - "Bundle: Pretty Good Pioneering Statue": ItemData(frozenset({G.Parts}), 1338048), - "Bundle: Iron Ingot": ItemData(frozenset({G.Parts}), 1338049), - "Bundle: Iron Ore": ItemData(frozenset({G.Parts}), 1338050), - "Bundle: Iron Plate": ItemData(frozenset({G.Parts}), 1338051), - "Bundle: Iron Rod": ItemData(frozenset({G.Parts}), 1338052), - "Bundle: Golden Nut Statue": ItemData(frozenset({G.Parts}), 1338053), - "Bundle: Leaves": ItemData(frozenset({G.Parts}), 1338054), - "Bundle: Limestone": ItemData(frozenset({G.Parts}), 1338055), - "Bundle: Magnetic Field Generator": ItemData(frozenset({G.Parts}), 1338056), - "Bundle: Mercer Sphere": ItemData(frozenset({G.Parts}), 1338057), - "Bundle: Modular Engine": ItemData(frozenset({G.Parts}), 1338058), - "Bundle: Modular Frame": ItemData(frozenset({G.Parts}), 1338059), - "Bundle: Motor": ItemData(frozenset({G.Parts}), 1338060), - "Bundle: Mycelia": ItemData(frozenset({G.Parts}), 1338061), - "Bundle: Non-fissile Uranium": ItemData(frozenset({G.Trap}), 1338062, C.trap), - "Bundle: Nuclear Pasta": ItemData(frozenset({G.Parts}), 1338063), - "Bundle: Lizard Doggo Statue": ItemData(frozenset({G.Parts}), 1338064), - "Bundle: Organic Data Capsule": ItemData(frozenset({G.Parts}), 1338065), - "Bundle: Packaged Alumina Solution": ItemData(frozenset({G.Parts}), 1338066), - "Bundle: Packaged Fuel": ItemData(frozenset({G.Parts}), 1338067), - "Bundle: Packaged Heavy Oil Residue": ItemData(frozenset({G.Parts}), 1338068), - "Bundle: Packaged Liquid Biofuel": ItemData(frozenset({G.Parts}), 1338069), - "Bundle: Packaged Nitric Acid": ItemData(frozenset({G.Parts}), 1338070), - "Bundle: Packaged Nitrogen Gas": ItemData(frozenset({G.Parts}), 1338071), - "Bundle: Packaged Oil": ItemData(frozenset({G.Parts}), 1338072), - "Bundle: Packaged Sulfuric Acid": ItemData(frozenset({G.Parts}), 1338073), - "Bundle: Packaged Turbofuel": ItemData(frozenset({G.Parts}), 1338074), - "Bundle: Packaged Water": ItemData(frozenset({G.Parts}), 1338075), - "Bundle: Petroleum Coke": ItemData(frozenset({G.Parts}), 1338076), - "Bundle: Plastic": ItemData(frozenset({G.Parts}), 1338077), - "Bundle: Plutonium Fuel Rod": ItemData(frozenset({G.Trap}), 1338078, C.trap), - "Bundle: Plutonium Pellet": ItemData(frozenset({G.Trap}), 1338079, C.trap), - "Bundle: Plutonium Waste": ItemData(frozenset({G.Trap}), 1338080, C.trap), - "Bundle: Polymer Resin": ItemData(frozenset({G.Parts}), 1338081), - "Bundle: Power Shard": ItemData(frozenset({G.Parts}), 1338082), - "Bundle: Confusing Creature Statue": ItemData(frozenset({G.Parts}), 1338083), - "Bundle: Pressure Conversion Cube": ItemData(frozenset({G.Parts}), 1338084), - "Bundle: Alien Power Matrix": ItemData(frozenset({G.Parts}), 1338085), #1.0 - "Bundle: Quartz Crystal": ItemData(frozenset({G.Parts}), 1338086), - "Bundle: Quickwire": ItemData(frozenset({G.Parts}), 1338087), - "Bundle: Radio Control Unit": ItemData(frozenset({G.Parts}), 1338088), - "Bundle: Raw Quartz": ItemData(frozenset({G.Parts}), 1338089), - "Bundle: Reinforced Iron Plate": ItemData(frozenset({G.Parts}), 1338090), - "Bundle: Rotor": ItemData(frozenset({G.Parts}), 1338091), - "Bundle: Rubber": ItemData(frozenset({G.Parts}), 1338092), - "Bundle: SAM": ItemData(frozenset({G.Parts}), 1338093), # 1.0 - "Bundle: Screw": ItemData(frozenset({G.Parts}), 1338094), - "Bundle: Silica": ItemData(frozenset({G.Parts}), 1338095), - "Bundle: Smart Plating": ItemData(frozenset({G.Parts}), 1338096), - "Bundle: Smokeless Powder": ItemData(frozenset({G.Parts}), 1338097), - "Bundle: Solid Biofuel": ItemData(frozenset({G.Parts}), 1338098), - "Bundle: Somersloop": ItemData(frozenset({G.Parts}), 1338099), - "Bundle: Stator": ItemData(frozenset({G.Parts}), 1338100), - "Bundle: Silver Hog Statue": ItemData(frozenset({G.Parts}), 1338101), - "Bundle: Steel Beam": ItemData(frozenset({G.Parts}), 1338102), - "Bundle: Steel Ingot": ItemData(frozenset({G.Parts}), 1338103), - "Bundle: Steel Pipe": ItemData(frozenset({G.Parts}), 1338104), - "Bundle: Sulfur": ItemData(frozenset({G.Parts}), 1338105), - "Bundle: Supercomputer": ItemData(frozenset({G.Parts}), 1338106), - "Bundle: Superposition Oscillator": ItemData(frozenset({G.Parts}), 1338107), - "Bundle: Thermal Propulsion Rocket": ItemData(frozenset({G.Parts}), 1338108), - "Bundle: Turbo Motor": ItemData(frozenset({G.Parts}), 1338109), - "Bundle: Hog Remains": ItemData(frozenset({G.Parts}), 1338110), - "Bundle: Uranium": ItemData(frozenset({G.Trap}), 1338111, C.trap), - "Bundle: Uranium Fuel Rod": ItemData(frozenset({G.Trap}), 1338112, C.trap), - "Bundle: Uranium Waste": ItemData(frozenset({G.Trap}), 1338113, C.trap), - "Bundle: Versatile Framework": ItemData(frozenset({G.Parts}), 1338114), - "Bundle: Wire": ItemData(frozenset({G.Parts}), 1338115), - "Bundle: Wood": ItemData(frozenset({G.Parts}), 1338116), - "Bundle: Plasma Spitter Remains": ItemData(frozenset({G.Parts}), 1338117), - "Bundle: Stinger Remains": ItemData(frozenset({G.Parts}), 1338118), - "Bundle: Hatcher Remains": ItemData(frozenset({G.Parts}), 1338119), - "Bundle: Alien DNA Capsule": ItemData(frozenset({G.Parts}), 1338120), -# 1.0 - "Bundle: Diamonds": ItemData(frozenset({G.Parts}), 1338121), - "Bundle: Time Crystal": ItemData(frozenset({G.Parts}), 1338122), - "Bundle: Ficsite Ingot": ItemData(frozenset({G.Parts}), 1338123), - "Bundle: Ficsite Trigon": ItemData(frozenset({G.Parts}), 1338124), - "Bundle: Reanimated SAM": ItemData(frozenset({G.Parts}), 1338125), - "Bundle: SAM Fluctuator": ItemData(frozenset({G.Parts}), 1338126), - "Bundle: Biochemical Sculptor": ItemData(frozenset({G.Parts}), 1338127), - "Bundle: Ballistic Warp Drive": ItemData(frozenset({G.Parts}), 1338128), - "Bundle: Ficsonium": ItemData(frozenset({G.Trap}), 1338129, C.trap), - "Bundle: Ficsonium Fuel Rod": ItemData(frozenset({G.Trap}), 1338130, C.trap), - "Bundle: Packaged Rocket Fuel": ItemData(frozenset({G.Parts}), 1338131), - "Bundle: Packaged Ionized Fuel": ItemData(frozenset({G.Parts}), 1338132), -# 1.0 - + "Bundle: Adaptive Control Unit": ItemData(G.Parts, 1338000), + "Bundle: AI Limiter": ItemData(G.Parts, 1338001), + "Bundle: Alclad Aluminum Sheet": ItemData(G.Parts, 1338002), + "Bundle: Blue Power Slug": ItemData(G.Parts, 1338003), + "Bundle: Yellow Power Slug": ItemData(G.Parts, 1338004), + "Bundle: Alien Protein": ItemData(G.Parts, 1338005), + "Bundle: Purple Power Slug": ItemData(G.Parts, 1338006), + "Bundle: Aluminum Casing": ItemData(G.Parts, 1338007), + "Bundle: Aluminum Ingot": ItemData(G.Parts, 1338008), + "Bundle: Aluminum Scrap": ItemData(G.Parts, 1338009), + "Bundle: Assembly Director System": ItemData(G.Parts, 1338010), + "Bundle: Automated Wiring": ItemData(G.Parts, 1338011), + "Bundle: Battery": ItemData(G.Parts, 1338012), + "Bundle: Bauxite": ItemData(G.Parts, 1338013), + "Bundle: Neural-Quantum Processor": ItemData(G.Parts, 1338014), #1.0 + "Bundle: Biomass": ItemData(G.Parts, 1338015), + "Bundle: Black Powder": ItemData(G.Parts, 1338016), + "Bundle: Cable": ItemData(G.Parts, 1338017), + "Bundle: Caterium Ingot": ItemData(G.Parts, 1338018), + "Bundle: Caterium Ore": ItemData(G.Parts, 1338019), + "Bundle: Circuit Board": ItemData(G.Parts, 1338020), + "Bundle: Coal": ItemData(G.Parts, 1338021), + "Bundle: Singularity Cell": ItemData(G.Parts, 1338022), #1.0 + "Bundle: Compacted Coal": ItemData(G.Parts, 1338023), + "Bundle: Computer": ItemData(G.Parts, 1338024), + "Bundle: Concrete": ItemData(G.Parts, 1338025), + "Bundle: Cooling System": ItemData(G.Parts, 1338026), + "Bundle: Copper Ingot": ItemData(G.Parts, 1338027), + "Bundle: Copper Ore": ItemData(G.Parts, 1338028), + "Bundle: Copper Powder": ItemData(G.Parts, 1338029), + "Bundle: Copper Sheet": ItemData(G.Parts, 1338030), + "Bundle: Adequate Pioneering Statue": ItemData(G.Parts, 1338031), + "Bundle: Crystal Oscillator": ItemData(G.Parts, 1338032), + "Bundle: Electromagnetic Control Rod": ItemData(G.Parts, 1338033), + "Bundle: Empty Canister": ItemData(G.Parts, 1338034), + "Bundle: Empty Fluid Tank": ItemData(G.Parts, 1338035), + "Bundle: Encased Industrial Beam": ItemData(G.Parts, 1338036), + "Bundle: Encased Plutonium Cell": ItemData(G.Trap, 1338037, C.trap), + "Bundle: Encased Uranium Cell": ItemData(G.Trap, 1338038, C.trap), + "Bundle: Fabric": ItemData(G.Parts, 1338039), + "Bundle: FICSIT Coupon": ItemData(G.Parts, 1338040), + "Bundle: AI Expansion Server": ItemData(G.Parts, 1338041), #1.0 + "Bundle: Fused Modular Frame": ItemData(G.Parts, 1338042), + "Bundle: Hard Drive": ItemData(G.Parts, 1338043, count=0), + "Bundle: Heat Sink": ItemData(G.Parts, 1338044), + "Bundle: Heavy Modular Frame": ItemData(G.Parts, 1338045), + "Bundle: High-Speed Connector": ItemData(G.Parts, 1338046), + "Bundle: Satisfactory Pioneering Statue": ItemData(G.Parts, 1338047), + "Bundle: Pretty Good Pioneering Statue": ItemData(G.Parts, 1338048), + "Bundle: Iron Ingot": ItemData(G.Parts, 1338049), + "Bundle: Iron Ore": ItemData(G.Parts, 1338050), + "Bundle: Iron Plate": ItemData(G.Parts, 1338051), + "Bundle: Iron Rod": ItemData(G.Parts, 1338052), + "Bundle: Golden Nut Statue": ItemData(G.Parts, 1338053), + "Bundle: Leaves": ItemData(G.Parts, 1338054), + "Bundle: Limestone": ItemData(G.Parts, 1338055), + "Bundle: Magnetic Field Generator": ItemData(G.Parts, 1338056), + "Bundle: Mercer Sphere": ItemData(G.Parts, 1338057, count=0), + "Bundle: Modular Engine": ItemData(G.Parts, 1338058), + "Bundle: Modular Frame": ItemData(G.Parts, 1338059), + "Bundle: Motor": ItemData(G.Parts, 1338060), + "Bundle: Mycelia": ItemData(G.Parts, 1338061), + "Bundle: Non-fissile Uranium": ItemData(G.Trap, 1338062, C.trap), + "Bundle: Nuclear Pasta": ItemData(G.Parts, 1338063), + "Bundle: Lizard Doggo Statue": ItemData(G.Parts, 1338064), + "Bundle: Organic Data Capsule": ItemData(G.Parts, 1338065), + "Bundle: Packaged Alumina Solution": ItemData(G.Parts, 1338066), + "Bundle: Packaged Fuel": ItemData(G.Parts, 1338067), + "Bundle: Packaged Heavy Oil Residue": ItemData(G.Parts, 1338068), + "Bundle: Packaged Liquid Biofuel": ItemData(G.Parts, 1338069), + "Bundle: Packaged Nitric Acid": ItemData(G.Parts, 1338070), + "Bundle: Packaged Nitrogen Gas": ItemData(G.Parts, 1338071), + "Bundle: Packaged Oil": ItemData(G.Parts, 1338072), + "Bundle: Packaged Sulfuric Acid": ItemData(G.Parts, 1338073), + "Bundle: Packaged Turbofuel": ItemData(G.Parts, 1338074), + "Bundle: Packaged Water": ItemData(G.Parts, 1338075), + "Bundle: Petroleum Coke": ItemData(G.Parts, 1338076), + "Bundle: Plastic": ItemData(G.Parts, 1338077), + "Bundle: Plutonium Fuel Rod": ItemData(G.Trap, 1338078, C.trap), + "Bundle: Plutonium Pellet": ItemData(G.Trap, 1338079, C.trap), + "Bundle: Plutonium Waste": ItemData(G.Trap, 1338080, C.trap), + "Bundle: Polymer Resin": ItemData(G.Parts, 1338081), + "Bundle: Power Shard": ItemData(G.Parts, 1338082, count=0), + "Bundle: Confusing Creature Statue": ItemData(G.Parts, 1338083), + "Bundle: Pressure Conversion Cube": ItemData(G.Parts, 1338084), + "Bundle: Alien Power Matrix": ItemData(G.Parts, 1338085), #1.0 + "Bundle: Quartz Crystal": ItemData(G.Parts, 1338086), + "Bundle: Quickwire": ItemData(G.Parts, 1338087), + "Bundle: Radio Control Unit": ItemData(G.Parts, 1338088), + "Bundle: Raw Quartz": ItemData(G.Parts, 1338089), + "Bundle: Reinforced Iron Plate": ItemData(G.Parts, 1338090), + "Bundle: Rotor": ItemData(G.Parts, 1338091), + "Bundle: Rubber": ItemData(G.Parts, 1338092), + "Bundle: SAM": ItemData(G.Parts, 1338093), # 1.0 + "Bundle: Screw": ItemData(G.Parts, 1338094), + "Bundle: Silica": ItemData(G.Parts, 1338095), + "Bundle: Smart Plating": ItemData(G.Parts, 1338096), + "Bundle: Smokeless Powder": ItemData(G.Parts, 1338097), + "Bundle: Solid Biofuel": ItemData(G.Parts, 1338098), + "Bundle: Somersloop": ItemData(G.Parts, 1338099, count=0), + "Bundle: Stator": ItemData(G.Parts, 1338100), + "Bundle: Silver Hog Statue": ItemData(G.Parts, 1338101), + "Bundle: Steel Beam": ItemData(G.Parts, 1338102), + "Bundle: Steel Ingot": ItemData(G.Parts, 1338103), + "Bundle: Steel Pipe": ItemData(G.Parts, 1338104), + "Bundle: Sulfur": ItemData(G.Parts, 1338105), + "Bundle: Supercomputer": ItemData(G.Parts, 1338106), + "Bundle: Superposition Oscillator": ItemData(G.Parts, 1338107), + "Bundle: Thermal Propulsion Rocket": ItemData(G.Parts, 1338108), + "Bundle: Turbo Motor": ItemData(G.Parts, 1338109), + "Bundle: Hog Remains": ItemData(G.Parts, 1338110), + "Bundle: Uranium": ItemData(G.Trap, 1338111, C.trap), + "Bundle: Uranium Fuel Rod": ItemData(G.Trap, 1338112, C.trap), + "Bundle: Uranium Waste": ItemData(G.Trap, 1338113, C.trap), + "Bundle: Versatile Framework": ItemData(G.Parts, 1338114), + "Bundle: Wire": ItemData(G.Parts, 1338115), + "Bundle: Wood": ItemData(G.Parts, 1338116), + "Bundle: Plasma Spitter Remains": ItemData(G.Parts, 1338117), + "Bundle: Stinger Remains": ItemData(G.Parts, 1338118), + "Bundle: Hatcher Remains": ItemData(G.Parts, 1338119), + "Bundle: Alien DNA Capsule": ItemData(G.Parts, 1338120), + "Bundle: Diamonds": ItemData(G.Parts, 1338121), + "Bundle: Time Crystal": ItemData(G.Parts, 1338122), + "Bundle: Ficsite Ingot": ItemData(G.Parts, 1338123), + "Bundle: Ficsite Trigon": ItemData(G.Parts, 1338124), + "Bundle: Reanimated SAM": ItemData(G.Parts, 1338125), + "Bundle: SAM Fluctuator": ItemData(G.Parts, 1338126), + "Bundle: Biochemical Sculptor": ItemData(G.Parts, 1338127), + "Bundle: Ballistic Warp Drive": ItemData(G.Parts, 1338128), + "Bundle: Ficsonium": ItemData(G.Trap, 1338129, C.trap), + "Bundle: Ficsonium Fuel Rod": ItemData(G.Trap, 1338130, C.trap), + "Bundle: Packaged Rocket Fuel": ItemData(G.Parts, 1338131), + "Bundle: Packaged Ionized Fuel": ItemData(G.Parts, 1338132), #1338131 - 1338149 Reserved for future parts - - # Equipment / Ammo - "Bundle: Bacon Agaric": ItemData(frozenset({G.Ammo}), 1338150), - "Bundle: Beryl Nut": ItemData(frozenset({G.Ammo}), 1338151), - "Bundle: Blade Runners": ItemData(frozenset({G.Equipment}), 1338152), - "Bundle: Boom Box": ItemData(frozenset({G.Equipment}), 1338153), - "Bundle: Chainsaw": ItemData(frozenset({G.Equipment}), 1338154), - "Bundle: Cluster Nobelisk": ItemData(frozenset({G.Ammo}), 1338155), - #"Bundle: Color Gun": ItemData(frozenset({G.Equipment}), 1338156), Removed in U8 - "Bundle: Cup": ItemData(frozenset({G.Equipment}), 1338157), - "Bundle: Cup (gold)": ItemData(frozenset({G.Equipment}), 1338158, count=0), - "Bundle: Explosive Rebar": ItemData(frozenset({G.Ammo}), 1338159), - "Bundle: Factory Cart": ItemData(frozenset({G.Equipment}), 1338160), - "Bundle: Factory Cart (golden)": ItemData(frozenset({G.Equipment}), 1338161, count=0), - "Bundle: Gas Mask": ItemData(frozenset({G.Equipment}), 1338162), - "Bundle: Gas Nobelisk": ItemData(frozenset({G.Ammo}), 1338163), - "Bundle: Hazmat Suit": ItemData(frozenset({G.Equipment}), 1338164), - "Bundle: Homing Rifle Ammo": ItemData(frozenset({G.Ammo}), 1338165), - "Bundle: Hover Pack": ItemData(frozenset({G.Equipment}), 1338166), - "Bundle: Iron Rebar": ItemData(frozenset({G.Ammo}), 1338167), - "Bundle: Jetpack": ItemData(frozenset({G.Equipment}), 1338168), - "Bundle: Medicinal Inhaler": ItemData(frozenset({G.Ammo}), 1338169), - "Bundle: Nobelisk": ItemData(frozenset({G.Ammo}), 1338170), - "Bundle: Nobelisk Detonator": ItemData(frozenset({G.Equipment}), 1338171), - "Bundle: Nuke Nobelisk": ItemData(frozenset({G.Ammo}), 1338172), - "Bundle: Object Scanner": ItemData(frozenset({G.Equipment}), 1338173), - "Bundle: Paleberry": ItemData(frozenset({G.Ammo}), 1338174), - "Bundle: Parachute": ItemData(frozenset({G.Equipment}), 1338175), - "Bundle: Pulse Nobelisk": ItemData(frozenset({G.Ammo}), 1338176), - "Bundle: Rebar Gun": ItemData(frozenset({G.Equipment}), 1338177), - "Bundle: Rifle": ItemData(frozenset({G.Equipment}), 1338178), - "Bundle: Rifle Ammo": ItemData(frozenset({G.Ammo}), 1338179), - "Bundle: Shatter Rebar": ItemData(frozenset({G.Ammo}), 1338180), - "Bundle: Stun Rebar": ItemData(frozenset({G.Ammo}), 1338181), - "Bundle: Turbo Rifle Ammo": ItemData(frozenset({G.Ammo}), 1338182), - "Bundle: Xeno-Basher": ItemData(frozenset({G.Equipment}), 1338183), - "Bundle: Xeno-Zapper": ItemData(frozenset({G.Equipment}), 1338184), - "Bundle: Zipline": ItemData(frozenset({G.Equipment}), 1338185), - "Bundle: Portable Miner": ItemData(frozenset({G.Equipment}), 1338186), - "Bundle: Gas Filter": ItemData(frozenset({G.Ammo}), 1338187), - # Other - "Small Inflated Pocket Dimension": ItemData(frozenset({G.Upgrades}), 1338188, C.useful, 11), - "Inflated Pocket Dimension": ItemData(frozenset({G.Upgrades}), 1338189, C.useful, 5), - "Expanded Toolbelt": ItemData(frozenset({G.Upgrades}), 1338190, C.useful, 5), - "Dimensional Depot upload from inventory": ItemData(frozenset({G.Upgrades}), 1338191, C.useful), - - #1338191 - 1338199 Reserved for future equipment/ammo + #1338150 - 1338199 Equipment / Ammo + "Bundle: Bacon Agaric": ItemData(G.Ammo, 1338150), + "Bundle: Beryl Nut": ItemData(G.Ammo, 1338151), + "Bundle: Blade Runners": ItemData(G.Equipment, 1338152, count=0), + "Bundle: Boom Box": ItemData(G.Equipment, 1338153, count=0), + "Bundle: Chainsaw": ItemData(G.Equipment, 1338154, count=0), + "Bundle: Cluster Nobelisk": ItemData(G.Ammo, 1338155), + "Bundle: Iodine-Infused Filter": ItemData(G.Ammo, 1338156), #1.1 + "Bundle: Cup": ItemData(G.Equipment, 1338157, count=0), + "Bundle: Cup (gold)": ItemData(G.Equipment, 1338158, count=0), + "Bundle: Explosive Rebar": ItemData(G.Ammo, 1338159), + "Bundle: Factory Cart": ItemData(G.Equipment, 1338160, count=0), + "Bundle: Factory Cart (golden)": ItemData(G.Equipment, 1338161, count=0), + "Bundle: Gas Mask": ItemData(G.Equipment, 1338162, count=0), + "Bundle: Gas Nobelisk": ItemData(G.Ammo, 1338163), + "Bundle: Hazmat Suit": ItemData(G.Equipment, 1338164, count=0), + "Bundle: Homing Rifle Ammo": ItemData(G.Ammo, 1338165), + "Bundle: Hoverpack": ItemData(G.Equipment, 1338166, count=0), + "Bundle: Iron Rebar": ItemData(G.Ammo, 1338167), + "Bundle: Jetpack": ItemData(G.Equipment, 1338168, count=0), + "Bundle: Medicinal Inhaler": ItemData(G.Ammo, 1338169), + "Bundle: Nobelisk": ItemData(G.Ammo, 1338170), + "Bundle: Nobelisk Detonator": ItemData(G.Equipment, 1338171, count=0), + "Bundle: Nuke Nobelisk": ItemData(G.Ammo, 1338172), + "Bundle: Object Scanner": ItemData(G.Equipment, 1338173, count=0), + "Bundle: Paleberry": ItemData(G.Ammo, 1338174), + "Bundle: Parachute": ItemData(G.Equipment, 1338175, count=0), + "Bundle: Pulse Nobelisk": ItemData(G.Ammo, 1338176), + "Bundle: Rebar Gun": ItemData(G.Equipment, 1338177, count=0), + "Bundle: Rifle": ItemData(G.Equipment, 1338178, count=0), + "Bundle: Rifle Ammo": ItemData(G.Ammo, 1338179), + "Bundle: Shatter Rebar": ItemData(G.Ammo, 1338180), + "Bundle: Stun Rebar": ItemData(G.Ammo, 1338181), + "Bundle: Turbo Rifle Ammo": ItemData(G.Ammo, 1338182), + "Bundle: Xeno-Basher": ItemData(G.Equipment, 1338183, count=0), + "Bundle: Xeno-Zapper": ItemData(G.Equipment, 1338184, count=0), + "Bundle: Zipline": ItemData(G.Equipment, 1338185, count=0), + "Bundle: Portable Miner": ItemData(G.Equipment, 1338186, count=0), + "Bundle: Gas Filter": ItemData(G.Ammo, 1338187), + # Special cases + "Small Inflated Pocket Dimension": ItemData(G.Upgrades, 1338188, C.useful, 11), + "Inflated Pocket Dimension": ItemData(G.Upgrades, 1338189, C.useful, 5), + "Expanded Toolbelt": ItemData(G.Upgrades, 1338190, C.useful, 5), + "Dimensional Depot upload from inventory": ItemData(G.Upgrades, 1338191, C.useful), +# added in 1.1 + "Bundle of Three: Power Shards": ItemData(G.Parts, 1338192), + "Bundle of Three: Mercer Spheres": ItemData(G.Parts, 1338193), + "Bundle of Four: Somersloops": ItemData(G.Parts, 1338194), + "Bundle of Three: Hard Drives": ItemData(G.Parts, 1338195), +# + #1338196 - 1338199 Reserved for future equipment/ammo #1338200+ Recipes / buildings / schematics - "Recipe: Reinforced Iron Plate": ItemData(frozenset({G.Recipe}), 1338200, C.progression), - "Recipe: Adhered Iron Plate": ItemData(frozenset({G.Recipe}), 1338201, C.progression), - "Recipe: Bolted Iron Plate": ItemData(frozenset({G.Recipe}), 1338202, C.progression), - "Recipe: Stitched Iron Plate": ItemData(frozenset({G.Recipe}), 1338203, C.progression), - "Recipe: Rotor": ItemData(frozenset({G.Recipe}), 1338204, C.progression), - "Recipe: Copper Rotor": ItemData(frozenset({G.Recipe}), 1338205, C.progression), - "Recipe: Steel Rotor": ItemData(frozenset({G.Recipe}), 1338206, C.progression), - "Recipe: Stator": ItemData(frozenset({G.Recipe}), 1338207, C.progression), - "Recipe: Quickwire Stator": ItemData(frozenset({G.Recipe}), 1338208, C.progression), - "Recipe: Plastic": ItemData(frozenset({G.Recipe}), 1338209, C.progression), - "Recipe: Residual Plastic": ItemData(frozenset({G.Recipe}), 1338210, C.progression), - "Recipe: Recycled Plastic": ItemData(frozenset({G.Recipe}), 1338211, C.progression), - "Recipe: Rubber": ItemData(frozenset({G.Recipe}), 1338212, C.progression), - "Recipe: Residual Rubber": ItemData(frozenset({G.Recipe}), 1338213, C.progression), - "Recipe: Recycled Rubber": ItemData(frozenset({G.Recipe}), 1338214, C.progression), - "Recipe: Iron Plate": ItemData(frozenset({G.Recipe}), 1338215, C.progression), - "Recipe: Coated Iron Plate": ItemData(frozenset({G.Recipe}), 1338216, C.progression), - "Recipe: Steel Cast Plate": ItemData(frozenset({G.Recipe}), 1338217, C.progression), # 1.0 - "Recipe: Iron Rod": ItemData(frozenset({G.Recipe}), 1338218, C.progression), - "Recipe: Steel Rod": ItemData(frozenset({G.Recipe}), 1338219, C.progression), - "Recipe: Screw": ItemData(frozenset({G.Recipe}), 1338220, C.progression), - "Recipe: Cast Screw": ItemData(frozenset({G.Recipe}), 1338221, C.progression), - "Recipe: Steel Screw": ItemData(frozenset({G.Recipe}), 1338222, C.progression), - "Recipe: Wire": ItemData(frozenset({G.Recipe}), 1338223, C.progression), - "Recipe: Fused Wire": ItemData(frozenset({G.Recipe}), 1338224, C.progression), - "Recipe: Iron Wire": ItemData(frozenset({G.Recipe}), 1338225, C.progression), - "Recipe: Caterium Wire": ItemData(frozenset({G.Recipe}), 1338226, C.progression), - "Recipe: Cable": ItemData(frozenset({G.Recipe}), 1338227, C.progression), - "Recipe: Coated Cable": ItemData(frozenset({G.Recipe}), 1338228, C.progression), - "Recipe: Insulated Cable": ItemData(frozenset({G.Recipe}), 1338229, C.progression), - "Recipe: Quickwire Cable": ItemData(frozenset({G.Recipe}), 1338230, C.progression), - "Recipe: Quickwire": ItemData(frozenset({G.Recipe}), 1338231, C.progression), - "Recipe: Fused Quickwire": ItemData(frozenset({G.Recipe}), 1338232, C.progression), - "Recipe: Copper Sheet": ItemData(frozenset({G.Recipe}), 1338233, C.progression), - "Recipe: Steamed Copper Sheet": ItemData(frozenset({G.Recipe}), 1338234, C.progression), - "Recipe: Steel Pipe": ItemData(frozenset({G.Recipe}), 1338235, C.progression), - "Recipe: Steel Beam": ItemData(frozenset({G.Recipe}), 1338236, C.progression), - "Recipe: Neural-Quantum Processor": ItemData(frozenset({G.Recipe}), 1338237, C.progression), # 1.0 - "Recipe: Heavy Oil Residue": ItemData(frozenset({G.Recipe}), 1338238, C.progression), - "Recipe: Polymer Resin": ItemData(frozenset({G.Recipe}), 1338239, C.progression), - "Recipe: Fuel": ItemData(frozenset({G.Recipe}), 1338240, C.progression), - "Recipe: Residual Fuel": ItemData(frozenset({G.Recipe}), 1338241, C.progression), - "Recipe: Diluted Fuel (refinery)": ItemData(frozenset({G.Recipe}), 1338242, C.progression), - "Recipe: AI Expansion Server": ItemData(frozenset({G.Recipe}), 1338243, C.progression), # 1.0 - "Recipe: Concrete": ItemData(frozenset({G.Recipe}), 1338244, C.progression), - "Recipe: Rubber Concrete": ItemData(frozenset({G.Recipe}), 1338245, C.progression), - "Recipe: Wet Concrete": ItemData(frozenset({G.Recipe}), 1338246, C.progression), - "Recipe: Fine Concrete": ItemData(frozenset({G.Recipe}), 1338247, C.progression), - "Recipe: Silica": ItemData(frozenset({G.Recipe}), 1338248, C.progression), - "Recipe: Cheap Silica": ItemData(frozenset({G.Recipe}), 1338249, C.progression), - "Recipe: Quartz Crystal": ItemData(frozenset({G.Recipe}), 1338250, C.progression), - "Recipe: Pure Quartz Crystal": ItemData(frozenset({G.Recipe}), 1338251, C.progression), - "Recipe: Iron Ingot": ItemData(frozenset({G.Recipe}), 1338252, C.progression), - "Recipe: Pure Iron Ingot": ItemData(frozenset({G.Recipe}), 1338253, C.progression), - "Recipe: Iron Alloy Ingot": ItemData(frozenset({G.Recipe}), 1338254, C.progression), - "Recipe: Steel Ingot": ItemData(frozenset({G.Recipe}), 1338255, C.progression), - "Recipe: Coke Steel Ingot": ItemData(frozenset({G.Recipe}), 1338256, C.progression), - "Recipe: Compacted Steel Ingot": ItemData(frozenset({G.Recipe}), 1338257, C.progression), - "Recipe: Solid Steel Ingot": ItemData(frozenset({G.Recipe}), 1338258, C.progression), - "Recipe: Copper Ingot": ItemData(frozenset({G.Recipe}), 1338259, C.progression), - "Recipe: Copper Alloy Ingot": ItemData(frozenset({G.Recipe}), 1338260, C.progression), - "Recipe: Pure Copper Ingot": ItemData(frozenset({G.Recipe}), 1338261, C.progression), - "Recipe: Caterium Ingot": ItemData(frozenset({G.Recipe}), 1338262, C.progression), - "Recipe: Pure Caterium Ingot": ItemData(frozenset({G.Recipe}), 1338263, C.progression), - "Recipe: Alien Power Matrix": ItemData(frozenset({G.Recipe}), 1338264), # 1.0 - "Recipe: Ficsite Ingot (Aluminum)": ItemData(frozenset({G.Recipe}), 1338265, C.progression), # 1.0 - "Recipe: Ficsite Ingot (Caterium)": ItemData(frozenset({G.Recipe}), 1338266, C.progression), # 1.0 - "Recipe: Ficsite Ingot (Iron)": ItemData(frozenset({G.Recipe}), 1338267, C.progression), # 1.0 - "Recipe: Ficsite Trigon": ItemData(frozenset({G.Recipe}), 1338268, C.progression), # 1.0 - "Recipe: Reanimated SAM": ItemData(frozenset({G.Recipe}), 1338269, C.progression), # 1.0 - "Recipe: SAM Fluctuator": ItemData(frozenset({G.Recipe}), 1338270, C.progression), # 1.0 - "Recipe: Petroleum Coke": ItemData(frozenset({G.Recipe}), 1338271, C.progression), - "Recipe: Compacted Coal": ItemData(frozenset({G.Recipe}), 1338272, C.progression), - "Recipe: Motor": ItemData(frozenset({G.Recipe}), 1338273, C.progression), - "Recipe: Rigor Motor": ItemData(frozenset({G.Recipe}), 1338274, C.progression), - "Recipe: Electric Motor": ItemData(frozenset({G.Recipe}), 1338275, C.progression), - "Recipe: Modular Frame": ItemData(frozenset({G.Recipe}), 1338276, C.progression), - "Recipe: Bolted Frame": ItemData(frozenset({G.Recipe}), 1338277, C.progression), - "Recipe: Steeled Frame": ItemData(frozenset({G.Recipe}), 1338278, C.progression), - "Recipe: Heavy Modular Frame": ItemData(frozenset({G.Recipe}), 1338279, C.progression), - "Recipe: Heavy Flexible Frame": ItemData(frozenset({G.Recipe}), 1338280, C.progression), - "Recipe: Heavy Encased Frame": ItemData(frozenset({G.Recipe}), 1338281, C.progression), - "Recipe: Encased Industrial Beam": ItemData(frozenset({G.Recipe}), 1338282, C.progression), - "Recipe: Encased Industrial Pipe": ItemData(frozenset({G.Recipe}), 1338283, C.progression), - "Recipe: Computer": ItemData(frozenset({G.Recipe}), 1338284, C.progression), - "Recipe: Crystal Computer": ItemData(frozenset({G.Recipe}), 1338285, C.progression), - "Recipe: Caterium Computer": ItemData(frozenset({G.Recipe}), 1338286, C.progression), - "Recipe: Circuit Board": ItemData(frozenset({G.Recipe}), 1338287, C.progression), - "Recipe: Electrode Circuit Board": ItemData(frozenset({G.Recipe}), 1338288, C.progression), - "Recipe: Silicon Circuit Board": ItemData(frozenset({G.Recipe}), 1338289, C.progression), - "Recipe: Caterium Circuit Board": ItemData(frozenset({G.Recipe}), 1338290, C.progression), - "Recipe: Crystal Oscillator": ItemData(frozenset({G.Recipe}), 1338291, C.progression), - "Recipe: Insulated Crystal Oscillator": ItemData(frozenset({G.Recipe}), 1338292, C.progression), - "Recipe: AI Limiter": ItemData(frozenset({G.Recipe}), 1338293, C.progression), - "Recipe: Electromagnetic Control Rod": ItemData(frozenset({G.Recipe}), 1338294, C.progression), - "Recipe: Electromagnetic Connection Rod": ItemData(frozenset({G.Recipe}), 1338295, C.progression), - "Recipe: High-Speed Connector": ItemData(frozenset({G.Recipe}), 1338296, C.progression), - "Recipe: Silicon High-Speed Connector": ItemData(frozenset({G.Recipe}), 1338297, C.progression), - "Recipe: Smart Plating": ItemData(frozenset({G.Recipe}), 1338298, C.progression), - "Recipe: Plastic Smart Plating": ItemData(frozenset({G.Recipe}), 1338299, C.progression), - "Recipe: Versatile Framework": ItemData(frozenset({G.Recipe}), 1338300, C.progression), - "Recipe: Flexible Framework": ItemData(frozenset({G.Recipe}), 1338301, C.progression), - "Recipe: Automated Wiring": ItemData(frozenset({G.Recipe}), 1338302, C.progression), - "Recipe: Automated Speed Wiring": ItemData(frozenset({G.Recipe}), 1338303, C.progression), - "Recipe: Modular Engine": ItemData(frozenset({G.Recipe}), 1338304, C.progression), - "Recipe: Adaptive Control Unit": ItemData(frozenset({G.Recipe}), 1338305, C.progression), - "Recipe: Diluted Fuel": ItemData(frozenset({G.Recipe}), 1338306, C.progression), - "Recipe: Alumina Solution": ItemData(frozenset({G.Recipe}), 1338307, C.progression), - "Recipe: Automated Miner": ItemData(frozenset({G.Recipe}), 1338308, C.progression), - "Recipe: Singularity Cell": ItemData(frozenset({G.Recipe}), 1338309, C.progression), # 1.0 - "Recipe: Aluminum Scrap": ItemData(frozenset({G.Recipe}), 1338310, C.progression), - "Recipe: Electrode Aluminum Scrap": ItemData(frozenset({G.Recipe}), 1338311, C.progression), - "Recipe: Instant Scrap": ItemData(frozenset({G.Recipe}), 1338312, C.progression), - "Recipe: Aluminum Ingot": ItemData(frozenset({G.Recipe}), 1338313, C.progression), - "Recipe: Pure Aluminum Ingot": ItemData(frozenset({G.Recipe}), 1338314, C.progression), - "Recipe: Alclad Aluminum Sheet": ItemData(frozenset({G.Recipe}), 1338315, C.progression), - "Recipe: Aluminum Casing": ItemData(frozenset({G.Recipe}), 1338316, C.progression), - "Recipe: Alclad Casing": ItemData(frozenset({G.Recipe}), 1338317, C.progression), - "Recipe: Heat Sink": ItemData(frozenset({G.Recipe}), 1338318, C.progression), - "Recipe: Heat Exchanger": ItemData(frozenset({G.Recipe}), 1338319, C.progression), - "Recipe: Synthetic Power Shard": ItemData(frozenset({G.Recipe}), 1338320, C.progression), - "Recipe: Nitric Acid": ItemData(frozenset({G.Recipe}), 1338321, C.progression), - "Recipe: Fused Modular Frame": ItemData(frozenset({G.Recipe}), 1338322, C.progression), - "Recipe: Heat-Fused Frame": ItemData(frozenset({G.Recipe}), 1338323, C.progression), - "Recipe: Radio Control Unit": ItemData(frozenset({G.Recipe}), 1338324, C.progression), - "Recipe: Radio Connection Unit": ItemData(frozenset({G.Recipe}), 1338325, C.progression), - "Recipe: Radio Control System": ItemData(frozenset({G.Recipe}), 1338326, C.progression), - "Recipe: Pressure Conversion Cube": ItemData(frozenset({G.Recipe}), 1338327, C.progression), - "Recipe: Cooling System": ItemData(frozenset({G.Recipe}), 1338328, C.progression), - "Recipe: Cooling Device": ItemData(frozenset({G.Recipe}), 1338329, C.progression), - "Recipe: Turbo Motor": ItemData(frozenset({G.Recipe}), 1338330, C.progression), - "Recipe: Turbo Electric Motor": ItemData(frozenset({G.Recipe}), 1338331, C.progression), - "Recipe: Turbo Pressure Motor": ItemData(frozenset({G.Recipe}), 1338332, C.progression), - "Recipe: Battery": ItemData(frozenset({G.Recipe}), 1338333, C.progression), - "Recipe: Classic Battery": ItemData(frozenset({G.Recipe}), 1338334, C.progression), - "Recipe: Supercomputer": ItemData(frozenset({G.Recipe}), 1338335, C.progression), - "Recipe: OC Supercomputer": ItemData(frozenset({G.Recipe}), 1338336, C.progression), - "Recipe: Super-State Computer": ItemData(frozenset({G.Recipe}), 1338337, C.progression), - "Recipe: Biochemical Sculptor": ItemData(frozenset({G.Recipe}), 1338338, C.progression), # 1.0 - "Recipe: Sulfuric Acid": ItemData(frozenset({G.Recipe}), 1338339, C.progression), - "Recipe: Ballistic Warp Drive": ItemData(frozenset({G.Recipe}), 1338340, C.progression), # 1.0 - "Recipe: Encased Uranium Cell": ItemData(frozenset({G.Recipe}), 1338341, C.progression), - "Recipe: Infused Uranium Cell": ItemData(frozenset({G.Recipe}), 1338342, C.progression), - "Recipe: Uranium Fuel Rod": ItemData(frozenset({G.Recipe}), 1338343, C.progression), - "Recipe: Uranium Fuel Unit": ItemData(frozenset({G.Recipe}), 1338344, C.progression), - "Recipe: Aluminum Beam": ItemData(frozenset({G.Recipe}), 1338345, C.progression), # 1.0 - "Recipe: Aluminum Rod": ItemData(frozenset({G.Recipe}), 1338346, C.progression), # 1.0 - "Recipe: Basic Iron Ingot": ItemData(frozenset({G.Recipe}), 1338347, C.progression), # 1.0 - "Recipe: Non-fissile Uranium": ItemData(frozenset({G.Recipe}), 1338348, C.progression), - "Recipe: Fertile Uranium": ItemData(frozenset({G.Recipe}), 1338349, C.progression), - "Recipe: Plutonium Pellet": ItemData(frozenset({G.Recipe}), 1338350), - "Recipe: Encased Plutonium Cell": ItemData(frozenset({G.Recipe}), 1338351), - "Recipe: Instant Plutonium Cell": ItemData(frozenset({G.Recipe}), 1338352), - "Recipe: Plutonium Fuel Rod": ItemData(frozenset({G.Recipe}), 1338353), - "Recipe: Plutonium Fuel Unit": ItemData(frozenset({G.Recipe}), 1338354), - "Recipe: Gas Filter": ItemData(frozenset({G.Recipe}), 1338355, C.progression), - "Recipe: Iodine Infused Filter": ItemData(frozenset({G.Recipe}), 1338356, C.progression), - "Recipe: Assembly Director System": ItemData(frozenset({G.Recipe}), 1338357, C.progression), - "Recipe: Magnetic Field Generator": ItemData(frozenset({G.Recipe}), 1338358, C.progression), - "Recipe: Copper Powder": ItemData(frozenset({G.Recipe}), 1338359, C.progression), - "Recipe: Nuclear Pasta": ItemData(frozenset({G.Recipe}), 1338360, C.progression), - "Recipe: Thermal Propulsion Rocket": ItemData(frozenset({G.Recipe}), 1338361, C.progression), - "Recipe: Ficsonium": ItemData(frozenset({G.Recipe}), 1338362), # 1.0 - "Recipe: Ficsonium Fuel Rod": ItemData(frozenset({G.Recipe}), 1338363), # 1.0 - "Recipe: Dark Matter Crystal": ItemData(frozenset({G.Recipe}), 1338364, C.progression), # 1.0 - "Recipe: Dark Matter Crystallization": ItemData(frozenset({G.Recipe}), 1338365, C.progression), # 1.0 - "Recipe: Dark Matter Trap": ItemData(frozenset({G.Recipe}), 1338366, C.progression), # 1.0 - "Recipe: Pulse Nobelisk": ItemData(frozenset({G.Recipe}), 1338367, C.useful), - "Recipe: Hatcher Protein": ItemData(frozenset({G.Recipe}), 1338368, C.progression), - "Recipe: Hog Protein": ItemData(frozenset({G.Recipe}), 1338369, C.progression), - "Recipe: Spitter Protein": ItemData(frozenset({G.Recipe}), 1338370, C.progression), - "Recipe: Stinger Protein": ItemData(frozenset({G.Recipe}), 1338371, C.progression), - "Recipe: Biomass (Leaves)": ItemData(frozenset({G.Recipe}), 1338372, C.progression), - "Recipe: Biomass (Wood)": ItemData(frozenset({G.Recipe}), 1338373, C.progression), - "Recipe: Biomass (Mycelia)": ItemData(frozenset({G.Recipe}), 1338374, C.progression), - "Recipe: Biomass (Alien Protein)": ItemData(frozenset({G.Recipe}), 1338375, C.progression), - "Recipe: Turbo Rifle Ammo (Packaged)": ItemData(frozenset({G.Recipe}), 1338376), - "Recipe: Fabric": ItemData(frozenset({G.Recipe}), 1338377, C.progression), - "Recipe: Polyester Fabric": ItemData(frozenset({G.Recipe}), 1338378, C.progression), - "Recipe: Solid Biofuel": ItemData(frozenset({G.Recipe}), 1338379, C.progression), - "Recipe: Liquid Biofuel": ItemData(frozenset({G.Recipe}), 1338380, C.progression), - "Recipe: Empty Canister": ItemData(frozenset({G.Recipe}), 1338381, C.progression), - "Recipe: Coated Iron Canister": ItemData(frozenset({G.Recipe}), 1338382, C.progression), - "Recipe: Steel Canister": ItemData(frozenset({G.Recipe}), 1338383, C.progression), - "Recipe: Empty Fluid Tank": ItemData(frozenset({G.Recipe}), 1338384, C.progression), - "Recipe: Packaged Alumina Solution": ItemData(frozenset({G.Recipe}), 1338385, C.progression), - "Recipe: Packaged Fuel": ItemData(frozenset({G.Recipe}), 1338386, C.progression), - "Recipe: Diluted Packaged Fuel": ItemData(frozenset({G.Recipe}), 1338387, C.progression), - "Recipe: Packaged Heavy Oil Residue": ItemData(frozenset({G.Recipe}), 1338388, C.progression), - "Recipe: Packaged Liquid Biofuel": ItemData(frozenset({G.Recipe}), 1338389, C.progression), - "Recipe: Packaged Nitric Acid": ItemData(frozenset({G.Recipe}), 1338390, C.progression), - "Recipe: Packaged Nitrogen Gas": ItemData(frozenset({G.Recipe}), 1338391, C.progression), - "Recipe: Packaged Oil": ItemData(frozenset({G.Recipe}), 1338392, C.progression), - "Recipe: Packaged Sulfuric Acid": ItemData(frozenset({G.Recipe}), 1338393, C.progression), - "Recipe: Packaged Turbofuel": ItemData(frozenset({G.Recipe}), 1338394, C.progression), - "Recipe: Packaged Water": ItemData(frozenset({G.Recipe}), 1338395, C.progression), - "Recipe: Turbofuel": ItemData(frozenset({G.Recipe}), 1338396, C.progression), - "Recipe: Turbo Heavy Fuel": ItemData(frozenset({G.Recipe}), 1338397, C.progression), - "Recipe: Turbo Blend Fuel": ItemData(frozenset({G.Recipe}), 1338398, C.progression), - "Recipe: Hazmat Suit": ItemData(frozenset({G.Recipe}), 1338399, C.progression), - "Recipe: Gas Mask": ItemData(frozenset({G.Recipe}), 1338400, C.progression), - "Recipe: Black Powder": ItemData(frozenset({G.Recipe}), 1338401, C.progression), - "Recipe: Blade Runners": ItemData(frozenset({G.Recipe}), 1338402, C.useful), - "Recipe: Chainsaw": ItemData(frozenset({G.Recipe}), 1338403, C.useful), - "Recipe: Cluster Nobelisk": ItemData(frozenset({G.Recipe}), 1338404), - "Recipe: Explosive Rebar": ItemData(frozenset({G.Recipe}), 1338405), - "Recipe: Factory Cart": ItemData(frozenset({G.Recipe}), 1338406, C.useful), - "Recipe: Gas Nobelisk": ItemData(frozenset({G.Recipe}), 1338407), - "Recipe: Golden Factory Cart": ItemData(frozenset({G.Recipe}), 1338408), - "Recipe: Homing Rifle Ammo": ItemData(frozenset({G.Recipe}), 1338409), - "Recipe: Iron Rebar": ItemData(frozenset({G.Recipe}), 1338410, C.progression), - "Recipe: Nobelisk": ItemData(frozenset({G.Recipe}), 1338411, C.progression), - "Recipe: Nuke Nobelisk": ItemData(frozenset({G.Recipe}), 1338412), - "Recipe: Nutritional Inhaler": ItemData(frozenset({G.Recipe}), 1338413, C.useful), - "Recipe: Object Scanner": ItemData(frozenset({G.Recipe}), 1338414, C.progression), - "Recipe: Parachute": ItemData(frozenset({G.Recipe}), 1338415, C.useful), - "Recipe: Protein Inhaler": ItemData(frozenset({G.Recipe}), 1338416, C.useful), - "Recipe: Rebar Gun": ItemData(frozenset({G.Recipe}), 1338417, C.useful), - "Recipe: Rifle": ItemData(frozenset({G.Recipe}), 1338418, C.useful), - "Recipe: Rifle Ammo": ItemData(frozenset({G.Recipe}), 1338419, C.progression), - "Recipe: Shatter Rebar": ItemData(frozenset({G.Recipe}), 1338420), - "Recipe: Stun Rebar": ItemData(frozenset({G.Recipe}), 1338421), - "Recipe: Therapeutic Inhaler": ItemData(frozenset({G.Recipe}), 1338422, C.useful), - "Recipe: Turbo Rifle Ammo": ItemData(frozenset({G.Recipe}), 1338423), - "Recipe: Vitamin Inhaler": ItemData(frozenset({G.Recipe}), 1338424, C.useful), - "Recipe: Xeno-Basher": ItemData(frozenset({G.Recipe}), 1338425, C.useful), - "Recipe: Xeno-Zapper": ItemData(frozenset({G.Recipe}), 1338426, C.useful), - "Recipe: Zipline": ItemData(frozenset({G.Recipe}), 1338427, C.useful), - "Recipe: Fine Black Powder": ItemData(frozenset({G.Recipe}), 1338428, C.progression), - "Recipe: Smokeless Powder": ItemData(frozenset({G.Recipe}), 1338429, C.progression), - "Recipe: Alien DNA Capsule": ItemData(frozenset({G.Recipe}), 1338430, C.progression), - "Recipe: Power Shard (1)": ItemData(frozenset({G.Recipe}), 1338431, C.progression), - "Recipe: Power Shard (2)": ItemData(frozenset({G.Recipe}), 1338432, C.useful), - "Recipe: Power Shard (5)": ItemData(frozenset({G.Recipe}), 1338433, C.useful), + "Recipe: Reinforced Iron Plate": ItemData(G.Recipe, 1338200, C.progression), + "Recipe: Adhered Iron Plate": ItemData(G.Recipe, 1338201, C.progression), + "Recipe: Bolted Iron Plate": ItemData(G.Recipe, 1338202, C.progression), + "Recipe: Stitched Iron Plate": ItemData(G.Recipe, 1338203, C.progression), + "Recipe: Rotor": ItemData(G.Recipe, 1338204, C.progression), + "Recipe: Copper Rotor": ItemData(G.Recipe, 1338205, C.progression), + "Recipe: Steel Rotor": ItemData(G.Recipe, 1338206, C.progression), + "Recipe: Stator": ItemData(G.Recipe, 1338207, C.progression), + "Recipe: Quickwire Stator": ItemData(G.Recipe, 1338208, C.progression), + "Recipe: Plastic": ItemData(G.Recipe, 1338209, C.progression), + "Recipe: Residual Plastic": ItemData(G.Recipe, 1338210, C.progression), + "Recipe: Recycled Plastic": ItemData(G.Recipe, 1338211, C.progression), + "Recipe: Rubber": ItemData(G.Recipe, 1338212, C.progression), + "Recipe: Residual Rubber": ItemData(G.Recipe, 1338213, C.progression), + "Recipe: Recycled Rubber": ItemData(G.Recipe, 1338214, C.progression), + "Recipe: Iron Plate": ItemData(G.Recipe, 1338215, C.progression), + "Recipe: Coated Iron Plate": ItemData(G.Recipe, 1338216, C.progression), + "Recipe: Steel Cast Plate": ItemData(G.Recipe, 1338217, C.progression), # 1.0 + "Recipe: Iron Rod": ItemData(G.Recipe, 1338218, C.progression), + "Recipe: Steel Rod": ItemData(G.Recipe, 1338219, C.progression), + "Recipe: Screw": ItemData(G.Recipe, 1338220, C.progression), + "Recipe: Cast Screw": ItemData(G.Recipe, 1338221, C.progression), + "Recipe: Steel Screw": ItemData(G.Recipe, 1338222, C.progression), + "Recipe: Wire": ItemData(G.Recipe, 1338223, C.progression), + "Recipe: Fused Wire": ItemData(G.Recipe, 1338224, C.progression), + "Recipe: Iron Wire": ItemData(G.Recipe, 1338225, C.progression), + "Recipe: Caterium Wire": ItemData(G.Recipe, 1338226, C.progression), + "Recipe: Cable": ItemData(G.Recipe, 1338227, C.progression), + "Recipe: Coated Cable": ItemData(G.Recipe, 1338228, C.progression), + "Recipe: Insulated Cable": ItemData(G.Recipe, 1338229, C.progression), + "Recipe: Quickwire Cable": ItemData(G.Recipe, 1338230, C.progression), + "Recipe: Quickwire": ItemData(G.Recipe, 1338231, C.progression), + "Recipe: Fused Quickwire": ItemData(G.Recipe, 1338232, C.progression), + "Recipe: Copper Sheet": ItemData(G.Recipe, 1338233, C.progression), + "Recipe: Steamed Copper Sheet": ItemData(G.Recipe, 1338234, C.progression), + "Recipe: Steel Pipe": ItemData(G.Recipe, 1338235, C.progression), + "Recipe: Steel Beam": ItemData(G.Recipe, 1338236, C.progression), + "Recipe: Neural-Quantum Processor": ItemData(G.Recipe, 1338237, C.progression), # 1.0 + "Recipe: Heavy Oil Residue": ItemData(G.Recipe, 1338238, C.progression), + "Recipe: Polymer Resin": ItemData(G.Recipe, 1338239, C.progression), + "Recipe: Fuel": ItemData(G.Recipe, 1338240, C.progression), + "Recipe: Residual Fuel": ItemData(G.Recipe, 1338241, C.progression), + "Recipe: Diluted Fuel (refinery)": ItemData(G.Recipe, 1338242, C.progression), + "Recipe: AI Expansion Server": ItemData(G.Recipe, 1338243, C.progression), # 1.0 + "Recipe: Concrete": ItemData(G.Recipe, 1338244, C.progression), + "Recipe: Rubber Concrete": ItemData(G.Recipe, 1338245, C.progression), + "Recipe: Wet Concrete": ItemData(G.Recipe, 1338246, C.progression), + "Recipe: Fine Concrete": ItemData(G.Recipe, 1338247, C.progression), + "Recipe: Silica": ItemData(G.Recipe, 1338248, C.progression), + "Recipe: Cheap Silica": ItemData(G.Recipe, 1338249, C.progression), + "Recipe: Quartz Crystal": ItemData(G.Recipe, 1338250, C.progression), + "Recipe: Pure Quartz Crystal": ItemData(G.Recipe, 1338251, C.progression), + "Recipe: Iron Ingot": ItemData(G.Recipe, 1338252, C.progression), + "Recipe: Pure Iron Ingot": ItemData(G.Recipe, 1338253, C.progression), + "Recipe: Iron Alloy Ingot": ItemData(G.Recipe, 1338254, C.progression), + "Recipe: Steel Ingot": ItemData(G.Recipe, 1338255, C.progression), + "Recipe: Coke Steel Ingot": ItemData(G.Recipe, 1338256, C.progression), + "Recipe: Compacted Steel Ingot": ItemData(G.Recipe, 1338257, C.progression), + "Recipe: Solid Steel Ingot": ItemData(G.Recipe, 1338258, C.progression), + "Recipe: Copper Ingot": ItemData(G.Recipe, 1338259, C.progression), + "Recipe: Copper Alloy Ingot": ItemData(G.Recipe, 1338260, C.progression), + "Recipe: Pure Copper Ingot": ItemData(G.Recipe, 1338261, C.progression), + "Recipe: Caterium Ingot": ItemData(G.Recipe, 1338262, C.progression), + "Recipe: Pure Caterium Ingot": ItemData(G.Recipe, 1338263, C.progression), + "Recipe: Alien Power Matrix": ItemData(G.Recipe, 1338264), # 1.0 + "Recipe: Ficsite Ingot (Aluminum)": ItemData(G.Recipe, 1338265, C.progression), # 1.0 + "Recipe: Ficsite Ingot (Caterium)": ItemData(G.Recipe, 1338266, C.progression), # 1.0 + "Recipe: Ficsite Ingot (Iron)": ItemData(G.Recipe, 1338267, C.progression), # 1.0 + "Recipe: Ficsite Trigon": ItemData(G.Recipe, 1338268, C.progression), # 1.0 + "Recipe: Reanimated SAM": ItemData(G.Recipe, 1338269, C.progression), # 1.0 + "Recipe: SAM Fluctuator": ItemData(G.Recipe, 1338270, C.progression), # 1.0 + "Recipe: Petroleum Coke": ItemData(G.Recipe, 1338271, C.progression), + "Recipe: Compacted Coal": ItemData(G.Recipe, 1338272, C.progression), + "Recipe: Motor": ItemData(G.Recipe, 1338273, C.progression), + "Recipe: Rigor Motor": ItemData(G.Recipe, 1338274, C.progression), + "Recipe: Electric Motor": ItemData(G.Recipe, 1338275, C.progression), + "Recipe: Modular Frame": ItemData(G.Recipe, 1338276, C.progression), + "Recipe: Bolted Frame": ItemData(G.Recipe, 1338277, C.progression), + "Recipe: Steeled Frame": ItemData(G.Recipe, 1338278, C.progression), + "Recipe: Heavy Modular Frame": ItemData(G.Recipe, 1338279, C.progression), + "Recipe: Heavy Flexible Frame": ItemData(G.Recipe, 1338280, C.progression), + "Recipe: Heavy Encased Frame": ItemData(G.Recipe, 1338281, C.progression), + "Recipe: Encased Industrial Beam": ItemData(G.Recipe, 1338282, C.progression), + "Recipe: Encased Industrial Pipe": ItemData(G.Recipe, 1338283, C.progression), + "Recipe: Computer": ItemData(G.Recipe, 1338284, C.progression), + "Recipe: Crystal Computer": ItemData(G.Recipe, 1338285, C.progression), + "Recipe: Caterium Computer": ItemData(G.Recipe, 1338286, C.progression), + "Recipe: Circuit Board": ItemData(G.Recipe, 1338287, C.progression), + "Recipe: Electrode Circuit Board": ItemData(G.Recipe, 1338288, C.progression), + "Recipe: Silicon Circuit Board": ItemData(G.Recipe, 1338289, C.progression), + "Recipe: Caterium Circuit Board": ItemData(G.Recipe, 1338290, C.progression), + "Recipe: Crystal Oscillator": ItemData(G.Recipe, 1338291, C.progression), + "Recipe: Insulated Crystal Oscillator": ItemData(G.Recipe, 1338292, C.progression), + "Recipe: AI Limiter": ItemData(G.Recipe, 1338293, C.progression), + "Recipe: Electromagnetic Control Rod": ItemData(G.Recipe, 1338294, C.progression), + "Recipe: Electromagnetic Connection Rod": ItemData(G.Recipe, 1338295, C.progression), + "Recipe: High-Speed Connector": ItemData(G.Recipe, 1338296, C.progression), + "Recipe: Silicon High-Speed Connector": ItemData(G.Recipe, 1338297, C.progression), + "Recipe: Smart Plating": ItemData(G.Recipe, 1338298, C.progression), + "Recipe: Plastic Smart Plating": ItemData(G.Recipe, 1338299, C.progression), + "Recipe: Versatile Framework": ItemData(G.Recipe, 1338300, C.progression), + "Recipe: Flexible Framework": ItemData(G.Recipe, 1338301, C.progression), + "Recipe: Automated Wiring": ItemData(G.Recipe, 1338302, C.progression), + "Recipe: Automated Speed Wiring": ItemData(G.Recipe, 1338303, C.progression), + "Recipe: Modular Engine": ItemData(G.Recipe, 1338304, C.progression), + "Recipe: Adaptive Control Unit": ItemData(G.Recipe, 1338305, C.progression), + "Recipe: Diluted Fuel": ItemData(G.Recipe, 1338306, C.progression), + "Recipe: Alumina Solution": ItemData(G.Recipe, 1338307, C.progression), + "Recipe: Automated Miner": ItemData(G.Recipe, 1338308, C.progression), + "Recipe: Singularity Cell": ItemData(G.Recipe, 1338309, C.progression), # 1.0 + "Recipe: Aluminum Scrap": ItemData(G.Recipe, 1338310, C.progression), + "Recipe: Electrode Aluminum Scrap": ItemData(G.Recipe, 1338311, C.progression), + "Recipe: Instant Scrap": ItemData(G.Recipe, 1338312, C.progression), + "Recipe: Aluminum Ingot": ItemData(G.Recipe, 1338313, C.progression), + "Recipe: Pure Aluminum Ingot": ItemData(G.Recipe, 1338314, C.progression), + "Recipe: Alclad Aluminum Sheet": ItemData(G.Recipe, 1338315, C.progression), + "Recipe: Aluminum Casing": ItemData(G.Recipe, 1338316, C.progression), + "Recipe: Alclad Casing": ItemData(G.Recipe, 1338317, C.progression), + "Recipe: Heat Sink": ItemData(G.Recipe, 1338318, C.progression), + "Recipe: Heat Exchanger": ItemData(G.Recipe, 1338319, C.progression), + "Recipe: Synthetic Power Shard": ItemData(G.Recipe, 1338320, C.progression), + "Recipe: Nitric Acid": ItemData(G.Recipe, 1338321, C.progression), + "Recipe: Fused Modular Frame": ItemData(G.Recipe, 1338322, C.progression), + "Recipe: Heat-Fused Frame": ItemData(G.Recipe, 1338323, C.progression), + "Recipe: Radio Control Unit": ItemData(G.Recipe, 1338324, C.progression), + "Recipe: Radio Connection Unit": ItemData(G.Recipe, 1338325, C.progression), + "Recipe: Radio Control System": ItemData(G.Recipe, 1338326, C.progression), + "Recipe: Pressure Conversion Cube": ItemData(G.Recipe, 1338327, C.progression), + "Recipe: Cooling System": ItemData(G.Recipe, 1338328, C.progression), + "Recipe: Cooling Device": ItemData(G.Recipe, 1338329, C.progression), + "Recipe: Turbo Motor": ItemData(G.Recipe, 1338330, C.progression), + "Recipe: Turbo Electric Motor": ItemData(G.Recipe, 1338331, C.progression), + "Recipe: Turbo Pressure Motor": ItemData(G.Recipe, 1338332, C.progression), + "Recipe: Battery": ItemData(G.Recipe, 1338333, C.progression), + "Recipe: Classic Battery": ItemData(G.Recipe, 1338334, C.progression), + "Recipe: Supercomputer": ItemData(G.Recipe, 1338335, C.progression), + "Recipe: OC Supercomputer": ItemData(G.Recipe, 1338336, C.progression), + "Recipe: Super-State Computer": ItemData(G.Recipe, 1338337, C.progression), + "Recipe: Biochemical Sculptor": ItemData(G.Recipe, 1338338, C.progression), # 1.0 + "Recipe: Sulfuric Acid": ItemData(G.Recipe, 1338339, C.progression), + "Recipe: Ballistic Warp Drive": ItemData(G.Recipe, 1338340, C.progression), # 1.0 + "Recipe: Encased Uranium Cell": ItemData(G.Recipe, 1338341, C.progression), + "Recipe: Infused Uranium Cell": ItemData(G.Recipe, 1338342, C.progression), + "Recipe: Uranium Fuel Rod": ItemData(G.Recipe, 1338343, C.progression), + "Recipe: Uranium Fuel Unit": ItemData(G.Recipe, 1338344, C.progression), + "Recipe: Aluminum Beam": ItemData(G.Recipe, 1338345, C.progression), # 1.0 + "Recipe: Aluminum Rod": ItemData(G.Recipe, 1338346, C.progression), # 1.0 + "Recipe: Basic Iron Ingot": ItemData(G.Recipe, 1338347, C.progression), # 1.0 + "Recipe: Non-fissile Uranium": ItemData(G.Recipe, 1338348, C.progression), + "Recipe: Fertile Uranium": ItemData(G.Recipe, 1338349, C.progression), + "Recipe: Plutonium Pellet": ItemData(G.Recipe, 1338350), + "Recipe: Encased Plutonium Cell": ItemData(G.Recipe, 1338351), + "Recipe: Instant Plutonium Cell": ItemData(G.Recipe, 1338352), + "Recipe: Plutonium Fuel Rod": ItemData(G.Recipe, 1338353), + "Recipe: Plutonium Fuel Unit": ItemData(G.Recipe, 1338354), + "Recipe: Gas Filter": ItemData(G.Recipe, 1338355, C.progression), + "Recipe: Iodine-Infused Filter": ItemData(G.Recipe, 1338356, C.progression), + "Recipe: Assembly Director System": ItemData(G.Recipe, 1338357, C.progression), + "Recipe: Magnetic Field Generator": ItemData(G.Recipe, 1338358, C.progression), + "Recipe: Copper Powder": ItemData(G.Recipe, 1338359, C.progression), + "Recipe: Nuclear Pasta": ItemData(G.Recipe, 1338360, C.progression), + "Recipe: Thermal Propulsion Rocket": ItemData(G.Recipe, 1338361, C.progression), + "Recipe: Ficsonium": ItemData(G.Recipe, 1338362), # 1.0 + "Recipe: Ficsonium Fuel Rod": ItemData(G.Recipe, 1338363), # 1.0 + "Recipe: Dark Matter Crystal": ItemData(G.Recipe, 1338364, C.progression), # 1.0 + "Recipe: Dark Matter Crystallization": ItemData(G.Recipe, 1338365, C.progression), # 1.0 + "Recipe: Dark Matter Trap": ItemData(G.Recipe, 1338366, C.progression), # 1.0 + "Recipe: Pulse Nobelisk": ItemData(G.Recipe, 1338367, C.useful), + "Recipe: Hatcher Protein": ItemData(G.Recipe, 1338368, C.progression), + "Recipe: Hog Protein": ItemData(G.Recipe, 1338369, C.progression), + "Recipe: Spitter Protein": ItemData(G.Recipe, 1338370, C.progression), + "Recipe: Stinger Protein": ItemData(G.Recipe, 1338371, C.progression), + "Recipe: Biomass (Leaves)": ItemData(G.Recipe, 1338372, C.progression), + "Recipe: Biomass (Wood)": ItemData(G.Recipe, 1338373, C.progression), + "Recipe: Biomass (Mycelia)": ItemData(G.Recipe, 1338374, C.progression), + "Recipe: Biomass (Alien Protein)": ItemData(G.Recipe, 1338375, C.progression), + "Recipe: Turbo Rifle Ammo (Packaged)": ItemData(G.Recipe, 1338376, C.useful), + "Recipe: Fabric": ItemData(G.Recipe, 1338377, C.progression), + "Recipe: Polyester Fabric": ItemData(G.Recipe, 1338378, C.progression), + "Recipe: Solid Biofuel": ItemData(G.Recipe, 1338379, C.progression), + "Recipe: Liquid Biofuel": ItemData(G.Recipe, 1338380, C.progression), + "Recipe: Empty Canister": ItemData(G.Recipe, 1338381, C.progression), + "Recipe: Coated Iron Canister": ItemData(G.Recipe, 1338382, C.progression), + "Recipe: Steel Canister": ItemData(G.Recipe, 1338383, C.progression), + "Recipe: Empty Fluid Tank": ItemData(G.Recipe, 1338384, C.progression), + "Recipe: Packaged Alumina Solution": ItemData(G.Recipe, 1338385, C.progression), + "Recipe: Packaged Fuel": ItemData(G.Recipe, 1338386, C.progression), + "Recipe: Diluted Packaged Fuel": ItemData(G.Recipe, 1338387, C.progression), + "Recipe: Packaged Heavy Oil Residue": ItemData(G.Recipe, 1338388, C.progression), + "Recipe: Packaged Liquid Biofuel": ItemData(G.Recipe, 1338389, C.progression), + "Recipe: Packaged Nitric Acid": ItemData(G.Recipe, 1338390, C.progression), + "Recipe: Packaged Nitrogen Gas": ItemData(G.Recipe, 1338391, C.progression), + "Recipe: Packaged Oil": ItemData(G.Recipe, 1338392, C.progression), + "Recipe: Packaged Sulfuric Acid": ItemData(G.Recipe, 1338393, C.progression), + "Recipe: Packaged Turbofuel": ItemData(G.Recipe, 1338394, C.progression), + "Recipe: Packaged Water": ItemData(G.Recipe, 1338395, C.progression), + "Recipe: Turbofuel": ItemData(G.Recipe, 1338396, C.progression), + "Recipe: Turbo Heavy Fuel": ItemData(G.Recipe, 1338397, C.progression), + "Recipe: Turbo Blend Fuel": ItemData(G.Recipe, 1338398, C.progression), + "Recipe: Hazmat Suit": ItemData(G.Recipe, 1338399, C.progression), + "Recipe: Gas Mask": ItemData(G.Recipe, 1338400, C.progression), + "Recipe: Black Powder": ItemData(G.Recipe, 1338401, C.progression), + "Recipe: Blade Runners": ItemData(G.Recipe, 1338402, C.useful), + "Recipe: Chainsaw": ItemData(G.Recipe, 1338403, C.useful), + "Recipe: Cluster Nobelisk": ItemData(G.Recipe, 1338404, C.useful), + "Recipe: Explosive Rebar": ItemData(G.Recipe, 1338405, C.useful), + "Recipe: Factory Cart": ItemData(G.Recipe, 1338406, C.useful), + "Recipe: Gas Nobelisk": ItemData(G.Recipe, 1338407, C.useful), + "Recipe: Golden Factory Cart": ItemData(G.Recipe, 1338408), + "Recipe: Homing Rifle Ammo": ItemData(G.Recipe, 1338409, C.useful), + "Recipe: Iron Rebar": ItemData(G.Recipe, 1338410, C.progression), + "Recipe: Nobelisk": ItemData(G.Recipe, 1338411, C.progression), + "Recipe: Nuke Nobelisk": ItemData(G.Recipe, 1338412, C.useful), + "Recipe: Nutritional Inhaler": ItemData(G.Recipe, 1338413, C.useful), + "Recipe: Object Scanner": ItemData(G.Recipe, 1338414, C.progression), + "Recipe: Parachute": ItemData(G.Recipe, 1338415, C.useful), + "Recipe: Protein Inhaler": ItemData(G.Recipe, 1338416, C.useful), + "Recipe: Rebar Gun": ItemData(G.Recipe, 1338417, C.useful), + "Recipe: Rifle": ItemData(G.Recipe, 1338418, C.useful), + "Recipe: Rifle Ammo": ItemData(G.Recipe, 1338419, C.progression), + "Recipe: Shatter Rebar": ItemData(G.Recipe, 1338420, C.useful), + "Recipe: Stun Rebar": ItemData(G.Recipe, 1338421, C.useful), + "Recipe: Therapeutic Inhaler": ItemData(G.Recipe, 1338422, C.useful), + "Recipe: Turbo Rifle Ammo": ItemData(G.Recipe, 1338423, C.useful), + "Recipe: Vitamin Inhaler": ItemData(G.Recipe, 1338424, C.useful), + "Recipe: Xeno-Basher": ItemData(G.Recipe, 1338425, C.useful), + "Recipe: Xeno-Zapper": ItemData(G.Recipe, 1338426, C.useful), + "Recipe: Zipline": ItemData(G.Recipe, 1338427, C.useful), + "Recipe: Fine Black Powder": ItemData(G.Recipe, 1338428, C.progression), + "Recipe: Smokeless Powder": ItemData(G.Recipe, 1338429, C.progression), + "Recipe: Alien DNA Capsule": ItemData(G.Recipe, 1338430, C.progression), + "Recipe: Power Shard (1)": ItemData(G.Recipe, 1338431, C.progression), + "Recipe: Power Shard (2)": ItemData(G.Recipe, 1338432, C.useful), + "Recipe: Power Shard (5)": ItemData(G.Recipe, 1338433, C.useful), # 1.0 - "Recipe: Diamonds": ItemData(frozenset({G.Recipe}), 1338434, C.progression), - "Recipe: Cloudy Diamonds": ItemData(frozenset({G.Recipe}), 1338435, C.progression), - "Recipe: Oil-Based Diamonds": ItemData(frozenset({G.Recipe}), 1338436, C.progression), - "Recipe: Petroleum Diamonds": ItemData(frozenset({G.Recipe}), 1338437, C.progression), - "Recipe: Pink Diamonds": ItemData(frozenset({G.Recipe}), 1338438, C.progression), - "Recipe: Turbo Diamonds": ItemData(frozenset({G.Recipe}), 1338439, C.progression), - "Recipe: Time Crystal": ItemData(frozenset({G.Recipe}), 1338440, C.progression), - "Recipe: Superposition Oscillator": ItemData(frozenset({G.Recipe}), 1338441, C.progression), - #"Recipe: Excited Photonic Matter": ItemData(frozenset({G.Recipe}), 1338442, C.progression), should probably be unlocked with converter - "Recipe: Rocket Fuel": ItemData(frozenset({G.Recipe}), 1338443, C.progression), - "Recipe: Nitro Rocket Fuel": ItemData(frozenset({G.Recipe}), 1338444, C.progression), - "Recipe: Ionized Fuel": ItemData(frozenset({G.Recipe}), 1338445, C.useful), - "Recipe: Packaged Rocket Fuel": ItemData(frozenset({G.Recipe}), 1338446, C.progression), - "Recipe: Packaged Ionized Fuel": ItemData(frozenset({G.Recipe}), 1338447, C.useful), - "Recipe: Dark-Ion Fuel": ItemData(frozenset({G.Recipe}), 1338448, C.useful), - "Recipe: Quartz Purification": ItemData(frozenset({G.Recipe}), 1338449, C.progression), - "Recipe: Fused Quartz Crystal": ItemData(frozenset({G.Recipe}), 1338450, C.progression), - "Recipe: Leached Caterium Ingot": ItemData(frozenset({G.Recipe}), 1338451, C.progression), - "Recipe: Leached Copper Ingot": ItemData(frozenset({G.Recipe}), 1338452, C.progression), - "Recipe: Leached Iron ingot": ItemData(frozenset({G.Recipe}), 1338453, C.progression), - "Recipe: Molded Beam": ItemData(frozenset({G.Recipe}), 1338454, C.progression), - "Recipe: Molded Steel Pipe": ItemData(frozenset({G.Recipe}), 1338455, C.progression), - "Recipe: Plastic AI Limiter": ItemData(frozenset({G.Recipe}), 1338456, C.progression), - "Recipe: Tempered Caterium Ingot": ItemData(frozenset({G.Recipe}), 1338457, C.progression), - "Recipe: Tempered Copper Ingot": ItemData(frozenset({G.Recipe}), 1338458, C.progression), + "Recipe: Diamonds": ItemData(G.Recipe, 1338434, C.progression), + "Recipe: Cloudy Diamonds": ItemData(G.Recipe, 1338435, C.progression), + "Recipe: Oil-Based Diamonds": ItemData(G.Recipe, 1338436, C.progression), + "Recipe: Petroleum Diamonds": ItemData(G.Recipe, 1338437, C.progression), + "Recipe: Pink Diamonds": ItemData(G.Recipe, 1338438, C.progression), + "Recipe: Turbo Diamonds": ItemData(G.Recipe, 1338439, C.progression), + "Recipe: Time Crystal": ItemData(G.Recipe, 1338440, C.progression), + "Recipe: Superposition Oscillator": ItemData(G.Recipe, 1338441, C.progression), + #"Recipe: Excited Photonic Matter": ItemData(G.Recipe, 1338442, C.progression), unlocked with converter + "Recipe: Rocket Fuel": ItemData(G.Recipe, 1338443, C.progression), + "Recipe: Nitro Rocket Fuel": ItemData(G.Recipe, 1338444, C.progression), + "Recipe: Ionized Fuel": ItemData(G.Recipe, 1338445, C.useful), + "Recipe: Packaged Rocket Fuel": ItemData(G.Recipe, 1338446, C.progression), + "Recipe: Packaged Ionized Fuel": ItemData(G.Recipe, 1338447, C.useful), + "Recipe: Dark-Ion Fuel": ItemData(G.Recipe, 1338448, C.useful), + "Recipe: Quartz Purification": ItemData(G.Recipe, 1338449, C.progression), + "Recipe: Fused Quartz Crystal": ItemData(G.Recipe, 1338450, C.progression), + "Recipe: Leached Caterium Ingot": ItemData(G.Recipe, 1338451, C.progression), + "Recipe: Leached Copper Ingot": ItemData(G.Recipe, 1338452, C.progression), + "Recipe: Leached Iron ingot": ItemData(G.Recipe, 1338453, C.progression), + "Recipe: Molded Beam": ItemData(G.Recipe, 1338454, C.progression), + "Recipe: Molded Steel Pipe": ItemData(G.Recipe, 1338455, C.progression), + "Recipe: Plastic AI Limiter": ItemData(G.Recipe, 1338456, C.progression), + "Recipe: Tempered Caterium Ingot": ItemData(G.Recipe, 1338457, C.progression), + "Recipe: Tempered Copper Ingot": ItemData(G.Recipe, 1338458, C.progression), # 1.0 - #1338459 - 1338599 Reserved for future recipes +# added in 1.1 or missed + "Recipe: Iron Pipe": ItemData(G.Recipe, 1338459, C.progression), + "Recipe: Biocoal": ItemData(G.Recipe, 1338460, C.useful), + "Recipe: Charcoal": ItemData(G.Recipe, 1338461, C.useful), + "Recipe: Sloppy Alumina": ItemData(G.Recipe, 1338462, C.progression), + "Recipe: Hoverpack": ItemData(G.Recipe, 1338463, C.useful), + "Recipe: Jetpack": ItemData(G.Recipe, 1338464, C.useful), + "Recipe: Nobelisk Detonator": ItemData(G.Recipe, 1338465, C.progression), + "Recipe: Portable Miner": ItemData(G.Recipe, 1338466, C.progression), +# + #1338467 - 1338599 Reserved for future recipes #1338400 - 1338899 buildings / others - "Building: Constructor": ItemData(frozenset({G.Building}), 1338600, C.progression), - "Building: Assembler": ItemData(frozenset({G.Building}), 1338601, C.progression), - "Building: Manufacturer": ItemData(frozenset({G.Building}), 1338602, C.progression), - "Building: Packager": ItemData(frozenset({G.Building}), 1338603, C.progression), - "Building: Refinery": ItemData(frozenset({G.Building}), 1338604, C.progression), - "Building: Blender": ItemData(frozenset({G.Building}), 1338605, C.progression), - "Building: Particle Accelerator": ItemData(frozenset({G.Building}), 1338606, C.progression), - "Building: Biomass Burner": ItemData(frozenset({G.Building}), 1338607, C.progression), - "Building: Coal Generator": ItemData(frozenset({G.Building}), 1338608, C.progression), - "Building: Geothermal Generator": ItemData(frozenset({G.Building}), 1338609, C.progression), - "Building: Nuclear Power Plant": ItemData(frozenset({G.Building}), 1338610, C.progression), - "Building: Miner Mk.1": ItemData(frozenset({G.Building}), 1338611, C.progression), - "Building: Miner Mk.2": ItemData(frozenset({G.Building}), 1338612, C.progression), - "Building: Miner Mk.3": ItemData(frozenset({G.Building}), 1338613, C.progression), - "Building: Oil Extractor": ItemData(frozenset({G.Building}), 1338614, C.progression), - "Building: Water Extractor": ItemData(frozenset({G.Building}), 1338615, C.progression), - "Building: Smelter": ItemData(frozenset({G.Building}), 1338616, C.progression), - "Building: Foundry": ItemData(frozenset({G.Building}), 1338617, C.progression), - "Building: Fuel Generator": ItemData(frozenset({G.Building}), 1338618, C.progression), - "Building: Resource Well Pressurizer": ItemData(frozenset({G.Building}), 1338619, C.progression), - "Building: Equipment Workshop": ItemData(frozenset({G.Building}), 1338620, C.progression), - "Building: AWESOME Sink": ItemData(frozenset({G.Building}), 1338621, C.progression), - "Building: AWESOME Shop": ItemData(frozenset({G.Building}), 1338622, C.progression), - "Building: Painted Beams": ItemData(frozenset({G.Beams}), 1338623, C.filler), - "Building: Blueprint Designer": ItemData(frozenset({G.Building}), 1338624, C.filler), - "Building: Fluid Buffer": ItemData(frozenset({G.Building}), 1338625, C.filler), - "Building: Industrial Fluid Buffer": ItemData(frozenset({G.Building}), 1338626, C.filler), - "Building: Jump Pad": ItemData(frozenset({G.Building}), 1338627, C.filler), - "Building: Ladder": ItemData(frozenset({G.Building}), 1338628, C.filler), - "Building: MAM": ItemData(frozenset({G.Building}), 1338629, C.progression), - "Building: Personal Storage Box": ItemData(frozenset({G.Building}), 1338630, C.filler), - "Building: Power Storage": ItemData(frozenset({G.Building}), 1338631, C.progression), - "Building: U-Jelly Landing Pad": ItemData(frozenset({G.Building}), 1338632, C.useful), - "Building: Power Switch": ItemData(frozenset({G.Building}), 1338633, C.useful), - "Building: Priority Power Switch": ItemData(frozenset({G.Building}), 1338634, C.useful), - "Building: Storage Container": ItemData(frozenset({G.Building}), 1338635, C.useful, 0), - "Building: Lookout Tower": ItemData(frozenset({G.Building}), 1338636, C.filler), - #"Building: Power Pole Mk.1": ItemData(frozenset({G.Building}), 1338637, C.progression), # available from start - "Building: Power Pole Mk.2": ItemData(frozenset({G.Building}), 1338638, C.useful), - "Building: Power Pole Mk.3": ItemData(frozenset({G.Building}), 1338639, C.useful), - "Building: Industrial Storage Container": ItemData(frozenset({G.Building}), 1338640, C.filler), - "Building: Conveyor Merger": ItemData(frozenset({G.Building}), 1338641, C.progression), - "Building: Conveyor Splitter": ItemData(frozenset({G.Building}), 1338642, C.progression), - "Building: Conveyor Mk.1": ItemData(frozenset({G.Building, G.ConveyorMk1}), 1338643, C.progression), - "Building: Conveyor Mk.2": ItemData(frozenset({G.Building, G.ConveyorMk2}), 1338644, C.progression), - "Building: Conveyor Mk.3": ItemData(frozenset({G.Building, G.ConveyorMk3}), 1338645, C.progression), - "Building: Conveyor Mk.4": ItemData(frozenset({G.Building, G.ConveyorMk4}), 1338646, C.progression), - "Building: Conveyor Mk.5": ItemData(frozenset({G.Building, G.ConveyorMk5}), 1338647, C.progression), - "Building: Conveyor Lift Mk.1": ItemData(frozenset({G.Building, G.ConveyorMk1}), 1338648, C.useful), - "Building: Conveyor Lift Mk.2": ItemData(frozenset({G.Building, G.ConveyorMk2}), 1338649, C.useful), - "Building: Conveyor Lift Mk.3": ItemData(frozenset({G.Building, G.ConveyorMk3}), 1338650, C.useful), - "Building: Conveyor Lift Mk.4": ItemData(frozenset({G.Building, G.ConveyorMk4}), 1338651, C.useful), - "Building: Conveyor Lift Mk.5": ItemData(frozenset({G.Building, G.ConveyorMk5}), 1338652, C.useful), - "Building: Metal Beams": ItemData(frozenset({G.Beams}), 1338653, C.filler, 0), - "Building: Stackable Conveyor Pole": ItemData(frozenset({G.Building, G.ConveyorSupports}), 1338654, C.useful), - "Building: Conveyor Wall Mount": ItemData(frozenset({G.Building, G.ConveyorSupports}), 1338655, C.useful, 0), - "Building: Conveyor Lift Floor Hole": ItemData(frozenset({G.Building, G.ConveyorSupports}), 1338656, C.useful, 0), - "Building: Conveyor Ceiling Mount": ItemData(frozenset({G.Building, G.ConveyorSupports}), 1338657, C.useful, 0), - "Building: Pipes Mk.1": ItemData(frozenset({G.Building, G.PipesMk1}), 1338658, C.progression), - "Building: Pipes Mk.2": ItemData(frozenset({G.Building, G.PipesMk2}), 1338659, C.progression), - "Building: Pipeline Pump Mk.1": ItemData(frozenset({G.Building, G.PipesMk1}), 1338660, C.progression), - "Building: Pipeline Pump Mk.2": ItemData(frozenset({G.Building, G.PipesMk2}), 1338661, C.progression), - "Building: Pipeline Junction Cross": ItemData(frozenset({G.Building, G.PipesMk1, G.PipesMk2}), 1338662, C.progression), - "Building: Valve": ItemData(frozenset({G.Building, G.PipesMk1, G.PipesMk2}), 1338663, C.useful), - "Building: Stackable Pipeline Support": ItemData(frozenset({G.Building, G.PipelineSupports}), 1338664, C.useful, 0), - "Building: Wall Pipeline Support": ItemData(frozenset({G.Building, G.PipelineSupports}), 1338665, C.useful, 0), - "Building: Pipeline Wall Hole": ItemData(frozenset({G.Building, G.PipelineSupports}), 1338666, C.useful, 0), - "Building: Pipeline Floor Hole": ItemData(frozenset({G.Building, G.PipelineSupports}), 1338667, C.useful, 0), - "Building: Lights Control Panel": ItemData(frozenset({G.Building, G.Lights}), 1338668, C.filler, 0), - "Building: Wall Mounted Flood Light": ItemData(frozenset({G.Building, G.Lights}), 1338669, C.filler, 0), - "Building: Street Light": ItemData(frozenset({G.Building, G.Lights}), 1338670, C.filler, 0), - "Building: Flood Light Tower": ItemData(frozenset({G.Building, G.Lights}), 1338671, C.filler, 0), - "Building: Ceiling Light": ItemData(frozenset({G.Building, G.Lights}), 1338672, C.filler, 0), - "Building: Power Tower": ItemData(frozenset({G.Building}), 1338673, C.useful), - "Building: Walls Orange": ItemData(frozenset({G.Building, G.Walls}), 1338674, C.progression), - "Building: Radar Tower": ItemData(frozenset({G.Building}), 1338675, C.useful), - "Building: Smart Splitter": ItemData(frozenset({G.Building}), 1338676, C.useful), - "Building: Programmable Splitter": ItemData(frozenset({G.Building}), 1338677, C.useful), - "Building: Label Sign Bundle": ItemData(frozenset({G.Building, G.Signs}), 1338678, C.filler, 0), - "Building: Display Sign Bundle": ItemData(frozenset({G.Building, G.Signs}), 1338679, C.filler, 0), - "Building: Billboard Set": ItemData(frozenset({G.Building, G.Signs}), 1338680, C.filler, 0), - "Building: Walls Metal": ItemData(frozenset({G.Building, G.Walls}), 1338681, C.filler, 0), - "Building: Metal Pillar": ItemData(frozenset({G.Pilars}), 1338682, C.filler, 0), - "Building: Concrete Pillar": ItemData(frozenset({G.Pilars}), 1338683, C.filler, 0), - "Building: Frame Pillar": ItemData(frozenset({G.Pilars}), 1338684, C.filler, 0), - "Building: Walls Concrete": ItemData(frozenset({G.Building, G.Walls}), 1338685, C.filler, 0), - #"Building: Big Metal Pillar": ItemData(frozenset({G.Pilars}), 1338686, C.filler, 0), - #"Building: Big Concrete Pillar": ItemData(frozenset({G.Pilars}), 1338687, C.filler, 0), - #"Building: Big Frame Pillar": ItemData(frozenset({G.Pilars}), 1338688, C.filler, 0), - #"Building: Beam Support": ItemData(frozenset({G.Beams}), 1338689, C.filler, 0), - #"Building: Beam Connector": ItemData(frozenset({G.Beams}), 1338690, C.filler, 0), - #"Building: Beam Connector Double": ItemData(frozenset({G.Beams}), 1338691, C.filler, 0), - "Building: Foundation": ItemData(frozenset({G.Building, G.Foundations}), 1338692, C.progression), - "Building: Half Foundation": ItemData(frozenset({G.Foundations}), 1338693, C.filler, 0), - "Building: Corner Ramp Pack": ItemData(frozenset({G.Foundations}), 1338694, C.filler, 0), - "Building: Inverted Ramp Pack": ItemData(frozenset({G.Foundations}), 1338695, C.filler, 0), - "Building: Inverted Corner Ramp Pack": ItemData(frozenset({G.Foundations}), 1338696, C.filler, 0), - "Building: Quarter Pipes Pack": ItemData(frozenset({G.Foundations}), 1338697, C.filler, 0), - "Building: Quarter Pipe Extensions Pack": ItemData(frozenset({G.Foundations}), 1338698, C.filler, 0), - "Building: Frame foundation": ItemData(frozenset({G.Foundations}), 1338699, C.filler, 0), - "Building: Wall Outlet Mk.1": ItemData(frozenset({G.Building}), 1338700, C.useful), - "Building: Wall Outlet Mk.2": ItemData(frozenset({G.Building}), 1338701, C.useful), - "Building: Wall Outlet Mk.3": ItemData(frozenset({G.Building}), 1338702, C.useful), - "Building: Modern Catwalks": ItemData(frozenset({G.Building}), 1338703, C.filler, 0), - "Building: Industrial Walkways": ItemData(frozenset({G.Building}), 1338704, C.filler, 0), - "Building: Stairs": ItemData(frozenset({G.Building}), 1338705, C.filler, 0), - "Building: Clean Pipeline Mk.1": ItemData(frozenset({G.Building}), 1338706, C.filler, 0), - "Building: Clean Pipeline Mk.2": ItemData(frozenset({G.Building}), 1338707, C.filler, 0), - "Building: Road Barrier": ItemData(frozenset({G.Building}), 1338708, C.filler, 0), - "Building: Modern Railing": ItemData(frozenset({G.Building}), 1338709, C.filler, 0), - "Building: Industrial Railing": ItemData(frozenset({G.Building}), 1338710, C.filler, 0), - "Building: Double Ramp Pack": ItemData(frozenset({G.Foundations}), 1338711, C.filler, 0), - "Building: Conveyor Walls": ItemData(frozenset({G.Walls}), 1338712, C.filler, 0), - "Building: Inverted Ramp Wall Bundle": ItemData(frozenset({G.Walls}), 1338713, C.filler, 0), - "Building: Ramp Wall Bundle": ItemData(frozenset({G.Walls}), 1338714, C.filler, 0), - "Building: Door Walls": ItemData(frozenset({G.Walls}), 1338715, C.filler, 0), - "Building: Tilted Walls": ItemData(frozenset({G.Walls}), 1338716, C.filler, 0), - "Building: Windowed Walls": ItemData(frozenset({G.Walls}), 1338717, C.filler, 0), - "Building: Steel-framed Windows": ItemData(frozenset({G.Walls}), 1338718, C.filler, 0), - "Building: Gates": ItemData(frozenset({G.Walls}), 1338719, C.filler, 0), - "Building: Roofs": ItemData(frozenset({G.Walls}), 1338720, C.filler, 0), - "Building: Roof Corners": ItemData(frozenset({G.Walls}), 1338721, C.filler, 0), - -# 1.0 - "Building: Converter": ItemData(frozenset({G.Building}), 1338722, C.progression), - "Building: Quantum Encoder": ItemData(frozenset({G.Building}), 1338723, C.progression), - "Building: Portal": ItemData(frozenset({G.Building}), 1338724, C.filler), - "Building: Conveyor Mk.6": ItemData(frozenset({G.Building, G.ConveyorMk6}), 1338725, C.progression), - "Building: Conveyor Lift Mk.6": ItemData(frozenset({G.Building, G.ConveyorMk6}), 1338726, C.useful), - "Building: Alien Power Augmenter": ItemData(frozenset({G.Building}), 1338727, C.progression), - "Building: Dimensional Depot Uploader": ItemData(frozenset({G.Building}), 1338728, C.useful), -# 1.0 - + "Building: Constructor": ItemData(G.Building, 1338600, C.progression), # unlocked by default + "Building: Assembler": ItemData(G.Building, 1338601, C.progression), + "Building: Manufacturer": ItemData(G.Building, 1338602, C.progression), + "Building: Packager": ItemData(G.Building, 1338603, C.progression), + "Building: Refinery": ItemData(G.Building, 1338604, C.progression), + "Building: Blender": ItemData(G.Building, 1338605, C.progression), + "Building: Particle Accelerator": ItemData(G.Building, 1338606, C.progression), + "Building: Biomass Burner": ItemData(G.Building, 1338607, C.progression), # unlocked by default + "Building: Coal Generator": ItemData(G.Building, 1338608, C.progression), + "Building: Geothermal Generator": ItemData(G.Building, 1338609, C.progression), + "Building: Nuclear Power Plant": ItemData(G.Building, 1338610, C.progression), + "Building: Miner Mk.1": ItemData(G.Building, 1338611, C.progression), # unlocked by default + "Building: Miner Mk.2": ItemData(G.Building, 1338612, C.progression), + "Building: Miner Mk.3": ItemData(G.Building, 1338613, C.progression), + "Building: Oil Extractor": ItemData(G.Building, 1338614, C.progression), + "Building: Water Extractor": ItemData(G.Building, 1338615, C.progression), + "Building: Smelter": ItemData(G.Building, 1338616, C.progression), # unlocked by default + "Building: Foundry": ItemData(G.Building, 1338617, C.progression), + "Building: Fuel Generator": ItemData(G.Building, 1338618, C.progression), + "Building: Resource Well Pressurizer": ItemData(G.Building, 1338619, C.progression), + "Building: Equipment Workshop": ItemData(G.Building, 1338620, C.progression), + "Building: AWESOME Sink": ItemData(G.Building | G.AlwaysUseful, 1338621, C.progression), + "Building: AWESOME Shop": ItemData(G.Building | G.AlwaysUseful, 1338622, C.progression), + "Building: Painted Beams": ItemData(G.Beams, 1338623, C.filler), + "Building: Blueprint Designer": ItemData(G.Building, 1338624, C.filler, 0), # unlocked by default + "Building: Fluid Buffer": ItemData(G.Building, 1338625, C.filler), + "Building: Industrial Fluid Buffer": ItemData(G.Building, 1338626, C.filler), + "Building: Jump Pad": ItemData(G.Building, 1338627, C.filler), + "Building: Ladder": ItemData(G.Building, 1338628, C.filler), + "Building: MAM": ItemData(G.Building | G.AlwaysUseful, 1338629, C.progression), + "Building: Personal Storage Box": ItemData(G.Building, 1338630, C.filler), + "Building: Power Storage": ItemData(G.Building | G.AlwaysUseful, 1338631, C.progression), + "Building: U-Jelly Landing Pad": ItemData(G.Building, 1338632, C.useful), + "Building: Power Switch": ItemData(G.Building, 1338633, C.useful), + "Building: Priority Power Switch": ItemData(G.Building, 1338634, C.useful), + "Building: Storage Container": ItemData(G.Building, 1338635, C.useful, 0), + "Building: Lookout Tower": ItemData(G.Building, 1338636, C.filler), + #"Building: Power Pole Mk.1": ItemData(G.Building, 1338637, C.progression), # unlocked by default + "Building: Power Pole Mk.2": ItemData(G.Building, 1338638, C.useful), + "Building: Power Pole Mk.3": ItemData(G.Building, 1338639, C.useful), + "Building: Industrial Storage Container": ItemData(G.Building, 1338640, C.filler), + "Building: Conveyor Merger": ItemData(G.Building | G.AlwaysUseful, 1338641, C.progression), + "Building: Conveyor Splitter": ItemData(G.Building | G.AlwaysUseful, 1338642, C.progression), + "Building: Conveyor Mk.1": ItemData(G.Building | G.ConveyorMk1, 1338643, C.progression), # unlocked by default + "Building: Conveyor Mk.2": ItemData(G.Building | G.ConveyorMk2, 1338644, C.progression), + "Building: Conveyor Mk.3": ItemData(G.Building | G.ConveyorMk3, 1338645, C.progression), + "Building: Conveyor Mk.4": ItemData(G.Building | G.ConveyorMk4, 1338646, C.progression), + "Building: Conveyor Mk.5": ItemData(G.Building | G.ConveyorMk5, 1338647, C.progression), + "Building: Conveyor Lift Mk.1": ItemData(G.Building | G.ConveyorMk1, 1338648, C.useful), + "Building: Conveyor Lift Mk.2": ItemData(G.Building | G.ConveyorMk2, 1338649, C.useful), + "Building: Conveyor Lift Mk.3": ItemData(G.Building | G.ConveyorMk3, 1338650, C.useful), + "Building: Conveyor Lift Mk.4": ItemData(G.Building | G.ConveyorMk4, 1338651, C.useful), + "Building: Conveyor Lift Mk.5": ItemData(G.Building | G.ConveyorMk5, 1338652, C.useful), + "Building: Metal Beams": ItemData(G.Beams, 1338653, C.filler, 0), + "Building: Stackable Conveyor Pole": ItemData(G.Building | G.ConveyorSupports, 1338654, C.useful), + "Building: Conveyor Wall Mount": ItemData(G.Building | G.ConveyorSupports, 1338655, C.useful, 0), + "Building: Conveyor Lift Floor Hole": ItemData(G.Building | G.ConveyorSupports, 1338656, C.useful, 0), + "Building: Conveyor Ceiling Mount": ItemData(G.Building | G.ConveyorSupports, 1338657, C.useful, 0), + "Building: Pipes Mk.1": ItemData(G.Building | G.PipesMk1, 1338658, C.progression), + "Building: Pipes Mk.2": ItemData(G.Building | G.PipesMk2, 1338659, C.progression), + "Building: Pipeline Pump Mk.1": ItemData(G.Building | G.PipesMk1, 1338660, C.progression), + "Building: Pipeline Pump Mk.2": ItemData(G.Building | G.PipesMk2, 1338661, C.progression), + "Building: Pipeline Junction Cross": ItemData(G.Building | G.PipesMk1 | G.PipesMk2, 1338662, C.progression), + "Building: Valve": ItemData(G.Building | G.PipesMk1 | G.PipesMk2, 1338663, C.useful), + "Building: Stackable Pipeline Support": ItemData(G.Building | G.PipelineSupports, 1338664, C.useful, 0), + "Building: Wall Pipeline Support": ItemData(G.Building | G.PipelineSupports, 1338665, C.useful, 0), + "Building: Pipeline Wall Hole": ItemData(G.Building | G.PipelineSupports, 1338666, C.useful, 0), + "Building: Pipeline Floor Hole": ItemData(G.Building | G.PipelineSupports, 1338667, C.useful, 0), + "Building: Lights Control Panel": ItemData(G.Building | G.Lights, 1338668, C.filler, 0), + "Building: Wall Mounted Flood Light": ItemData(G.Building | G.Lights, 1338669, C.filler, 0), + "Building: Street Light": ItemData(G.Building | G.Lights, 1338670, C.filler, 0), + "Building: Flood Light Tower": ItemData(G.Building | G.Lights, 1338671, C.filler, 0), + "Building: Ceiling Light": ItemData(G.Building | G.Lights, 1338672, C.filler, 0), + "Building: Power Tower": ItemData(G.Building, 1338673, C.useful), + "Building: Walls Orange": ItemData(G.Building | G.Walls, 1338674, C.progression), + "Building: Radar Tower": ItemData(G.Building, 1338675, C.useful), + "Building: Smart Splitter": ItemData(G.Building, 1338676, C.useful), + "Building: Programmable Splitter": ItemData(G.Building, 1338677, C.useful), + "Building: Label Sign Bundle": ItemData(G.Building | G.Signs, 1338678, C.filler, 0), + "Building: Display Sign Bundle": ItemData(G.Building | G.Signs, 1338679, C.filler, 0), + "Building: Billboard Set": ItemData(G.Building | G.Signs, 1338680, C.filler, 0), + #1338681 Moved to cosmetics - 1.1 + "Building: Metal Pillar": ItemData(G.Pilars, 1338682, C.filler, 0), + "Building: Concrete Pillar": ItemData(G.Pilars, 1338683, C.filler, 0), + "Building: Frame Pillar": ItemData(G.Pilars, 1338684, C.filler, 0), + #1338685 - 1338691 Moved to cosmetics - 1.1 + "Building: Foundation": ItemData(G.Building | G.Foundations | G.AlwaysUseful, 1338692, C.progression), + "Building: Half Foundation": ItemData(G.Foundations, 1338693, C.filler, 0), + "Building: Corner Ramp Pack": ItemData(G.Foundations, 1338694, C.filler, 0), + "Building: Inverted Ramp Pack": ItemData(G.Foundations, 1338695, C.filler, 0), + "Building: Inverted Corner Ramp Pack": ItemData(G.Foundations, 1338696, C.filler, 0), + "Building: Quarter Pipes Pack": ItemData(G.Foundations, 1338697, C.filler, 0), + "Building: Quarter Pipe Extensions Pack": ItemData(G.Foundations, 1338698, C.filler, 0), + "Building: Frame Foundation": ItemData(G.Foundations, 1338699, C.filler, 0), + "Building: Wall Outlet Mk.1": ItemData(G.Building, 1338700, C.useful), + "Building: Wall Outlet Mk.2": ItemData(G.Building, 1338701, C.useful), + "Building: Wall Outlet Mk.3": ItemData(G.Building, 1338702, C.useful), + "Building: Modern Catwalks": ItemData(G.Building, 1338703, C.filler, 0), + "Building: Industrial Walkways": ItemData(G.Building, 1338704, C.filler, 0), + "Building: Stairs": ItemData(G.Building, 1338705, C.filler, 0), + "Building: Clean Pipeline Mk.1": ItemData(G.Building, 1338706, C.filler, 0), + "Building: Clean Pipeline Mk.2": ItemData(G.Building, 1338707, C.filler, 0), + "Building: Road Barrier": ItemData(G.Building, 1338708, C.filler, 0), + "Building: Modern Railing": ItemData(G.Building, 1338709, C.filler, 0), + "Building: Industrial Railing": ItemData(G.Building, 1338710, C.filler, 0), + "Building: Double Ramp Pack": ItemData(G.Foundations, 1338711, C.filler, 0), + "Building: Conveyor Walls": ItemData(G.Walls, 1338712, C.filler, 0), + "Building: Inverted Ramp Wall Bundle": ItemData(G.Walls, 1338713, C.filler, 0), + "Building: Ramp Wall Bundle": ItemData(G.Walls, 1338714, C.filler, 0), + "Building: Door Walls": ItemData(G.Walls, 1338715, C.filler, 0), + "Building: Tilted Walls": ItemData(G.Walls, 1338716, C.filler, 0), + "Building: Windowed Walls": ItemData(G.Walls, 1338717, C.filler, 0), + "Building: Steel-framed Windows": ItemData(G.Walls, 1338718, C.filler, 0), + "Building: Gates": ItemData(G.Walls, 1338719, C.filler, 0), + "Building: Roofs": ItemData(G.Walls, 1338720, C.filler, 0), + "Building: Roof Corners": ItemData(G.Walls, 1338721, C.filler, 0), + "Building: Converter": ItemData(G.Building, 1338722, C.progression), + "Building: Quantum Encoder": ItemData(G.Building, 1338723, C.progression), + "Building: Portal": ItemData(G.Building, 1338724, C.filler), + "Building: Conveyor Mk.6": ItemData(G.Building | G.ConveyorMk6, 1338725, C.progression), + "Building: Conveyor Lift Mk.6": ItemData(G.Building | G.ConveyorMk6, 1338726, C.useful), + "Building: Alien Power Augmenter": ItemData(G.Building, 1338727, C.progression), + "Building: Dimensional Depot Uploader": ItemData(G.Building, 1338728, C.useful), #1338729 - 1338749 Reserved for Cosmetics + "Customizer: Asphalt Foundation Material": ItemData(G.Customizer | G.Foundations, 1338750, C.filler, 0), + "Customizer: Concrete Foundation Material": ItemData(G.Customizer | G.Foundations, 1338751, C.filler, 0), + "Customizer: Concrete Wall Material": ItemData(G.Customizer | G.Walls, 1338752, C.filler, 0), + "Customizer: Glass Roof Material": ItemData(G.Customizer | G.Walls, 1338753, C.filler, 0), + "Customizer: Grip Metal Foundation Material": ItemData(G.Customizer | G.Foundations, 1338754, C.filler, 0), + "Customizer: Coated Concrete Foundation Material": ItemData(G.Customizer | G.Foundations, 1338755, C.filler, 0), + "Customizer: Metal Roof Material": ItemData(G.Customizer | G.Walls, 1338756, C.filler, 0), + "Customizer: Steel Wall Material": ItemData(G.Customizer | G.Walls, 1338757, C.filler, 0), + "Customizer: Tar Roof Material": ItemData(G.Customizer | G.Walls, 1338758, C.filler, 0), + "Customizer: Arrow Patterns": ItemData(G.Customizer | G.Foundations, 1338759, C.filler, 0), + "Customizer: Dotted Line Patterns": ItemData(G.Customizer | G.Foundations, 1338760, C.filler, 0), + "Customizer: Solid Line Patterns": ItemData(G.Customizer | G.Foundations, 1338761, C.filler, 0), + "Customizer: Factory Icon Patterns": ItemData(G.Customizer | G.Foundations, 1338762, C.filler, 0), + "Customizer: Transportation Icon Patterns": ItemData(G.Customizer | G.Foundations, 1338763, C.filler, 0), + "Customizer: Number Patterns": ItemData(G.Customizer | G.Foundations, 1338764, C.filler, 0), + "Customizer: Pathway Patterns": ItemData(G.Customizer | G.Foundations, 1338765, C.filler, 0), + "Customizer: Factory Zone Patterns": ItemData(G.Customizer | G.Foundations, 1338766, C.filler, 0), + "Customizer: Steel-Framed Windows": ItemData(G.Customizer | G.Walls, 1338767, C.filler, 0), + "Customizer: Construction Fences": ItemData(G.Customizer, 1338768, C.filler, 0), + "Customizer: Unpainted Finish": ItemData(G.Customizer, 1338769, C.filler, 0), + "Customizer: Copper Paint Finish": ItemData(G.Customizer, 1338770, C.filler, 0), + "Customizer: Chrome Paint Finish": ItemData(G.Customizer, 1338771, C.filler, 0), + "Customizer: Carbon Steel Finish": ItemData(G.Customizer, 1338772, C.filler, 0), + "Customizer: Caterium Paint Finish": ItemData(G.Customizer, 1338773, C.filler, 0), - "Customizer: Asphalt Foundation Material": ItemData(frozenset({G.Customizer, G.Foundations}), 1338750, C.filler, 0), - "Customizer: Concrete Foundation Material": ItemData(frozenset({G.Customizer, G.Foundations}), 1338751, C.filler, 0), - "Customizer: Concrete Wall Material": ItemData(frozenset({G.Customizer, G.Walls}), 1338752, C.filler, 0), - "Customizer: Glass Roof Material": ItemData(frozenset({G.Customizer, G.Walls}), 1338753, C.filler, 0), - "Customizer: Grip Metal Foundation Material": ItemData(frozenset({G.Customizer, G.Foundations}), 1338754, C.filler, 0), - "Customizer: Coated Concrete Foundation Material": ItemData(frozenset({G.Customizer, G.Foundations}), 1338755, C.filler, 0), - "Customizer: Metal Roof Material": ItemData(frozenset({G.Customizer, G.Walls}), 1338756, C.filler, 0), - "Customizer: Steel Wall Material": ItemData(frozenset({G.Customizer, G.Walls}), 1338757, C.filler, 0), - "Customizer: Tar Roof Material": ItemData(frozenset({G.Customizer, G.Walls}), 1338758, C.filler, 0), - "Customizer: Arrow Patterns": ItemData(frozenset({G.Customizer, G.Foundations}), 1338759, C.filler, 0), - "Customizer: Dotted Line Patterns": ItemData(frozenset({G.Customizer, G.Foundations}), 1338760, C.filler, 0), - "Customizer: Solid Line Patterns": ItemData(frozenset({G.Customizer, G.Foundations}), 1338761, C.filler, 0), - "Customizer: Factory Icon Patterns": ItemData(frozenset({G.Customizer, G.Foundations}), 1338762, C.filler, 0), - "Customizer: Transportation Icon Patterns": ItemData(frozenset({G.Customizer, G.Foundations}), 1338763, C.filler, 0), - "Customizer: Number Patterns": ItemData(frozenset({G.Customizer, G.Foundations}), 1338764, C.filler, 0), - "Customizer: Pathway Patterns": ItemData(frozenset({G.Customizer, G.Foundations}), 1338765, C.filler, 0), - "Customizer: Factory Zone Patterns": ItemData(frozenset({G.Customizer, G.Foundations}), 1338766, C.filler, 0), - -# 1.0 - "Customizer: Steel-Framed Windows": ItemData(frozenset({G.Customizer, G.Walls}), 1338767, C.filler, 0), - "Customizer: Construction Fences": ItemData(frozenset({G.Customizer}), 1338768, C.filler, 0), - "Customizer: Unpainted Finish": ItemData(frozenset({G.Customizer}), 1338769, C.filler, 0), - "Customizer: Copper Paint Finish": ItemData(frozenset({G.Customizer}), 1338770, C.filler, 0), - "Customizer: Chrome Paint Finish": ItemData(frozenset({G.Customizer}), 1338771, C.filler, 0), - "Customizer: Carbon Steel Finish": ItemData(frozenset({G.Customizer}), 1338772, C.filler, 0), - "Customizer: Caterium Paint Finish": ItemData(frozenset({G.Customizer}), 1338773, C.filler, 0), -# 1.0 - - #1338773 - 1338799 Reserved for buildings + #1338774 - 1338799 Reserved for buildings # Transports 1338800 - 1338898 # Drones (including Drone) - "Transport: Drones": ItemData(frozenset({G.Transport}), 1338800, C.useful), - + "Transport: Drones": ItemData(G.Transport, 1338800, C.useful), # Trains (including Empty Platform, rails, station, locomotive) - "Transport: Trains": ItemData(frozenset({G.Transport, G.Trains}), 1338801, C.useful), - "Transport: Fluid Trains": ItemData(frozenset({G.Transport, G.Trains}), 1338802, C.useful), - + "Transport: Trains": ItemData(G.Transport | G.Trains, 1338801, C.useful), + "Transport: Fluid Trains": ItemData(G.Transport | G.Trains, 1338802, C.useful), # Tracker / Truck (including truck station) - "Transport: Tractor": ItemData(frozenset({G.Transport, G.Vehicles}), 1338803, C.useful), - "Transport: Truck": ItemData(frozenset({G.Transport, G.Vehicles}), 1338804, C.useful), - "Transport: Explorer": ItemData(frozenset({G.Transport, G.Vehicles}), 1338805, C.useful), - "Transport: Factory Cart": ItemData(frozenset({G.Transport, G.Vehicles}), 1338806, C.useful), - "Transport: Factory Cart (golden)": ItemData(frozenset({G.Transport, G.Vehicles}), 1338807, C.filler), - "Transport: Cyber Wagon": ItemData(frozenset({G.Transport, G.Vehicles}), 1338808, C.filler), - + "Transport: Tractor": ItemData(G.Transport | G.Vehicles, 1338803, C.useful), + "Transport: Truck": ItemData(G.Transport | G.Vehicles, 1338804, C.useful), + "Transport: Explorer": ItemData(G.Transport | G.Vehicles, 1338805, C.useful), + "Transport: Factory Cart": ItemData(G.Transport | G.Vehicles, 1338806, C.useful), + "Transport: Factory Cart (golden)": ItemData(G.Transport | G.Vehicles, 1338807, C.filler), + "Transport: Cyber Wagon": ItemData(G.Transport | G.Vehicles | G.Trap, 1338808, C.filler), # Hypertubes (including supports / pipes / entrance / holes) - "Transport: Hypertube": ItemData(frozenset({G.Transport, G.HyperTubes}), 1338809, C.useful), - "Transport: Hypertube Floor Hole": ItemData(frozenset({G.Transport, G.HyperTubes}), 1338810, C.filler), - "Transport: Hypertube Wall Support": ItemData(frozenset({G.Transport, G.HyperTubes}), 1338811, C.filler), - "Transport: Hypertube Wall Hole": ItemData(frozenset({G.Transport, G.HyperTubes}), 1338812, C.filler), + "Transport: Hypertube": ItemData(G.Transport | G.HyperTubes, 1338809, C.useful), + "Transport: Hypertube Floor Hole": ItemData(G.Transport | G.HyperTubes, 1338810, C.filler), + "Transport: Hypertube Wall Support": ItemData(G.Transport | G.HyperTubes, 1338811, C.filler), + "Transport: Hypertube Wall Hole": ItemData(G.Transport | G.HyperTubes, 1338812, C.filler), #1338900 - 1338998 Handled by trap system (includes a few non-trap things) # Regenerate via /Script/Blutility.EditorUtilityWidgetBlueprint'/Archipelago/Debug/EU_GenerateTrapIds.EU_GenerateTrapIds' - "Trap: Hog": ItemData(frozenset({G.Trap}), 1338900, C.trap), - "Trap: Alpha Hog": ItemData(frozenset({G.Trap}), 1338901, C.trap), - "Trap: Johnny": ItemData(frozenset({G.Trap}), 1338902, C.trap), - "Trap: Cliff Hog": ItemData(frozenset({G.Trap}), 1338903, C.trap), - "Trap: Nuclear Hog": ItemData(frozenset({G.Trap}), 1338904, C.trap), - "Trap: Not the Bees": ItemData(frozenset({G.Trap}), 1338905, C.trap), - "Trap: Hatcher": ItemData(frozenset({G.Trap}), 1338906, C.trap), - "Trap: Doggo with Pulse Nobelisk": ItemData(frozenset({G.Trap}), 1338907, C.trap), - "Trap: Doggo with Nuke Nobelisk": ItemData(frozenset({G.Trap}), 1338908, C.trap), - "Doggo with Power Slug": ItemData(frozenset({G.Parts}), 1338909, C.filler), - "Trap: Doggo with Gas Nobelisk": ItemData(frozenset({G.Trap}), 1338910, C.trap), - "Trap: Spore Flower": ItemData(frozenset({G.Trap}), 1338911, C.trap), - "Trap: Stinger": ItemData(frozenset({G.Trap}), 1338912, C.trap), - "Trap: Gas Stinger": ItemData(frozenset({G.Trap}), 1338913, C.trap), - "Trap: Small Stinger": ItemData(frozenset({G.Trap}), 1338914, C.trap), - "Trap: Spitter": ItemData(frozenset({G.Trap}), 1338915, C.trap), - "Trap: Alpha Spitter": ItemData(frozenset({G.Trap}), 1338916, C.trap), - "Trap: Nuclear Waste Drop": ItemData(frozenset({G.Trap}), 1338917, C.trap), - "Trap: Plutonium Waste Drop": ItemData(frozenset({G.Trap}), 1338918, C.trap), - "Trap: Elite Hatcher": ItemData(frozenset({G.Trap}), 1338919, C.trap), - "Trap: Can of Beans": ItemData(frozenset({G.Trap}), 1338920, C.trap), - "Trap: Fart Cloud": ItemData(frozenset({G.Trap}), 1338921, C.trap), + "Trap: Hog": ItemData(G.Trap, 1338900, C.trap), + "Trap: Alpha Hog": ItemData(G.Trap, 1338901, C.trap), + "Trap: Johnny": ItemData(G.Trap, 1338902, C.trap), + "Trap: Cliff Hog": ItemData(G.Trap, 1338903, C.trap), + "Trap: Nuclear Hog": ItemData(G.Trap, 1338904, C.trap), + "Trap: Not the Bees": ItemData(G.Trap, 1338905, C.trap), + "Trap: Hatcher": ItemData(G.Trap, 1338906, C.trap), + "Trap: Doggo with Pulse Nobelisk": ItemData(G.Trap, 1338907, C.trap), + "Trap: Doggo with Nuke Nobelisk": ItemData(G.Trap, 1338908, C.trap), + "Doggo with Power Slug": ItemData(G.Parts, 1338909, C.filler), + "Trap: Doggo with Gas Nobelisk": ItemData(G.Trap, 1338910, C.trap), + "Trap: Spore Flower": ItemData(G.Trap, 1338911, C.trap), + "Trap: Stinger": ItemData(G.Trap, 1338912, C.trap), + "Trap: Gas Stinger": ItemData(G.Trap, 1338913, C.trap), + "Trap: Small Stinger": ItemData(G.Trap, 1338914, C.trap), + "Trap: Spitter": ItemData(G.Trap, 1338915, C.trap), + "Trap: Alpha Spitter": ItemData(G.Trap, 1338916, C.trap), + "Trap: Nuclear Waste Drop": ItemData(G.Trap, 1338917, C.trap), + "Trap: Plutonium Waste Drop": ItemData(G.Trap, 1338918, C.trap), + "Trap: Elite Hatcher": ItemData(G.Trap, 1338919, C.trap), + "Trap: Can of Beans": ItemData(G.Trap, 1338920, C.trap), + "Trap: Fart Cloud": ItemData(G.Trap, 1338921, C.trap), - #Item id range upper bound - "Building: Space Elevator": ItemData(frozenset({G.Building}), 1338999, C.progression) + "Building: Space Elevator": ItemData(G.Building, 1338999, C.progression), + + # Resource singles + "Single: Adaptive Control Unit": ItemData(G.Parts, 1339000, count=0), + "Single: AI Limiter": ItemData(G.Parts, 1339001, count=0), + "Single: Alclad Aluminum Sheet": ItemData(G.Parts, 1339002, count=0), + "Single: Blue Power Slug": ItemData(G.Parts, 1339003, count=0), + "Single: Yellow Power Slug": ItemData(G.Parts, 1339004, count=0), + "Single: Alien Protein": ItemData(G.Parts, 1339005, count=0), + "Single: Purple Power Slug": ItemData(G.Parts, 1339006, count=0), + "Single: Aluminum Casing": ItemData(G.Parts, 1339007, count=0), + "Single: Aluminum Ingot": ItemData(G.Parts, 1339008, count=0), + "Single: Aluminum Scrap": ItemData(G.Parts, 1339009, count=0), + "Single: Assembly Director System": ItemData(G.Parts, 1339010, count=0), + "Single: Automated Wiring": ItemData(G.Parts, 1339011, count=0), + "Single: Battery": ItemData(G.Parts, 1339012, count=0), + "Single: Bauxite": ItemData(G.Parts, 1339013, count=0), + "Single: Neural-Quantum Processor": ItemData(G.Parts, 1339014, count=0), + "Single: Biomass": ItemData(G.Parts, 1339015, count=0), + "Single: Black Powder": ItemData(G.Parts, 1339016, count=0), + "Single: Cable": ItemData(G.Parts, 1339017, count=0), + "Single: Caterium Ingot": ItemData(G.Parts, 1339018, count=0), + "Single: Caterium Ore": ItemData(G.Parts, 1339019, count=0), + "Single: Circuit Board": ItemData(G.Parts, 1339020, count=0), + "Single: Coal": ItemData(G.Parts, 1339021, count=0), + "Single: Singularity Cell": ItemData(G.Parts, 1339022, count=0), + "Single: Compacted Coal": ItemData(G.Parts, 1339023, count=0), + "Single: Computer": ItemData(G.Parts, 1339024, count=0), + "Single: Concrete": ItemData(G.Parts, 1339025, count=0), + "Single: Cooling System": ItemData(G.Parts, 1339026, count=0), + "Single: Copper Ingot": ItemData(G.Parts, 1339027, count=0), + "Single: Copper Ore": ItemData(G.Parts, 1339028, count=0), + "Single: Copper Powder": ItemData(G.Parts, 1339029, count=0), + "Single: Copper Sheet": ItemData(G.Parts, 1339030, count=0), + "Single: Adequate Pioneering Statue": ItemData(G.Parts, 1339031, count=0), + "Single: Crystal Oscillator": ItemData(G.Parts, 1339032, count=0), + "Single: Electromagnetic Control Rod": ItemData(G.Parts, 1339033, count=0), + "Single: Empty Canister": ItemData(G.Parts, 1339034, count=0), + "Single: Empty Fluid Tank": ItemData(G.Parts, 1339035, count=0), + "Single: Encased Industrial Beam": ItemData(G.Parts, 1339036, count=0), + "Single: Encased Plutonium Cell": ItemData(G.Trap, 1339037, C.trap, count=0), + "Single: Encased Uranium Cell": ItemData(G.Trap, 1339038, C.trap, count=0), + "Single: Fabric": ItemData(G.Parts, 1339039, count=0), + "Single: FICSIT Coupon": ItemData(G.Parts, 1339040, count=0), + "Single: AI Expansion Server": ItemData(G.Parts, 1339041, count=0), + "Single: Fused Modular Frame": ItemData(G.Parts, 1339042, count=0), + "Single: Hard Drive": ItemData(G.Parts, 1339043, count=0), + "Single: Heat Sink": ItemData(G.Parts, 1339044, count=0), + "Single: Heavy Modular Frame": ItemData(G.Parts, 1339045, count=0), + "Single: High-Speed Connector": ItemData(G.Parts, 1339046, count=0), + "Single: Satisfactory Pioneering Statue": ItemData(G.Parts, 1339047, count=0), + "Single: Pretty Good Pioneering Statue": ItemData(G.Parts, 1339048, count=0), + "Single: Iron Ingot": ItemData(G.Parts, 1339049, count=0), + "Single: Iron Ore": ItemData(G.Parts, 1339050, count=0), + "Single: Iron Plate": ItemData(G.Parts, 1339051, count=0), + "Single: Iron Rod": ItemData(G.Parts, 1339052, count=0), + "Single: Golden Nut Statue": ItemData(G.Parts, 1339053, count=0), + "Single: Leaves": ItemData(G.Parts, 1339054, count=0), + "Single: Limestone": ItemData(G.Parts, 1339055, count=0), + "Single: Magnetic Field Generator": ItemData(G.Parts, 1339056, count=0), + "Single: Mercer Sphere": ItemData(G.Parts, 1339057, count=0), + "Single: Modular Engine": ItemData(G.Parts, 1339058, count=0), + "Single: Modular Frame": ItemData(G.Parts, 1339059, count=0), + "Single: Motor": ItemData(G.Parts, 1339060, count=0), + "Single: Mycelia": ItemData(G.Parts, 1339061, count=0), + "Single: Non-fissile Uranium": ItemData(G.Trap, 1339062, C.trap, count=0), + "Single: Nuclear Pasta": ItemData(G.Parts, 1339063, count=0), + "Single: Lizard Doggo Statue": ItemData(G.Parts, 1339064, count=0), + "Single: Organic Data Capsule": ItemData(G.Parts, 1339065, count=0), + "Single: Packaged Alumina Solution": ItemData(G.Parts, 1339066, count=0), + "Single: Packaged Fuel": ItemData(G.Parts, 1339067, count=0), + "Single: Packaged Heavy Oil Residue": ItemData(G.Parts, 1339068, count=0), + "Single: Packaged Liquid Biofuel": ItemData(G.Parts, 1339069, count=0), + "Single: Packaged Nitric Acid": ItemData(G.Parts, 1339070, count=0), + "Single: Packaged Nitrogen Gas": ItemData(G.Parts, 1339071, count=0), + "Single: Packaged Oil": ItemData(G.Parts, 1339072, count=0), + "Single: Packaged Sulfuric Acid": ItemData(G.Parts, 1339073, count=0), + "Single: Packaged Turbofuel": ItemData(G.Parts, 1339074, count=0), + "Single: Packaged Water": ItemData(G.Parts, 1339075, count=0), + "Single: Petroleum Coke": ItemData(G.Parts, 1339076, count=0), + "Single: Plastic": ItemData(G.Parts, 1339077, count=0), + "Single: Plutonium Fuel Rod": ItemData(G.Trap, 1339078, C.trap, count=0), + "Single: Plutonium Pellet": ItemData(G.Trap, 1339079, C.trap, count=0), + "Single: Plutonium Waste": ItemData(G.Trap, 1339080, C.trap, count=0), + "Single: Polymer Resin": ItemData(G.Parts, 1339081, count=0), + "Single: Power Shard": ItemData(G.Parts, 1339082, count=0), + "Single: Confusing Creature Statue": ItemData(G.Parts, 1339083, count=0), + "Single: Pressure Conversion Cube": ItemData(G.Parts, 1339084, count=0), + "Single: Alien Power Matrix": ItemData(G.Parts, 1339085, count=0), + "Single: Quartz Crystal": ItemData(G.Parts, 1339086, count=0), + "Single: Quickwire": ItemData(G.Parts, 1339087, count=0), + "Single: Radio Control Unit": ItemData(G.Parts, 1339088, count=0), + "Single: Raw Quartz": ItemData(G.Parts, 1339089, count=0), + "Single: Reinforced Iron Plate": ItemData(G.Parts, 1339090, count=0), + "Single: Rotor": ItemData(G.Parts, 1339091, count=0), + "Single: Rubber": ItemData(G.Parts, 1339092, count=0), + "Single: SAM": ItemData(G.Parts, 1339093, count=0), + "Single: Screw": ItemData(G.Parts, 1339094, count=0), + "Single: Silica": ItemData(G.Parts, 1339095, count=0), + "Single: Smart Plating": ItemData(G.Parts, 1339096, count=0), + "Single: Smokeless Powder": ItemData(G.Parts, 1339097, count=0), + "Single: Solid Biofuel": ItemData(G.Parts, 1339098, count=0), + "Single: Somersloop": ItemData(G.Parts, 1339099, count=0), + "Single: Stator": ItemData(G.Parts, 1339100, count=0), + "Single: Silver Hog Statue": ItemData(G.Parts, 1339101, count=0), + "Single: Steel Beam": ItemData(G.Parts, 1339102, count=0), + "Single: Steel Ingot": ItemData(G.Parts, 1339103, count=0), + "Single: Steel Pipe": ItemData(G.Parts, 1339104, count=0), + "Single: Sulfur": ItemData(G.Parts, 1339105, count=0), + "Single: Supercomputer": ItemData(G.Parts, 1339106, count=0), + "Single: Superposition Oscillator": ItemData(G.Parts, 1339107, count=0), + "Single: Thermal Propulsion Rocket": ItemData(G.Parts, 1339108, count=0), + "Single: Turbo Motor": ItemData(G.Parts, 1339109, count=0), + "Single: Hog Remains": ItemData(G.Parts, 1339110, count=0), + "Single: Uranium": ItemData(G.Trap, 1339111, C.trap, count=0), + "Single: Uranium Fuel Rod": ItemData(G.Trap, 1339112, C.trap, count=0), + "Single: Uranium Waste": ItemData(G.Trap, 1339113, C.trap, count=0), + "Single: Versatile Framework": ItemData(G.Parts, 1339114, count=0), + "Single: Wire": ItemData(G.Parts, 1339115, count=0), + "Single: Wood": ItemData(G.Parts, 1339116, count=0), + "Single: Plasma Spitter Remains": ItemData(G.Parts, 1339117, count=0), + "Single: Stinger Remains": ItemData(G.Parts, 1339118, count=0), + "Single: Hatcher Remains": ItemData(G.Parts, 1339119, count=0), + "Single: Alien DNA Capsule": ItemData(G.Parts, 1339120, count=0), + "Single: Diamonds": ItemData(G.Parts, 1339121, count=0), + "Single: Time Crystal": ItemData(G.Parts, 1339122, count=0), + "Single: Ficsite Ingot": ItemData(G.Parts, 1339123, count=0), + "Single: Ficsite Trigon": ItemData(G.Parts, 1339124, count=0), + "Single: Reanimated SAM": ItemData(G.Parts, 1339125, count=0), + "Single: SAM Fluctuator": ItemData(G.Parts, 1339126, count=0), + "Single: Biochemical Sculptor": ItemData(G.Parts, 1339127, count=0), + "Single: Ballistic Warp Drive": ItemData(G.Parts, 1339128, count=0), + "Single: Ficsonium": ItemData(G.Trap, 1339129, C.trap, count=0), + "Single: Ficsonium Fuel Rod": ItemData(G.Trap, 1339130, C.trap, count=0), + "Single: Packaged Rocket Fuel": ItemData(G.Parts, 1339131, count=0), + "Single: Packaged Ionized Fuel": ItemData(G.Parts, 1339132, count=0), + #1339133 - 1339149 Reserved for future parts + #1339150 - 1339199 Equipment / Ammo + "Single: Bacon Agaric": ItemData(G.Ammo, 1339150, count=0), + "Single: Beryl Nut": ItemData(G.Ammo, 1339151, count=0), + "Single: Blade Runners": ItemData(G.Equipment, 1339152), + "Single: Boom Box": ItemData(G.Equipment, 1339153), + "Single: Chainsaw": ItemData(G.Equipment, 1339154), + "Single: Cluster Nobelisk": ItemData(G.Ammo, 1339155, count=0), + "Single: Iodine-Infused Filter": ItemData(G.Ammo, 1339156, count=0), #1.1 + "Single: Cup": ItemData(G.Equipment, 1339157), + "Single: Cup (gold)": ItemData(G.Equipment, 1339158, count=0), + "Single: Explosive Rebar": ItemData(G.Ammo, 1339159, count=0), + "Single: Factory Cart": ItemData(G.Equipment, 1339160), + "Single: Factory Cart (golden)": ItemData(G.Equipment, 1339161, count=0), + "Single: Gas Mask": ItemData(G.Equipment, 1339162), + "Single: Gas Nobelisk": ItemData(G.Ammo, 1339163, count=0), + "Single: Hazmat Suit": ItemData(G.Equipment, 1339164), + "Single: Homing Rifle Ammo": ItemData(G.Ammo, 1339165, count=0), + "Single: Hoverpack": ItemData(G.Equipment, 1339166), + "Single: Iron Rebar": ItemData(G.Ammo, 1339167, count=0), + "Single: Jetpack": ItemData(G.Equipment, 1339168), + "Single: Medicinal Inhaler": ItemData(G.Ammo, 1339169, count=0), + "Single: Nobelisk": ItemData(G.Ammo, 1339170, count=0), + "Single: Nobelisk Detonator": ItemData(G.Equipment, 1339171), + "Single: Nuke Nobelisk": ItemData(G.Ammo, 1339172, count=0), + "Single: Object Scanner": ItemData(G.Equipment, 1339173), + "Single: Paleberry": ItemData(G.Ammo, 1339174, count=0), + "Single: Parachute": ItemData(G.Equipment, 1339175), + "Single: Pulse Nobelisk": ItemData(G.Ammo, 1339176, count=0), + "Single: Rebar Gun": ItemData(G.Equipment, 1339177), + "Single: Rifle": ItemData(G.Equipment, 1339178), + "Single: Rifle Ammo": ItemData(G.Ammo, 1339179, count=0), + "Single: Shatter Rebar": ItemData(G.Ammo, 1339180, count=0), + "Single: Stun Rebar": ItemData(G.Ammo, 1339181, count=0), + "Single: Turbo Rifle Ammo": ItemData(G.Ammo, 1339182, count=0), + "Single: Xeno-Basher": ItemData(G.Equipment, 1339183), + "Single: Xeno-Zapper": ItemData(G.Equipment, 1339184), + "Single: Zipline": ItemData(G.Equipment, 1339185), + "Single: Portable Miner": ItemData(G.Equipment, 1339186), + "Single: Gas Filter": ItemData(G.Ammo, 1339187, count=0) } - non_unique_item_categories: ClassVar[Set[G]] = frozenset({ G.Parts, G.Equipment, G.Ammo, G.Trap, G.Upgrades }) - pool_item_categories: ClassVar[Set[G]] = frozenset({G.Recipe, G.Building, G.Equipment, G.Transport, G.Upgrades}) - item_names_and_ids: ClassVar[Dict[str, int]] = {name: item_data.code for name, item_data in item_data.items()} - filler_items: ClassVar[Tuple[str, ...]] = tuple(item for item, details in item_data.items() - if not details.category.isdisjoint(frozenset({ G.Parts, G.Ammo }))) + non_unique_item_categories: ClassVar[G] = G.Parts | G.Equipment | G.Ammo | G.Trap | G.Upgrades + pool_item_categories: ClassVar[G] = G.Recipe | G.Building | G.Equipment | G.Transport | G.Upgrades + item_names_and_ids: ClassVar[dict[str, int]] = {name: item_data.code for name, item_data in item_data.items()} + filler_items: ClassVar[tuple[str, ...]] = tuple(item for item, details in item_data.items() + if details.category & (G.Parts | G.Ammo)) @classmethod - def get_item_names_per_category(cls) -> Dict[str, Set[str]]: - categories: Dict[str, Set[str]] = {} + def get_item_names_per_category(cls) -> dict[str, set[str]]: + categories: dict[str, set[str]] = {} for name, data in cls.item_data.items(): for category in data.category: @@ -697,121 +863,17 @@ class Items: return categories - player: int logic: GameLogic random: Random - precalculated_progression_recipes: Optional[Dict[str, Recipe]] - precalculated_progression_recipes_names: Optional[Set[str]] + critical_path: CriticalPathCalculator - - def __init__(self, player: Optional[int], logic: GameLogic, random: Random, options: SatisfactoryOptions): + def __init__(self, player: Optional[int], logic: GameLogic, random: Random, + options: SatisfactoryOptions, critical_path: CriticalPathCalculator): self.player = player self.logic = logic self.random = random - - if options.experimental_generation: # TODO major performance boost if we can get it stable - self.precalculated_progression_recipes = self.select_progression_recipes() - self.precalculated_progression_recipes_names = set( - recipe.name for recipe in self.precalculated_progression_recipes.values() - ) - else: - self.precalculated_progression_recipes = None - self.precalculated_progression_recipes_names = None - - - def select_recipe_for_part_that_does_not_depend_on_parent_recipes(self, - part: str, parts_to_avoid: Dict[str, str]) -> Recipe: - - recipes: List[Recipe] = list(self.logic.recipes[part]) - - implicit_recipe = next(filter(lambda r: r.implicitly_unlocked, recipes), None) - if implicit_recipe: - return implicit_recipe - - while (len(recipes) > 0): - recipe: Recipe = recipes.pop(self.random.randrange(len(recipes))) - - if recipe.inputs and any(input in parts_to_avoid for input in recipe.inputs): - continue - - return recipe - - raise Exception(f"No recipe available for {part}") - - - def build_progression_recipe_tree(self, parts: tuple[str, ...], selected_recipes: Dict[str, str]): - for part in parts: - recipe: Recipe = \ - self.select_recipe_for_part_that_does_not_depend_on_parent_recipes(part, selected_recipes) - - selected_recipes[part] = recipe.name - - child_recipes: Dict[str, Recipe] = {} - if (recipe.inputs): - for input in recipe.inputs: - child_recipes[input] = \ - self.select_recipe_for_part_that_does_not_depend_on_parent_recipes(input, selected_recipes) - - for part, child_recipe in child_recipes.items(): - selected_recipes[part] = child_recipe.name - - for child_recipe in child_recipes.values(): - if child_recipe.inputs: - self.build_progression_recipe_tree(child_recipe.inputs, selected_recipes) - - - def select_progression_recipes(self) -> Dict[str, Recipe]: - selected_recipes: Dict[str, Recipe] = {} - - while not self.is_beatable(selected_recipes): - selected_recipes = self.select_random_progression_recipes() - - return selected_recipes - - - def is_beatable(self, recipes: Dict[str, Recipe]) -> bool: - if not recipes: - return False - - craftable_parts: Set[str] = set() - pending_recipes_by_part: Dict[str, Recipe] = copy.deepcopy(recipes) - - for part, recipe_tuples in self.logic.recipes.items(): - for recipe in recipe_tuples: - if recipe.implicitly_unlocked: - craftable_parts.add(part) - - while pending_recipes_by_part: - new_collected_parts: Set[str] = set() - - for part, recipe in pending_recipes_by_part.items(): - if all(input in craftable_parts for input in recipe.inputs): - new_collected_parts.add(part) - - if not new_collected_parts: - return False - - craftable_parts = craftable_parts.union(new_collected_parts) - - for part in new_collected_parts: - del pending_recipes_by_part[part] - - return True - - - def select_random_progression_recipes(self) -> Dict[str, Recipe]: - selected_recipes: Dict[str, str] = {} - - for part, recipes in self.logic.recipes.items(): - - implicit_recipe: Recipe = next(filter(lambda r: r.implicitly_unlocked, recipes), None) - if implicit_recipe: - continue - - selected_recipes[part] = self.random.choice(recipes) - - return selected_recipes + self.critical_path = critical_path @classmethod @@ -819,33 +881,34 @@ class Items: data: ItemData = cls.item_data[name] type = data.type - if type == C.progression and not name.startswith("Building: ") and \ - instance and instance.precalculated_progression_recipes_names: - if name not in instance.precalculated_progression_recipes_names: + if type == C.progression \ + and instance and instance.critical_path.required_item_names \ + and (data.category & (G.Recipe | G.Building)) and not (data.category & G.AlwaysUseful) \ + and name not in instance.critical_path.required_item_names: type = C.useful - logging.info(f"Downscaling .. {name}") - else: - logging.warn(f"Preserving .. {name}") return Item(name, type, data.code, player) - def get_filler_item_name(self, random: Random, options: SatisfactoryOptions) -> str: + def get_filler_item_name(self, filler_items: tuple[str, ...], random: Random, options: SatisfactoryOptions) -> str: trap_chance: int = options.trap_chance.value enabled_traps: List[str] = list(options.trap_selection_override.value) if enabled_traps and random.random() < (trap_chance / 100): return random.choice(enabled_traps) else: - return random.choice(self.filler_items) + return random.choice(filler_items) - def get_excluded_items(self, multiworld: MultiWorld, options: SatisfactoryOptions) -> Set[str]: - excluded_items: Set[str] = set() + def get_excluded_items(self, multiworld: MultiWorld, options: SatisfactoryOptions) -> set[str]: + excluded_items: set[str] = set() + excluded_items.update("Bundle: "+ part for part in self.critical_path.parts_to_exclude) + excluded_items.update(recipe for recipe in self.critical_path.recipes_to_exclude) + excluded_items.update("Building: "+ building for building in self.critical_path.buildings_to_exclude) for item in multiworld.precollected_items[self.player]: if item.name in self.item_data \ - and self.item_data[item.name].category.isdisjoint(self.non_unique_item_categories) \ + and not (self.item_data[item.name].category & self.non_unique_item_categories) \ and item.name not in options.start_inventory_from_pool: excluded_items.add(item.name) @@ -854,37 +917,30 @@ class Items: def build_item_pool(self, random: Random, multiworld: MultiWorld, - options: SatisfactoryOptions, number_of_locations: int) -> List[Item]: - excluded_from_pool: Set[str] = self.get_excluded_items(multiworld, options) \ + options: SatisfactoryOptions, number_of_locations: int) -> list[Item]: + excluded_from_pool: set[str] = self.get_excluded_items(multiworld, options) \ .union(self.logic.implicitly_unlocked_recipes.keys()) - pool: List[Item] = [] + pool: list[Item] = [] for name, data in self.item_data.items(): - if name == "Building: Blueprint Designer": - halp = 10 - if data.count > 0 \ - and not data.category.isdisjoint(self.pool_item_categories) \ + and data.category & self.pool_item_categories \ and name not in excluded_from_pool: for _ in range(data.count): item = self.create_item(self, name, self.player) - pool.append(item) + if item.classification != C.filler: + pool.append(item) - for _ in range(number_of_locations - len(pool)): - item = self.create_item(self, self.get_filler_item_name(random, options), self.player) + filler_pool_size: int = number_of_locations - len(pool) + if (filler_pool_size < 0): + raise Exception(f"Location pool starved, trying to add {len(pool)} items to {number_of_locations} locations") + + filtered_filler_items = tuple(item for item in self.filler_items if item not in excluded_from_pool) + + for _ in range(filler_pool_size): + filler_item_name = self.get_filler_item_name(filtered_filler_items, random, options) + item = self.create_item(self, filler_item_name, self.player) pool.append(item) return pool - - - def write_progression_chain(self, multiworld: MultiWorld, spoiler_handle: TextIO): - if self.precalculated_progression_recipes: - player_name = f'{multiworld.get_player_name(self.player)}: ' if multiworld.players > 1 else '' - spoiler_handle.write('\n\nSelected Satisfactory Recipes:\n\n') - spoiler_handle.write('\n'.join( - f"{player_name}{part} -> {recipe.name}" - for part, recipes_per_part in self.logic.recipes.items() - for recipe in recipes_per_part - if recipe.name in self.precalculated_progression_recipes_names - )) diff --git a/worlds/satisfactory/Locations.py b/worlds/satisfactory/Locations.py index f0776968e1..68543b054f 100644 --- a/worlds/satisfactory/Locations.py +++ b/worlds/satisfactory/Locations.py @@ -1,13 +1,15 @@ -from typing import List, Optional, Callable, Tuple, Dict, Iterable, ClassVar +from typing import ClassVar, Optional +from collections.abc import Iterable, Callable +from math import ceil, floor from BaseClasses import CollectionState from .GameLogic import GameLogic, Recipe, Building, PowerInfrastructureLevel, DropPodData from .StateLogic import StateLogic, EventId, part_event_prefix, building_event_prefix from .Items import Items from .Options import SatisfactoryOptions -from math import ceil, floor - +from .CriticalPathCalculator import CriticalPathCalculator class LocationData(): + __slots__ = ("region", "name", "event_name", "code", "non_progression", "rule") region: str name: str event_name: str @@ -27,42 +29,27 @@ class LocationData(): class Part(LocationData): @staticmethod - def get_parts(state_logic: StateLogic, recipes: Tuple[Recipe, ...], name: str, items: Items) -> List[LocationData]: - recipes_per_region: Dict[str, List[Recipe]] = {} + def get_parts(state_logic: StateLogic, recipes: tuple[Recipe, ...], name: str, + final_elevator_tier: int) -> list[LocationData]: + recipes_per_region: dict[str, list[Recipe]] = {} for recipe in recipes: + if recipe.minimal_tier > final_elevator_tier: + continue + recipes_per_region.setdefault(recipe.building or "Overworld", []).append(recipe) - return [Part(state_logic, region, recipes_for_region, name, items) + return [Part(state_logic, region, recipes_for_region, name) for region, recipes_for_region in recipes_per_region.items()] - def __init__(self, state_logic: StateLogic, region: str, recipes: Iterable[Recipe], name: str, items: Items): - super().__init__(region, part_event_prefix + name + region, EventId, part_event_prefix + name, - rule = self.can_produce_any_recipe_for_part(state_logic, recipes, name, items)) + def __init__(self, state_logic: StateLogic, region: str, recipes: Iterable[Recipe], name: str): + super().__init__(region, part_event_prefix + name + " in " + region, EventId, part_event_prefix + name, + rule = self.can_produce_any_recipe_for_part(state_logic, recipes)) - def can_produce_any_recipe_for_part(self, state_logic: StateLogic, recipes: Iterable[Recipe], - name: str, items: Items) -> Callable[[CollectionState], bool]: + def can_produce_any_recipe_for_part(self, state_logic: StateLogic, recipes: Iterable[Recipe]) \ + -> Callable[[CollectionState], bool]: def can_build_by_any_recipe(state: CollectionState) -> bool: - if name == "Steel Ingot": - debug = True - - if items.precalculated_progression_recipes and name in items.precalculated_progression_recipes: - can_produce: bool = state_logic.can_produce_specific_recipe_for_part( - state, items.precalculated_progression_recipes[name]) - - can_produce_anyway: bool - if can_produce: - return can_produce - else: - can_produce_anyway = \ - any(state_logic.can_produce_specific_recipe_for_part(state, recipe) for recipe in recipes) - - if can_produce_anyway: - debug = True - - return False # can_produce_anyway - else: - return any(state_logic.can_produce_specific_recipe_for_part(state, recipe) for recipe in recipes) + return any(state_logic.can_produce_specific_recipe_for_part(state, recipe) for recipe in recipes) return can_build_by_any_recipe @@ -76,10 +63,7 @@ class EventBuilding(LocationData): ) -> Callable[[CollectionState], bool]: def can_build(state: CollectionState) -> bool: - if building.name == "Building: Foundry": - debug = True - - return state_logic.has_recipe(state, building) \ + return (building.implicitly_unlocked or state_logic.has_recipe(state, building)) \ and state_logic.can_power(state, building.power_requirement) \ and state_logic.can_produce_all_allowing_handcrafting(state, game_logic, building.inputs) @@ -132,16 +116,16 @@ class ShopSlot(LocationData): if not state_logic or cost < 20: return True elif (cost >= 20 and cost < 50): - return state_logic.is_game_phase(state, 1) + return state_logic.is_elevator_tier(state, 1) elif (cost >= 50 and cost < 100): - return state_logic.is_game_phase(state, 2) + return state_logic.is_elevator_tier(state, 2) else: - return state_logic.is_game_phase(state, 3) + return state_logic.is_elevator_tier(state, 3) return can_purchase -class DropPod(LocationData): +class HardDrive(LocationData): def __init__(self, data: DropPodData, state_logic: Optional[StateLogic], locationId: int, tier: int, can_hold_progression: bool): @@ -149,12 +133,6 @@ class DropPod(LocationData): # we currently do not know how many hdd require gas or radioactive protection # coordinates are for us to reference them, there is no real link between coordinate and check def get_region(gassed: Optional[bool], radioactive: Optional[bool]) -> str: - #if radioactive: - # return "Radioactive Area" - #elif gassed: - # return "Gas Area" - #else: - # return "Overworld" return f"Hub Tier {tier}" def get_rule(unlocked_by: Optional[str], power_needed: int) -> Callable[[CollectionState], bool]: @@ -177,6 +155,7 @@ class Locations(): options: Optional[SatisfactoryOptions] state_logic: Optional[StateLogic] items: Optional[Items] + critical_path: Optional[CriticalPathCalculator] hub_location_start: ClassVar[int] = 1338000 max_tiers: ClassVar[int] = 10 @@ -186,14 +165,17 @@ class Locations(): drop_pod_location_id_end: ClassVar[int] = 1338699 def __init__(self, game_logic: Optional[GameLogic] = None, options: Optional[SatisfactoryOptions] = None, - state_logic: Optional[StateLogic] = None, items: Optional[Items] = None): + state_logic: Optional[StateLogic] = None, items: Optional[Items] = None, + critical_path: Optional[CriticalPathCalculator] = None): self.game_logic = game_logic self.options = options self.state_logic = state_logic self.items = items + self.critical_path = critical_path - def get_base_location_table(self) -> List[LocationData]: - return [ + + def get_base_location_table(self, max_tier: int) -> list[LocationData]: + all_locations = [ MamSlot("Alien Organisms", "Inflated Pocket Dimension", 1338500), MamSlot("Alien Organisms", "Hostile Organism Detection", 1338501), MamSlot("Alien Organisms", "Expanded Toolbelt", 1338502), @@ -262,15 +244,15 @@ class Locations(): MamSlot("Sulfur", "Explosive Rebar", 1338565), MamSlot("Sulfur", "Cluster Nobelisk", 1338566), MamSlot("Sulfur", "Experimental Power Generation", 1338567), - MamSlot("Sulfur", "Turbo Rifle Ammo", 1338568), + # 1338568 Turbo Rifle Ammo MamSlot("Sulfur", "Turbo Fuel", 1338569), MamSlot("Sulfur", "Expanded Toolbelt", 1338570), - MamSlot("Sulfur", "Nuclear Deterrent Development", 1338571), + # 1338571 Nuclear Deterrent Development # 1.0 - MamSlot("Power Slugs", "Synthetic Power Shards", 1338572), - MamSlot("Sulfur", "Rocket Fuel", 1338573), - MamSlot("Sulfur", "Ionized Fuel", 1338574), + # 1338572 Synthetic Power Shards + # 1338573 Rocket Fuel + # 1338574 Ionized Fuel MamSlot("Alien Technology", "SAM Analysis", 1338575), MamSlot("Alien Technology", "SAM Reanimation", 1338576), MamSlot("Alien Technology", "SAM Fluctuator", 1338577), @@ -289,7 +271,7 @@ class Locations(): MamSlot("Alien Technology", "Alien Energy Harvesting", 1338590), MamSlot("Alien Technology", "Production Amplifier", 1338591), MamSlot("Alien Technology", "Power Augmenter", 1338592), - MamSlot("Alien Technology", "Alien Power Matrix", 1338593), + # 1338593 Alien Power Matrix # 1.0 # 1338600 - 1338699 - Harddrives - Harddrives @@ -306,93 +288,135 @@ class Locations(): ShopSlot(self.state_logic, 10, 50, 1338709) ] - def get_locations_for_data_package(self) -> Dict[str, int]: + #TODO: should be based on self.game_logic + if max_tier > 8: + all_locations.append(MamSlot("Power Slugs", "Synthetic Power Shards", 1338572)) + if max_tier > 8: + all_locations.append(MamSlot("Alien Technology", "Alien Power Matrix", 1338593)) + if max_tier > 2: + all_locations.append(MamSlot("Sulfur", "Turbo Rifle Ammo", 1338568)) + if max_tier > 2: + all_locations.append(MamSlot("Sulfur", "Nuclear Deterrent Development", 1338571)) + if max_tier > 4: + all_locations.append(MamSlot("Sulfur", "Rocket Fuel", 1338573)) + if max_tier > 6: + all_locations.append(MamSlot("Sulfur", "Ionized Fuel", 1338574)) + + return all_locations + + def get_locations_for_data_package(self) -> dict[str, int]: "Must include all possible location names and their id's" - location_table = self.get_base_location_table() - location_table.extend(self.get_hub_locations()) - location_table.extend(self.get_drop_pod_locations()) + # 1338000 - 1338499 - Milestones + # 1338500 - 1338599 - Mam + # 1338600 - 1338699 - Harddrives + # 1338700 - 1338709 - Shop + # 1338999 - Upper bound + + location_table = self.get_base_location_table(self.max_tiers) + location_table.extend(self.get_hub_locations(True, self.max_tiers)) + location_table.extend(self.get_hard_drive_locations(True, self.max_tiers, set())) location_table.append(LocationData("Overworld", "UpperBound", 1338999)) return {location.name: location.code for location in location_table} - def get_locations(self) -> List[LocationData]: + def get_locations(self) -> list[LocationData]: "Only return location used in this game based on settings" if not self.game_logic or not self.options or not self.state_logic or not self.items: raise Exception("Locations need to be initialized with logic, options and items before using this method") - location_table = self.get_base_location_table() - location_table.extend(self.get_hub_locations()) - location_table.extend(self.get_drop_pod_locations()) - location_table.extend(self.get_logical_event_locations()) + max_tier_for_game = min(self.options.final_elevator_package * 2, len(self.game_logic.hub_layout)) + + location_table = self.get_base_location_table(max_tier_for_game) + location_table.extend(self.get_hub_locations(False, max_tier_for_game)) + location_table.extend(self.get_hard_drive_locations(False, max_tier_for_game,self.critical_path.required_parts)) + location_table.extend(self.get_logical_event_locations(self.options.final_elevator_package)) return location_table - def get_hub_locations(self) -> List[LocationData]: - location_table: List[LocationData] = [] + def get_hub_locations(self, for_data_package: bool, max_tier: int) -> list[LocationData]: + location_table: list[LocationData] = [] + + number_of_slots_per_milestone_for_game: int + if (for_data_package): + number_of_slots_per_milestone_for_game = self.max_slots + else: + if self.options.final_elevator_package <= 2: + number_of_slots_per_milestone_for_game = 10 + else: + number_of_slots_per_milestone_for_game = self.game_logic.slots_per_milestone hub_location_id = self.hub_location_start - for tier in range(1, self.max_tiers + 1): + for tier in range(1, max_tier + 1): for milestone in range(1, self.max_milestones + 1): - for slot in range(1, self.max_slots + 1): - if not self.game_logic: + for slot in range(1, number_of_slots_per_milestone_for_game + 1): + if for_data_package: location_table.append(HubSlot(tier, milestone, slot, hub_location_id)) else: - if tier <= len(self.game_logic.hub_layout) \ + if tier <= max_tier \ and milestone <= len(self.game_logic.hub_layout[tier - 1]) \ - and slot <= self.game_logic.slots_per_milestone: + and slot <= number_of_slots_per_milestone_for_game: + location_table.append(HubSlot(tier, milestone, slot, hub_location_id)) hub_location_id += 1 return location_table - def get_logical_event_locations(self) -> List[LocationData]: - location_table: List[LocationData] = [] + def get_logical_event_locations(self, final_elevator_tier: int) -> list[LocationData]: + location_table: list[LocationData] = [] # for performance plan is to upfront calculated everything we need # and than create one massive state.has_all for each logical gate (hub tiers, elevator tiers) location_table.extend( ElevatorTier(index, self.state_logic, self.game_logic) - for index, parts in enumerate(self.game_logic.space_elevator_tiers)) + for index, parts in enumerate(self.game_logic.space_elevator_tiers) + if index < self.options.final_elevator_package) location_table.extend( - part + part for part_name, recipes in self.game_logic.recipes.items() - for part in Part.get_parts(self.state_logic, recipes, part_name, self.items)) + if part_name in self.critical_path.required_parts + for part in Part.get_parts(self.state_logic, recipes, part_name, final_elevator_tier)) location_table.extend( EventBuilding(self.game_logic, self.state_logic, name, building) - for name, building in self.game_logic.buildings.items()) + for name, building in self.game_logic.buildings.items() + if name in self.critical_path.required_buildings) location_table.extend( PowerInfrastructure(self.game_logic, self.state_logic, power_level, recipes) - for power_level, recipes in self.game_logic.requirement_per_powerlevel.items()) + for power_level, recipes in self.game_logic.requirement_per_powerlevel.items() + if power_level <= self.critical_path.required_power_level) return location_table - def get_drop_pod_locations(self) -> List[LocationData]: - drop_pod_locations: List[DropPod] = [] + def get_hard_drive_locations(self, for_data_package: bool, max_tier: int, available_parts: set[str]) \ + -> list[LocationData]: + hard_drive_locations: list[HardDrive] = [] - bucket_size: int = 0 - drop_pod_data: List[DropPodData] = [] - - if self.game_logic: - bucket_size = floor( - (self.drop_pod_location_id_end - self.drop_pod_location_id_start) / len(self.game_logic.hub_layout)) - - drop_pod_data = self.game_logic.drop_pods + bucket_size: int + drop_pod_data: list[DropPodData] + if for_data_package: + bucket_size = 0 + drop_pod_data = [] + else: + bucket_size = floor((self.drop_pod_location_id_end - self.drop_pod_location_id_start) / max_tier) + drop_pod_data: list[DropPodData] = self.game_logic.drop_pods # sort, easily obtainable first, should be deterministic drop_pod_data.sort(key = lambda data: ("!" if data.item == None else data.item) + str(data.x - data.z)) for location_id in range(self.drop_pod_location_id_start, self.drop_pod_location_id_end + 1): - if not self.game_logic or not self.state_logic or not self.options: - drop_pod_locations.append(DropPod(DropPodData(0, 0, 0, None, 0), None, location_id, 1, False)) + if for_data_package: + hard_drive_locations.append(HardDrive(DropPodData(0, 0, 0, None, 0), None, location_id, 1, False)) else: location_id_normalized: int = location_id - self.drop_pod_location_id_start + data: DropPodData = drop_pod_data[location_id_normalized] can_hold_progression: bool = location_id_normalized < self.options.hard_drive_progression_limit.value - tier = min(ceil((location_id_normalized + 1) / bucket_size), len(self.game_logic.hub_layout)) + tier = min(ceil((location_id_normalized + 1) / bucket_size), max_tier) - drop_pod_locations.append(DropPod(data, self.state_logic, location_id, tier, can_hold_progression)) + if not data.item or data.item in available_parts: + hard_drive_locations.append( + HardDrive(data, self.state_logic, location_id, tier, can_hold_progression)) - return drop_pod_locations \ No newline at end of file + return hard_drive_locations \ No newline at end of file diff --git a/worlds/satisfactory/Options.py b/worlds/satisfactory/Options.py index f9ca8bd72a..ee95e8708a 100644 --- a/worlds/satisfactory/Options.py +++ b/worlds/satisfactory/Options.py @@ -1,8 +1,9 @@ from dataclasses import dataclass -from typing import Dict, List, Any, Tuple, ClassVar, cast +from typing import ClassVar, Any, cast from enum import IntEnum -from Options import PerGameCommonOptions, DeathLink, AssembleOptions, Visibility -from Options import Range, Toggle, OptionSet, StartInventoryPool, NamedRange, Choice +from Options import PerGameCommonOptions, DeathLinkMixin, AssembleOptions, Visibility +from Options import Range, NamedRange, Toggle, DefaultOnToggle, OptionSet, StartInventoryPool, Choice +from schema import Schema, And class Placement(IntEnum): starting_inventory = 0 @@ -10,7 +11,7 @@ class Placement(IntEnum): somewhere = 2 class PlacementLogicMeta(AssembleOptions): - def __new__(mcs, name: str, bases: Tuple[type], attrs: Dict[Any, Any]) -> "PlacementLogicMeta": + def __new__(mcs, name: str, bases: tuple[type], attrs: dict[Any, Any]) -> "PlacementLogicMeta": if "default" in attrs and isinstance(attrs["default"], Placement): attrs["default"] = int(attrs["default"]) @@ -23,7 +24,7 @@ class PlacementLogic(Choice, metaclass=PlacementLogicMeta): option_somewhere = Placement.somewhere class ChoiceMapMeta(AssembleOptions): - def __new__(mcs, name: str, bases: Tuple[type], attrs: Dict[Any, Any]) -> "ChoiceMapMeta": + def __new__(mcs, name: str, bases: tuple[type], attrs: dict[Any, Any]) -> "ChoiceMapMeta": if "choices" in attrs: for index, choice in enumerate(attrs["choices"].keys()): option_name = "option_" + choice.replace(' ', '_') @@ -34,36 +35,36 @@ class ChoiceMapMeta(AssembleOptions): class ChoiceMap(Choice, metaclass=ChoiceMapMeta): # TODO `default` doesn't do anything, default is always the first `choices` value. if uncommented it messes up the template file generation (caps mismatch) - choices: ClassVar[Dict[str, List[str]]] + choices: ClassVar[dict[str, list[str]]] - def get_selected_list(self) -> List[str]: + def get_selected_list(self) -> list[str]: for index, choice in enumerate(self.choices.keys()): if index == self.value: return self.choices[choice] - class ElevatorTier(NamedRange): """ - Ship these Space Elevator packages to finish. - Does nothing if *Space Elevator Tier* goal is not enabled. + Put these Shipments to Space Elevator packages in logic. + if your goal selection contains *Space Elevator Tier* then the goal will be to complete these shipments. """ display_name = "Goal: Space Elevator shipment" default = 2 range_start = 1 - range_end = 4 + range_end = 5 special_range_names = { "one package (tiers 1-2)": 1, "two packages (tiers 1-4)": 2, "three packages (tiers 1-6)": 3, - "four packages (tiers 7-8)": 4, - "five packages (tier 9)": 5, + "four packages (tiers 1-8)": 4, + "five packages (tiers 1-9)": 5, } -class ResourceSinkPoints(NamedRange): +class ResourceSinkPointsTotal(NamedRange): """ + Does nothing if *AWESOME Sink Points (total)* goal is not enabled. + Sink an amount of items totalling this amount of points to finish. This setting is a *point count*, not a *coupon* count! - Does nothing if *AWESOME Sink Points* goal is not enabled. In the base game, it takes 347 coupons to unlock every non-repeatable purchase, or 1895 coupons to purchase every non-producible item. @@ -72,7 +73,7 @@ class ResourceSinkPoints(NamedRange): If you have *Free Samples* enabled, consider setting this higher so that you can't reach the goal just by sinking your Free Samples. """ # Coupon data for above comment from https://satisfactory.wiki.gg/wiki/AWESOME_Shop - display_name = "Goal: AWESOME Sink points" + display_name = "Goal: AWESOME Sink points total" default = 2166000 range_start = 2166000 range_end = 18436379500 @@ -99,6 +100,37 @@ class ResourceSinkPoints(NamedRange): "1000 coupons (~18b points)": 18436379500 } +class ResourceSinkPointsPerMinute(NamedRange): + """ + Does nothing if *AWESOME Sink Points (per minute)* goal is not enabled. + + Continuously Sink an amount of items to maintain a sink points per minute of this amount of points for 10 minutes to finish. + This setting is in *points per minute* on the orange track so no DNA Capsules! + + Use the **TFIT - Ficsit Information Tool** mod or the Satisfactory wiki to find out how many points items are worth. + """ + # Coupon data for above comment from https://satisfactory.wiki.gg/wiki/AWESOME_Shop + display_name = "Goal: AWESOME Sink points per minute" + default = 50000 + range_start = 1000 + range_end = 10000000 + special_range_names = { + "~500 screw/min": 1000, + "~100 reinforced iron plate/min": 12000, + "~100 stator/min": 24000, + "~100 modular frame/min": 40000, + "~100 smart plating/min": 50000, + "~20 crystal oscillator/min": 60000, + "~50 motor/min": 76000, + "~10 heavy modular frame/min": 100000, + "~10 radio control unit": 300000, + "~10 heavy modular frame/min": 625000, + "~10 supercomputer/min": 1000000, + "~10 pressure conversion cube/min": 2500000, + "~10 nuclear pasta/min": 5000000, + "~4 ballistic warp drive/min": 10000000, + } + class HardDriveProgressionLimit(Range): """ How many Hard Drives can contain progression items. @@ -242,7 +274,7 @@ class TrapSelectionOverride(OptionSet): valid_keys = _trap_types default = {} -class EnergyLink(Toggle): +class EnergyLink(DefaultOnToggle): """ Allow transferring energy to and from other worlds using the Power Storage building. No energy is lost in the transfer on Satisfactory's side, but other worlds may have other settings. @@ -334,6 +366,31 @@ class StartingInventoryPreset(ChoiceMap): } # default = "Archipelago" # TODO `default` doesn't do anything, default is always the first `choices` value. if uncommented it messes up the template file generation (caps mismatch) +class ExplorationCollectableCount(Range): + """ + Does nothing if *Exploration Collectables* goal is not enabled. + + Collect this amount of Mercer Spheres and Summer Sloops each to finish. + """ + display_name = "Goal: Exploration Collectables" + default = 20 + range_start = 20 + range_end = 100 + +class MilestoneCostMultiplier(Range): + """ + Multiplies the amount of resources needed to unlock a milestone by this factor + + The value is in percentage: + 50 = half cost + 100 = normal milestone cost + 200 = double the cost + """ + display_name = "Milestone cost multiplier %" + default = 100 + range_start = 1 + range_end = 500 + class GoalSelection(OptionSet): """ What will be your goal(s)? @@ -342,11 +399,14 @@ class GoalSelection(OptionSet): display_name = "Select your Goals" valid_keys = { "Space Elevator Tier", - "AWESOME Sink Points", - # "Exploration", - # "FICSMAS Tree", + "AWESOME Sink Points (total)", + "AWESOME Sink Points (per minute)", + "Exploration Collectables", + # "Erect a FICSMAS Tree", } default = {"Space Elevator Tier"} + schema = Schema(And(set, len), + error = "yaml does not specify a goal, the Satisfactory option `goal_selection` is empty") class GoalRequirement(Choice): """ @@ -366,11 +426,13 @@ class ExperimentalGeneration(Toggle): visibility = Visibility.none @dataclass -class SatisfactoryOptions(PerGameCommonOptions): +class SatisfactoryOptions(PerGameCommonOptions, DeathLinkMixin): goal_selection: GoalSelection goal_requirement: GoalRequirement final_elevator_package: ElevatorTier - final_awesome_sink_points: ResourceSinkPoints + final_awesome_sink_points_total: ResourceSinkPointsTotal + final_awesome_sink_points_per_minute: ResourceSinkPointsPerMinute + final_exploration_collectables_amount: ExplorationCollectableCount hard_drive_progression_limit: HardDriveProgressionLimit free_sample_equipment: FreeSampleEquipment free_sample_buildings: FreeSampleBuildings @@ -381,10 +443,10 @@ class SatisfactoryOptions(PerGameCommonOptions): awesome_logic_placement: AwesomeLogic energy_link_logic_placement: EnergyLinkLogic splitter_placement: SplitterLogic + milestone_cost_multiplier: MilestoneCostMultiplier trap_chance: TrapChance trap_selection_preset: TrapSelectionPreset trap_selection_override: TrapSelectionOverride - death_link: DeathLink energy_link: EnergyLink start_inventory_from_pool: StartInventoryPool experimental_generation: ExperimentalGeneration diff --git a/worlds/satisfactory/Regions.py b/worlds/satisfactory/Regions.py index f39d951e47..9909942013 100644 --- a/worlds/satisfactory/Regions.py +++ b/worlds/satisfactory/Regions.py @@ -1,9 +1,11 @@ -from typing import List, Set, Dict, Tuple, Optional, Callable +from typing import Optional +from collections.abc import Callable from BaseClasses import MultiWorld, Region, Location, Item, CollectionState from .Locations import LocationData from .GameLogic import GameLogic, PowerInfrastructureLevel from .StateLogic import StateLogic from .Options import SatisfactoryOptions, Placement +from .CriticalPathCalculator import CriticalPathCalculator class SatisfactoryLocation(Location): game: str = "Satisfactory" @@ -29,48 +31,50 @@ class SatisfactoryLocation(Location): return not item.advancement -def create_regions_and_return_locations(world: MultiWorld, options: SatisfactoryOptions, player: int, - game_logic: GameLogic, state_logic: StateLogic, locations: List[LocationData]): +def create_regions_and_return_locations(world: MultiWorld, options: SatisfactoryOptions, player: int, + game_logic: GameLogic, state_logic: StateLogic, critical_path: CriticalPathCalculator, + locations: list[LocationData]): - region_names: List[str] = [ - "Menu", + region_names: list[str] = [ "Overworld", - "Gas Area", - "Radioactive Area", "Mam", "AWESOME Shop" ] for hub_tier, milestones_per_hub_tier in enumerate(game_logic.hub_layout, 1): + if (hub_tier > (options.final_elevator_package * 2)): + break + region_names.append(f"Hub Tier {hub_tier}") for minestone, _ in enumerate(milestones_per_hub_tier, 1): region_names.append(f"Hub {hub_tier}-{minestone}") for building_name, building in game_logic.buildings.items(): - if building.can_produce: + if building.can_produce and building_name in critical_path.required_buildings: region_names.append(building_name) for tree_name, tree in game_logic.man_trees.items(): region_names.append(tree_name) for node in tree.nodes: - region_names.append(f"{tree_name}: {node.name}") + if node.minimal_tier <= options.final_elevator_package: + region_names.append(f"{tree_name}: {node.name}") - locations_per_region: Dict[str, LocationData] = get_locations_per_region(locations) - regions: Dict[str, Region] = create_regions(world, player, locations_per_region, region_names) + locations_per_region: dict[str, LocationData] = get_locations_per_region(locations) + regions: dict[str, Region] = create_regions(world, player, locations_per_region, region_names) if __debug__: throwIfAnyLocationIsNotAssignedToARegion(regions, locations_per_region.keys()) world.regions += regions.values() - super_early_game_buildings: List[str] = [ + super_early_game_buildings: list[str] = [ "Foundation", "Walls Orange" ] - early_game_buildings: List[str] = [ + early_game_buildings: list[str] = [ PowerInfrastructureLevel.Automated.to_name() ] @@ -85,39 +89,46 @@ def create_regions_and_return_locations(world: MultiWorld, options: Satisfactory super_early_game_buildings.append("Conveyor Splitter") super_early_game_buildings.append("Conveyor Merger") - connect(regions, "Menu", "Overworld") + if options.final_elevator_package == 1: + super_early_game_buildings.extend(early_game_buildings) + connect(regions, "Overworld", "Hub Tier 1") connect(regions, "Hub Tier 1", "Hub Tier 2", lambda state: state_logic.can_build_all(state, super_early_game_buildings)) - connect(regions, "Hub Tier 2", "Hub Tier 3", lambda state: state.has("Elevator Tier 1", player) + + if options.final_elevator_package >= 2: + connect(regions, "Hub Tier 2", "Hub Tier 3", lambda state: state.has("Elevator Tier 1", player) and state_logic.can_build_all(state, early_game_buildings)) - connect(regions, "Hub Tier 3", "Hub Tier 4") - connect(regions, "Hub Tier 4", "Hub Tier 5", lambda state: state.has("Elevator Tier 2", player)) - connect(regions, "Hub Tier 5", "Hub Tier 6") - connect(regions, "Hub Tier 6", "Hub Tier 7", lambda state: state.has("Elevator Tier 3", player)) - connect(regions, "Hub Tier 7", "Hub Tier 8") - connect(regions, "Hub Tier 8", "Hub Tier 9", lambda state: state.has("Elevator Tier 4", player)) - connect(regions, "Overworld", "Gas Area", lambda state: - state_logic.can_produce_all(state, ("Gas Mask", "Gas Filter"))) - connect(regions, "Overworld", "Radioactive Area", lambda state: - state_logic.can_produce_all(state, ("Hazmat Suit", "Iodine Infused Filter"))) + connect(regions, "Hub Tier 3", "Hub Tier 4") + if options.final_elevator_package >= 3: + connect(regions, "Hub Tier 4", "Hub Tier 5", lambda state: state.has("Elevator Tier 2", player)) + connect(regions, "Hub Tier 5", "Hub Tier 6") + if options.final_elevator_package >= 4: + connect(regions, "Hub Tier 6", "Hub Tier 7", lambda state: state.has("Elevator Tier 3", player)) + connect(regions, "Hub Tier 7", "Hub Tier 8") + if options.final_elevator_package >= 5: + connect(regions, "Hub Tier 8", "Hub Tier 9", lambda state: state.has("Elevator Tier 4", player)) + connect(regions, "Overworld", "Mam", lambda state: state_logic.can_build(state, "MAM")) connect(regions, "Overworld", "AWESOME Shop", lambda state: state_logic.can_build_all(state, ("AWESOME Shop", "AWESOME Sink"))) - def can_produce_all_allowing_handcrafting(parts: Tuple[str, ...]) -> Callable[[CollectionState], bool]: + def can_produce_all_allowing_handcrafting(parts: tuple[str, ...]) -> Callable[[CollectionState], bool]: def logic_rule(state: CollectionState): return state_logic.can_produce_all_allowing_handcrafting(state, game_logic, parts) return logic_rule for hub_tier, milestones_per_hub_tier in enumerate(game_logic.hub_layout, 1): + if (hub_tier > (options.final_elevator_package * 2)): + break + for minestone, parts_per_milestone in enumerate(milestones_per_hub_tier, 1): connect(regions, f"Hub Tier {hub_tier}", f"Hub {hub_tier}-{minestone}", can_produce_all_allowing_handcrafting(parts_per_milestone.keys())) for building_name, building in game_logic.buildings.items(): - if building.can_produce: + if building.can_produce and building_name in critical_path.required_buildings: connect(regions, "Overworld", building_name, lambda state, building_name=building_name: state_logic.can_build(state, building_name)) @@ -125,16 +136,20 @@ def create_regions_and_return_locations(world: MultiWorld, options: Satisfactory connect(regions, "Mam", tree_name) for node in tree.nodes: + if node.minimal_tier > options.final_elevator_package: + continue + if not node.depends_on: connect(regions, tree_name, f"{tree_name}: {node.name}", lambda state, parts=node.unlock_cost.keys(): state_logic.can_produce_all(state, parts)) else: for parent in node.depends_on: - connect(regions, f"{tree_name}: {parent}", f"{tree_name}: {node.name}", - lambda state, parts=node.unlock_cost.keys(): state_logic.can_produce_all(state, parts)) + if f"{tree_name}: {parent}" in region_names: + connect(regions, f"{tree_name}: {parent}", f"{tree_name}: {node.name}", + lambda state, parts=node.unlock_cost.keys(): state_logic.can_produce_all(state, parts)) -def throwIfAnyLocationIsNotAssignedToARegion(regions: Dict[str, Region], regionNames: Set[str]): +def throwIfAnyLocationIsNotAssignedToARegion(regions: dict[str, Region], regionNames: set[str]): existingRegions = set() for region in regions.keys(): @@ -145,7 +160,7 @@ def throwIfAnyLocationIsNotAssignedToARegion(regions: Dict[str, Region], regionN def create_region(world: MultiWorld, player: int, - locations_per_region: Dict[str, List[LocationData]], name: str) -> Region: + locations_per_region: dict[str, list[LocationData]], name: str) -> Region: region = Region(name, player, world) @@ -157,10 +172,10 @@ def create_region(world: MultiWorld, player: int, return region -def create_regions(world: MultiWorld, player: int, locations_per_region: Dict[str, List[LocationData]], - region_names: List[str]) -> Dict[str, Region]: +def create_regions(world: MultiWorld, player: int, locations_per_region: dict[str, list[LocationData]], + region_names: list[str]) -> dict[str, Region]: - regions: Dict[str, Region] = {} + regions: dict[str, Region] = {} for name in region_names: regions[name] = create_region(world, player, locations_per_region, name) @@ -168,7 +183,7 @@ def create_regions(world: MultiWorld, player: int, locations_per_region: Dict[st return regions -def connect(regions: Dict[str, Region], source: str, target: str, +def connect(regions: dict[str, Region], source: str, target: str, rule: Optional[Callable[[CollectionState], bool]] = None): sourceRegion = regions[source] @@ -177,8 +192,8 @@ def connect(regions: Dict[str, Region], source: str, target: str, sourceRegion.connect(targetRegion, rule=rule) -def get_locations_per_region(locations: List[LocationData]) -> Dict[str, List[LocationData]]: - per_region: Dict[str, List[LocationData]] = {} +def get_locations_per_region(locations: list[LocationData]) -> dict[str, list[LocationData]]: + per_region: dict[str, list[LocationData]] = {} for location in locations: per_region.setdefault(location.region, []).append(location) diff --git a/worlds/satisfactory/StateLogic.py b/worlds/satisfactory/StateLogic.py index d0b1dc3aea..ffe7bf5135 100644 --- a/worlds/satisfactory/StateLogic.py +++ b/worlds/satisfactory/StateLogic.py @@ -1,4 +1,5 @@ -from typing import Tuple, List, Optional, Set, Iterable +from typing import Optional +from collections.abc import Iterable from BaseClasses import CollectionState from .GameLogic import GameLogic, Recipe, PowerInfrastructureLevel from .Options import SatisfactoryOptions @@ -11,7 +12,7 @@ building_event_prefix = "Can Build: " class StateLogic: player: int options: SatisfactoryOptions - initial_unlocked_items: Set[str] + initial_unlocked_items: set[str] def __init__(self, player: int, options: SatisfactoryOptions): self.player = player @@ -38,14 +39,11 @@ class StateLogic: return power_level is None or state.has(building_event_prefix + power_level.to_name(), self.player) def can_produce_all(self, state: CollectionState, parts: Optional[Iterable[str]]) -> bool: - if parts and "SAM" in parts: - debug = "Now" - - return parts is None or \ + return parts is None or \ state.has_all(map(self.to_part_event, parts), self.player) def can_produce_all_allowing_handcrafting(self, state: CollectionState, logic: GameLogic, - parts: Optional[Tuple[str, ...]]) -> bool: + parts: Optional[tuple[str, ...]]) -> bool: def can_handcraft_part(part: str) -> bool: if self.can_produce(state, part): @@ -53,7 +51,7 @@ class StateLogic: elif part not in logic.handcraftable_recipes: return False - recipes: List[Recipe] = logic.handcraftable_recipes[part] + recipes: list[Recipe] = logic.handcraftable_recipes[part] return any( self.has_recipe(state, recipe) @@ -79,8 +77,10 @@ class StateLogic: and self.can_build(state, recipe.building) \ and self.can_produce_all(state, recipe.inputs) - def is_game_phase(self, state: CollectionState, phase: int) -> bool: - return state.has(f"Elevator Tier {phase}", self.player) + def is_elevator_tier(self, state: CollectionState, phase: int) -> bool: + limited_phase = min(self.options.final_elevator_package, phase) + + return state.has(f"Elevator Tier {limited_phase}", self.player) @staticmethod def to_part_event(part: str) -> str: diff --git a/worlds/satisfactory/Web.py b/worlds/satisfactory/Web.py index 34701976f1..1be0e10f57 100644 --- a/worlds/satisfactory/Web.py +++ b/worlds/satisfactory/Web.py @@ -1,7 +1,6 @@ from BaseClasses import Tutorial from ..AutoWorld import WebWorld - class SatisfactoryWebWorld(WebWorld): theme = "dirt" setup = Tutorial( diff --git a/worlds/satisfactory/__init__.py b/worlds/satisfactory/__init__.py index ef9e29b3fb..6effd58f93 100644 --- a/worlds/satisfactory/__init__.py +++ b/worlds/satisfactory/__init__.py @@ -1,11 +1,12 @@ -from typing import Dict, List, Set, TextIO, ClassVar, Tuple -from BaseClasses import Item, MultiWorld, ItemClassification, CollectionState +from typing import TextIO, ClassVar +from BaseClasses import Item, ItemClassification, CollectionState from .GameLogic import GameLogic from .Items import Items from .Locations import Locations, LocationData from .StateLogic import EventId, StateLogic from .Options import SatisfactoryOptions, Placement from .Regions import SatisfactoryLocation, create_regions_and_return_locations +from .CriticalPathCalculator import CriticalPathCalculator from .Web import SatisfactoryWebWorld from ..AutoWorld import World @@ -20,8 +21,8 @@ class SatisfactoryWorld(World): options_dataclass = SatisfactoryOptions options: SatisfactoryOptions topology_present = False - data_version = 0 web = SatisfactoryWebWorld() + origin_region_name = "Overworld" item_name_to_id = Items.item_names_and_ids location_name_to_id = Locations().get_locations_for_data_package() @@ -30,19 +31,12 @@ class SatisfactoryWorld(World): game_logic: ClassVar[GameLogic] = GameLogic() state_logic: StateLogic items: Items - - def __init__(self, multiworld: "MultiWorld", player: int): - super().__init__(multiworld, player) - self.items = None - + critical_path: CriticalPathCalculator def generate_early(self) -> None: self.state_logic = StateLogic(self.player, self.options) - self.items = Items(self.player, self.game_logic, self.random, self.options) - - if not self.options.goal_selection.value: - raise Exception("""Satisfactory: player {} needs to choose a goal, the option goal_selection is empty""" - .format(self.multiworld.player_name[self.player])) + self.critical_path = CriticalPathCalculator(self.game_logic, self.random, self.options) + self.items = Items(self.player, self.game_logic, self.random, self.options, self.critical_path) if self.options.mam_logic_placement.value == Placement.starting_inventory: self.push_precollected("Building: MAM") @@ -58,16 +52,17 @@ class SatisfactoryWorld(World): if not self.options.trap_selection_override.value: self.options.trap_selection_override.value = self.options.trap_selection_preset.get_selected_list() - starting_inventory: List[str] = self.options.starting_inventory_preset.get_selected_list() + starting_inventory: list[str] = self.options.starting_inventory_preset.get_selected_list() for item_name in starting_inventory: self.push_precollected(item_name) def create_regions(self) -> None: - locations: List[LocationData] = \ - Locations(self.game_logic, self.options, self.state_logic, self.items).get_locations() + locations: list[LocationData] = \ + Locations(self.game_logic, self.options, self.state_logic, self.items, self.critical_path).get_locations() create_regions_and_return_locations( - self.multiworld, self.options, self.player, self.game_logic, self.state_logic, locations) + self.multiworld, self.options, self.player, self.game_logic, self.state_logic, self.critical_path, + locations) def create_items(self) -> None: @@ -79,21 +74,16 @@ class SatisfactoryWorld(World): def set_rules(self) -> None: - resource_sink_goal: bool = "AWESOME Sink Points" in self.options.goal_selection + resource_sink_goal: bool = "AWESOME Sink Points (total)" in self.options.goal_selection \ + or "AWESOME Sink Points (per minute)" in self.options.goal_selection - last_elevator_tier: int = \ - len(self.game_logic.space_elevator_tiers) if resource_sink_goal \ - else self.options.final_elevator_package.value - - required_parts: Set[str] = set(self.game_logic.space_elevator_tiers[last_elevator_tier - 1].keys()) + required_parts = set(self.game_logic.space_elevator_tiers[self.options.final_elevator_package.value - 1].keys()) if resource_sink_goal: required_parts.union(self.game_logic.buildings["AWESOME Sink"].inputs) - required_parts_tuple: Tuple[str, ...] = tuple(required_parts) - self.multiworld.completion_condition[self.player] = \ - lambda state: self.state_logic.can_produce_all(state, required_parts_tuple) + lambda state: self.state_logic.can_produce_all(state, required_parts) def collect(self, state: CollectionState, item: Item) -> bool: @@ -110,8 +100,8 @@ class SatisfactoryWorld(World): return change - def fill_slot_data(self) -> Dict[str, object]: - slot_hub_layout: List[List[Dict[str, int]]] = [] + def fill_slot_data(self) -> dict[str, object]: + slot_hub_layout: list[list[dict[str, int]]] = [] for tier, milestones in enumerate(self.game_logic.hub_layout, 1): slot_hub_layout.append([]) @@ -120,7 +110,8 @@ class SatisfactoryWorld(World): for part, amount in parts.items(): # ItemIDs of bundles are shared with their component item bundled_name = f"Bundle: {part}" - slot_hub_layout[tier - 1][milestone - 1][self.item_name_to_id[bundled_name]] = amount + multiplied_amount = max(amount * (self.options.milestone_cost_multiplier / 100), 1) + slot_hub_layout[tier - 1][milestone - 1][self.item_name_to_id[bundled_name]] = multiplied_amount return { "Data": { @@ -130,8 +121,8 @@ class SatisfactoryWorld(World): "GoalSelection": self.options.goal_selection.value, "GoalRequirement": self.options.goal_requirement.value, "FinalElevatorTier": self.options.final_elevator_package.value, - "FinalResourceSinkPoints": self.options.final_awesome_sink_points.value, - "EnableHardDriveGacha": True if self.options.hard_drive_progression_limit else False, + "FinalResourceSinkPointsTotal": self.options.final_awesome_sink_points_total.value, + "FinalResourceSinkPointsPerMinute": self.options.final_awesome_sink_points_per_minute.value, "FreeSampleEquipment": self.options.free_sample_equipment.value, "FreeSampleBuildings": self.options.free_sample_buildings.value, "FreeSampleParts": self.options.free_sample_parts.value, @@ -139,19 +130,20 @@ class SatisfactoryWorld(World): "EnergyLink": bool(self.options.energy_link) } }, + "SlotDataVersion": 1, "DeathLink": bool(self.options.death_link) } - def write_spoiler(self, spoiler_handle: TextIO): - self.items.write_progression_chain(self.multiworld, spoiler_handle) + def write_spoiler(self, spoiler_handle: TextIO) -> None: + pass def get_filler_item_name(self) -> str: - return self.items.get_filler_item_name(self.random, self.options) + return self.items.get_filler_item_name(self.items.filler_items, self.random, self.options) - def setup_events(self): + def setup_events(self) -> None: location: SatisfactoryLocation for location in self.multiworld.get_locations(self.player): if location.address == EventId: