mirror of
https://github.com/MarioSpore/Grinch-AP.git
synced 2025-10-21 20:21:32 -06:00
Factorio: add Traps
This commit is contained in:
@@ -8,11 +8,10 @@ import string
|
||||
|
||||
import Utils
|
||||
import logging
|
||||
import functools
|
||||
|
||||
from . import Options
|
||||
|
||||
factorio_id = 2 ** 17
|
||||
factorio_id = factorio_base_id = 2 ** 17
|
||||
source_folder = os.path.join(os.path.dirname(__file__), "data")
|
||||
|
||||
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?
|
||||
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.factorio_id = factorio_id
|
||||
self.ingredients = ingredients
|
||||
self.progressive = progressive
|
||||
self.has_modifier = has_modifier
|
||||
if unlocks:
|
||||
self.unlocks = unlocks
|
||||
else:
|
||||
self.unlocks = set()
|
||||
|
||||
def build_rule(self, player: int):
|
||||
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:
|
||||
return CustomTechnology(self, world, allowed_packs, player)
|
||||
|
||||
def useful(self) -> bool:
|
||||
return self.has_modifier or self.unlocks
|
||||
|
||||
|
||||
class CustomTechnology(Technology):
|
||||
"""A particularly configured Technology for a world."""
|
||||
@@ -114,7 +129,7 @@ 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())
|
||||
return min(ingredients / amount for product, amount in self.products.items())
|
||||
|
||||
@property
|
||||
def base_cost(self) -> Dict[str, int]:
|
||||
@@ -122,7 +137,8 @@ class Recipe(FactorioElement):
|
||||
for ingredient, cost in self.ingredients.items():
|
||||
if ingredient in all_product_sources:
|
||||
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:
|
||||
ingredients[ingredient] += cost
|
||||
return ingredients
|
||||
@@ -134,39 +150,40 @@ class Recipe(FactorioElement):
|
||||
total_energy = self.energy
|
||||
for ingredient, cost in self.ingredients.items():
|
||||
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))
|
||||
total_energy += ingredient_recipe.total_energy / craft_count * cost
|
||||
break
|
||||
return total_energy
|
||||
|
||||
|
||||
class Machine(FactorioElement):
|
||||
def __init__(self, name, categories):
|
||||
self.name: str = name
|
||||
self.categories: set = categories
|
||||
|
||||
|
||||
recipe_sources: Dict[str, Set[str]] = {} # recipe_name -> technology source
|
||||
|
||||
# recipes and technologies can share names in Factorio
|
||||
for technology_name in sorted(raw):
|
||||
data = raw[technology_name]
|
||||
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
|
||||
tech_table[technology_name] = technology.factorio_id
|
||||
technology_table[technology_name] = technology
|
||||
|
||||
recipe_sources: Dict[str, str] = {} # recipe_name -> technology source
|
||||
|
||||
for technology, data in raw.items():
|
||||
for recipe_name in data["unlocks"]:
|
||||
recipe_sources.setdefault(recipe_name, set()).add(technology)
|
||||
for recipe_name in technology.unlocks:
|
||||
recipe_sources.setdefault(recipe_name, set()).add(technology_name)
|
||||
|
||||
del (raw)
|
||||
|
||||
recipes = {}
|
||||
all_product_sources: Dict[str, Set[Recipe]] = {"character": set()}
|
||||
# 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():
|
||||
# example:
|
||||
@@ -193,7 +210,7 @@ for name, categories in raw_machines.items():
|
||||
# add electric mining drill as a crafting machine to resolve uranium-ore
|
||||
machines["electric-mining-drill"] = Machine("electric-mining-drill", {"mining"})
|
||||
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)
|
||||
|
||||
# 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)
|
||||
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)))
|
||||
|
||||
|
||||
advancement_technologies: Set[str] = set()
|
||||
for ingredient_name in all_ingredient_names:
|
||||
technologies = required_technologies[ingredient_name]
|
||||
@@ -317,17 +333,17 @@ for tech_name in tech_table:
|
||||
progressive_incs.add(tech_name)
|
||||
|
||||
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:
|
||||
progressive.append(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
|
||||
for old_name in set(progressive_rows):
|
||||
prog_name = "progressive-" + old_name.rsplit("-", 1)[0]
|
||||
progressive_rows[prog_name] = tuple([old_name] + progressive_rows[old_name])
|
||||
del(progressive_rows[old_name])
|
||||
del (progressive_rows[old_name])
|
||||
|
||||
# no -1 start
|
||||
base_starts = set()
|
||||
@@ -336,12 +352,12 @@ for remnant in progressive_incs:
|
||||
base_starts.add(remnant[:-2])
|
||||
|
||||
for root in base_starts:
|
||||
seeking = root+"-2"
|
||||
seeking = root + "-2"
|
||||
progressive = [root]
|
||||
while seeking in progressive_incs:
|
||||
progressive.append(seeking)
|
||||
seeking = seeking[:-1]+str(int(seeking[-1])+1)
|
||||
progressive_rows["progressive-"+root] = tuple(progressive)
|
||||
seeking = seeking[:-1] + str(int(seeking[-1]) + 1)
|
||||
progressive_rows["progressive-" + root] = tuple(progressive)
|
||||
|
||||
# science packs
|
||||
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():
|
||||
progressive_rows[target] += progressive_rows[source]
|
||||
|
||||
|
||||
base_tech_table = tech_table.copy() # without progressive techs
|
||||
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)
|
||||
factorio_id += 1
|
||||
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_technology_table[root] = progressive_technology
|
||||
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()
|
||||
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()}
|
||||
|
||||
rel_cost = {
|
||||
"wood" : 10000,
|
||||
"wood": 10000,
|
||||
"iron-ore": 1,
|
||||
"copper-ore": 1,
|
||||
"stone": 1,
|
||||
@@ -431,6 +451,7 @@ rel_cost = {
|
||||
blacklist: Set[str] = all_ingredient_names | {"rocket-part", "crude-oil", "water", "sulfuric-acid", "petroleum-gas",
|
||||
"light-oil", "heavy-oil", "lubricant", "steam"}
|
||||
|
||||
|
||||
@Utils.cache_argsless
|
||||
def get_science_pack_pools() -> Dict[str, Set[str]]:
|
||||
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
|
||||
return cost
|
||||
|
||||
|
||||
science_pack_pools = {}
|
||||
already_taken = blacklist.copy()
|
||||
current_difficulty = 5
|
||||
|
||||
Reference in New Issue
Block a user