Factorio: add Traps
This commit is contained in:
parent
16701249b4
commit
9408557f03
|
@ -16,9 +16,9 @@ from MultiServer import mark_raw
|
||||||
|
|
||||||
import Utils
|
import Utils
|
||||||
import random
|
import random
|
||||||
from NetUtils import RawJSONtoTextParser, NetworkItem, ClientStatus, JSONtoTextParser, JSONMessagePart
|
from NetUtils import NetworkItem, ClientStatus, JSONtoTextParser, JSONMessagePart
|
||||||
|
|
||||||
from worlds.factorio.Technologies import lookup_id_to_name
|
from worlds.factorio import Factorio
|
||||||
|
|
||||||
os.makedirs("logs", exist_ok=True)
|
os.makedirs("logs", exist_ok=True)
|
||||||
|
|
||||||
|
@ -196,10 +196,10 @@ async def factorio_server_watcher(ctx: FactorioContext):
|
||||||
transfer_item: NetworkItem = ctx.items_received[ctx.send_index]
|
transfer_item: NetworkItem = ctx.items_received[ctx.send_index]
|
||||||
item_id = transfer_item.item
|
item_id = transfer_item.item
|
||||||
player_name = ctx.player_names[transfer_item.player]
|
player_name = ctx.player_names[transfer_item.player]
|
||||||
if item_id not in lookup_id_to_name:
|
if item_id not in Factorio.item_id_to_name:
|
||||||
logging.error(f"Cannot send unknown item ID: {item_id}")
|
factorio_server_logger.error(f"Cannot send unknown item ID: {item_id}")
|
||||||
else:
|
else:
|
||||||
item_name = lookup_id_to_name[item_id]
|
item_name = Factorio.item_id_to_name[item_id]
|
||||||
factorio_server_logger.info(f"Sending {item_name} to Nauvis from {player_name}.")
|
factorio_server_logger.info(f"Sending {item_name} to Nauvis from {player_name}.")
|
||||||
ctx.rcon_client.send_command(f'/ap-get-technology {item_name}\t{ctx.send_index}\t{player_name}')
|
ctx.rcon_client.send_command(f'/ap-get-technology {item_name}\t{ctx.send_index}\t{player_name}')
|
||||||
ctx.send_index += 1
|
ctx.send_index += 1
|
||||||
|
|
|
@ -117,6 +117,40 @@ Factorio:
|
||||||
starting_items:
|
starting_items:
|
||||||
burner-mining-drill: 19
|
burner-mining-drill: 19
|
||||||
stone-furnace: 19
|
stone-furnace: 19
|
||||||
|
# Note: Total amount of traps cannot exceed 4, if the sum of them is higher it will get automatically capped.
|
||||||
|
evolution_traps:
|
||||||
|
# Trap items that when received increase the enemy evolution.
|
||||||
|
0: 1
|
||||||
|
1: 0
|
||||||
|
2: 0
|
||||||
|
3: 0
|
||||||
|
4: 0
|
||||||
|
random: 0
|
||||||
|
random-low: 0
|
||||||
|
random-middle: 0
|
||||||
|
random-high: 0
|
||||||
|
evolution_trap_increase:
|
||||||
|
# If present, % increase of Evolution with each trap received.
|
||||||
|
5: 0
|
||||||
|
10: 1
|
||||||
|
15: 0
|
||||||
|
20: 0
|
||||||
|
100: 0
|
||||||
|
random: 0
|
||||||
|
random-low: 0
|
||||||
|
random-middle: 0
|
||||||
|
random-high: 0
|
||||||
|
attack_traps:
|
||||||
|
# Trap items that when received trigger an attack on your base.
|
||||||
|
0: 1
|
||||||
|
1: 0
|
||||||
|
2: 0
|
||||||
|
3: 0
|
||||||
|
4: 0
|
||||||
|
random: 0
|
||||||
|
random-low: 0
|
||||||
|
random-middle: 0
|
||||||
|
random-high: 0
|
||||||
world_gen:
|
world_gen:
|
||||||
# frequency, size, richness, terrain segmentation, starting area and water are all of https://wiki.factorio.com/Types/MapGenSize
|
# frequency, size, richness, terrain segmentation, starting area and water are all of https://wiki.factorio.com/Types/MapGenSize
|
||||||
# inverse of water scale
|
# inverse of water scale
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
import typing
|
import typing
|
||||||
|
|
||||||
from Options import Choice, OptionDict, Option, DefaultOnToggle
|
from Options import Choice, OptionDict, Option, DefaultOnToggle, Range
|
||||||
from schema import Schema, Optional, And, Or
|
from schema import Schema, Optional, And, Or
|
||||||
|
|
||||||
# schema helpers
|
# schema helpers
|
||||||
|
@ -125,6 +125,27 @@ class FactorioStartItems(OptionDict):
|
||||||
default = {"burner-mining-drill": 19, "stone-furnace": 19}
|
default = {"burner-mining-drill": 19, "stone-furnace": 19}
|
||||||
|
|
||||||
|
|
||||||
|
class TrapCount(Range):
|
||||||
|
range_end = 4
|
||||||
|
|
||||||
|
|
||||||
|
class AttackTrapCount(TrapCount):
|
||||||
|
"""Trap items that when received trigger an attack on your base."""
|
||||||
|
displayname = "Attack Traps"
|
||||||
|
|
||||||
|
|
||||||
|
class EvolutionTrapCount(TrapCount):
|
||||||
|
"""Trap items that when received increase the enemy evolution."""
|
||||||
|
displayname = "Evolution Traps"
|
||||||
|
|
||||||
|
|
||||||
|
class EvolutionTrapIncrease(Range):
|
||||||
|
displayname = "Evolution Trap % Effect"
|
||||||
|
range_start = 1
|
||||||
|
default = 10
|
||||||
|
range_end = 100
|
||||||
|
|
||||||
|
|
||||||
class FactorioWorldGen(OptionDict):
|
class FactorioWorldGen(OptionDict):
|
||||||
displayname = "World Generation"
|
displayname = "World Generation"
|
||||||
# FIXME: do we want default be a rando-optimized default or in-game DS?
|
# FIXME: do we want default be a rando-optimized default or in-game DS?
|
||||||
|
@ -257,9 +278,11 @@ class FactorioWorldGen(OptionDict):
|
||||||
else:
|
else:
|
||||||
raise NotImplementedError(f"Cannot Convert from non-dictionary, got {type(data)}")
|
raise NotImplementedError(f"Cannot Convert from non-dictionary, got {type(data)}")
|
||||||
|
|
||||||
|
|
||||||
class ImportedBlueprint(DefaultOnToggle):
|
class ImportedBlueprint(DefaultOnToggle):
|
||||||
displayname = "Blueprints"
|
displayname = "Blueprints"
|
||||||
|
|
||||||
|
|
||||||
factorio_options: typing.Dict[str, type(Option)] = {
|
factorio_options: typing.Dict[str, type(Option)] = {
|
||||||
"max_science_pack": MaxSciencePack,
|
"max_science_pack": MaxSciencePack,
|
||||||
"tech_tree_layout": TechTreeLayout,
|
"tech_tree_layout": TechTreeLayout,
|
||||||
|
@ -272,5 +295,8 @@ factorio_options: typing.Dict[str, type(Option)] = {
|
||||||
"recipe_ingredients": RecipeIngredients,
|
"recipe_ingredients": RecipeIngredients,
|
||||||
"imported_blueprints": ImportedBlueprint,
|
"imported_blueprints": ImportedBlueprint,
|
||||||
"world_gen": FactorioWorldGen,
|
"world_gen": FactorioWorldGen,
|
||||||
"progressive": Progressive
|
"progressive": Progressive,
|
||||||
|
"evolution_traps": EvolutionTrapCount,
|
||||||
|
"attack_traps": AttackTrapCount,
|
||||||
|
"evolution_trap_increase": EvolutionTrapIncrease,
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,11 +8,10 @@ import string
|
||||||
|
|
||||||
import Utils
|
import Utils
|
||||||
import logging
|
import logging
|
||||||
import functools
|
|
||||||
|
|
||||||
from . import Options
|
from . import Options
|
||||||
|
|
||||||
factorio_id = 2 ** 17
|
factorio_id = factorio_base_id = 2 ** 17
|
||||||
source_folder = os.path.join(os.path.dirname(__file__), "data")
|
source_folder = os.path.join(os.path.dirname(__file__), "data")
|
||||||
|
|
||||||
with open(os.path.join(source_folder, "techs.json")) as f:
|
with open(os.path.join(source_folder, "techs.json")) as f:
|
||||||
|
@ -38,11 +37,24 @@ class FactorioElement():
|
||||||
|
|
||||||
|
|
||||||
class Technology(FactorioElement): # maybe make subclass of Location?
|
class Technology(FactorioElement): # maybe make subclass of Location?
|
||||||
def __init__(self, name: str, ingredients: Set[str], factorio_id: int, progressive: Tuple[str] = ()):
|
has_modifier: bool
|
||||||
|
factorio_id: int
|
||||||
|
name: str
|
||||||
|
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] = (),
|
||||||
|
has_modifier: bool = False, unlocks: Union[Set[str], bool] = None):
|
||||||
self.name = name
|
self.name = name
|
||||||
self.factorio_id = factorio_id
|
self.factorio_id = factorio_id
|
||||||
self.ingredients = ingredients
|
self.ingredients = ingredients
|
||||||
self.progressive = progressive
|
self.progressive = progressive
|
||||||
|
self.has_modifier = has_modifier
|
||||||
|
if unlocks:
|
||||||
|
self.unlocks = unlocks
|
||||||
|
else:
|
||||||
|
self.unlocks = set()
|
||||||
|
|
||||||
def build_rule(self, player: int):
|
def build_rule(self, player: int):
|
||||||
logging.debug(f"Building rules for {self.name}")
|
logging.debug(f"Building rules for {self.name}")
|
||||||
|
@ -63,6 +75,9 @@ class Technology(FactorioElement): # maybe make subclass of Location?
|
||||||
def get_custom(self, world, allowed_packs: Set[str], player: int) -> CustomTechnology:
|
def get_custom(self, world, allowed_packs: Set[str], player: int) -> CustomTechnology:
|
||||||
return CustomTechnology(self, world, allowed_packs, player)
|
return CustomTechnology(self, world, allowed_packs, player)
|
||||||
|
|
||||||
|
def useful(self) -> bool:
|
||||||
|
return self.has_modifier or self.unlocks
|
||||||
|
|
||||||
|
|
||||||
class CustomTechnology(Technology):
|
class CustomTechnology(Technology):
|
||||||
"""A particularly configured Technology for a world."""
|
"""A particularly configured Technology for a world."""
|
||||||
|
@ -114,7 +129,7 @@ class Recipe(FactorioElement):
|
||||||
@property
|
@property
|
||||||
def rel_cost(self) -> float:
|
def rel_cost(self) -> float:
|
||||||
ingredients = sum(self.ingredients.values())
|
ingredients = sum(self.ingredients.values())
|
||||||
return min(ingredients/amount for product, amount in self.products.items())
|
return min(ingredients / amount for product, amount in self.products.items())
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def base_cost(self) -> Dict[str, int]:
|
def base_cost(self) -> Dict[str, int]:
|
||||||
|
@ -122,7 +137,8 @@ class Recipe(FactorioElement):
|
||||||
for ingredient, cost in self.ingredients.items():
|
for ingredient, cost in self.ingredients.items():
|
||||||
if ingredient in all_product_sources:
|
if ingredient in all_product_sources:
|
||||||
for recipe in all_product_sources[ingredient]:
|
for recipe in all_product_sources[ingredient]:
|
||||||
ingredients.update({name: amount*cost/recipe.products[ingredient] for name, amount in recipe.base_cost.items()})
|
ingredients.update({name: amount * cost / recipe.products[ingredient] for name, amount in
|
||||||
|
recipe.base_cost.items()})
|
||||||
else:
|
else:
|
||||||
ingredients[ingredient] += cost
|
ingredients[ingredient] += cost
|
||||||
return ingredients
|
return ingredients
|
||||||
|
@ -134,39 +150,40 @@ class Recipe(FactorioElement):
|
||||||
total_energy = self.energy
|
total_energy = self.energy
|
||||||
for ingredient, cost in self.ingredients.items():
|
for ingredient, cost in self.ingredients.items():
|
||||||
if ingredient in all_product_sources:
|
if ingredient in all_product_sources:
|
||||||
for ingredient_recipe in all_product_sources[ingredient]: # FIXME: this may select the wrong recipe
|
for ingredient_recipe in all_product_sources[ingredient]: # FIXME: this may select the wrong recipe
|
||||||
craft_count = max((n for name, n in ingredient_recipe.products.items() if name == ingredient))
|
craft_count = max((n for name, n in ingredient_recipe.products.items() if name == ingredient))
|
||||||
total_energy += ingredient_recipe.total_energy / craft_count * cost
|
total_energy += ingredient_recipe.total_energy / craft_count * cost
|
||||||
break
|
break
|
||||||
return total_energy
|
return total_energy
|
||||||
|
|
||||||
|
|
||||||
class Machine(FactorioElement):
|
class Machine(FactorioElement):
|
||||||
def __init__(self, name, categories):
|
def __init__(self, name, categories):
|
||||||
self.name: str = name
|
self.name: str = name
|
||||||
self.categories: set = categories
|
self.categories: set = categories
|
||||||
|
|
||||||
|
|
||||||
|
recipe_sources: Dict[str, Set[str]] = {} # recipe_name -> technology source
|
||||||
|
|
||||||
# recipes and technologies can share names in Factorio
|
# recipes and technologies can share names in Factorio
|
||||||
for technology_name in sorted(raw):
|
for technology_name in sorted(raw):
|
||||||
data = raw[technology_name]
|
data = raw[technology_name]
|
||||||
current_ingredients = set(data["ingredients"])
|
current_ingredients = set(data["ingredients"])
|
||||||
technology = Technology(technology_name, current_ingredients, factorio_id)
|
technology = Technology(technology_name, current_ingredients, factorio_id,
|
||||||
|
has_modifier=data["has_modifier"], unlocks=set(data["unlocks"]))
|
||||||
factorio_id += 1
|
factorio_id += 1
|
||||||
tech_table[technology_name] = technology.factorio_id
|
tech_table[technology_name] = technology.factorio_id
|
||||||
technology_table[technology_name] = technology
|
technology_table[technology_name] = technology
|
||||||
|
for recipe_name in technology.unlocks:
|
||||||
recipe_sources: Dict[str, str] = {} # recipe_name -> technology source
|
recipe_sources.setdefault(recipe_name, set()).add(technology_name)
|
||||||
|
|
||||||
for technology, data in raw.items():
|
|
||||||
for recipe_name in data["unlocks"]:
|
|
||||||
recipe_sources.setdefault(recipe_name, set()).add(technology)
|
|
||||||
|
|
||||||
del (raw)
|
del (raw)
|
||||||
|
|
||||||
recipes = {}
|
recipes = {}
|
||||||
all_product_sources: Dict[str, Set[Recipe]] = {"character": set()}
|
all_product_sources: Dict[str, Set[Recipe]] = {"character": set()}
|
||||||
# add uranium mining to logic graph. TODO: add to automatic extractor for mod support
|
# add uranium mining to logic graph. TODO: add to automatic extractor for mod support
|
||||||
raw_recipes["uranium-ore"] = {"ingredients": {"sulfuric-acid": 1}, "products": {"uranium-ore": 1}, "category": "mining", "energy": 2}
|
raw_recipes["uranium-ore"] = {"ingredients": {"sulfuric-acid": 1}, "products": {"uranium-ore": 1}, "category": "mining",
|
||||||
|
"energy": 2}
|
||||||
|
|
||||||
for recipe_name, recipe_data in raw_recipes.items():
|
for recipe_name, recipe_data in raw_recipes.items():
|
||||||
# example:
|
# example:
|
||||||
|
@ -193,7 +210,7 @@ for name, categories in raw_machines.items():
|
||||||
# add electric mining drill as a crafting machine to resolve uranium-ore
|
# add electric mining drill as a crafting machine to resolve uranium-ore
|
||||||
machines["electric-mining-drill"] = Machine("electric-mining-drill", {"mining"})
|
machines["electric-mining-drill"] = Machine("electric-mining-drill", {"mining"})
|
||||||
machines["assembling-machine-1"].categories.add("crafting-with-fluid") # mod enables this
|
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
|
machines["character"].categories.add("basic-crafting") # somehow this is implied and not exported
|
||||||
del (raw_machines)
|
del (raw_machines)
|
||||||
|
|
||||||
# build requirements graph for all technology ingredients
|
# build requirements graph for all technology ingredients
|
||||||
|
@ -265,10 +282,9 @@ for category_name, machine_name in machine_per_category.items():
|
||||||
techs |= recursively_get_unlocking_technologies(machine_name)
|
techs |= recursively_get_unlocking_technologies(machine_name)
|
||||||
required_category_technologies[category_name] = frozenset(techs)
|
required_category_technologies[category_name] = frozenset(techs)
|
||||||
|
|
||||||
required_technologies: Dict[str, FrozenSet[Technology]] = Utils.KeyedDefaultDict(lambda ingredient_name : frozenset(
|
required_technologies: Dict[str, FrozenSet[Technology]] = Utils.KeyedDefaultDict(lambda ingredient_name: frozenset(
|
||||||
recursively_get_unlocking_technologies(ingredient_name, unlock_func=unlock)))
|
recursively_get_unlocking_technologies(ingredient_name, unlock_func=unlock)))
|
||||||
|
|
||||||
|
|
||||||
advancement_technologies: Set[str] = set()
|
advancement_technologies: Set[str] = set()
|
||||||
for ingredient_name in all_ingredient_names:
|
for ingredient_name in all_ingredient_names:
|
||||||
technologies = required_technologies[ingredient_name]
|
technologies = required_technologies[ingredient_name]
|
||||||
|
@ -317,17 +333,17 @@ for tech_name in tech_table:
|
||||||
progressive_incs.add(tech_name)
|
progressive_incs.add(tech_name)
|
||||||
|
|
||||||
for root, progressive in progressive_rows.items():
|
for root, progressive in progressive_rows.items():
|
||||||
seeking = root[:-1]+str(int(root[-1])+1)
|
seeking = root[:-1] + str(int(root[-1]) + 1)
|
||||||
while seeking in progressive_incs:
|
while seeking in progressive_incs:
|
||||||
progressive.append(seeking)
|
progressive.append(seeking)
|
||||||
progressive_incs.remove(seeking)
|
progressive_incs.remove(seeking)
|
||||||
seeking = seeking[:-1]+str(int(seeking[-1])+1)
|
seeking = seeking[:-1] + str(int(seeking[-1]) + 1)
|
||||||
|
|
||||||
# make root entry the progressive name
|
# make root entry the progressive name
|
||||||
for old_name in set(progressive_rows):
|
for old_name in set(progressive_rows):
|
||||||
prog_name = "progressive-" + old_name.rsplit("-", 1)[0]
|
prog_name = "progressive-" + old_name.rsplit("-", 1)[0]
|
||||||
progressive_rows[prog_name] = tuple([old_name] + progressive_rows[old_name])
|
progressive_rows[prog_name] = tuple([old_name] + progressive_rows[old_name])
|
||||||
del(progressive_rows[old_name])
|
del (progressive_rows[old_name])
|
||||||
|
|
||||||
# no -1 start
|
# no -1 start
|
||||||
base_starts = set()
|
base_starts = set()
|
||||||
|
@ -336,12 +352,12 @@ for remnant in progressive_incs:
|
||||||
base_starts.add(remnant[:-2])
|
base_starts.add(remnant[:-2])
|
||||||
|
|
||||||
for root in base_starts:
|
for root in base_starts:
|
||||||
seeking = root+"-2"
|
seeking = root + "-2"
|
||||||
progressive = [root]
|
progressive = [root]
|
||||||
while seeking in progressive_incs:
|
while seeking in progressive_incs:
|
||||||
progressive.append(seeking)
|
progressive.append(seeking)
|
||||||
seeking = seeking[:-1]+str(int(seeking[-1])+1)
|
seeking = seeking[:-1] + str(int(seeking[-1]) + 1)
|
||||||
progressive_rows["progressive-"+root] = tuple(progressive)
|
progressive_rows["progressive-" + root] = tuple(progressive)
|
||||||
|
|
||||||
# science packs
|
# science packs
|
||||||
progressive_rows["progressive-science-pack"] = tuple(Options.MaxSciencePack.get_ordered_science_packs())[1:]
|
progressive_rows["progressive-science-pack"] = tuple(Options.MaxSciencePack.get_ordered_science_packs())[1:]
|
||||||
|
@ -381,7 +397,6 @@ source_target_mapping: Dict[str, str] = {
|
||||||
for source, target in source_target_mapping.items():
|
for source, target in source_target_mapping.items():
|
||||||
progressive_rows[target] += progressive_rows[source]
|
progressive_rows[target] += progressive_rows[source]
|
||||||
|
|
||||||
|
|
||||||
base_tech_table = tech_table.copy() # without progressive techs
|
base_tech_table = tech_table.copy() # without progressive techs
|
||||||
base_technology_table = technology_table.copy()
|
base_technology_table = technology_table.copy()
|
||||||
|
|
||||||
|
@ -393,7 +408,9 @@ for root in sorted_rows:
|
||||||
assert all(tech in tech_table for tech in progressive)
|
assert all(tech in tech_table for tech in progressive)
|
||||||
factorio_id += 1
|
factorio_id += 1
|
||||||
progressive_technology = Technology(root, technology_table[progressive_rows[root][0]].ingredients, factorio_id,
|
progressive_technology = Technology(root, technology_table[progressive_rows[root][0]].ingredients, factorio_id,
|
||||||
progressive)
|
progressive,
|
||||||
|
has_modifier=any(technology_table[tech].has_modifier for tech in progressive),
|
||||||
|
unlocks=any(technology_table[tech].unlocks for tech in progressive))
|
||||||
progressive_tech_table[root] = progressive_technology.factorio_id
|
progressive_tech_table[root] = progressive_technology.factorio_id
|
||||||
progressive_technology_table[root] = progressive_technology
|
progressive_technology_table[root] = progressive_technology
|
||||||
if any(tech in advancement_technologies for tech in progressive):
|
if any(tech in advancement_technologies for tech in progressive):
|
||||||
|
@ -412,10 +429,13 @@ technology_table.update(progressive_technology_table)
|
||||||
common_tech_table: Dict[str, int] = {tech_name: tech_id for tech_name, tech_id in base_tech_table.items()
|
common_tech_table: Dict[str, int] = {tech_name: tech_id for tech_name, tech_id in base_tech_table.items()
|
||||||
if tech_name not in progressive_tech_table}
|
if tech_name not in progressive_tech_table}
|
||||||
|
|
||||||
|
useless_technologies: Set[str] = {tech_name for tech_name in common_tech_table
|
||||||
|
if not technology_table[tech_name].useful()}
|
||||||
|
|
||||||
lookup_id_to_name: Dict[int, str] = {item_id: item_name for item_name, item_id in tech_table.items()}
|
lookup_id_to_name: Dict[int, str] = {item_id: item_name for item_name, item_id in tech_table.items()}
|
||||||
|
|
||||||
rel_cost = {
|
rel_cost = {
|
||||||
"wood" : 10000,
|
"wood": 10000,
|
||||||
"iron-ore": 1,
|
"iron-ore": 1,
|
||||||
"copper-ore": 1,
|
"copper-ore": 1,
|
||||||
"stone": 1,
|
"stone": 1,
|
||||||
|
@ -431,6 +451,7 @@ rel_cost = {
|
||||||
blacklist: Set[str] = all_ingredient_names | {"rocket-part", "crude-oil", "water", "sulfuric-acid", "petroleum-gas",
|
blacklist: Set[str] = all_ingredient_names | {"rocket-part", "crude-oil", "water", "sulfuric-acid", "petroleum-gas",
|
||||||
"light-oil", "heavy-oil", "lubricant", "steam"}
|
"light-oil", "heavy-oil", "lubricant", "steam"}
|
||||||
|
|
||||||
|
|
||||||
@Utils.cache_argsless
|
@Utils.cache_argsless
|
||||||
def get_science_pack_pools() -> Dict[str, Set[str]]:
|
def get_science_pack_pools() -> Dict[str, Set[str]]:
|
||||||
def get_estimated_difficulty(recipe: Recipe):
|
def get_estimated_difficulty(recipe: Recipe):
|
||||||
|
@ -441,7 +462,6 @@ def get_science_pack_pools() -> Dict[str, Set[str]]:
|
||||||
cost += rel_cost.get(ingredient_name, 1) * amount
|
cost += rel_cost.get(ingredient_name, 1) * amount
|
||||||
return cost
|
return cost
|
||||||
|
|
||||||
|
|
||||||
science_pack_pools = {}
|
science_pack_pools = {}
|
||||||
already_taken = blacklist.copy()
|
already_taken = blacklist.copy()
|
||||||
current_difficulty = 5
|
current_difficulty = 5
|
||||||
|
|
|
@ -6,7 +6,7 @@ from BaseClasses import Region, Entrance, Location, Item
|
||||||
from .Technologies import base_tech_table, recipe_sources, base_technology_table, advancement_technologies, \
|
from .Technologies import base_tech_table, recipe_sources, base_technology_table, advancement_technologies, \
|
||||||
all_ingredient_names, all_product_sources, required_technologies, get_rocket_requirements, rocket_recipes, \
|
all_ingredient_names, all_product_sources, required_technologies, get_rocket_requirements, rocket_recipes, \
|
||||||
progressive_technology_table, common_tech_table, tech_to_progressive_lookup, progressive_tech_table, \
|
progressive_technology_table, common_tech_table, tech_to_progressive_lookup, progressive_tech_table, \
|
||||||
get_science_pack_pools, Recipe, recipes, technology_table, tech_table
|
get_science_pack_pools, Recipe, recipes, technology_table, tech_table, factorio_base_id, useless_technologies
|
||||||
from .Shapes import get_shapes
|
from .Shapes import get_shapes
|
||||||
from .Mod import generate_mod
|
from .Mod import generate_mod
|
||||||
from .Options import factorio_options, Silo
|
from .Options import factorio_options, Silo
|
||||||
|
@ -18,35 +18,48 @@ class FactorioItem(Item):
|
||||||
game = "Factorio"
|
game = "Factorio"
|
||||||
|
|
||||||
|
|
||||||
|
all_items = tech_table.copy()
|
||||||
|
all_items["Attack Trap"] = factorio_base_id - 1
|
||||||
|
all_items["Evolution Trap"] = factorio_base_id - 2
|
||||||
|
|
||||||
|
|
||||||
class Factorio(World):
|
class Factorio(World):
|
||||||
game: str = "Factorio"
|
game: str = "Factorio"
|
||||||
static_nodes = {"automation", "logistics", "rocket-silo"}
|
static_nodes = {"automation", "logistics", "rocket-silo"}
|
||||||
custom_recipes = {}
|
custom_recipes = {}
|
||||||
additional_advancement_technologies = set()
|
additional_advancement_technologies = set()
|
||||||
|
|
||||||
item_name_to_id = tech_table
|
item_name_to_id = all_items
|
||||||
location_name_to_id = base_tech_table
|
location_name_to_id = base_tech_table
|
||||||
|
|
||||||
data_version = 3
|
data_version = 4
|
||||||
|
|
||||||
def generate_basic(self):
|
def generate_basic(self):
|
||||||
want_progressives = collections.defaultdict(lambda: self.world.progressive[self.player].
|
player = self.player
|
||||||
|
want_progressives = collections.defaultdict(lambda: self.world.progressive[player].
|
||||||
want_progressives(self.world.random))
|
want_progressives(self.world.random))
|
||||||
skip_silo = self.world.silo[self.player].value == Silo.option_spawn
|
skip_silo = self.world.silo[player].value == Silo.option_spawn
|
||||||
|
evolution_traps_wanted = self.world.evolution_traps[player].value
|
||||||
|
attack_traps_wanted = self.world.attack_traps[player].value
|
||||||
|
traps_wanted = ["Evolution Trap"] * evolution_traps_wanted + ["Attack Trap"] * attack_traps_wanted
|
||||||
|
self.world.random.shuffle(traps_wanted)
|
||||||
for tech_name in base_tech_table:
|
for tech_name in base_tech_table:
|
||||||
if skip_silo and tech_name == "rocket-silo":
|
if traps_wanted and tech_name in useless_technologies:
|
||||||
continue
|
self.world.itempool.append(self.create_item(traps_wanted.pop()))
|
||||||
progressive_item_name = tech_to_progressive_lookup.get(tech_name, tech_name)
|
elif skip_silo and tech_name == "rocket-silo":
|
||||||
want_progressive = want_progressives[progressive_item_name]
|
pass
|
||||||
item_name = progressive_item_name if want_progressive else tech_name
|
|
||||||
tech_item = self.create_item(item_name)
|
|
||||||
if tech_name in self.static_nodes:
|
|
||||||
self.world.get_location(tech_name, self.player).place_locked_item(tech_item)
|
|
||||||
else:
|
else:
|
||||||
self.world.itempool.append(tech_item)
|
progressive_item_name = tech_to_progressive_lookup.get(tech_name, tech_name)
|
||||||
map_basic_settings = self.world.world_gen[self.player].value["basic"]
|
want_progressive = want_progressives[progressive_item_name]
|
||||||
|
item_name = progressive_item_name if want_progressive else tech_name
|
||||||
|
tech_item = self.create_item(item_name)
|
||||||
|
if tech_name in self.static_nodes:
|
||||||
|
self.world.get_location(tech_name, player).place_locked_item(tech_item)
|
||||||
|
else:
|
||||||
|
self.world.itempool.append(tech_item)
|
||||||
|
map_basic_settings = self.world.world_gen[player].value["basic"]
|
||||||
if map_basic_settings.get("seed", None) is None: # allow seed 0
|
if map_basic_settings.get("seed", None) is None: # allow seed 0
|
||||||
map_basic_settings["seed"] = self.world.slot_seeds[self.player].randint(0, 2**32-1) # 32 bit uint
|
map_basic_settings["seed"] = self.world.slot_seeds[player].randint(0, 2 ** 32 - 1) # 32 bit uint
|
||||||
|
|
||||||
generate_output = generate_mod
|
generate_output = generate_mod
|
||||||
|
|
||||||
|
@ -263,7 +276,9 @@ class Factorio(World):
|
||||||
self.additional_advancement_technologies |= prog_add
|
self.additional_advancement_technologies |= prog_add
|
||||||
|
|
||||||
def create_item(self, name: str) -> Item:
|
def create_item(self, name: str) -> Item:
|
||||||
assert name in tech_table
|
if name in tech_table:
|
||||||
return FactorioItem(name, name in advancement_technologies or
|
return FactorioItem(name, name in advancement_technologies or
|
||||||
name in self.additional_advancement_technologies,
|
name in self.additional_advancement_technologies,
|
||||||
tech_table[name], self.player)
|
tech_table[name], self.player)
|
||||||
|
elif name in all_items:
|
||||||
|
return FactorioItem(name, False, all_items[name], self.player)
|
||||||
|
|
|
@ -7,6 +7,7 @@ FREE_SAMPLES = {{ free_samples }}
|
||||||
SLOT_NAME = "{{ slot_name }}"
|
SLOT_NAME = "{{ slot_name }}"
|
||||||
SEED_NAME = "{{ seed_name }}"
|
SEED_NAME = "{{ seed_name }}"
|
||||||
FREE_SAMPLE_BLACKLIST = {{ dict_to_lua(free_sample_blacklist) }}
|
FREE_SAMPLE_BLACKLIST = {{ dict_to_lua(free_sample_blacklist) }}
|
||||||
|
TRAP_EVO_FACTOR = {{ evolution_trap_increase }} / 100
|
||||||
|
|
||||||
{% if not imported_blueprints -%}
|
{% if not imported_blueprints -%}
|
||||||
function set_permissions()
|
function set_permissions()
|
||||||
|
@ -369,15 +370,15 @@ commands.add_command("ap-get-technology", "Grant a technology, used by the Archi
|
||||||
local tech
|
local tech
|
||||||
local force = game.forces["player"]
|
local force = game.forces["player"]
|
||||||
chunks = split(call.parameter, "\t")
|
chunks = split(call.parameter, "\t")
|
||||||
local tech_name = chunks[1]
|
local item_name = chunks[1]
|
||||||
local index = chunks[2]
|
local index = chunks[2]
|
||||||
local source = chunks[3] or "Archipelago"
|
local source = chunks[3] or "Archipelago"
|
||||||
if progressive_technologies[tech_name] ~= nil then
|
if progressive_technologies[item_name] ~= nil then
|
||||||
if global.index_sync[index] == nil then -- not yet received prog item
|
if global.index_sync[index] == nil then -- not yet received prog item
|
||||||
global.index_sync[index] = tech_name
|
global.index_sync[index] = item_name
|
||||||
local tech_stack = progressive_technologies[tech_name]
|
local tech_stack = progressive_technologies[item_name]
|
||||||
for _, tech_name in ipairs(tech_stack) do
|
for _, item_name in ipairs(tech_stack) do
|
||||||
tech = force.technologies[tech_name]
|
tech = force.technologies[item_name]
|
||||||
if tech.researched ~= true then
|
if tech.researched ~= true then
|
||||||
game.print({"", "Received [technology=" .. tech.name .. "] from ", source})
|
game.print({"", "Received [technology=" .. tech.name .. "] from ", source})
|
||||||
game.play_sound({path="utility/research_completed"})
|
game.play_sound({path="utility/research_completed"})
|
||||||
|
@ -386,8 +387,8 @@ commands.add_command("ap-get-technology", "Grant a technology, used by the Archi
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
elseif force.technologies[tech_name] ~= nil then
|
elseif force.technologies[item_name] ~= nil then
|
||||||
tech = force.technologies[tech_name]
|
tech = force.technologies[item_name]
|
||||||
if tech ~= nil then
|
if tech ~= nil then
|
||||||
if global.index_sync[index] ~= nil and global.index_sync[index] ~= tech then
|
if global.index_sync[index] ~= nil and global.index_sync[index] ~= tech then
|
||||||
game.print("Warning: Desync Detected. Duplicate/Missing items may occur.")
|
game.print("Warning: Desync Detected. Duplicate/Missing items may occur.")
|
||||||
|
@ -399,8 +400,21 @@ commands.add_command("ap-get-technology", "Grant a technology, used by the Archi
|
||||||
tech.researched = true
|
tech.researched = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
elseif item_name == "Attack Trap" then
|
||||||
|
if global.index_sync[index] == nil then -- not yet received trap
|
||||||
|
game.print({"", "Received Attack Trap from ", source})
|
||||||
|
global.index_sync[index] = item_name
|
||||||
|
local spawn_position = force.get_spawn_position(game.get_surface(1))
|
||||||
|
game.surfaces["nauvis"].build_enemy_base(spawn_position, 25)
|
||||||
|
end
|
||||||
|
elseif item_name == "Evolution Trap" then
|
||||||
|
if global.index_sync[index] == nil then -- not yet received trap
|
||||||
|
global.index_sync[index] = item_name
|
||||||
|
game.forces["enemy"].evolution_factor = game.forces["enemy"].evolution_factor + TRAP_EVO_FACTOR
|
||||||
|
game.print({"", "Received Evolution Trap from ", source, ". New factor:", game.forces["enemy"].evolution_factor})
|
||||||
|
end
|
||||||
else
|
else
|
||||||
game.print("Unknown Technology " .. tech_name)
|
game.print("Unknown Item " .. item_name)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue