mirror of
https://github.com/ArchipelagoMW/Archipelago.git
synced 2026-03-23 13:43:20 -07:00
Progress commmit incase my pc crashes
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
from random import Random
|
||||
from typing import Set, Tuple
|
||||
from typing import Optional
|
||||
from collections.abc import Iterable
|
||||
from .GameLogic import GameLogic, Recipe
|
||||
from .Options import SatisfactoryOptions
|
||||
from .Options import SatisfactoryOptions
|
||||
@@ -8,17 +9,18 @@ class CriticalPathCalculator:
|
||||
logic: GameLogic
|
||||
random: Random
|
||||
|
||||
potential_required_parts: Set[str]
|
||||
potential_required_buildings: Set[str]
|
||||
potential_required_parts: set[str]
|
||||
potential_required_buildings: set[str]
|
||||
potential_required_belt_speed: int
|
||||
potential_required_pipes: bool
|
||||
potential_required_radioactive: bool
|
||||
potential_required_power: int
|
||||
potential_required_recipes_names: Set[str]
|
||||
potential_required_recipes_names: set[str]
|
||||
|
||||
def __init__(self, logic: GameLogic, random: Random, options: SatisfactoryOptions):
|
||||
self.logic = logic
|
||||
self.random = random
|
||||
self.options = options
|
||||
|
||||
self.potential_required_parts = set()
|
||||
self.potential_required_buildings = set()
|
||||
@@ -27,27 +29,59 @@ class CriticalPathCalculator:
|
||||
self.potential_required_radioactive = False
|
||||
self.potential_required_power: int = 1
|
||||
|
||||
self.select_minimal_required_parts_for(
|
||||
tuple(self.logic.space_elevator_tiers[options.final_elevator_package - 1].keys())
|
||||
)
|
||||
for i in range(self.potential_required_belt_speed, 1):
|
||||
self.select_minimal_required_parts_for(self.logic.buildings[f"Conveyor Mk.{i}"].inputs)
|
||||
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:
|
||||
# Bullet Guidance System - Rifle Ammo
|
||||
# Stun Rebar - Iron Rebar
|
||||
# Radar Technology - Heavy Modular Frame
|
||||
# Turbo Rifle Ammo - Packaged Turbofuel, Rifle Ammo
|
||||
# Nuclear Deterrent Development - Encased Uranium Cell
|
||||
# Rocket Fuel - Packaged Turbofuel
|
||||
# Ionized Fuel - Ionized Fuel
|
||||
if node.name == "Hostile Organism Detection":
|
||||
Debug = True
|
||||
|
||||
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")
|
||||
|
||||
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(self.logic.buildings["Pipeline Pump Mk.1"].inputs)
|
||||
self.select_minimal_required_parts_for(self.logic.buildings["Pipeline Pump Mk.2"].inputs)
|
||||
self.select_minimal_required_parts_for_building("Pipes Mk.1")
|
||||
self.select_minimal_required_parts_for_building("Pipeline Pump Mk.1")
|
||||
if self.potential_required_radioactive:
|
||||
self.select_minimal_required_parts_for(self.logic.recipes["Hazmat Suit"][0].inputs)
|
||||
self.select_minimal_required_parts_for(self.logic.recipes["Iodine Infused Filter"][0].inputs)
|
||||
for i in range(self.potential_required_belt_speed, 1):
|
||||
for i in range(1, self.potential_required_power + 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.potential_required_buildings.add(power_recipe.building)
|
||||
|
||||
self.select_minimal_required_parts_for_building(power_recipe.building)
|
||||
|
||||
self.potential_required_recipes_names = set(
|
||||
recipe.name
|
||||
for part in self.potential_required_parts
|
||||
for recipe in self.logic.recipes[part]
|
||||
if recipe.minimal_tier <= self.options.final_elevator_package
|
||||
)
|
||||
self.potential_required_recipes_names.update(
|
||||
"Building: "+ building
|
||||
@@ -56,24 +90,53 @@ class CriticalPathCalculator:
|
||||
|
||||
debug = True
|
||||
|
||||
def select_minimal_required_parts_for_building(self, building: str) -> None:
|
||||
self.select_minimal_required_parts_for(self.logic.buildings[building].inputs)
|
||||
self.potential_required_buildings.add(building)
|
||||
|
||||
def select_minimal_required_parts_for(self, parts: Tuple[str]) -> None:
|
||||
if parts:
|
||||
for part in parts:
|
||||
if part in self.potential_required_parts:
|
||||
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.potential_required_parts:
|
||||
continue
|
||||
|
||||
if part == "Radio Control Unit":
|
||||
Debug = True
|
||||
|
||||
self.potential_required_parts.add(part)
|
||||
|
||||
for recipe in self.logic.recipes[part]:
|
||||
if part == "Fuel":
|
||||
Debug = True
|
||||
|
||||
if recipe.minimal_tier > self.options.final_elevator_package:
|
||||
continue
|
||||
|
||||
self.potential_required_parts.add(part)
|
||||
if recipe.minimal_belt_speed == 5:
|
||||
Debug = True
|
||||
|
||||
for recipe in self.logic.recipes[part]:
|
||||
self.potential_required_belt_speed = \
|
||||
max(self.potential_required_belt_speed, recipe.minimal_belt_speed)
|
||||
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:
|
||||
if recipe.building == "Blender":
|
||||
debug = True
|
||||
|
||||
self.select_minimal_required_parts_for(recipe.inputs)
|
||||
self.select_minimal_required_parts_for(self.logic.buildings[recipe.building].inputs)
|
||||
|
||||
self.potential_required_buildings.add(recipe.building)
|
||||
|
||||
if self.logic.buildings[recipe.building].power_requirement:
|
||||
self.potential_required_power = \
|
||||
max(self.potential_required_power, self.logic.buildings[recipe.building].power_requirement)
|
||||
max(self.potential_required_power,
|
||||
self.logic.buildings[recipe.building].power_requirement)
|
||||
|
||||
debug = True
|
||||
@@ -56,13 +56,14 @@ class Recipe():
|
||||
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, ...]
|
||||
minimal_tier: int
|
||||
|
||||
needs_pipes: bool
|
||||
is_radio_active: bool
|
||||
|
||||
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,6 +71,7 @@ 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]
|
||||
if inputs:
|
||||
@@ -100,11 +102,14 @@ class MamNode():
|
||||
"""All game items must be submitted to purchase this MamNode"""
|
||||
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():
|
||||
@@ -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),
|
||||
@@ -277,14 +282,14 @@ class GameLogic:
|
||||
Recipe("Silica", "Constructor", ("Raw Quartz", ), handcraftable=True),
|
||||
Recipe("Alumina Solution", "Refinery", ("Bauxite", "Water"), additional_outputs=("Alumina Solution", ), minimal_belt_speed=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),
|
||||
@@ -364,48 +369,48 @@ class GameLogic:
|
||||
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")), ),
|
||||
"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": (
|
||||
@@ -438,7 +443,7 @@ class GameLogic:
|
||||
"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")), ),
|
||||
"Alien Protein": (
|
||||
@@ -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": (
|
||||
@@ -488,7 +493,7 @@ class GameLogic:
|
||||
"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": (
|
||||
@@ -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=2)), # 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": (
|
||||
@@ -580,7 +585,7 @@ class GameLogic:
|
||||
"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")),
|
||||
@@ -783,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)
|
||||
@@ -829,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)
|
||||
@@ -855,12 +860,12 @@ 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
|
||||
))
|
||||
}
|
||||
|
||||
|
||||
@@ -28,10 +28,14 @@ class LocationData():
|
||||
|
||||
class Part(LocationData):
|
||||
@staticmethod
|
||||
def get_parts(state_logic: StateLogic, recipes: Tuple[Recipe, ...], name: str, items: Items) -> List[LocationData]:
|
||||
def get_parts(state_logic: StateLogic, recipes: Tuple[Recipe, ...], name: str, items: Items,
|
||||
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)
|
||||
@@ -44,6 +48,9 @@ class Part(LocationData):
|
||||
def can_produce_any_recipe_for_part(self, state_logic: StateLogic, recipes: Iterable[Recipe],
|
||||
name: str, items: Items) -> Callable[[CollectionState], bool]:
|
||||
def can_build_by_any_recipe(state: CollectionState) -> bool:
|
||||
if name == "Iron 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])
|
||||
@@ -74,7 +81,10 @@ class EventBuilding(LocationData):
|
||||
) -> Callable[[CollectionState], bool]:
|
||||
|
||||
def can_build(state: CollectionState) -> bool:
|
||||
return state_logic.has_recipe(state, building) \
|
||||
if building.name == "Building: Manufacturer":
|
||||
debug = True
|
||||
|
||||
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)
|
||||
|
||||
@@ -92,6 +102,9 @@ class PowerInfrastructure(LocationData):
|
||||
) -> Callable[[CollectionState], bool]:
|
||||
|
||||
def can_power(state: CollectionState) -> bool:
|
||||
if powerLevel == PowerInfrastructureLevel.Automated:
|
||||
debug = True
|
||||
|
||||
return any(state_logic.can_power(state, level) for level in PowerInfrastructureLevel if level > powerLevel)\
|
||||
or any(state_logic.can_build(state, recipe.building) and
|
||||
state_logic.can_produce_all_allowing_handcrafting(state, game_logic, recipe.inputs)
|
||||
@@ -127,11 +140,11 @@ 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
|
||||
|
||||
@@ -309,7 +322,7 @@ class Locations():
|
||||
|
||||
location_table = self.get_base_location_table()
|
||||
location_table.extend(self.get_hub_locations(True, self.max_tiers))
|
||||
location_table.extend(self.get_drop_pod_locations(True, self.max_tiers))
|
||||
location_table.extend(self.get_drop_pod_locations(True, self.max_tiers, set()))
|
||||
location_table.append(LocationData("Overworld", "UpperBound", 1338999))
|
||||
|
||||
return {location.name: location.code for location in location_table}
|
||||
@@ -324,8 +337,8 @@ class Locations():
|
||||
|
||||
location_table = self.get_base_location_table()
|
||||
location_table.extend(self.get_hub_locations(False, max_tier_for_game))
|
||||
location_table.extend(self.get_drop_pod_locations(False, max_tier_for_game))
|
||||
location_table.extend(self.get_logical_event_locations())
|
||||
location_table.extend(self.get_drop_pod_locations(False, max_tier_for_game, self.critical_path.potential_required_parts))
|
||||
location_table.extend(self.get_logical_event_locations(self.options.final_elevator_package))
|
||||
|
||||
return location_table
|
||||
|
||||
@@ -358,7 +371,7 @@ class Locations():
|
||||
|
||||
return location_table
|
||||
|
||||
def get_logical_event_locations(self) -> 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
|
||||
@@ -372,7 +385,7 @@ class Locations():
|
||||
part
|
||||
for part_name, recipes in self.game_logic.recipes.items()
|
||||
if part_name in self.critical_path.potential_required_parts
|
||||
for part in Part.get_parts(self.state_logic, recipes, part_name, self.items))
|
||||
for part in Part.get_parts(self.state_logic, recipes, part_name, self.items, final_elevator_tier))
|
||||
location_table.extend(
|
||||
EventBuilding(self.game_logic, self.state_logic, name, building)
|
||||
for name, building in self.game_logic.buildings.items()
|
||||
@@ -384,7 +397,8 @@ class Locations():
|
||||
|
||||
return location_table
|
||||
|
||||
def get_drop_pod_locations(self, for_data_package: bool, max_tier: int) -> List[LocationData]:
|
||||
def get_drop_pod_locations(self, for_data_package: bool, max_tier: int, available_parts: set[str]) \
|
||||
-> List[LocationData]:
|
||||
drop_pod_locations: List[DropPod] = []
|
||||
|
||||
bucket_size: int
|
||||
@@ -403,10 +417,15 @@ class Locations():
|
||||
drop_pod_locations.append(DropPod(DropPodData(0, 0, 0, None, 0), None, location_id, 1, False))
|
||||
else:
|
||||
location_id_normalized: int = location_id - self.drop_pod_location_id_start
|
||||
|
||||
if location_id_normalized == 81:
|
||||
debug = True
|
||||
|
||||
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), 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:
|
||||
drop_pod_locations.append(DropPod(data, self.state_logic, location_id, tier, can_hold_progression))
|
||||
|
||||
return drop_pod_locations
|
||||
@@ -33,7 +33,6 @@ def create_regions_and_return_locations(world: MultiWorld, options: Satisfactory
|
||||
game_logic: GameLogic, state_logic: StateLogic, locations: List[LocationData]):
|
||||
|
||||
region_names: List[str] = [
|
||||
"Menu",
|
||||
"Overworld",
|
||||
"Gas Area",
|
||||
"Radioactive Area",
|
||||
@@ -89,9 +88,8 @@ def create_regions_and_return_locations(world: MultiWorld, options: Satisfactory
|
||||
super_early_game_buildings.append("Conveyor Merger")
|
||||
|
||||
if options.final_elevator_package == 1:
|
||||
super_early_game_buildings.append(early_game_buildings)
|
||||
super_early_game_buildings.extend(early_game_buildings)
|
||||
|
||||
connect(regions, "Menu", "Overworld")
|
||||
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))
|
||||
|
||||
@@ -60,6 +60,9 @@ class StateLogic:
|
||||
return not parts or all(can_handcraft_part(part) for part in parts)
|
||||
|
||||
def can_produce_specific_recipe_for_part(self, state: CollectionState, recipe: Recipe) -> bool:
|
||||
if recipe.name == "Recipe: Iron Ingot":
|
||||
debug = True
|
||||
|
||||
if recipe.needs_pipes and (
|
||||
not self.can_build_any(state, ("Pipes Mk.1", "Pipes Mk.2")) or
|
||||
not self.can_build_any(state, ("Pipeline Pump Mk.1", "Pipeline Pump Mk.2"))):
|
||||
@@ -76,8 +79,8 @@ 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:
|
||||
limited_phase = min(self.options.final_elevator_package * 2, phase)
|
||||
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)
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ class SatisfactoryWorld(World):
|
||||
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()
|
||||
|
||||
Reference in New Issue
Block a user