Refactoring the data extraction for factorio

Extracted more information with a modified version of Archipelago extractor.   Matching PR for the extractor on its respective github.
This commit is contained in:
CaitSith2
2022-09-21 02:42:59 -07:00
parent 6d5ddf3cad
commit de8eff39b3
10 changed files with 504 additions and 72 deletions
+5 -2
View File
@@ -14,7 +14,7 @@ import Patch
from . import Options
from .Technologies import tech_table, recipes, free_sample_exclusions, progressive_technology_table, \
base_tech_table, tech_to_progressive_lookup, fluids
base_tech_table, tech_to_progressive_lookup, fluids, mods
template_env: Optional[jinja2.Environment] = None
@@ -34,7 +34,8 @@ base_info = {
"factorio_version": "1.1",
"dependencies": [
"base >= 1.1.0",
"? science-not-invited"
"? science-not-invited",
"! archipelago-extractor"
]
}
@@ -191,6 +192,8 @@ def generate_mod(world, output_directory: str):
f.write(locale_content)
info = base_info.copy()
info["name"] = mod_name
for mod in mods.values():
info["dependencies"].append(f"{mod.name} >= {mod.version}")
with open(os.path.join(mod_dir, "info.json"), "wt") as f:
json.dump(info, f, indent=4)
+236 -57
View File
@@ -22,13 +22,14 @@ def load_json_data(data_name: str) -> Union[List[str], Dict[str, Any]]:
import pkgutil
return json.loads(pkgutil.get_data(__name__, "data/" + data_name + ".json").decode())
# TODO: Make use of the lab information. (it has info on the science packs)
techs_future = pool.submit(load_json_data, "techs")
recipes_future = pool.submit(load_json_data, "recipes")
resources_future = pool.submit(load_json_data, "resources")
machines_future = pool.submit(load_json_data, "machines")
fluids_future = pool.submit(load_json_data, "fluids")
items_future = pool.submit(load_json_data, "items")
mods_future = pool.submit(load_json_data, "mods")
tech_table: Dict[str, int] = {}
technology_table: Dict[str, Technology] = {}
@@ -94,6 +95,8 @@ class CustomTechnology(Technology):
def __init__(self, origin: Technology, world, allowed_packs: Set[str], player: int):
ingredients = origin.ingredients & allowed_packs
if origin.ingredients and not ingredients:
logging.warning(f"Technology {origin.name} has no vanilla science packs. Custom science packs are not supported.")
military_allowed = "military-science-pack" in allowed_packs \
and ((ingredients & {"chemical-science-pack", "production-science-pack", "utility-science-pack"})
or origin.name == "rocket-silo")
@@ -103,7 +106,8 @@ class CustomTechnology(Technology):
ingredients.add("military-science-pack")
ingredients = list(ingredients)
ingredients.sort() # deterministic sample
ingredients = world.random.sample(ingredients, world.random.randint(1, len(ingredients)))
if ingredients:
ingredients = world.random.sample(ingredients, world.random.randint(1, len(ingredients)))
elif origin.name == "rocket-silo" and military_allowed:
ingredients.add("military-science-pack")
super(CustomTechnology, self).__init__(origin.name, ingredients, origin.factorio_id)
@@ -115,13 +119,17 @@ class Recipe(FactorioElement):
ingredients: Dict[str, int]
products: Dict[str, int]
energy: float
mining: bool
unlocked_at_start: bool
def __init__(self, name: str, category: str, ingredients: Dict[str, int], products: Dict[str, int], energy: float):
def __init__(self, name: str, category: str, ingredients: Dict[str, int], products: Dict[str, int], energy: float, mining: bool, unlocked_at_start: bool):
self.name = name
self.category = category
self.ingredients = ingredients
self.products = products
self.energy = energy
self.mining = mining
self.unlocked_at_start = unlocked_at_start
def __repr__(self):
return f"{self.__class__.__name__}({self.name})"
@@ -147,7 +155,9 @@ class Recipe(FactorioElement):
@property
def rel_cost(self) -> float:
ingredients = sum(self.ingredients.values())
return min(ingredients / amount for product, amount in self.products.items())
if all(amount == 0 for amount in self.products.values()):
return float('inf')
return min(ingredients / amount for product, amount in self.products.items() if amount > 0)
@property
def base_cost(self) -> Dict[str, int]:
@@ -164,6 +174,16 @@ class Recipe(FactorioElement):
ingredients[ingredient] += cost
return ingredients
def detect_recursive_loop(self, recipes: Counter) -> bool:
for ingredient in self.ingredients.keys():
if ingredient in all_product_sources:
for recipe in all_product_sources[ingredient]:
if recipe.ingredients:
recipes[self.name] += 1
if recipes[self.name] >= 10 or recipe.detect_recursive_loop(recipes):
return True
return False
@property
def total_energy(self) -> float:
"""Total required energy (crafting time) for single craft"""
@@ -182,10 +202,52 @@ class Recipe(FactorioElement):
class Machine(FactorioElement):
def __init__(self, name, categories):
def __init__(self, name, categories, machine_type, speed):
self.name: str = name
self.categories: set = categories
self.machine_type: str = machine_type
self.speed: float = speed
class Lab(FactorioElement):
def __init__(self, name, inputs):
self.name: str = name
self.inputs: set = inputs
class Mod(FactorioElement):
def __init__(self, name, version):
self.name: str = name
self.version: str = version
class Item(FactorioElement):
def __init__(self, name, stack_size, stackable, place_result, burnt_result, fuel_value, fuel_category, rocket_launch_products):
self.name: str = name
self.stack_size: int = stack_size
self.stackable: bool = stackable
self.place_result: str = place_result
self.burnt_result: str = burnt_result
self.fuel_value: int = fuel_value
self.fuel_category: str = fuel_category
self.rocket_launch_products: Dict[str, int] = rocket_launch_products
items: Dict[str, Item] = {}
for name, item_data in items_future.result().items():
item = Item(name,
item_data.get("stack_size"),
item_data.get("stackable"),
item_data.get("place_result", None),
item_data.get("burnt_result", None),
item_data.get("fuel_value", 0),
item_data.get("fuel_category", None),
item_data.get("rocket_launch_products", {}))
items[name] = item
del items_future
fluids: Dict[str, Dict[str, int]] = dict(fluids_future.result())
del fluids_future
print(fluids)
recipe_sources: Dict[str, Set[str]] = {} # recipe_name -> technology source
@@ -213,38 +275,120 @@ for resource_name, resource_data in resources_future.result().items():
if "required_fluid" in resource_data else {},
"products": {data["name"]: data["amount"] for data in resource_data["products"].values()},
"energy": resource_data["mining_time"],
"category": resource_data["category"]
"category": resource_data["category"],
"mining": True,
"unlocked_at_start": True
}
del resources_future
machines: Dict[str, Machine] = {}
labs: Dict[str, Lab] = {}
for name, prototype in machines_future.result().items():
for machine_type, machine_data in prototype.items():
print(f"{name}: {machine_type}: {machine_data}")
if machine_type == "lab":
lab = Lab(name, machine_data.get("inputs", set()))
labs[name] = lab
if machine_type == "offshore-pump":
fluid = machine_data.get("fluid", None)
speed = machine_data.get("speed", None)
if not fluid or not speed:
continue
category = f"offshore-pumping-{fluid}-{speed}"
raw_recipes[category] = {
"ingredients": {},
"products": {fluid: (speed*60)},
"energy": 1,
"category": category,
"mining": True,
"unlocked_at_start": True
}
machine = Machine(name, {category}, machine_data.get("type"), 1)
machines[name] = machine
if machine_type == "crafting":
categories = machine_data.get("categories", set())
if not categories:
continue
print(set(categories))
# TODO: Use speed / fluid_box info
speed = machine_data.get("speed", 1)
input_fluid_box = machine_data.get("input_fluid_box", 0)
output_fluid_box = machine_data.get("output_fluid_box", 0)
machine = Machine(name, set(categories), machine_data.get("type"), speed)
machines[name] = machine
if machine_type == "mining":
categories = machine_data.get("categories", set())
if not categories:
continue
print(set(categories))
speed = machine_data.get("speed", 1)
input_fluid_box = machine_data.get("input_fluid_box", False) # Can this machine mine resources with required fluids?
output_fluid_box = machine_data.get("output_fluid_box", False) # Can this machine mine fluid resources?
machine = machines.setdefault(name, Machine(name, set(categories), machine_data.get("type"), speed))
machine.categories |= set(categories) # character has both crafting and basic-solid
machine.speed = (machine.speed + speed) / 2
machines[name] = machine
if machine_type == "boiler":
input_fluid = machine_data.get("input_fluid")
output_fluid = machine_data.get("output_fluid")
target_temperature = machine_data.get("target_temperature")
energy_usage = machine_data.get("energy_usage")
amount = energy_usage / (target_temperature - fluids[input_fluid].get("default_temperature", 15)) / fluids[input_fluid].get("heat_capacity", 1)
amount *= 60
amount = int(amount)
category = f"boiling-{amount}-{input_fluid}-to-{output_fluid}-at-{target_temperature}-degrees-centigrade"
raw_recipes[category] = {
"ingredients": {input_fluid: amount},
"products": {output_fluid: amount},
"energy": 1,
"category": category,
"mining": False,
"unlocked_at_start": True
}
machine = Machine(name, {category}, machine_data.get("type"), 1)
machines[name] = machine
# TODO: set up machine/recipe pairs for burners in order to retrieve the burnt_result from items.
# TODO: set up machine/recipe pairs for retrieving rocket_launch_products from items.
del machines_future
for recipe_name, recipe_data in raw_recipes.items():
# example:
# "accumulator":{"ingredients":{"iron-plate":2,"battery":5},"products":{"accumulator":1},"category":"crafting"}
# FIXME: add mining?
recipe = Recipe(recipe_name, recipe_data["category"], recipe_data["ingredients"],
recipe_data["products"], recipe_data["energy"] if "energy" in recipe_data else 0)
recipe_data["products"], recipe_data.get("energy", 0), recipe_data.get("mining", False), recipe_data.get("unlocked_at_start", False))
recipes[recipe_name] = recipe
if set(recipe.products).isdisjoint(
# prevents loop recipes like uranium centrifuging
set(recipe.ingredients)) and ("empty-barrel" not in recipe.products or recipe.name == "empty-barrel") and \
not recipe_name.endswith("-reprocessing"):
for product_name in recipe.products:
if set(recipe.products).isdisjoint(set(recipe.ingredients)):
for product_name in [product_name for product_name, amount in recipe.products.items() if amount > 0]:
all_product_sources.setdefault(product_name, set()).add(recipe)
if recipe.detect_recursive_loop(Counter()):
# prevents loop recipes like uranium centrifuging and fluid unbarreling
all_product_sources.setdefault(product_name, set()).remove(recipe)
if not all_product_sources[product_name]:
del (all_product_sources[product_name])
machines: Dict[str, Machine] = {}
machines["assembling-machine-1"].categories |= machines["assembling-machine-3"].categories # mod enables this
machines["assembling-machine-2"].categories |= machines["assembling-machine-3"].categories
# machines["character"].categories.add("basic-crafting")
# charter only knows the categories of "crafting" and "basic-solid" by default.
for name, categories in machines_future.result().items():
machine = Machine(name, set(categories))
machines[name] = machine
# add electric mining drill as a crafting machine to resolve basic-solid (mining)
machines["electric-mining-drill"] = Machine("electric-mining-drill", {"basic-solid"})
machines["pumpjack"] = Machine("pumpjack", {"basic-fluid"})
machines["assembling-machine-1"].categories.add("crafting-with-fluid") # mod enables this
machines["character"].categories.add("basic-crafting") # somehow this is implied and not exported
mods: Dict[str, Mod] = {}
for name, version in mods_future.result().items():
if name in ["base"]:
continue
mod = Mod(name, version)
mods[name] = mod
del mods_future
del machines_future
# build requirements graph for all technology ingredients
@@ -254,7 +398,10 @@ for technology in technology_table.values():
def unlock_just_tech(recipe: Recipe, _done) -> Set[Technology]:
current_technologies = recipe.unlocking_technologies
if recipe.unlocked_at_start:
current_technologies = set()
else:
current_technologies = recipe.unlocking_technologies
for ingredient_name in recipe.ingredients:
current_technologies |= recursively_get_unlocking_technologies(ingredient_name, _done,
unlock_func=unlock_just_tech)
@@ -262,7 +409,10 @@ def unlock_just_tech(recipe: Recipe, _done) -> Set[Technology]:
def unlock(recipe: Recipe, _done) -> Set[Technology]:
current_technologies = recipe.unlocking_technologies
if recipe.unlocked_at_start:
current_technologies = set()
else:
current_technologies = recipe.unlocking_technologies
for ingredient_name in recipe.ingredients:
current_technologies |= recursively_get_unlocking_technologies(ingredient_name, _done, unlock_func=unlock)
current_technologies |= required_category_technologies[recipe.category]
@@ -291,19 +441,36 @@ def recursively_get_unlocking_technologies(ingredient_name, _done=None, unlock_f
required_machine_technologies: Dict[str, FrozenSet[Technology]] = {}
for ingredient_name in machines:
if ingredient_name == "character":
required_machine_technologies[ingredient_name] = frozenset()
continue
required_machine_technologies[ingredient_name] = frozenset(recursively_get_unlocking_technologies(ingredient_name))
print(f"{ingredient_name}: {required_machine_technologies[ingredient_name]}")
for ingredient_name in labs:
required_machine_technologies[ingredient_name] = frozenset(recursively_get_unlocking_technologies(ingredient_name))
logical_machines = {}
machine_tech_cost = {}
for category in machines["character"].categories:
machine_tech_cost[category] = (10000, "character", machines["character"].speed)
for machine in machines.values():
if machine.name == "character":
continue
for category in machine.categories:
current_cost, current_machine = machine_tech_cost.get(category, (10000, "character"))
machine_cost = len(required_machine_technologies[machine.name])
if machine_cost < current_cost:
machine_tech_cost[category] = machine_cost, machine.name
if machine.machine_type == "character" and not machine_cost:
machine_cost = 10000
if category in machine_tech_cost:
current_cost, current_machine, current_speed = machine_tech_cost.get(category)
if machine_cost < current_cost or (machine_cost == current_cost and machine.speed > current_speed):
machine_tech_cost[category] = machine_cost, machine.name, machine.speed
else:
machine_tech_cost[category] = machine_cost, machine.name, machine.speed
machine_per_category: Dict[str: str] = {}
for category, (cost, machine_name) in machine_tech_cost.items():
for category, (cost, machine_name, speed) in machine_tech_cost.items():
machine_per_category[category] = machine_name
del machine_tech_cost
@@ -313,7 +480,12 @@ required_category_technologies: Dict[str, FrozenSet[FrozenSet[Technology]]] = {}
for category_name, machine_name in machine_per_category.items():
techs = set()
techs |= recursively_get_unlocking_technologies(machine_name)
if category_name in machines["character"].categories and techs:
# Character crafting/mining categories always have no tech assigned.
techs = set()
machine_per_category[category_name] = "character"
required_category_technologies[category_name] = frozenset(techs)
print(f"{category_name}: {required_category_technologies[category_name]}")
required_technologies: Dict[str, FrozenSet[Technology]] = Utils.KeyedDefaultDict(lambda ingredient_name: frozenset(
recursively_get_unlocking_technologies(ingredient_name, unlock_func=unlock)))
@@ -447,34 +619,39 @@ useless_technologies: Set[str] = {tech_name for tech_name in common_tech_table
lookup_id_to_name: Dict[int, str] = {item_id: item_name for item_name, item_id in tech_table.items()}
rel_cost = {
"wood": 10000,
"iron-ore": 1,
"copper-ore": 1,
"stone": 1,
"crude-oil": 0.5,
"water": 0.001,
"coal": 1,
"raw-fish": 1000,
"steam": 0.01,
"used-up-uranium-fuel-cell": 1000
}
print("\n\nReletive costs:")
rel_cost = {}
for name, recipe in {name: recipe for name, recipe in recipes.items() if recipe.mining and not recipe.ingredients}.items():
machine = machines[machine_per_category[recipe.category]]
cost = recipe.energy / machine.speed
print(f"Cost of {name}: {cost} = {recipe.energy} / {machine.speed}")
for product_name, amount in recipe.products.items():
print(f"cost of {amount} x {product_name} = {(cost / amount)}")
rel_cost[product_name] = cost / amount
def get_estimated_difficulty(recipe: Recipe):
base_ingredients = recipe.base_cost
cost = 0
for ingredient_name, amount in base_ingredients.items():
cost += rel_cost.get(ingredient_name, 1000) * amount
return cost
for name, recipe in {name: recipe for name, recipe in recipes.items() if recipe.mining and recipe.ingredients}.items():
machine = machines[machine_per_category[recipe.category]]
cost = (recipe.energy / machine.speed) + get_estimated_difficulty(recipe)
for product_name, amount in recipe.products.items():
rel_cost[product_name] = cost / amount
print(rel_cost)
exclusion_list: Set[str] = all_ingredient_names | {"rocket-part", "used-up-uranium-fuel-cell"}
fluids: Set[str] = set(fluids_future.result())
del fluids_future
@Utils.cache_argsless
def get_science_pack_pools() -> Dict[str, Set[str]]:
def get_estimated_difficulty(recipe: Recipe):
base_ingredients = recipe.base_cost
cost = 0
for ingredient_name, amount in base_ingredients.items():
cost += rel_cost.get(ingredient_name, 1) * amount
return cost
science_pack_pools: Dict[str, Set[str]] = {}
already_taken = exclusion_list.copy()
current_difficulty = 5
@@ -484,12 +661,15 @@ def get_science_pack_pools() -> Dict[str, Set[str]]:
if (science_pack != "automation-science-pack" or not recipe.recursive_unlocking_technologies) \
and get_estimated_difficulty(recipe) < current_difficulty:
current |= set(recipe.products)
if science_pack == "automation-science-pack" and recipe.recursive_unlocking_technologies and recipe.unlocked_at_start:
print(f"Recipe: {name}")
print(f"Category: {recipe.category}")
print(f"unlocking_technologies: {recipe.recursive_unlocking_technologies}")
print(f"Estimated Difficulty: {get_estimated_difficulty(recipe)}")
if science_pack == "automation-science-pack":
# Can't handcraft automation science if fluids end up in its recipe, making the seed impossible.
current -= fluids
elif science_pack == "logistic-science-pack":
current |= {"steam"}
current -= set(fluids)
current -= already_taken
already_taken |= current
@@ -498,10 +678,9 @@ def get_science_pack_pools() -> Dict[str, Set[str]]:
return science_pack_pools
item_stack_sizes: Dict[str, int] = items_future.result()
non_stacking_items: Set[str] = {item for item, stack in item_stack_sizes.items() if stack == 1}
stacking_items: Set[str] = set(item_stack_sizes) - non_stacking_items
valid_ingredients: Set[str] = stacking_items | fluids
non_stacking_items: Set[str] = {name for name, item in items.items() if not item.stackable}
stacking_items: Set[str] = set(items) - non_stacking_items
valid_ingredients: Set[str] = stacking_items | set(fluids)
# cleanup async helpers
pool.shutdown()
+25 -6
View File
@@ -224,7 +224,7 @@ class Factorio(World):
liquids_used += 1 if new_ingredient in fluids else 0
new_ingredients[new_ingredient] = 1
return Recipe(original.name, self.get_category(original.category, liquids_used), new_ingredients,
original.products, original.energy)
original.products, original.energy, original.mining, original.unlocked_at_start)
def make_balanced_recipe(self, original: Recipe, pool: typing.Set[str], factor: float = 1,
allow_liquids: int = 2) -> Recipe:
@@ -258,6 +258,8 @@ class Factorio(World):
ingredient_energy = 2
if not ingredient_raw:
ingredient_raw = 1
if not ingredient_energy:
ingredient_energy = 1/60
if remaining_num_ingredients == 1:
max_raw = 1.1 * remaining_raw
min_raw = 0.9 * remaining_raw
@@ -293,13 +295,18 @@ class Factorio(World):
continue # can't use this ingredient as we already have maximum liquid in our recipe.
ingredient_recipe = recipes.get(ingredient, None)
if not ingredient_recipe and ingredient.endswith("-barrel"):
ingredient_recipe = recipes.get(f"fill-{ingredient}", None)
if not ingredient_recipe and ingredient in all_product_sources:
ingredient_recipe = min(all_product_sources[ingredient], key=lambda recipe: recipe.rel_cost)
if not ingredient_recipe:
logging.warning(f"missing recipe for {ingredient}")
continue
ingredient_raw = sum((count for ingredient, count in ingredient_recipe.base_cost.items()))
ingredient_energy = ingredient_recipe.total_energy
if not ingredient_raw:
ingredient_raw = 1
if not ingredient_energy:
ingredient_energy = 1/60
num_raw = remaining_raw / ingredient_raw / remaining_num_ingredients
num_energy = remaining_energy / ingredient_energy / remaining_num_ingredients
num = int(min(num_raw, num_energy))
@@ -317,7 +324,7 @@ class Factorio(World):
logging.warning("could not randomize recipe")
return Recipe(original.name, self.get_category(original.category, liquids_used), new_ingredients,
original.products, original.energy)
original.products, original.energy, original.mining, original.unlocked_at_start)
def set_custom_technologies(self):
custom_technologies = {}
@@ -329,12 +336,24 @@ class Factorio(World):
def set_custom_recipes(self):
original_rocket_part = recipes["rocket-part"]
science_pack_pools = get_science_pack_pools()
for science_pack, items in science_pack_pools.items():
print(f"{science_pack}: {items}")
print()
valid_pool = sorted(science_pack_pools[self.world.max_science_pack[self.player].get_max_pack()] & valid_ingredients)
if len(valid_pool) < 3:
# Not enough items in max pool. Extend to entire pool.
valid_pool = []
for pack in self.world.max_science_pack[self.player].get_ordered_science_packs():
valid_pool += sorted(science_pack_pools[pack] & valid_ingredients)
if len(valid_pool) < 3:
raise Exception("Not enough ingredients available for generation.")
self.world.random.shuffle(valid_pool)
self.custom_recipes = {"rocket-part": Recipe("rocket-part", original_rocket_part.category,
{valid_pool[x]: 10 for x in range(3)},
original_rocket_part.products,
original_rocket_part.energy)}
original_rocket_part.energy,
original_rocket_part.mining,
original_rocket_part.unlocked_at_start)}
if self.world.recipe_ingredients[self.player]:
valid_pool = []
@@ -363,7 +382,7 @@ class Factorio(World):
bridge = "ap-energy-bridge"
new_recipe = self.make_quick_recipe(
Recipe(bridge, "crafting", {"replace_1": 1, "replace_2": 1, "replace_3": 1},
{bridge: 1}, 10),
{bridge: 1}, 10, False, self.world.energy_link[self.player].value),
sorted(science_pack_pools[self.world.max_science_pack[self.player].get_ordered_science_packs()[0]]))
for ingredient_name in new_recipe.ingredients:
new_recipe.ingredients[ingredient_name] = self.world.random.randint(10, 100)
+1 -1
View File
@@ -1 +1 @@
["fluid-unknown","water","crude-oil","steam","heavy-oil","light-oil","petroleum-gas","sulfuric-acid","lubricant"]
{"fluid-unknown":{"default_temperature":0,"max_temperature":0,"heat_capacity":1000},"water":{"default_temperature":15,"max_temperature":100,"heat_capacity":200},"crude-oil":{"default_temperature":25,"max_temperature":25,"heat_capacity":100},"steam":{"default_temperature":15,"max_temperature":1000,"heat_capacity":200},"heavy-oil":{"default_temperature":25,"max_temperature":25,"heat_capacity":100},"light-oil":{"default_temperature":25,"max_temperature":25,"heat_capacity":100},"petroleum-gas":{"default_temperature":25,"max_temperature":25,"heat_capacity":100},"sulfuric-acid":{"default_temperature":25,"max_temperature":25,"heat_capacity":100},"lubricant":{"default_temperature":25,"max_temperature":25,"heat_capacity":100}}
File diff suppressed because one or more lines are too long
+221 -1
View File
@@ -1 +1,221 @@
{"stone-furnace":{"smelting":true},"steel-furnace":{"smelting":true},"electric-furnace":{"smelting":true},"assembling-machine-1":{"crafting":true,"basic-crafting":true,"advanced-crafting":true},"assembling-machine-2":{"basic-crafting":true,"crafting":true,"advanced-crafting":true,"crafting-with-fluid":true},"assembling-machine-3":{"basic-crafting":true,"crafting":true,"advanced-crafting":true,"crafting-with-fluid":true},"oil-refinery":{"oil-processing":true},"chemical-plant":{"chemistry":true},"centrifuge":{"centrifuging":true},"rocket-silo":{"rocket-building":true},"character":{"crafting":true}}
{
"boiler":{
"boiler":{
"type":"boiler",
"input_fluid":"water",
"output_fluid":"steam",
"target_temperature":165,
"energy_usage":30000
}
},
"nuclear-reactor":{
"fuel_burner":{
"type":"reactor",
"categories":{
"nuclear":true
},
"energy_usage":666666.666666666627861559391021728515625
}
},
"heat-exchanger":{
"boiler":{
"type":"boiler",
"input_fluid":"water",
"output_fluid":"steam",
"target_temperature":500,
"energy_usage":166666.66666666665696538984775543212890625
}
},
"burner-mining-drill":{
"mining":{
"type":"mining-drill",
"categories":{
"basic-solid":true
},
"speed":0.25,
"input_fluid_box":false,
"output_fluid_box":false
}
},
"electric-mining-drill":{
"mining":{
"type":"mining-drill",
"categories":{
"basic-solid":true
},
"speed":0.5,
"input_fluid_box":true,
"output_fluid_box":false
}
},
"offshore-pump":{
"offshore-pump":{
"type":"offshore-pump",
"fluid":"water",
"speed":20
}
},
"pumpjack":{
"mining":{
"type":"mining-drill",
"categories":{
"basic-fluid":true
},
"speed":1,
"input_fluid_box":false,
"output_fluid_box":true
}
},
"stone-furnace":{
"crafting":{
"type":"furnace",
"speed":1,
"categories":{
"smelting":true
},
"input_fluid_box":0,
"output_fluid_box":0
}
},
"steel-furnace":{
"crafting":{
"type":"furnace",
"speed":2,
"categories":{
"smelting":true
},
"input_fluid_box":0,
"output_fluid_box":0
}
},
"electric-furnace":{
"crafting":{
"type":"furnace",
"speed":2,
"categories":{
"smelting":true
},
"input_fluid_box":0,
"output_fluid_box":0
}
},
"assembling-machine-1":{
"crafting":{
"type":"assembling-machine",
"speed":0.5,
"categories":{
"crafting":true,
"basic-crafting":true,
"advanced-crafting":true
},
"input_fluid_box":0,
"output_fluid_box":0
}
},
"assembling-machine-2":{
"crafting":{
"type":"assembling-machine",
"speed":0.75,
"categories":{
"basic-crafting":true,
"crafting":true,
"advanced-crafting":true,
"crafting-with-fluid":true
},
"input_fluid_box":1,
"output_fluid_box":1
}
},
"assembling-machine-3":{
"crafting":{
"type":"assembling-machine",
"speed":1.25,
"categories":{
"basic-crafting":true,
"crafting":true,
"advanced-crafting":true,
"crafting-with-fluid":true
},
"input_fluid_box":1,
"output_fluid_box":1
}
},
"oil-refinery":{
"crafting":{
"type":"assembling-machine",
"speed":1,
"categories":{
"oil-processing":true
},
"input_fluid_box":2,
"output_fluid_box":3
}
},
"chemical-plant":{
"crafting":{
"type":"assembling-machine",
"speed":1,
"categories":{
"chemistry":true
},
"input_fluid_box":2,
"output_fluid_box":2
}
},
"centrifuge":{
"crafting":{
"type":"assembling-machine",
"speed":1,
"categories":{
"centrifuging":true
},
"input_fluid_box":0,
"output_fluid_box":0
}
},
"lab":{
"lab":{
"inputs":[
"automation-science-pack",
"logistic-science-pack",
"military-science-pack",
"chemical-science-pack",
"production-science-pack",
"utility-science-pack",
"space-science-pack"
]
}
},
"rocket-silo":{
"crafting":{
"type":"rocket-silo",
"speed":1,
"categories":{
"rocket-building":true
},
"fixed_recipe":"rocket-part",
"input_fluid_box":0,
"output_fluid_box":0
}
},
"character":{
"crafting":{
"type":"character",
"speed":1,
"categories":{
"crafting":true
},
"input_fluid_box":0,
"output_fluid_box":0
},
"mining":{
"type":"character",
"categories":{
"basic-solid":true
},
"speed":0.5,
"input_fluid_box":false,
"output_fluid_box":false
}
}
}
+2 -1
View File
@@ -8,6 +8,7 @@
"factorio_version": "1.1",
"dependencies": [
"base >= 1.1.0",
"? science-not-invited"
"? science-not-invited",
"! archipelago-extractor"
]
}
@@ -141,6 +141,9 @@ end
{# This got complex, but seems to be required to hit all corner cases #}
function adjust_energy(recipe_name, factor)
local recipe = data.raw.recipe[recipe_name]
if recipe == nil then
error("Some mod that is installed has removed recipe \"" .. recipe_name .. "\"")
end
local energy = recipe.energy_required
if (recipe.normal ~= nil) then
@@ -168,6 +171,9 @@ end
function set_energy(recipe_name, energy)
local recipe = data.raw.recipe[recipe_name]
if recipe == nil then
error("Some mod that is installed has removed recipe \"" .. recipe_name .. "\"")
end
if (recipe.normal ~= nil) then
recipe.normal.energy_required = energy
@@ -188,6 +194,9 @@ data.raw["ammo"]["artillery-shell"].stack_size = 10
{# each randomized tech gets set to be invisible, with new nodes added that trigger those #}
{%- for original_tech_name, item_name, receiving_player, advancement in locations %}
original_tech = technologies["{{original_tech_name}}"]
if original_tech == nil then
error("Some mod that is installed has removed tech \"{{original_tech_name}}\"")
end
{#- the tech researched by the local player #}
new_tree_copy = table.deepcopy(template_tech)
new_tree_copy.name = "ap-{{ tech_table[original_tech_name] }}-"{# use AP ID #}
@@ -220,13 +229,13 @@ data:extend{new_tree_copy}
{% endfor %}
{% if recipe_time_scale %}
{%- for recipe_name, recipe in recipes.items() %}
{%- if recipe.category not in ("basic-solid", "basic-fluid") %}
{%- if not recipe.mining %}
adjust_energy("{{ recipe_name }}", {{ flop_random(*recipe_time_scale) }})
{%- endif %}
{%- endfor -%}
{% elif recipe_time_range %}
{%- for recipe_name, recipe in recipes.items() %}
{%- if recipe.category not in ("basic-solid", "basic-fluid") %}
{%- if not recipe.mining %}
set_energy("{{ recipe_name }}", {{ flop_random(*recipe_time_range) }})
{%- endif %}
{%- endfor -%}
+1
View File
@@ -0,0 +1 @@
{"base":"1.1.69","archipelago-extractor":"1.1.1"}
File diff suppressed because one or more lines are too long