From c8309b2acdc684c851b3b4befd9c52f82251e530 Mon Sep 17 00:00:00 2001 From: Jarno Westhof Date: Sun, 13 Apr 2025 00:16:48 +0200 Subject: [PATCH] Implemented random Tier 0 --- worlds/satisfactory/CriticalPathCalculator.py | 91 +++++++++++++++++-- worlds/satisfactory/GameLogic.py | 48 +++++----- worlds/satisfactory/Items.py | 10 +- worlds/satisfactory/Options.py | 14 ++- worlds/satisfactory/Regions.py | 31 +++---- 5 files changed, 135 insertions(+), 59 deletions(-) diff --git a/worlds/satisfactory/CriticalPathCalculator.py b/worlds/satisfactory/CriticalPathCalculator.py index 1f165487e4..d774717f7d 100644 --- a/worlds/satisfactory/CriticalPathCalculator.py +++ b/worlds/satisfactory/CriticalPathCalculator.py @@ -23,6 +23,7 @@ class CriticalPathCalculator: implicitly_unlocked: set[str] handcraftable_parts: dict[str, list[Recipe]] + tier_0_recipes: set[str] def __init__(self, logic: GameLogic, random: Random, options: SatisfactoryOptions): self.logic = logic @@ -35,9 +36,6 @@ class CriticalPathCalculator: self.__potential_required_belt_speed = 1 - selected_power_infrastructure: dict[int, Recipe] = {} - - self.configure_implicitly_unlocked_and_handcraftable_parts() self.select_minimal_required_parts_for(self.logic.space_elevator_tiers[options.final_elevator_package-1].keys()) @@ -75,7 +73,6 @@ class CriticalPathCalculator: 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) @@ -88,6 +85,7 @@ class CriticalPathCalculator: self.required_item_names.update({"Building: "+ building for building in self.required_buildings}) self.calculate_excluded_things() + self.select_starter_recipes() def select_minimal_required_parts_for_building(self, building: str) -> None: @@ -190,7 +188,84 @@ class CriticalPathCalculator: if recipe.handcraftable: self.handcraftable_parts.setdefault(part, []).append(recipe) - if self.options.randomize_tier_0: - pass - #decide what to re-randomize, like smelter / iron ingot etc - #self.implicitly_unlocked.remove("") \ No newline at end of file + + def select_starter_recipes(self) -> None: + # cable is left unaffected as all its alternative recipes require refinery + if not self.options.randomize_starter_recipes: + self.tier_0_recipes = { + "Recipe: Iron Ingot", + "Recipe: Iron Plate", + "Recipe: Iron Rod", + "Recipe: Copper Ingot", + "Recipe: Wire", + "Recipe: Concrete", + "Recipe: Screw", + "Recipe: Reinforced Iron Plate" + } + else: + # we only allow basic parts to be made without the need of refineries + # could be made more based of GameLogic rather than hardcoded but this is likely faster + # would likely need to be based of GameLogic when we add mod support + self.tier_0_recipes = set() + + self.tier_0_recipes.add(self.random.choice( + ("Recipe: Iron Ingot", "Recipe: Basic Iron Ingot", "Recipe: Iron Alloy Ingot"))) + + selected_recipe = self.random.choice(("Recipe: Iron Plate", "Recipe: Steel Cast Plate")) + self.tier_0_recipes.add(selected_recipe) + if selected_recipe == "Recipe: Steel Cast Plate": + self.add_steel_ingot_to_starter_recipes() + + selected_recipe = self.random.choice(("Recipe: Iron Rod", "Recipe: Steel Rod")) + self.tier_0_recipes.add(selected_recipe) + if selected_recipe == "Recipe: Steel Rod": + self.add_steel_ingot_to_starter_recipes() + + self.tier_0_recipes.add(self.random.choice(("Recipe: Copper Ingot", "Recipe: Copper Alloy Ingot"))) + + selected_recipe = self.random.choice( + ("Recipe: Wire", "Recipe: Caterium Wire", "Recipe: Fused Wire", "Recipe: Iron Wire")) + self.tier_0_recipes.add(selected_recipe) + if selected_recipe in {"Recipe: Caterium Wire", "Recipe: Fused Wire"}: + # add Caterium Ingot + self.tier_0_recipes.add("Recipe: Caterium Ingot") + + selected_recipe = self.random.choice(("Recipe: Concrete", "Recipe: Fine Concrete")) + self.tier_0_recipes.add(selected_recipe) + if selected_recipe == "Recipe: Fine Concrete": + # add Silica + self.tier_0_recipes.add(self.random.choice(("Recipe: Silica", "Recipe: Cheap Silica"))) + + selected_recipe = self.random.choice(("Recipe: Screw", "Recipe: Cast Screw", "Recipe: Steel Screw")) + self.tier_0_recipes.add(selected_recipe) + if selected_recipe == "Recipe: Steel Screw": + # add Steel Beam and steel Ingot + self.add_steel_ingot_to_starter_recipes() + self.tier_0_recipes.add(self.random.choice(("Recipe: Steel Beam", "Recipe: Molded Beam"))) + + self.tier_0_recipes.add(self.random.choice( + ("Recipe: Reinforced Iron Plate", "Recipe: Bolted Iron Plate", "Recipe: Stitched Iron Plate"))) + + for part, recipes in self.logic.recipes.items(): + for recipe in recipes: + if recipe.name in self.tier_0_recipes: + if part in self.handcraftable_parts: + self.handcraftable_parts[part].append(recipe) + else: + self.handcraftable_parts[part] = [recipe] + self.tier_0_recipes.add(self.logic.buildings[recipe.building].name) + + self.implicitly_unlocked.update(self.tier_0_recipes) + + def add_steel_ingot_to_starter_recipes(self) -> None: + if "Recipe: Steel Ingot" not in self.tier_0_recipes \ + and "Recipe: Compacted Steel Ingot" not in self.tier_0_recipes \ + and "Recipe: Solid Steel Ingot" not in self.tier_0_recipes: + + selected_recipe = self.random.choice( + ("Recipe: Steel Ingot", "Recipe: Compacted Steel Ingot", "Recipe: Solid Steel Ingot")) + + self.tier_0_recipes.add(selected_recipe) + + if selected_recipe == "Recipe: Compacted Steel Ingot": + self.tier_0_recipes.add("Recipe: Compacted Coal") diff --git a/worlds/satisfactory/GameLogic.py b/worlds/satisfactory/GameLogic.py index 5748ce29c5..7b6e5d559e 100644 --- a/worlds/satisfactory/GameLogic.py +++ b/worlds/satisfactory/GameLogic.py @@ -205,7 +205,7 @@ class GameLogic: # Recipes "Reinforced Iron Plate": ( - Recipe("Reinforced Iron Plate", "Assembler", ("Iron Plate", "Screw"), handcraftable=True, implicitly_unlocked=True), + Recipe("Reinforced Iron Plate", "Assembler", ("Iron Plate", "Screw")), Recipe("Adhered Iron Plate", "Assembler", ("Iron Plate", "Rubber")), Recipe("Bolted Iron Plate", "Assembler", ("Iron Plate", "Screw"), minimal_belt_speed=3), Recipe("Stitched Iron Plate", "Assembler", ("Iron Plate", "Wire"))), @@ -225,19 +225,19 @@ class GameLogic: Recipe("Residual Rubber", "Refinery", ("Polymer Resin", "Water")), Recipe("Recycled Rubber", "Refinery", ("Plastic", "Fuel"))), "Iron Plate": ( - Recipe("Iron Plate", "Constructor", ("Iron Ingot", ), handcraftable=True, implicitly_unlocked=True), + Recipe("Iron Plate", "Constructor", ("Iron Ingot", )), Recipe("Coated Iron Plate", "Assembler", ("Iron Ingot", "Plastic"), minimal_belt_speed=2), Recipe("Steel Cast Plate", "Foundry", ("Iron Ingot", "Steel Ingot"))), "Iron Rod": ( - Recipe("Iron Rod", "Constructor", ("Iron Ingot", ), handcraftable=True, implicitly_unlocked=True), + Recipe("Iron Rod", "Constructor", ("Iron Ingot", )), Recipe("Steel Rod", "Constructor", ("Steel Ingot", )), Recipe("Aluminum Rod", "Constructor", ("Aluminum Ingot", ))), "Screw": ( - Recipe("Screw", "Constructor", ("Iron Rod", ), handcraftable=True, implicitly_unlocked=True), + Recipe("Screw", "Constructor", ("Iron Rod", )), Recipe("Cast Screw", "Constructor", ("Iron Ingot", )), Recipe("Steel Screw", "Constructor", ("Steel Beam", ), minimal_belt_speed=3)), "Wire": ( - Recipe("Wire", "Constructor", ("Copper Ingot", ), handcraftable=True, implicitly_unlocked=True), + Recipe("Wire", "Constructor", ("Copper Ingot", )), Recipe("Fused Wire", "Assembler", ("Copper Ingot", "Caterium Ingot"), minimal_belt_speed=2), Recipe("Iron Wire", "Constructor", ("Iron Ingot", )), Recipe("Caterium Wire", "Constructor", ("Caterium Ingot", ), minimal_belt_speed=2)), @@ -274,7 +274,7 @@ class GameLogic: 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), + Recipe("Concrete", "Constructor", ("Limestone", )), Recipe("Fine Concrete", "Assembler", ("Limestone", "Silica")), Recipe("Rubber Concrete", "Assembler", ("Limestone", "Rubber")), Recipe("Wet Concrete", "Refinery", ("Limestone", "Water"), minimal_belt_speed=2)), @@ -291,7 +291,7 @@ class GameLogic: 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, minimal_tier=2)), "Iron Ingot": ( - Recipe("Iron Ingot", "Smelter", ("Iron Ore", ), handcraftable=True, implicitly_unlocked=True), + Recipe("Iron Ingot", "Smelter", ("Iron Ore", )), Recipe("Pure Iron Ingot", "Refinery", ("Iron Ore", "Water"), minimal_belt_speed=2), Recipe("Iron Alloy Ingot", "Foundry", ("Iron Ore", "Copper Ore")), Recipe("Basic Iron Ingot", "Foundry", ("Iron Ore", "Limestone")), @@ -302,7 +302,7 @@ class GameLogic: Recipe("Compacted Steel Ingot", "Foundry", ("Iron Ore", "Compacted Coal")), Recipe("Solid Steel Ingot", "Foundry", ("Iron Ingot", "Coal"))), "Copper Ingot": ( - Recipe("Copper Ingot", "Smelter", ("Copper Ore", ), handcraftable=True, implicitly_unlocked=True), + Recipe("Copper Ingot", "Smelter", ("Copper Ore", )), Recipe("Copper Alloy Ingot", "Foundry", ("Copper Ore", "Iron Ore"), minimal_belt_speed=2), Recipe("Pure Copper Ingot", "Refinery", ("Copper Ore", "Water")), Recipe("Leached Copper Ingot", "Refinery", ("Copper Ore", "Sulfuric Acid"), minimal_belt_speed=2), @@ -580,7 +580,7 @@ class GameLogic: } buildings: dict[str, Building] = { - "Constructor": Building("Constructor", ("Reinforced Iron Plate", "Cable"), PowerInfrastructureLevel.Basic, implicitly_unlocked=True), + "Constructor": Building("Constructor", ("Reinforced Iron Plate", "Cable"), PowerInfrastructureLevel.Basic), "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), @@ -597,7 +597,7 @@ class GameLogic: "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), + "Smelter": Building("Smelter", ("Iron Rod", "Wire"), PowerInfrastructureLevel.Basic), "Foundry": Building("Foundry", ("Modular Frame", "Rotor", "Concrete"), PowerInfrastructureLevel.Basic), "Resource Well Pressurizer": Building("Resource Well Pressurizer", ("Wire", "Rubber", "Encased Industrial Beam", "Motor", "Steel Beam", "Plastic"), PowerInfrastructureLevel.Advanced), "Equipment Workshop": Building("Equipment Workshop", ("Iron Plate", "Iron Rod"), implicitly_unlocked=True), @@ -744,20 +744,20 @@ class GameLogic: MamNode("Hostile Organism Detection", {"Alien DNA Capsule":10,"Crystal Oscillator":5,"High-Speed Connector":5,}, depends_on=("Bio-Organic Properties", )), #(Research_AOrganisms_2_C) MamNode("Expanded Toolbelt", {"Alien DNA Capsule":5,"Steel Beam":500,}, depends_on=("Inflated Pocket Dimension", )), #(Research_ACarapace_3_C) MamNode("Bio-Organic Properties", {"Alien Protein":5,}, depends_on=("Spitter Research", "Hog Research", "Hatcher Research", "Stinger Research")), #(Research_AO_DNACapsule_C) - MamNode("Stinger Research", {"Stinger Remains":1,}, depends_on=()), #(Research_AO_Stinger_C) - MamNode("Hatcher Research", {"Hatcher Remains":1,}, depends_on=()), #(Research_AO_Hatcher_C) - MamNode("Hog Research", {"Hog Remains":1,}, depends_on=()), #(Research_ACarapace_0_C) - MamNode("Spitter Research", {"Plasma Spitter Remains":1,}, depends_on=()), #(Research_AOrgans_0_C) + MamNode("Stinger Research", {"Stinger Remains":1,}, depends_on=tuple()), #(Research_AO_Stinger_C) + MamNode("Hatcher Research", {"Hatcher Remains":1,}, depends_on=tuple()), #(Research_AO_Hatcher_C) + MamNode("Hog Research", {"Hog Remains":1,}, depends_on=tuple()), #(Research_ACarapace_0_C) + MamNode("Spitter Research", {"Plasma Spitter Remains":1,}, depends_on=tuple()), #(Research_AOrgans_0_C) MamNode("Structural Analysis", {"Alien DNA Capsule":5,"Iron Rod":100,}, depends_on=("Bio-Organic Properties", )), #(Research_AO_Pre_Rebar_C) MamNode("Protein Inhaler", {"Alien Protein":2,"Beryl Nut":20,"Rotor":50,}, depends_on=("Bio-Organic Properties", )), #(Research_AOrgans_2_C) MamNode("The Rebar Gun", {"Rotor":25,"Reinforced Iron Plate":50,"Screw":500,}, depends_on=("Structural Analysis", )), #(Research_ACarapace_2_C) )), # 1.0 "Alien Technology": MamTree(("SAM", "Mercer Sphere", "Somersloop"), ( - MamNode("SAM Analysis", {"SAM":10,}, depends_on=()), + MamNode("SAM Analysis", {"SAM":10,}, depends_on=tuple()), MamNode("SAM Reanimation", {"SAM":20,}, depends_on=("SAM Analysis",)), MamNode("SAM Fluctuator", {"Reanimated SAM":10,"Steel Pipe":100,"Wire":200,}, depends_on=("SAM Reanimation",)), - MamNode("Mercer Sphere Analysis", {"Mercer Sphere":1,}, depends_on=()), + MamNode("Mercer Sphere Analysis", {"Mercer Sphere":1,}, depends_on=tuple()), MamNode("Dimensional Depot", {"Mercer Sphere":1,"SAM Fluctuator":11,}, depends_on=("Mercer Sphere Analysis", "SAM Fluctuator")), MamNode("Manual Depot Uploader", {"Mercer Sphere":3,"Computer":17,"SAM Fluctuator":19,}, depends_on=("Dimensional Depot",)), MamNode("Depot Expansion (200%)", {"Mercer Sphere":3,"SAM Fluctuator":47,}, depends_on=("Dimensional Depot",)), @@ -768,7 +768,7 @@ class GameLogic: MamNode("Upload Upgrade: 60/min", {"Mercer Sphere":7,"SAM Fluctuator":103,}, depends_on=("Upload Upgrade: 30/min",)), MamNode("Upload Upgrade: 120/min", {"Mercer Sphere":13,"SAM Fluctuator":151,}, depends_on=("Upload Upgrade: 60/min",)), MamNode("Upload Upgrade: 240/min", {"Mercer Sphere":23,"SAM Fluctuator":199,}, depends_on=("Upload Upgrade: 120/min",)), - MamNode("Somersloop Analysis", {"Somersloop":1,}, depends_on=()), + MamNode("Somersloop Analysis", {"Somersloop":1,}, depends_on=tuple()), 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",)), @@ -779,7 +779,7 @@ class GameLogic: MamNode("Caterium Electronics", {"Quickwire":100,}, depends_on=("Quickwire", )), #(Research_Caterium_3_C) MamNode("Bullet Guidance System", {"High-Speed Connector":10,"Rifle Ammo":500,}, depends_on=("High-Speed Connector", )), #(Research_Caterium_6_3_C) MamNode("High-Speed Connector", {"Quickwire":500,"Plastic":50,}, depends_on=("Caterium Electronics", )), #(Research_Caterium_5_C) - MamNode("Caterium", {"Caterium Ore":10,}, depends_on=()), #(Research_Caterium_0_C) + MamNode("Caterium", {"Caterium Ore":10,}, depends_on=tuple()), #(Research_Caterium_0_C) MamNode("Caterium Ingots", {"Caterium Ore":50,}, depends_on=("Caterium", )), #(Research_Caterium_1_C) MamNode("Quickwire", {"Caterium Ingot":50,}, depends_on=("Caterium Ingots", )), #(Research_Caterium_2_C) MamNode("Power Switch", {"Steel Beam":100,"AI Limiter":50,}, depends_on=("AI Limiter", )), #(Research_Caterium_4_1_2_C) @@ -806,15 +806,15 @@ class GameLogic: MamNode("Gas Mask", {"Coal":10,"Fabric":50,"Steel Pipe":50}, depends_on=("Fabric", )), # 1.0 )), "Nutrients": MamTree(("Paleberry", "Beryl Nut", "Bacon Agaric"), ( # Nutrients (BPD_ResearchTree_Nutrients_C) - MamNode("Bacon Agaric", {"Bacon Agaric":1,}, depends_on=()), #(Research_Nutrients_2_C) - MamNode("Beryl Nut", {"Beryl Nut":5,}, depends_on=()), #(Research_Nutrients_1_C) - MamNode("Paleberry", {"Paleberry":2,}, depends_on=()), #(Research_Nutrients_0_C) + MamNode("Bacon Agaric", {"Bacon Agaric":1,}, depends_on=tuple()), #(Research_Nutrients_2_C) + MamNode("Beryl Nut", {"Beryl Nut":5,}, depends_on=tuple()), #(Research_Nutrients_1_C) + MamNode("Paleberry", {"Paleberry":2,}, depends_on=tuple()), #(Research_Nutrients_0_C) MamNode("Nutritional Processor", {"Modular Frame":25,"Steel Pipe":50,"Wire":500,}, depends_on=("Beryl Nut", "Bacon Agaric", "Paleberry")), #(Research_Nutrients_3_C) MamNode("Nutritional Inhaler", {"Bacon Agaric":2,"Paleberry":4,"Beryl Nut":10,}, depends_on=("Nutritional Processor", )), #(Research_Nutrients_4_C) )), "Power Slugs": MamTree(("Blue Power Slug", ), ( # Power Slugs (BPD_ResearchTree_PowerSlugs_C) MamNode("Slug Scanning", {"Iron Rod":50,"Wire":100,"Screw":200,}, depends_on=("Blue Power Slugs", )), #(Research_PowerSlugs_3_C) - MamNode("Blue Power Slugs", {"Blue Power Slug":1,}, depends_on=()), #(Research_PowerSlugs_1_C) + MamNode("Blue Power Slugs", {"Blue Power Slug":1,}, depends_on=tuple()), #(Research_PowerSlugs_1_C) 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) @@ -823,7 +823,7 @@ class GameLogic: "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) MamNode("Quartz Crystals", {"Raw Quartz":20,}, depends_on=("Quartz", )), #(Research_Quartz_1_1_C) - MamNode("Quartz", {"Raw Quartz":10,}, depends_on=()), #(Research_Quartz_0_C) + MamNode("Quartz", {"Raw Quartz":10,}, depends_on=tuple()), #(Research_Quartz_0_C) MamNode("Shatter Rebar", {"Quartz Crystal":30,"Iron Rebar":150,}, depends_on=("Quartz Crystals", )), #(Research_Quartz_2_1_C) MamNode("Silica", {"Raw Quartz":20,}, depends_on=("Quartz", )), #(Research_Quartz_1_2_C) MamNode("Explosive Resonance Application", {"Crystal Oscillator":5,"Nobelisk":100,}, depends_on=("Crystal Oscillator", )), #(Research_Quartz_3_4_C) @@ -837,7 +837,7 @@ class GameLogic: "Sulfur": MamTree(("Sulfur", ), ( # Sulfur (BPD_ResearchTree_Sulfur_C) MamNode("The Nobelisk Detonator", {"Black Powder":50,"Steel Pipe":100,"Cable":200,}, depends_on=("Black Powder", )), #(Research_Sulfur_3_1_C) MamNode("Smokeless Powder", {"Black Powder":100,"Plastic":50,}, depends_on=("Black Powder", )), #(Research_Sulfur_3_C) - MamNode("Sulfur", {"Sulfur":10,}, depends_on=()), #(Research_Sulfur_0_C) + MamNode("Sulfur", {"Sulfur":10,}, depends_on=tuple()), #(Research_Sulfur_0_C) MamNode("Inflated Pocket Dimension", {"Smokeless Powder":50,"Computer":50,}, depends_on=("Nuclear Deterrent Development", "Turbo Rifle Ammo", "Cluster Nobelisk", "The Rifle")), #(Research_Sulfur_6_C) MamNode("The Rifle", {"Smokeless Powder":50,"Motor":100,"Rubber":200,}, depends_on=("Smokeless Powder", )), #(Research_Sulfur_4_1_C) MamNode("Compacted Coal", {"Hard Drive":1,"Sulfur":25,"Coal":25,}, depends_on=("Experimental Power Generation", )), #(Research_Sulfur_CompactedCoal_C) diff --git a/worlds/satisfactory/Items.py b/worlds/satisfactory/Items.py index 48a3d3b5a2..942c29b17b 100644 --- a/worlds/satisfactory/Items.py +++ b/worlds/satisfactory/Items.py @@ -947,14 +947,14 @@ class Items: pool.append(item) 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) + pool += [ + self.create_item(self, self.get_filler_item_name(filtered_filler_items, random, options), self.player) + for _ in range(filler_pool_size) + ] return pool diff --git a/worlds/satisfactory/Options.py b/worlds/satisfactory/Options.py index 8f6936dfc9..3b135ca7cb 100644 --- a/worlds/satisfactory/Options.py +++ b/worlds/satisfactory/Options.py @@ -1,7 +1,7 @@ from dataclasses import dataclass from typing import ClassVar, Any, cast from enum import IntEnum -from Options import PerGameCommonOptions, DeathLinkMixin, AssembleOptions, Visibility, OptionGroup +from Options import PerGameCommonOptions, DeathLinkMixin, AssembleOptions, OptionGroup from Options import Range, NamedRange, Toggle, DefaultOnToggle, OptionSet, StartInventoryPool, Choice from schema import Schema, And @@ -421,9 +421,13 @@ class GoalRequirement(Choice): class RandomizeTier0(DefaultOnToggle): """ - Randomizer the way you obtain basic parts such as ingots and wire + Randomizes the recipes used to craft the default unlocked parts: + Iron Ingot, Iron Plate, Iron Rod, Copper Ingot, Wire, Concrete, Screw, Reinforced Iron Plate + + * They could require usage of Foundries or Assemblers that will than also get unlocked by default if needed + * They could require other ores to be mixed in """ - display_name = "Randomize tier 0 recipes" + display_name = "Randomize default part recipes" @dataclass class SatisfactoryOptions(PerGameCommonOptions, DeathLinkMixin): @@ -449,7 +453,7 @@ class SatisfactoryOptions(PerGameCommonOptions, DeathLinkMixin): trap_selection_override: TrapSelectionOverride energy_link: EnergyLink start_inventory_from_pool: StartInventoryPool - randomize_tier_0: RandomizeTier0 + randomize_starter_recipes: RandomizeTier0 option_groups = [ OptionGroup("Game Scope", [ @@ -492,7 +496,7 @@ option_presets: dict[str, dict[str, Any]] = { "goal_awesome_sink_points_total": 17804500, # 100 coupons "hard_drive_progression_limit": 20, "starting_inventory_preset": 3, # "Foundations" - "randomize_tier_0": False, + "randomizer_starter_recipes": False, "mam_logic_placement": int(Placement.starting_inventory), "awesome_logic_placement": int(Placement.starting_inventory), "energy_link_logic_placement": int(Placement.starting_inventory), diff --git a/worlds/satisfactory/Regions.py b/worlds/satisfactory/Regions.py index 9909942013..5b22a47041 100644 --- a/worlds/satisfactory/Regions.py +++ b/worlds/satisfactory/Regions.py @@ -50,9 +50,11 @@ def create_regions_and_return_locations(world: MultiWorld, options: Satisfactory 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 and building_name in critical_path.required_buildings: - region_names.append(building_name) + region_names += [ + building_name + for building_name, building in game_logic.buildings.items() + if building.can_produce and building_name in critical_path.required_buildings + ] for tree_name, tree in game_logic.man_trees.items(): region_names.append(tree_name) @@ -150,10 +152,7 @@ def create_regions_and_return_locations(world: MultiWorld, options: Satisfactory def throwIfAnyLocationIsNotAssignedToARegion(regions: dict[str, Region], regionNames: set[str]): - existingRegions = set() - - for region in regions.keys(): - existingRegions.add(region) + existingRegions = set(regions.keys()) if (regionNames - existingRegions): raise Exception(f"Satisfactory: the following regions are used in locations: {regionNames - existingRegions}, but no such region exists") @@ -165,22 +164,20 @@ def create_region(world: MultiWorld, player: int, region = Region(name, player, world) if name in locations_per_region: - for location_data in locations_per_region[name]: - location = SatisfactoryLocation(player, location_data, region) - region.locations.append(location) + region.locations += [ + SatisfactoryLocation(player, location_data, region) + for location_data in locations_per_region[name] + ] return 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] = {} - - for name in region_names: - regions[name] = create_region(world, player, locations_per_region, name) - - return regions + return { + name : create_region(world, player, locations_per_region, name) + for name in region_names + } def connect(regions: dict[str, Region], source: str, target: str,