Factorio: support 2.0 update (#4110)
- removed tutorialization (Craft/Do X to unlock tech) - start with everything needed for power, electric mining drills, science lab and automation science already unlocked - updated world gen - updated mod api use - updated fluid boxes (CaitSith2) - new option: free sample quality (needs quality mod) - removed old gruft, faster gen speed, faster load time - lists space age as explicitly not supported, so it prevents the game from trying to load both - fixes Y offset of traps being wrong (way higher than intended) - client now has a 5 second timeout to communicate with the bound factorio server, so it aborts actions if the server died - savegames are now stored in write_data_directory -> saves -> Archipelago - add cargo-landing-pad handling - starting rocket silo and cargo landing pad respect free sample quality - supports Factorio 2.0 --------- Co-authored-by: CaitSith2 <d_good@caitsith2.com>
This commit is contained in:
parent
b3e5ef876a
commit
f3413e9cef
|
@ -304,13 +304,13 @@ def stream_factorio_output(pipe, queue, process):
|
|||
|
||||
|
||||
async def factorio_server_watcher(ctx: FactorioContext):
|
||||
savegame_name = os.path.abspath(ctx.savegame_name)
|
||||
savegame_name = os.path.abspath(os.path.join(ctx.write_data_path, "saves", "Archipelago", ctx.savegame_name))
|
||||
if not os.path.exists(savegame_name):
|
||||
logger.info(f"Creating savegame {savegame_name}")
|
||||
subprocess.run((
|
||||
executable, "--create", savegame_name, "--preset", "archipelago"
|
||||
))
|
||||
factorio_process = subprocess.Popen((executable, "--start-server", ctx.savegame_name,
|
||||
factorio_process = subprocess.Popen((executable, "--start-server", savegame_name,
|
||||
*(str(elem) for elem in server_args)),
|
||||
stderr=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE,
|
||||
|
@ -331,7 +331,8 @@ async def factorio_server_watcher(ctx: FactorioContext):
|
|||
factorio_queue.task_done()
|
||||
|
||||
if not ctx.rcon_client and "Starting RCON interface at IP ADDR:" in msg:
|
||||
ctx.rcon_client = factorio_rcon.RCONClient("localhost", rcon_port, rcon_password)
|
||||
ctx.rcon_client = factorio_rcon.RCONClient("localhost", rcon_port, rcon_password,
|
||||
timeout=5)
|
||||
if not ctx.server:
|
||||
logger.info("Established bridge to Factorio Server. "
|
||||
"Ready to connect to Archipelago via /connect")
|
||||
|
@ -405,8 +406,7 @@ async def get_info(ctx: FactorioContext, rcon_client: factorio_rcon.RCONClient):
|
|||
info = json.loads(rcon_client.send_command("/ap-rcon-info"))
|
||||
ctx.auth = info["slot_name"]
|
||||
ctx.seed_name = info["seed_name"]
|
||||
# 0.2.0 addition, not present earlier
|
||||
death_link = bool(info.get("death_link", False))
|
||||
death_link = info["death_link"]
|
||||
ctx.energy_link_increment = info.get("energy_link", 0)
|
||||
logger.debug(f"Energy Link Increment: {ctx.energy_link_increment}")
|
||||
if ctx.energy_link_increment and ctx.ui:
|
||||
|
|
|
@ -35,9 +35,11 @@ base_info = {
|
|||
"author": "Berserker",
|
||||
"homepage": "https://archipelago.gg",
|
||||
"description": "Integration client for the Archipelago Randomizer",
|
||||
"factorio_version": "1.1",
|
||||
"factorio_version": "2.0",
|
||||
"dependencies": [
|
||||
"base >= 1.1.0",
|
||||
"base >= 2.0.15",
|
||||
"? quality >= 2.0.15",
|
||||
"! space-age",
|
||||
"? science-not-invited",
|
||||
"? factory-levels"
|
||||
]
|
||||
|
@ -133,21 +135,21 @@ def generate_mod(world: "Factorio", output_directory: str):
|
|||
"allowed_science_packs": world.options.max_science_pack.get_allowed_packs(),
|
||||
"custom_technologies": world.custom_technologies,
|
||||
"tech_tree_layout_prerequisites": world.tech_tree_layout_prerequisites,
|
||||
"slot_name": world.player_name, "seed_name": multiworld.seed_name,
|
||||
"slot_name": world.player_name,
|
||||
"seed_name": multiworld.seed_name,
|
||||
"slot_player": player,
|
||||
"starting_items": world.options.starting_items, "recipes": recipes,
|
||||
"random": random, "flop_random": flop_random,
|
||||
"recipes": recipes,
|
||||
"random": random,
|
||||
"flop_random": flop_random,
|
||||
"recipe_time_scale": recipe_time_scales.get(world.options.recipe_time.value, None),
|
||||
"recipe_time_range": recipe_time_ranges.get(world.options.recipe_time.value, None),
|
||||
"free_sample_blacklist": {item: 1 for item in free_sample_exclusions},
|
||||
"free_sample_quality_name": world.options.free_samples_quality.current_key,
|
||||
"progressive_technology_table": {tech.name: tech.progressive for tech in
|
||||
progressive_technology_table.values()},
|
||||
"custom_recipes": world.custom_recipes,
|
||||
"max_science_pack": world.options.max_science_pack.value,
|
||||
"liquids": fluids,
|
||||
"goal": world.options.goal.value,
|
||||
"energy_link": world.options.energy_link.value,
|
||||
"useless_technologies": useless_technologies,
|
||||
"removed_technologies": world.removed_technologies,
|
||||
"chunk_shuffle": 0,
|
||||
}
|
||||
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
import datetime
|
||||
import typing
|
||||
|
||||
from schema import Schema, Optional, And, Or
|
||||
|
||||
from Options import Choice, OptionDict, OptionSet, Option, DefaultOnToggle, Range, DeathLink, Toggle, \
|
||||
from Options import Choice, OptionDict, OptionSet, DefaultOnToggle, Range, DeathLink, Toggle, \
|
||||
StartInventoryPool, PerGameCommonOptions
|
||||
|
||||
# schema helpers
|
||||
|
@ -122,6 +121,18 @@ class FreeSamples(Choice):
|
|||
default = 3
|
||||
|
||||
|
||||
class FreeSamplesQuality(Choice):
|
||||
"""If free samples are on, determine the quality of the granted items.
|
||||
Requires the quality mod, which is part of the Space Age DLC. Without it, normal quality is given."""
|
||||
display_name = "Free Samples Quality"
|
||||
option_normal = 0
|
||||
option_uncommon = 1
|
||||
option_rare = 2
|
||||
option_epic = 3
|
||||
option_legendary = 4
|
||||
default = 0
|
||||
|
||||
|
||||
class TechTreeLayout(Choice):
|
||||
"""Selects how the tech tree nodes are interwoven.
|
||||
Single: No dependencies
|
||||
|
@ -284,17 +295,21 @@ class FactorioWorldGen(OptionDict):
|
|||
# FIXME: do we want default be a rando-optimized default or in-game DS?
|
||||
value: typing.Dict[str, typing.Dict[str, typing.Any]]
|
||||
default = {
|
||||
"terrain_segmentation": 0.5,
|
||||
"water": 1.5,
|
||||
"autoplace_controls": {
|
||||
# terrain
|
||||
"water": {"frequency": 1, "size": 1, "richness": 1},
|
||||
"nauvis_cliff": {"frequency": 1, "size": 1, "richness": 1},
|
||||
"starting_area_moisture": {"frequency": 1, "size": 1, "richness": 1},
|
||||
# resources
|
||||
"coal": {"frequency": 1, "size": 3, "richness": 6},
|
||||
"copper-ore": {"frequency": 1, "size": 3, "richness": 6},
|
||||
"crude-oil": {"frequency": 1, "size": 3, "richness": 6},
|
||||
"enemy-base": {"frequency": 1, "size": 1, "richness": 1},
|
||||
"iron-ore": {"frequency": 1, "size": 3, "richness": 6},
|
||||
"stone": {"frequency": 1, "size": 3, "richness": 6},
|
||||
"uranium-ore": {"frequency": 1, "size": 3, "richness": 6},
|
||||
# misc
|
||||
"trees": {"frequency": 1, "size": 1, "richness": 1},
|
||||
"uranium-ore": {"frequency": 1, "size": 3, "richness": 6}
|
||||
"enemy-base": {"frequency": 1, "size": 1, "richness": 1},
|
||||
},
|
||||
"seed": None,
|
||||
"starting_area": 1,
|
||||
|
@ -336,8 +351,6 @@ class FactorioWorldGen(OptionDict):
|
|||
}
|
||||
schema = Schema({
|
||||
"basic": {
|
||||
Optional("terrain_segmentation"): FloatRange(0.166, 6),
|
||||
Optional("water"): FloatRange(0.166, 6),
|
||||
Optional("autoplace_controls"): {
|
||||
str: {
|
||||
"frequency": FloatRange(0, 6),
|
||||
|
@ -438,6 +451,7 @@ class FactorioOptions(PerGameCommonOptions):
|
|||
silo: Silo
|
||||
satellite: Satellite
|
||||
free_samples: FreeSamples
|
||||
free_samples_quality: FreeSamplesQuality
|
||||
tech_tree_information: TechTreeInformation
|
||||
starting_items: FactorioStartItems
|
||||
free_sample_blacklist: FactorioFreeSampleBlacklist
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import orjson
|
||||
import logging
|
||||
import os
|
||||
import string
|
||||
import functools
|
||||
import pkgutil
|
||||
import string
|
||||
from collections import Counter
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
from typing import Dict, Set, FrozenSet, Tuple, Union, List, Any
|
||||
from typing import Dict, Set, FrozenSet, Tuple, Union, List, Any, Optional
|
||||
|
||||
import orjson
|
||||
|
||||
import Utils
|
||||
from . import Options
|
||||
|
@ -32,8 +32,23 @@ items_future = pool.submit(load_json_data, "items")
|
|||
tech_table: Dict[str, int] = {}
|
||||
technology_table: Dict[str, Technology] = {}
|
||||
|
||||
start_unlocked_recipes = {
|
||||
"offshore-pump",
|
||||
"boiler",
|
||||
"steam-engine",
|
||||
"automation-science-pack",
|
||||
"inserter",
|
||||
"small-electric-pole",
|
||||
"copper-cable",
|
||||
"lab",
|
||||
"electronic-circuit",
|
||||
"electric-mining-drill",
|
||||
"pipe",
|
||||
"pipe-to-ground",
|
||||
}
|
||||
|
||||
def always(state):
|
||||
|
||||
def always(state) -> bool:
|
||||
return True
|
||||
|
||||
|
||||
|
@ -50,15 +65,13 @@ class FactorioElement:
|
|||
class Technology(FactorioElement): # maybe make subclass of Location?
|
||||
has_modifier: bool
|
||||
factorio_id: int
|
||||
ingredients: Set[str]
|
||||
progressive: Tuple[str]
|
||||
unlocks: Union[Set[str], bool] # bool case is for progressive technologies
|
||||
|
||||
def __init__(self, name: str, ingredients: Set[str], factorio_id: int, progressive: Tuple[str] = (),
|
||||
def __init__(self, technology_name: str, factorio_id: int, progressive: Tuple[str] = (),
|
||||
has_modifier: bool = False, unlocks: Union[Set[str], bool] = None):
|
||||
self.name = name
|
||||
self.name = technology_name
|
||||
self.factorio_id = factorio_id
|
||||
self.ingredients = ingredients
|
||||
self.progressive = progressive
|
||||
self.has_modifier = has_modifier
|
||||
if unlocks:
|
||||
|
@ -66,19 +79,6 @@ class Technology(FactorioElement): # maybe make subclass of Location?
|
|||
else:
|
||||
self.unlocks = set()
|
||||
|
||||
def build_rule(self, player: int):
|
||||
logging.debug(f"Building rules for {self.name}")
|
||||
|
||||
return lambda state: all(state.has(f"Automated {ingredient}", player)
|
||||
for ingredient in self.ingredients)
|
||||
|
||||
def get_prior_technologies(self) -> Set[Technology]:
|
||||
"""Get Technologies that have to precede this one to resolve tree connections."""
|
||||
technologies = set()
|
||||
for ingredient in self.ingredients:
|
||||
technologies |= required_technologies[ingredient] # technologies that unlock the recipes
|
||||
return technologies
|
||||
|
||||
def __hash__(self):
|
||||
return self.factorio_id
|
||||
|
||||
|
@ -91,22 +91,22 @@ class Technology(FactorioElement): # maybe make subclass of Location?
|
|||
|
||||
class CustomTechnology(Technology):
|
||||
"""A particularly configured Technology for a world."""
|
||||
ingredients: Set[str]
|
||||
|
||||
def __init__(self, origin: Technology, world, allowed_packs: Set[str], player: int):
|
||||
ingredients = origin.ingredients & allowed_packs
|
||||
military_allowed = "military-science-pack" in allowed_packs \
|
||||
and ((ingredients & {"chemical-science-pack", "production-science-pack", "utility-science-pack"})
|
||||
or origin.name == "rocket-silo")
|
||||
ingredients = allowed_packs
|
||||
self.player = player
|
||||
if origin.name not in world.special_nodes:
|
||||
if military_allowed:
|
||||
ingredients.add("military-science-pack")
|
||||
ingredients = list(ingredients)
|
||||
ingredients.sort() # deterministic sample
|
||||
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)
|
||||
ingredients = set(world.random.sample(list(ingredients), world.random.randint(1, len(ingredients))))
|
||||
self.ingredients = ingredients
|
||||
super(CustomTechnology, self).__init__(origin.name, origin.factorio_id)
|
||||
|
||||
def get_prior_technologies(self) -> Set[Technology]:
|
||||
"""Get Technologies that have to precede this one to resolve tree connections."""
|
||||
technologies = set()
|
||||
for ingredient in self.ingredients:
|
||||
technologies |= required_technologies[ingredient] # technologies that unlock the recipes
|
||||
return technologies
|
||||
|
||||
|
||||
class Recipe(FactorioElement):
|
||||
|
@ -149,19 +149,22 @@ class Recipe(FactorioElement):
|
|||
ingredients = sum(self.ingredients.values())
|
||||
return min(ingredients / amount for product, amount in self.products.items())
|
||||
|
||||
@property
|
||||
@functools.cached_property
|
||||
def base_cost(self) -> Dict[str, int]:
|
||||
ingredients = Counter()
|
||||
for ingredient, cost in self.ingredients.items():
|
||||
if ingredient in all_product_sources:
|
||||
for recipe in all_product_sources[ingredient]:
|
||||
if recipe.ingredients:
|
||||
ingredients.update({name: amount * cost / recipe.products[ingredient] for name, amount in
|
||||
recipe.base_cost.items()})
|
||||
else:
|
||||
ingredients[ingredient] += recipe.energy * cost / recipe.products[ingredient]
|
||||
else:
|
||||
ingredients[ingredient] += cost
|
||||
try:
|
||||
for ingredient, cost in self.ingredients.items():
|
||||
if ingredient in all_product_sources:
|
||||
for recipe in all_product_sources[ingredient]:
|
||||
if recipe.ingredients:
|
||||
ingredients.update({name: amount * cost / recipe.products[ingredient] for name, amount in
|
||||
recipe.base_cost.items()})
|
||||
else:
|
||||
ingredients[ingredient] += recipe.energy * cost / recipe.products[ingredient]
|
||||
else:
|
||||
ingredients[ingredient] += cost
|
||||
except RecursionError as e:
|
||||
raise Exception(f"Infinite recursion in ingredients of {self}.") from e
|
||||
return ingredients
|
||||
|
||||
@property
|
||||
|
@ -191,9 +194,12 @@ recipe_sources: Dict[str, Set[str]] = {} # recipe_name -> technology source
|
|||
|
||||
# recipes and technologies can share names in Factorio
|
||||
for technology_name, data in sorted(techs_future.result().items()):
|
||||
current_ingredients = set(data["ingredients"])
|
||||
technology = Technology(technology_name, current_ingredients, factorio_tech_id,
|
||||
has_modifier=data["has_modifier"], unlocks=set(data["unlocks"]))
|
||||
technology = Technology(
|
||||
technology_name,
|
||||
factorio_tech_id,
|
||||
has_modifier=data["has_modifier"],
|
||||
unlocks=set(data["unlocks"]) - start_unlocked_recipes,
|
||||
)
|
||||
factorio_tech_id += 1
|
||||
tech_table[technology_name] = technology.factorio_id
|
||||
technology_table[technology_name] = technology
|
||||
|
@ -226,11 +232,12 @@ for recipe_name, recipe_data in raw_recipes.items():
|
|||
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 \
|
||||
set(recipe.ingredients)) and ("barrel" not in recipe.products or recipe.name == "barrel") and \
|
||||
not recipe_name.endswith("-reprocessing"):
|
||||
for product_name in recipe.products:
|
||||
all_product_sources.setdefault(product_name, set()).add(recipe)
|
||||
|
||||
assert all(recipe_name in raw_recipes for recipe_name in start_unlocked_recipes), "Unknown Recipe defined."
|
||||
|
||||
machines: Dict[str, Machine] = {}
|
||||
|
||||
|
@ -248,9 +255,7 @@ del machines_future
|
|||
|
||||
# build requirements graph for all technology ingredients
|
||||
|
||||
all_ingredient_names: Set[str] = set()
|
||||
for technology in technology_table.values():
|
||||
all_ingredient_names |= technology.ingredients
|
||||
all_ingredient_names: Set[str] = set(Options.MaxSciencePack.get_ordered_science_packs())
|
||||
|
||||
|
||||
def unlock_just_tech(recipe: Recipe, _done) -> Set[Technology]:
|
||||
|
@ -319,13 +324,17 @@ required_technologies: Dict[str, FrozenSet[Technology]] = Utils.KeyedDefaultDict
|
|||
recursively_get_unlocking_technologies(ingredient_name, unlock_func=unlock)))
|
||||
|
||||
|
||||
def get_rocket_requirements(silo_recipe: Recipe, part_recipe: Recipe, satellite_recipe: Recipe) -> Set[str]:
|
||||
def get_rocket_requirements(silo_recipe: Optional[Recipe], part_recipe: Recipe,
|
||||
satellite_recipe: Optional[Recipe], cargo_landing_pad_recipe: Optional[Recipe]) -> Set[str]:
|
||||
techs = set()
|
||||
if silo_recipe:
|
||||
for ingredient in silo_recipe.ingredients:
|
||||
techs |= recursively_get_unlocking_technologies(ingredient)
|
||||
for ingredient in part_recipe.ingredients:
|
||||
techs |= recursively_get_unlocking_technologies(ingredient)
|
||||
if cargo_landing_pad_recipe:
|
||||
for ingredient in cargo_landing_pad_recipe.ingredients:
|
||||
techs |= recursively_get_unlocking_technologies(ingredient)
|
||||
if satellite_recipe:
|
||||
techs |= satellite_recipe.unlocking_technologies
|
||||
for ingredient in satellite_recipe.ingredients:
|
||||
|
@ -382,15 +391,15 @@ progressive_rows["progressive-processing"] = (
|
|||
"uranium-processing", "kovarex-enrichment-process", "nuclear-fuel-reprocessing")
|
||||
progressive_rows["progressive-rocketry"] = ("rocketry", "explosive-rocketry", "atomic-bomb")
|
||||
progressive_rows["progressive-vehicle"] = ("automobilism", "tank", "spidertron")
|
||||
progressive_rows["progressive-train-network"] = ("railway", "fluid-wagon",
|
||||
"automated-rail-transportation", "rail-signals")
|
||||
progressive_rows["progressive-fluid-handling"] = ("fluid-handling", "fluid-wagon")
|
||||
progressive_rows["progressive-train-network"] = ("railway", "automated-rail-transportation")
|
||||
progressive_rows["progressive-engine"] = ("engine", "electric-engine")
|
||||
progressive_rows["progressive-armor"] = ("heavy-armor", "modular-armor", "power-armor", "power-armor-mk2")
|
||||
progressive_rows["progressive-personal-battery"] = ("battery-equipment", "battery-mk2-equipment")
|
||||
progressive_rows["progressive-energy-shield"] = ("energy-shield-equipment", "energy-shield-mk2-equipment")
|
||||
progressive_rows["progressive-wall"] = ("stone-wall", "gate")
|
||||
progressive_rows["progressive-follower"] = ("defender", "distractor", "destroyer")
|
||||
progressive_rows["progressive-inserter"] = ("fast-inserter", "stack-inserter")
|
||||
progressive_rows["progressive-inserter"] = ("fast-inserter", "bulk-inserter")
|
||||
progressive_rows["progressive-turret"] = ("gun-turret", "laser-turret")
|
||||
progressive_rows["progressive-flamethrower"] = ("flamethrower",) # leaving out flammables, as they do nothing
|
||||
progressive_rows["progressive-personal-roboport-equipment"] = ("personal-roboport-equipment",
|
||||
|
@ -402,7 +411,7 @@ sorted_rows = sorted(progressive_rows)
|
|||
source_target_mapping: Dict[str, str] = {
|
||||
"progressive-braking-force": "progressive-train-network",
|
||||
"progressive-inserter-capacity-bonus": "progressive-inserter",
|
||||
"progressive-refined-flammables": "progressive-flamethrower"
|
||||
"progressive-refined-flammables": "progressive-flamethrower",
|
||||
}
|
||||
|
||||
for source, target in source_target_mapping.items():
|
||||
|
@ -416,12 +425,14 @@ progressive_technology_table: Dict[str, Technology] = {}
|
|||
|
||||
for root in sorted_rows:
|
||||
progressive = progressive_rows[root]
|
||||
assert all(tech in tech_table for tech in progressive), "declared a progressive technology without base technology"
|
||||
assert all(tech in tech_table for tech in progressive), \
|
||||
(f"Declared a progressive technology ({root}) without base technology. "
|
||||
f"Missing: f{tuple(tech for tech in progressive if tech not in tech_table)}")
|
||||
factorio_tech_id += 1
|
||||
progressive_technology = Technology(root, technology_table[progressive[0]].ingredients, factorio_tech_id,
|
||||
progressive,
|
||||
progressive_technology = Technology(root, factorio_tech_id,
|
||||
tuple(progressive),
|
||||
has_modifier=any(technology_table[tech].has_modifier for tech in progressive),
|
||||
unlocks=any(technology_table[tech].unlocks for tech in progressive))
|
||||
unlocks=any(technology_table[tech].unlocks for tech in progressive),)
|
||||
progressive_tech_table[root] = progressive_technology.factorio_id
|
||||
progressive_technology_table[root] = progressive_technology
|
||||
|
||||
|
|
|
@ -2,10 +2,11 @@ from __future__ import annotations
|
|||
|
||||
import collections
|
||||
import logging
|
||||
import settings
|
||||
import typing
|
||||
|
||||
from BaseClasses import Region, Entrance, Location, Item, Tutorial, ItemClassification
|
||||
import Utils
|
||||
import settings
|
||||
from BaseClasses import Region, Location, Item, Tutorial, ItemClassification
|
||||
from worlds.AutoWorld import World, WebWorld
|
||||
from worlds.LauncherComponents import Component, components, Type, launch_subprocess
|
||||
from worlds.generic import Rules
|
||||
|
@ -14,7 +15,7 @@ from .Mod import generate_mod
|
|||
from .Options import FactorioOptions, MaxSciencePack, Silo, Satellite, TechTreeInformation, Goal, TechCostDistribution
|
||||
from .Shapes import get_shapes
|
||||
from .Technologies import base_tech_table, recipe_sources, base_technology_table, \
|
||||
all_ingredient_names, all_product_sources, required_technologies, get_rocket_requirements, \
|
||||
all_product_sources, required_technologies, get_rocket_requirements, \
|
||||
progressive_technology_table, common_tech_table, tech_to_progressive_lookup, progressive_tech_table, \
|
||||
get_science_pack_pools, Recipe, recipes, technology_table, tech_table, factorio_base_id, useless_technologies, \
|
||||
fluids, stacking_items, valid_ingredients, progressive_rows
|
||||
|
@ -97,19 +98,21 @@ class Factorio(World):
|
|||
item_name_groups = {
|
||||
"Progressive": set(progressive_tech_table.keys()),
|
||||
}
|
||||
required_client_version = (0, 5, 0)
|
||||
|
||||
required_client_version = (0, 5, 1)
|
||||
if Utils.version_tuple < required_client_version:
|
||||
raise Exception(f"Update Archipelago to use this world ({game}).")
|
||||
ordered_science_packs: typing.List[str] = MaxSciencePack.get_ordered_science_packs()
|
||||
tech_tree_layout_prerequisites: typing.Dict[FactorioScienceLocation, typing.Set[FactorioScienceLocation]]
|
||||
tech_mix: int = 0
|
||||
skip_silo: bool = False
|
||||
origin_region_name = "Nauvis"
|
||||
science_locations: typing.List[FactorioScienceLocation]
|
||||
|
||||
removed_technologies: typing.Set[str]
|
||||
settings: typing.ClassVar[FactorioSettings]
|
||||
|
||||
def __init__(self, world, player: int):
|
||||
super(Factorio, self).__init__(world, player)
|
||||
self.removed_technologies = useless_technologies.copy()
|
||||
self.advancement_technologies = set()
|
||||
self.custom_recipes = {}
|
||||
self.science_locations = []
|
||||
|
@ -208,11 +211,9 @@ class Factorio(World):
|
|||
for loc in self.science_locations:
|
||||
loc.revealed = True
|
||||
if self.skip_silo:
|
||||
removed = useless_technologies | {"rocket-silo"}
|
||||
else:
|
||||
removed = useless_technologies
|
||||
self.removed_technologies |= {"rocket-silo"}
|
||||
for tech_name in base_tech_table:
|
||||
if tech_name not in removed:
|
||||
if tech_name not in self.removed_technologies:
|
||||
progressive_item_name = tech_to_progressive_lookup.get(tech_name, tech_name)
|
||||
want_progressive = want_progressives[progressive_item_name]
|
||||
item_name = progressive_item_name if want_progressive else tech_name
|
||||
|
@ -240,40 +241,49 @@ class Factorio(World):
|
|||
custom_recipe = self.custom_recipes[ingredient]
|
||||
|
||||
location.access_rule = lambda state, ingredient=ingredient, custom_recipe=custom_recipe: \
|
||||
(ingredient not in technology_table or state.has(ingredient, player)) and \
|
||||
(not technology_table[ingredient].unlocks or state.has(ingredient, player)) and \
|
||||
all(state.has(technology.name, player) for sub_ingredient in custom_recipe.ingredients
|
||||
for technology in required_technologies[sub_ingredient]) and \
|
||||
all(state.has(technology.name, player) for technology in required_technologies[custom_recipe.crafting_machine])
|
||||
|
||||
else:
|
||||
location.access_rule = lambda state, ingredient=ingredient: \
|
||||
all(state.has(technology.name, player) for technology in required_technologies[ingredient])
|
||||
|
||||
for location in self.science_locations:
|
||||
Rules.set_rule(location, lambda state, ingredients=location.ingredients:
|
||||
Rules.set_rule(location, lambda state, ingredients=frozenset(location.ingredients):
|
||||
all(state.has(f"Automated {ingredient}", player) for ingredient in ingredients))
|
||||
prerequisites = shapes.get(location)
|
||||
if prerequisites:
|
||||
Rules.add_rule(location, lambda state, locations=
|
||||
prerequisites: all(state.can_reach(loc) for loc in locations))
|
||||
Rules.add_rule(location, lambda state, locations=frozenset(prerequisites):
|
||||
all(state.can_reach(loc) for loc in locations))
|
||||
|
||||
silo_recipe = None
|
||||
cargo_pad_recipe = None
|
||||
if self.options.silo == Silo.option_spawn:
|
||||
silo_recipe = self.custom_recipes["rocket-silo"] if "rocket-silo" in self.custom_recipes \
|
||||
else next(iter(all_product_sources.get("rocket-silo")))
|
||||
silo_recipe = self.get_recipe("rocket-silo")
|
||||
cargo_pad_recipe = self.get_recipe("cargo-landing-pad")
|
||||
part_recipe = self.custom_recipes["rocket-part"]
|
||||
satellite_recipe = None
|
||||
if self.options.goal == Goal.option_satellite:
|
||||
satellite_recipe = self.custom_recipes["satellite"] if "satellite" in self.custom_recipes \
|
||||
else next(iter(all_product_sources.get("satellite")))
|
||||
victory_tech_names = get_rocket_requirements(silo_recipe, part_recipe, satellite_recipe)
|
||||
if self.options.silo != Silo.option_spawn:
|
||||
victory_tech_names.add("rocket-silo")
|
||||
satellite_recipe = self.get_recipe("satellite")
|
||||
victory_tech_names = get_rocket_requirements(silo_recipe, part_recipe, satellite_recipe, cargo_pad_recipe)
|
||||
if self.options.silo == Silo.option_spawn:
|
||||
victory_tech_names -= {"rocket-silo"}
|
||||
else:
|
||||
victory_tech_names |= {"rocket-silo"}
|
||||
self.get_location("Rocket Launch").access_rule = lambda state: all(state.has(technology, player)
|
||||
for technology in
|
||||
victory_tech_names)
|
||||
|
||||
for tech_name in victory_tech_names:
|
||||
if not self.multiworld.get_all_state(True).has(tech_name, player):
|
||||
print(tech_name)
|
||||
self.multiworld.completion_condition[player] = lambda state: state.has('Victory', player)
|
||||
|
||||
def get_recipe(self, name: str) -> Recipe:
|
||||
return self.custom_recipes[name] if name in self.custom_recipes \
|
||||
else next(iter(all_product_sources.get(name)))
|
||||
|
||||
def generate_basic(self):
|
||||
map_basic_settings = self.options.world_gen.value["basic"]
|
||||
if map_basic_settings.get("seed", None) is None: # allow seed 0
|
||||
|
@ -321,9 +331,11 @@ class Factorio(World):
|
|||
|
||||
def make_quick_recipe(self, original: Recipe, pool: list, allow_liquids: int = 2,
|
||||
ingredients_offset: int = 0) -> Recipe:
|
||||
count: int = len(original.ingredients) + ingredients_offset
|
||||
assert len(pool) >= count, f"Can't pick {count} many items from pool {pool}."
|
||||
new_ingredients = {}
|
||||
liquids_used = 0
|
||||
for _ in range(len(original.ingredients) + ingredients_offset):
|
||||
for _ in range(count):
|
||||
new_ingredient = pool.pop()
|
||||
if new_ingredient in fluids:
|
||||
while liquids_used == allow_liquids and new_ingredient in fluids:
|
||||
|
@ -440,7 +452,8 @@ class Factorio(World):
|
|||
ingredients_offset = self.options.recipe_ingredients_offset
|
||||
original_rocket_part = recipes["rocket-part"]
|
||||
science_pack_pools = get_science_pack_pools()
|
||||
valid_pool = sorted(science_pack_pools[self.options.max_science_pack.get_max_pack()] & valid_ingredients)
|
||||
valid_pool = sorted(science_pack_pools[self.options.max_science_pack.get_max_pack()]
|
||||
& valid_ingredients)
|
||||
self.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 + ingredients_offset)},
|
||||
|
@ -489,7 +502,7 @@ class Factorio(World):
|
|||
|
||||
needed_recipes = self.options.max_science_pack.get_allowed_packs() | {"rocket-part"}
|
||||
if self.options.silo != Silo.option_spawn:
|
||||
needed_recipes |= {"rocket-silo"}
|
||||
needed_recipes |= {"rocket-silo", "cargo-landing-pad"}
|
||||
if self.options.goal.value == Goal.option_satellite:
|
||||
needed_recipes |= {"satellite"}
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
["fluid-unknown","water","crude-oil","steam","heavy-oil","light-oil","petroleum-gas","sulfuric-acid","lubricant"]
|
||||
["water","steam","crude-oil","petroleum-gas","light-oil","heavy-oil","lubricant","sulfuric-acid","parameter-0","parameter-1","parameter-2","parameter-3","parameter-4","parameter-5","parameter-6","parameter-7","parameter-8","parameter-9","fluid-unknown"]
|
File diff suppressed because one or more lines are too long
|
@ -1 +1 @@
|
|||
{"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}}
|
||||
{"stone-furnace":{"smelting":true},"steel-furnace":{"smelting":true},"electric-furnace":{"smelting":true},"assembling-machine-1":{"crafting":true,"basic-crafting":true,"advanced-crafting":true,"parameters":true},"assembling-machine-2":{"basic-crafting":true,"crafting":true,"advanced-crafting":true,"crafting-with-fluid":true,"parameters":true},"assembling-machine-3":{"basic-crafting":true,"crafting":true,"advanced-crafting":true,"crafting-with-fluid":true,"parameters":true},"oil-refinery":{"oil-processing":true,"parameters":true},"chemical-plant":{"chemistry":true,"parameters":true},"centrifuge":{"centrifuging":true,"parameters":true},"rocket-silo":{"rocket-building":true,"parameters":true},"character":{"crafting":true}}
|
|
@ -1,9 +1,9 @@
|
|||
function get_any_stack_size(name)
|
||||
local item = game.item_prototypes[name]
|
||||
local item = prototypes.item[name]
|
||||
if item ~= nil then
|
||||
return item.stack_size
|
||||
end
|
||||
item = game.equipment_prototypes[name]
|
||||
item = prototypes.equipment[name]
|
||||
if item ~= nil then
|
||||
return item.stack_size
|
||||
end
|
||||
|
@ -24,7 +24,7 @@ function split(s, sep)
|
|||
end
|
||||
|
||||
function random_offset_position(position, offset)
|
||||
return {x=position.x+math.random(-offset, offset), y=position.y+math.random(-1024, 1024)}
|
||||
return {x=position.x+math.random(-offset, offset), y=position.y+math.random(-offset, offset)}
|
||||
end
|
||||
|
||||
function fire_entity_at_players(entity_name, speed)
|
||||
|
@ -36,4 +36,4 @@ function fire_entity_at_players(entity_name, speed)
|
|||
target=current_character, speed=speed}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -143,24 +143,24 @@ function on_check_energy_link(event)
|
|||
local force = "player"
|
||||
local bridges = surface.find_entities_filtered({name="ap-energy-bridge", force=force})
|
||||
local bridgecount = table_size(bridges)
|
||||
global.forcedata[force].energy_bridges = bridgecount
|
||||
if global.forcedata[force].energy == nil then
|
||||
global.forcedata[force].energy = 0
|
||||
storage.forcedata[force].energy_bridges = bridgecount
|
||||
if storage.forcedata[force].energy == nil then
|
||||
storage.forcedata[force].energy = 0
|
||||
end
|
||||
if global.forcedata[force].energy < ENERGY_INCREMENT * bridgecount * 5 then
|
||||
if storage.forcedata[force].energy < ENERGY_INCREMENT * bridgecount * 5 then
|
||||
for i, bridge in ipairs(bridges) do
|
||||
if bridge.energy > ENERGY_INCREMENT*3 then
|
||||
global.forcedata[force].energy = global.forcedata[force].energy + (ENERGY_INCREMENT * ENERGY_LINK_EFFICIENCY)
|
||||
storage.forcedata[force].energy = storage.forcedata[force].energy + (ENERGY_INCREMENT * ENERGY_LINK_EFFICIENCY)
|
||||
bridge.energy = bridge.energy - ENERGY_INCREMENT
|
||||
end
|
||||
end
|
||||
end
|
||||
for i, bridge in ipairs(bridges) do
|
||||
if global.forcedata[force].energy < ENERGY_INCREMENT then
|
||||
if storage.forcedata[force].energy < ENERGY_INCREMENT then
|
||||
break
|
||||
end
|
||||
if bridge.energy < ENERGY_INCREMENT*2 and global.forcedata[force].energy > ENERGY_INCREMENT then
|
||||
global.forcedata[force].energy = global.forcedata[force].energy - ENERGY_INCREMENT
|
||||
if bridge.energy < ENERGY_INCREMENT*2 and storage.forcedata[force].energy > ENERGY_INCREMENT then
|
||||
storage.forcedata[force].energy = storage.forcedata[force].energy - ENERGY_INCREMENT
|
||||
bridge.energy = bridge.energy + ENERGY_INCREMENT
|
||||
end
|
||||
end
|
||||
|
@ -186,23 +186,41 @@ function check_spawn_silo(force)
|
|||
local surface = game.get_surface(1)
|
||||
local spawn_position = force.get_spawn_position(surface)
|
||||
spawn_entity(surface, force, "rocket-silo", spawn_position.x, spawn_position.y, 80, true, true)
|
||||
spawn_entity(surface, force, "cargo-landing-pad", spawn_position.x, spawn_position.y, 80, true, true)
|
||||
end
|
||||
end
|
||||
|
||||
function check_despawn_silo(force)
|
||||
if not force.players or #force.players < 1 and force.get_entity_count("rocket-silo") > 0 then
|
||||
local surface = game.get_surface(1)
|
||||
local spawn_position = force.get_spawn_position(surface)
|
||||
local x1 = spawn_position.x - 41
|
||||
local x2 = spawn_position.x + 41
|
||||
local y1 = spawn_position.y - 41
|
||||
local y2 = spawn_position.y + 41
|
||||
local silos = surface.find_entities_filtered{area = { {x1, y1}, {x2, y2} },
|
||||
name = "rocket-silo",
|
||||
force = force}
|
||||
for i,silo in ipairs(silos) do
|
||||
silo.destructible = true
|
||||
silo.destroy()
|
||||
if not force.players or #force.players < 1 then
|
||||
if force.get_entity_count("rocket-silo") > 0 then
|
||||
local surface = game.get_surface(1)
|
||||
local spawn_position = force.get_spawn_position(surface)
|
||||
local x1 = spawn_position.x - 41
|
||||
local x2 = spawn_position.x + 41
|
||||
local y1 = spawn_position.y - 41
|
||||
local y2 = spawn_position.y + 41
|
||||
local silos = surface.find_entities_filtered{area = { {x1, y1}, {x2, y2} },
|
||||
name = "rocket-silo",
|
||||
force = force}
|
||||
for i, silo in ipairs(silos) do
|
||||
silo.destructible = true
|
||||
silo.destroy()
|
||||
end
|
||||
end
|
||||
if force.get_entity_count("cargo-landing-pad") > 0 then
|
||||
local surface = game.get_surface(1)
|
||||
local spawn_position = force.get_spawn_position(surface)
|
||||
local x1 = spawn_position.x - 41
|
||||
local x2 = spawn_position.x + 41
|
||||
local y1 = spawn_position.y - 41
|
||||
local y2 = spawn_position.y + 41
|
||||
local pads = surface.find_entities_filtered{area = { {x1, y1}, {x2, y2} },
|
||||
name = "cargo-landing-pad",
|
||||
force = force}
|
||||
for i, pad in ipairs(pads) do
|
||||
pad.destructible = true
|
||||
pad.destroy()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -214,19 +232,18 @@ function on_force_created(event)
|
|||
if type(event.force) == "string" then -- should be of type LuaForce
|
||||
force = game.forces[force]
|
||||
end
|
||||
force.research_queue_enabled = true
|
||||
local data = {}
|
||||
data['earned_samples'] = {{ dict_to_lua(starting_items) }}
|
||||
data["victory"] = 0
|
||||
data["death_link_tick"] = 0
|
||||
data["energy"] = 0
|
||||
data["energy_bridges"] = 0
|
||||
global.forcedata[event.force] = data
|
||||
storage.forcedata[event.force] = data
|
||||
{%- if silo == 2 %}
|
||||
check_spawn_silo(force)
|
||||
{%- endif %}
|
||||
{%- for tech_name in useless_technologies %}
|
||||
force.technologies.{{ tech_name }}.researched = true
|
||||
{%- for tech_name in removed_technologies %}
|
||||
force.technologies["{{ tech_name }}"].researched = true
|
||||
{%- endfor %}
|
||||
end
|
||||
script.on_event(defines.events.on_force_created, on_force_created)
|
||||
|
@ -236,7 +253,7 @@ function on_force_destroyed(event)
|
|||
{%- if silo == 2 %}
|
||||
check_despawn_silo(event.force)
|
||||
{%- endif %}
|
||||
global.forcedata[event.force.name] = nil
|
||||
storage.forcedata[event.force.name] = nil
|
||||
end
|
||||
|
||||
function on_runtime_mod_setting_changed(event)
|
||||
|
@ -267,8 +284,8 @@ function on_player_created(event)
|
|||
-- FIXME: This (probably) fires before any other mod has a chance to change the player's force
|
||||
-- For now, they will (probably) always be on the 'player' force when this event fires.
|
||||
local data = {}
|
||||
data['pending_samples'] = table.deepcopy(global.forcedata[player.force.name]['earned_samples'])
|
||||
global.playerdata[player.index] = data
|
||||
data['pending_samples'] = table.deepcopy(storage.forcedata[player.force.name]['earned_samples'])
|
||||
storage.playerdata[player.index] = data
|
||||
update_player(player.index) -- Attempt to send pending free samples, if relevant.
|
||||
{%- if silo == 2 %}
|
||||
check_spawn_silo(game.players[event.player_index].force)
|
||||
|
@ -287,14 +304,14 @@ end
|
|||
script.on_event(defines.events.on_player_changed_force, on_player_changed_force)
|
||||
|
||||
function on_player_removed(event)
|
||||
global.playerdata[event.player_index] = nil
|
||||
storage.playerdata[event.player_index] = nil
|
||||
end
|
||||
script.on_event(defines.events.on_player_removed, on_player_removed)
|
||||
|
||||
function on_rocket_launched(event)
|
||||
if event.rocket and event.rocket.valid and global.forcedata[event.rocket.force.name]['victory'] == 0 then
|
||||
if event.rocket and event.rocket.valid and storage.forcedata[event.rocket.force.name]['victory'] == 0 then
|
||||
if event.rocket.get_item_count("satellite") > 0 or GOAL == 0 then
|
||||
global.forcedata[event.rocket.force.name]['victory'] = 1
|
||||
storage.forcedata[event.rocket.force.name]['victory'] = 1
|
||||
dumpInfo(event.rocket.force)
|
||||
game.set_game_state
|
||||
{
|
||||
|
@ -318,7 +335,7 @@ function update_player(index)
|
|||
if not character or not character.valid then
|
||||
return
|
||||
end
|
||||
local data = global.playerdata[index]
|
||||
local data = storage.playerdata[index]
|
||||
local samples = data['pending_samples']
|
||||
local sent
|
||||
--player.print(serpent.block(data['pending_samples']))
|
||||
|
@ -327,14 +344,17 @@ function update_player(index)
|
|||
for name, count in pairs(samples) do
|
||||
stack.name = name
|
||||
stack.count = count
|
||||
if game.item_prototypes[name] then
|
||||
if script.active_mods["quality"] then
|
||||
stack.quality = "{{ free_sample_quality_name }}"
|
||||
end
|
||||
if prototypes.item[name] then
|
||||
if character.can_insert(stack) then
|
||||
sent = character.insert(stack)
|
||||
else
|
||||
sent = 0
|
||||
end
|
||||
if sent > 0 then
|
||||
player.print("Received " .. sent .. "x [item=" .. name .. "]")
|
||||
player.print("Received " .. sent .. "x [item=" .. name .. ",quality={{ free_sample_quality_name }}]")
|
||||
data.suppress_full_inventory_message = false
|
||||
end
|
||||
if sent ~= count then -- Couldn't full send.
|
||||
|
@ -372,19 +392,19 @@ function add_samples(force, name, count)
|
|||
end
|
||||
t[name] = (t[name] or 0) + count
|
||||
end
|
||||
-- Add to global table of earned samples for future new players
|
||||
add_to_table(global.forcedata[force.name]['earned_samples'])
|
||||
-- Add to storage table of earned samples for future new players
|
||||
add_to_table(storage.forcedata[force.name]['earned_samples'])
|
||||
-- Add to existing players
|
||||
for _, player in pairs(force.players) do
|
||||
add_to_table(global.playerdata[player.index]['pending_samples'])
|
||||
add_to_table(storage.playerdata[player.index]['pending_samples'])
|
||||
update_player(player.index)
|
||||
end
|
||||
end
|
||||
|
||||
script.on_init(function()
|
||||
{% if not imported_blueprints %}set_permissions(){% endif %}
|
||||
global.forcedata = {}
|
||||
global.playerdata = {}
|
||||
storage.forcedata = {}
|
||||
storage.playerdata = {}
|
||||
-- Fire dummy events for all currently existing forces.
|
||||
local e = {}
|
||||
for name, _ in pairs(game.forces) do
|
||||
|
@ -420,12 +440,12 @@ script.on_event(defines.events.on_research_finished, function(event)
|
|||
if FREE_SAMPLES == 0 then
|
||||
return -- Nothing else to do
|
||||
end
|
||||
if not technology.effects then
|
||||
if not technology.prototype.effects then
|
||||
return -- No technology effects, so nothing to do.
|
||||
end
|
||||
for _, effect in pairs(technology.effects) do
|
||||
for _, effect in pairs(technology.prototype.effects) do
|
||||
if effect.type == "unlock-recipe" then
|
||||
local recipe = game.recipe_prototypes[effect.recipe]
|
||||
local recipe = prototypes.recipe[effect.recipe]
|
||||
for _, result in pairs(recipe.products) do
|
||||
if result.type == "item" and result.amount then
|
||||
local name = result.name
|
||||
|
@ -477,7 +497,7 @@ function kill_players(force)
|
|||
end
|
||||
|
||||
function spawn_entity(surface, force, name, x, y, radius, randomize, avoid_ores)
|
||||
local prototype = game.entity_prototypes[name]
|
||||
local prototype = prototypes.entity[name]
|
||||
local args = { -- For can_place_entity and place_entity
|
||||
name = prototype.name,
|
||||
position = {x = x, y = y},
|
||||
|
@ -537,7 +557,7 @@ function spawn_entity(surface, force, name, x, y, radius, randomize, avoid_ores)
|
|||
}
|
||||
local entities = surface.find_entities_filtered {
|
||||
area = collision_area,
|
||||
collision_mask = prototype.collision_mask
|
||||
collision_mask = prototype.collision_mask.layers
|
||||
}
|
||||
local can_place = true
|
||||
for _, entity in pairs(entities) do
|
||||
|
@ -560,6 +580,9 @@ function spawn_entity(surface, force, name, x, y, radius, randomize, avoid_ores)
|
|||
end
|
||||
args.build_check_type = defines.build_check_type.script
|
||||
args.create_build_effect_smoke = false
|
||||
if script.active_mods["quality"] then
|
||||
args.quality = "{{ free_sample_quality_name }}"
|
||||
end
|
||||
new_entity = surface.create_entity(args)
|
||||
if new_entity then
|
||||
new_entity.destructible = false
|
||||
|
@ -585,7 +608,7 @@ script.on_event(defines.events.on_entity_died, function(event)
|
|||
end
|
||||
|
||||
local force = event.entity.force
|
||||
global.forcedata[force.name].death_link_tick = game.tick
|
||||
storage.forcedata[force.name].death_link_tick = game.tick
|
||||
dumpInfo(force)
|
||||
kill_players(force)
|
||||
end, {LuaEntityDiedEventFilter = {["filter"] = "name", ["name"] = "character"}})
|
||||
|
@ -600,7 +623,7 @@ commands.add_command("ap-sync", "Used by the Archipelago client to get progress
|
|||
force = game.players[call.player_index].force
|
||||
end
|
||||
local research_done = {}
|
||||
local forcedata = chain_lookup(global, "forcedata", force.name)
|
||||
local forcedata = chain_lookup(storage, "forcedata", force.name)
|
||||
local data_collection = {
|
||||
["research_done"] = research_done,
|
||||
["victory"] = chain_lookup(forcedata, "victory"),
|
||||
|
@ -616,7 +639,7 @@ commands.add_command("ap-sync", "Used by the Archipelago client to get progress
|
|||
research_done[tech_name] = tech.researched
|
||||
end
|
||||
end
|
||||
rcon.print(game.table_to_json({["slot_name"] = SLOT_NAME, ["seed_name"] = SEED_NAME, ["info"] = data_collection}))
|
||||
rcon.print(helpers.table_to_json({["slot_name"] = SLOT_NAME, ["seed_name"] = SEED_NAME, ["info"] = data_collection}))
|
||||
end)
|
||||
|
||||
commands.add_command("ap-print", "Used by the Archipelago client to print messages", function (call)
|
||||
|
@ -655,8 +678,8 @@ end,
|
|||
}
|
||||
|
||||
commands.add_command("ap-get-technology", "Grant a technology, used by the Archipelago Client.", function(call)
|
||||
if global.index_sync == nil then
|
||||
global.index_sync = {}
|
||||
if storage.index_sync == nil then
|
||||
storage.index_sync = {}
|
||||
end
|
||||
local tech
|
||||
local force = game.forces["player"]
|
||||
|
@ -680,8 +703,8 @@ commands.add_command("ap-get-technology", "Grant a technology, used by the Archi
|
|||
end
|
||||
return
|
||||
elseif progressive_technologies[item_name] ~= nil then
|
||||
if global.index_sync[index] ~= item_name then -- not yet received prog item
|
||||
global.index_sync[index] = item_name
|
||||
if storage.index_sync[index] ~= item_name then -- not yet received prog item
|
||||
storage.index_sync[index] = item_name
|
||||
local tech_stack = progressive_technologies[item_name]
|
||||
for _, item_name in ipairs(tech_stack) do
|
||||
tech = force.technologies[item_name]
|
||||
|
@ -696,7 +719,7 @@ commands.add_command("ap-get-technology", "Grant a technology, used by the Archi
|
|||
elseif force.technologies[item_name] ~= nil then
|
||||
tech = force.technologies[item_name]
|
||||
if tech ~= nil then
|
||||
global.index_sync[index] = tech
|
||||
storage.index_sync[index] = tech
|
||||
if tech.researched ~= true then
|
||||
game.print({"", "Received [technology=" .. tech.name .. "] from ", source})
|
||||
game.play_sound({path="utility/research_completed"})
|
||||
|
@ -704,8 +727,8 @@ commands.add_command("ap-get-technology", "Grant a technology, used by the Archi
|
|||
end
|
||||
end
|
||||
elseif TRAP_TABLE[item_name] ~= nil then
|
||||
if global.index_sync[index] ~= item_name then -- not yet received trap
|
||||
global.index_sync[index] = item_name
|
||||
if storage.index_sync[index] ~= item_name then -- not yet received trap
|
||||
storage.index_sync[index] = item_name
|
||||
game.print({"", "Received ", item_name, " from ", source})
|
||||
TRAP_TABLE[item_name]()
|
||||
end
|
||||
|
@ -716,7 +739,7 @@ end)
|
|||
|
||||
|
||||
commands.add_command("ap-rcon-info", "Used by the Archipelago client to get information", function(call)
|
||||
rcon.print(game.table_to_json({
|
||||
rcon.print(helpers.table_to_json({
|
||||
["slot_name"] = SLOT_NAME,
|
||||
["seed_name"] = SEED_NAME,
|
||||
["death_link"] = DEATH_LINK,
|
||||
|
@ -726,7 +749,7 @@ end)
|
|||
|
||||
|
||||
{% if allow_cheats -%}
|
||||
commands.add_command("ap-spawn-silo", "Attempts to spawn a silo around 0,0", function(call)
|
||||
commands.add_command("ap-spawn-silo", "Attempts to spawn a silo and cargo landing pad around 0,0", function(call)
|
||||
spawn_entity(game.player.surface, game.player.force, "rocket-silo", 0, 0, 80, true, true)
|
||||
end)
|
||||
{% endif -%}
|
||||
|
@ -742,7 +765,7 @@ end)
|
|||
commands.add_command("ap-energylink", "Used by the Archipelago client to manage Energy Link", function(call)
|
||||
local change = tonumber(call.parameter or "0")
|
||||
local force = "player"
|
||||
global.forcedata[force].energy = global.forcedata[force].energy + change
|
||||
storage.forcedata[force].energy = storage.forcedata[force].energy + change
|
||||
end)
|
||||
|
||||
commands.add_command("energy-link", "Print the status of the Archipelago energy link.", function(call)
|
||||
|
|
|
@ -6,43 +6,46 @@ data.raw["rocket-silo"]["rocket-silo"].fluid_boxes = {
|
|||
production_type = "input",
|
||||
pipe_picture = assembler2pipepictures(),
|
||||
pipe_covers = pipecoverspictures(),
|
||||
volume = 1000,
|
||||
base_area = 10,
|
||||
base_level = -1,
|
||||
pipe_connections = {
|
||||
{ type = "input", position = { 0, 5 } },
|
||||
{ type = "input", position = { 0, -5 } },
|
||||
{ type = "input", position = { 5, 0 } },
|
||||
{ type = "input", position = { -5, 0 } }
|
||||
{ flow_direction = "input", direction = defines.direction.south, position = { 0, 4.2 } },
|
||||
{ flow_direction = "input", direction = defines.direction.north, position = { 0, -4.2 } },
|
||||
{ flow_direction = "input", direction = defines.direction.east, position = { 4.2, 0 } },
|
||||
{ flow_direction = "input", direction = defines.direction.west, position = { -4.2, 0 } }
|
||||
}
|
||||
},
|
||||
{
|
||||
production_type = "input",
|
||||
pipe_picture = assembler2pipepictures(),
|
||||
pipe_covers = pipecoverspictures(),
|
||||
volume = 1000,
|
||||
base_area = 10,
|
||||
base_level = -1,
|
||||
pipe_connections = {
|
||||
{ type = "input", position = { -3, 5 } },
|
||||
{ type = "input", position = { -3, -5 } },
|
||||
{ type = "input", position = { 5, -3 } },
|
||||
{ type = "input", position = { -5, -3 } }
|
||||
{ flow_direction = "input", direction = defines.direction.south, position = { -3, 4.2 } },
|
||||
{ flow_direction = "input", direction = defines.direction.north, position = { -3, -4.2 } },
|
||||
{ flow_direction = "input", direction = defines.direction.east, position = { 4.2, -3 } },
|
||||
{ flow_direction = "input", direction = defines.direction.west, position = { -4.2, -3 } }
|
||||
}
|
||||
},
|
||||
{
|
||||
production_type = "input",
|
||||
pipe_picture = assembler2pipepictures(),
|
||||
pipe_covers = pipecoverspictures(),
|
||||
volume = 1000,
|
||||
base_area = 10,
|
||||
base_level = -1,
|
||||
pipe_connections = {
|
||||
{ type = "input", position = { 3, 5 } },
|
||||
{ type = "input", position = { 3, -5 } },
|
||||
{ type = "input", position = { 5, 3 } },
|
||||
{ type = "input", position = { -5, 3 } }
|
||||
{ flow_direction = "input", direction = defines.direction.south, position = { 3, 4.2 } },
|
||||
{ flow_direction = "input", direction = defines.direction.north, position = { 3, -4.2 } },
|
||||
{ flow_direction = "input", direction = defines.direction.east, position = { 4.2, 3 } },
|
||||
{ flow_direction = "input", direction = defines.direction.west, position = { -4.2, 3 } }
|
||||
}
|
||||
},
|
||||
off_when_no_fluid_recipe = true
|
||||
}
|
||||
}
|
||||
data.raw["rocket-silo"]["rocket-silo"].fluid_boxes_off_when_no_fluid_recipe = true
|
||||
|
||||
{%- for recipe_name, recipe in custom_recipes.items() %}
|
||||
data.raw["recipe"]["{{recipe_name}}"].category = "{{recipe.category}}"
|
||||
|
|
|
@ -18,12 +18,9 @@ energy_bridge.energy_source.buffer_capacity = "50MJ"
|
|||
energy_bridge.energy_source.input_flow_limit = "10MW"
|
||||
energy_bridge.energy_source.output_flow_limit = "10MW"
|
||||
tint_icon(energy_bridge, energy_bridge_tint())
|
||||
energy_bridge.picture.layers[1].tint = energy_bridge_tint()
|
||||
energy_bridge.picture.layers[1].hr_version.tint = energy_bridge_tint()
|
||||
energy_bridge.charge_animation.layers[1].layers[1].tint = energy_bridge_tint()
|
||||
energy_bridge.charge_animation.layers[1].layers[1].hr_version.tint = energy_bridge_tint()
|
||||
energy_bridge.discharge_animation.layers[1].layers[1].tint = energy_bridge_tint()
|
||||
energy_bridge.discharge_animation.layers[1].layers[1].hr_version.tint = energy_bridge_tint()
|
||||
energy_bridge.chargable_graphics.picture.layers[1].tint = energy_bridge_tint()
|
||||
energy_bridge.chargable_graphics.charge_animation.layers[1].layers[1].tint = energy_bridge_tint()
|
||||
energy_bridge.chargable_graphics.discharge_animation.layers[1].layers[1].tint = energy_bridge_tint()
|
||||
data.raw["accumulator"]["ap-energy-bridge"] = energy_bridge
|
||||
|
||||
local energy_bridge_item = table.deepcopy(data.raw["item"]["accumulator"])
|
||||
|
@ -35,9 +32,9 @@ data.raw["item"]["ap-energy-bridge"] = energy_bridge_item
|
|||
|
||||
local energy_bridge_recipe = table.deepcopy(data.raw["recipe"]["accumulator"])
|
||||
energy_bridge_recipe.name = "ap-energy-bridge"
|
||||
energy_bridge_recipe.result = energy_bridge_item.name
|
||||
energy_bridge_recipe.results = { {type = "item", name = energy_bridge_item.name, amount = 1} }
|
||||
energy_bridge_recipe.energy_required = 1
|
||||
energy_bridge_recipe.enabled = {{ energy_link }}
|
||||
energy_bridge_recipe.enabled = {% if energy_link %}true{% else %}false{% endif %}
|
||||
energy_bridge_recipe.localised_name = "Archipelago EnergyLink Bridge"
|
||||
data.raw["recipe"]["ap-energy-bridge"] = energy_bridge_recipe
|
||||
|
||||
|
|
|
@ -26,4 +26,4 @@
|
|||
{type = {% if key in liquids %}"fluid"{% else %}"item"{% endif %}, name = "{{ key }}", amount = {{ value | safe }}}{% if not loop.last %},{% endif %}
|
||||
{% endfor -%}
|
||||
}
|
||||
{%- endmacro %}
|
||||
{%- endmacro %}
|
||||
|
|
|
@ -27,4 +27,4 @@ data:extend({
|
|||
default_value = false
|
||||
{% endif %}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1 +1 @@
|
|||
{"iron-ore":{"minable":true,"infinite":false,"category":"basic-solid","mining_time":1,"products":{"iron-ore":{"name":"iron-ore","amount":1}}},"copper-ore":{"minable":true,"infinite":false,"category":"basic-solid","mining_time":1,"products":{"copper-ore":{"name":"copper-ore","amount":1}}},"stone":{"minable":true,"infinite":false,"category":"basic-solid","mining_time":1,"products":{"stone":{"name":"stone","amount":1}}},"coal":{"minable":true,"infinite":false,"category":"basic-solid","mining_time":1,"products":{"coal":{"name":"coal","amount":1}}},"uranium-ore":{"minable":true,"infinite":false,"category":"basic-solid","mining_time":2,"required_fluid":"sulfuric-acid","fluid_amount":10,"products":{"uranium-ore":{"name":"uranium-ore","amount":1}}},"crude-oil":{"minable":true,"infinite":true,"infinite_depletion":10,"category":"basic-fluid","mining_time":1,"products":{"crude-oil":{"name":"crude-oil","amount":10}}}}
|
||||
{"iron-ore":{"minable":true,"infinite":false,"category":"basic-solid","mining_time":1,"products":{"iron-ore":{"name":"iron-ore","amount":1}}},"copper-ore":{"minable":true,"infinite":false,"category":"basic-solid","mining_time":1,"products":{"copper-ore":{"name":"copper-ore","amount":1}}},"stone":{"minable":true,"infinite":false,"category":"basic-solid","mining_time":1,"products":{"stone":{"name":"stone","amount":1}}},"coal":{"minable":true,"infinite":false,"category":"basic-solid","mining_time":1,"products":{"coal":{"name":"coal","amount":1}}},"crude-oil":{"minable":true,"infinite":true,"infinite_depletion":10,"category":"basic-fluid","mining_time":1,"products":{"crude-oil":{"name":"crude-oil","amount":10}}},"uranium-ore":{"minable":true,"infinite":false,"category":"basic-solid","mining_time":2,"required_fluid":"sulfuric-acid","fluid_amount":10,"products":{"uranium-ore":{"name":"uranium-ore","amount":1}}}}
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue