Factorio: add Progressive Option

This commit is contained in:
Fabian Dill 2021-07-04 22:21:53 +02:00
parent a11e840d36
commit e58ae58e24
11 changed files with 182 additions and 45 deletions

View File

@ -155,25 +155,24 @@ class MultiWorld():
@functools.cached_property @functools.cached_property
def player_ids(self): def player_ids(self):
yield from range(1, self.players + 1) return tuple(range(1, self.players + 1))
# Todo: make these automatic, or something like get_players_for_game(game_name) # Todo: make these automatic, or something like get_players_for_game(game_name)
@functools.cached_property @functools.cached_property
def alttp_player_ids(self): def alttp_player_ids(self):
yield from (player for player in range(1, self.players + 1) if self.game[player] == "A Link to the Past") return tuple(player for player in range(1, self.players + 1) if self.game[player] == "A Link to the Past")
@functools.cached_property @functools.cached_property
def hk_player_ids(self): def hk_player_ids(self):
yield from (player for player in range(1, self.players + 1) if self.game[player] == "Hollow Knight") return tuple(player for player in range(1, self.players + 1) if self.game[player] == "Hollow Knight")
@functools.cached_property @functools.cached_property
def factorio_player_ids(self): def factorio_player_ids(self):
yield from (player for player in range(1, self.players + 1) if self.game[player] == "Factorio") return tuple(player for player in range(1, self.players + 1) if self.game[player] == "Factorio")
@functools.cached_property @functools.cached_property
def minecraft_player_ids(self): def minecraft_player_ids(self):
yield from (player for player in range(1, self.players + 1) if self.game[player] == "Minecraft") return tuple(player for player in range(1, self.players + 1) if self.game[player] == "Minecraft")
def get_name_string_for_object(self, obj) -> str: def get_name_string_for_object(self, obj) -> str:
return obj.name if self.players == 1 else f'{obj.name} ({self.get_player_names(obj.player)})' return obj.name if self.players == 1 else f'{obj.name} ({self.get_player_names(obj.player)})'
@ -1337,8 +1336,6 @@ class Spoiler(object):
'shuffle': self.world.shuffle, 'shuffle': self.world.shuffle,
'item_pool': self.world.difficulty, 'item_pool': self.world.difficulty,
'item_functionality': self.world.item_functionality, 'item_functionality': self.world.item_functionality,
'gt_crystals': self.world.crystals_needed_for_gt,
'ganon_crystals': self.world.crystals_needed_for_ganon,
'open_pyramid': self.world.open_pyramid, 'open_pyramid': self.world.open_pyramid,
'accessibility': self.world.accessibility, 'accessibility': self.world.accessibility,
'hints': self.world.hints, 'hints': self.world.hints,
@ -1362,7 +1359,6 @@ class Spoiler(object):
'triforce_pieces_available': self.world.triforce_pieces_available, 'triforce_pieces_available': self.world.triforce_pieces_available,
'triforce_pieces_required': self.world.triforce_pieces_required, 'triforce_pieces_required': self.world.triforce_pieces_required,
'shop_shuffle': self.world.shop_shuffle, 'shop_shuffle': self.world.shop_shuffle,
'shop_item_slots': self.world.shop_item_slots,
'shuffle_prizes': self.world.shuffle_prizes, 'shuffle_prizes': self.world.shuffle_prizes,
'sprite_pool': self.world.sprite_pool, 'sprite_pool': self.world.sprite_pool,
'restrict_dungeon_item_on_boss': self.world.restrict_dungeon_item_on_boss, 'restrict_dungeon_item_on_boss': self.world.restrict_dungeon_item_on_boss,
@ -1418,7 +1414,6 @@ class Spoiler(object):
res = getattr(self.world, f_option)[player] res = getattr(self.world, f_option)[player]
outfile.write(f'{f_option+":":33}{bool_to_text(res) if type(res) == Options.Toggle else res.get_option_name()}\n') outfile.write(f'{f_option+":":33}{bool_to_text(res) if type(res) == Options.Toggle else res.get_option_name()}\n')
if player in self.world.alttp_player_ids: if player in self.world.alttp_player_ids:
for team in range(self.world.teams): for team in range(self.world.teams):
outfile.write('%s%s\n' % ( outfile.write('%s%s\n' % (
@ -1447,8 +1442,6 @@ class Spoiler(object):
outfile.write('Entrance Shuffle: %s\n' % self.metadata['shuffle'][player]) outfile.write('Entrance Shuffle: %s\n' % self.metadata['shuffle'][player])
if self.metadata['shuffle'][player] != "vanilla": if self.metadata['shuffle'][player] != "vanilla":
outfile.write('Entrance Shuffle Seed %s\n' % self.metadata['er_seeds'][player]) outfile.write('Entrance Shuffle Seed %s\n' % self.metadata['er_seeds'][player])
outfile.write('Crystals required for GT: %s\n' % self.metadata['gt_crystals'][player])
outfile.write('Crystals required for Ganon: %s\n' % self.metadata['ganon_crystals'][player])
outfile.write('Pyramid hole pre-opened: %s\n' % ( outfile.write('Pyramid hole pre-opened: %s\n' % (
'Yes' if self.metadata['open_pyramid'][player] else 'No')) 'Yes' if self.metadata['open_pyramid'][player] else 'No'))
@ -1471,8 +1464,6 @@ class Spoiler(object):
"f" in self.metadata["shop_shuffle"][player])) "f" in self.metadata["shop_shuffle"][player]))
outfile.write('Custom Potion Shop: %s\n' % outfile.write('Custom Potion Shop: %s\n' %
bool_to_text("w" in self.metadata["shop_shuffle"][player])) bool_to_text("w" in self.metadata["shop_shuffle"][player]))
outfile.write('Shop Item Slots: %s\n' %
self.metadata["shop_item_slots"][player])
outfile.write('Boss shuffle: %s\n' % self.metadata['boss_shuffle'][player]) outfile.write('Boss shuffle: %s\n' % self.metadata['boss_shuffle'][player])
outfile.write( outfile.write(
'Enemy shuffle: %s\n' % bool_to_text(self.metadata['enemy_shuffle'][player])) 'Enemy shuffle: %s\n' % bool_to_text(self.metadata['enemy_shuffle'][player]))

View File

@ -219,25 +219,41 @@ end)
commands.add_command("ap-get-technology", "Grant a technology, used by the Archipelago Client.", function(call) 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 = {}
end
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 tech_name = chunks[1]
local index = chunks[2] local index = chunks[2]
local source = chunks[3] or "Archipelago" local source = chunks[3] or "Archipelago"
local tech = force.technologies[tech_name] if progressive_technologies[tech_name] ~= nil then
if global.index_sync[index] == nil then -- not yet received prog item
if tech ~= nil then global.index_sync[index] = tech_name
if global.index_sync == nil then local tech_stack = progressive_technologies[tech_name]
global.index_sync = {} for _, tech_name in ipairs(tech_stack) do
tech = force.technologies[tech_name]
if tech.researched ~= true then
game.print({"", "Received [technology=" .. tech.name .. "] from ", source})
game.play_sound({path="utility/research_completed"})
tech.researched = true
return
end
end
end end
if global.index_sync[index] ~= nil and global.index_sync[index] ~= tech then elseif force.technologies[tech_name] ~= nil then
game.print("Warning: Desync Detected. Duplicate/Missing items may occur.") tech = force.technologies[tech_name]
end if tech ~= nil then
global.index_sync[index] = tech if global.index_sync[index] ~= nil and global.index_sync[index] ~= tech then
if tech.researched ~= true then game.print("Warning: Desync Detected. Duplicate/Missing items may occur.")
game.print({"", "Received [technology=" .. tech.name .. "] from ", source}) end
game.play_sound({path="utility/research_completed"}) global.index_sync[index] = tech
tech.researched = true if tech.researched ~= true then
game.print({"", "Received [technology=" .. tech.name .. "] from ", source})
game.play_sound({path="utility/research_completed"})
tech.researched = true
end
end end
else else
game.print("Unknown Technology " .. tech_name) game.print("Unknown Technology " .. tech_name)
@ -248,3 +264,6 @@ end)
commands.add_command("ap-rcon-info", "Used by the Archipelago client to get information", function(call) commands.add_command("ap-rcon-info", "Used by the Archipelago client to get information", function(call)
rcon.print(game.table_to_json({["slot_name"] = SLOT_NAME, ["seed_name"] = SEED_NAME})) rcon.print(game.table_to_json({["slot_name"] = SLOT_NAME, ["seed_name"] = SEED_NAME}))
end) end)
-- data
progressive_technologies = {{ dict_to_lua(progressive_technology_table) }}

View File

@ -72,9 +72,11 @@ prep_copy(new_tree_copy, original_tech)
{% if tech_cost_scale != 1 %} {% if tech_cost_scale != 1 %}
new_tree_copy.unit.count = math.max(1, math.floor(new_tree_copy.unit.count * {{ tech_cost_scale }})) new_tree_copy.unit.count = math.max(1, math.floor(new_tree_copy.unit.count * {{ tech_cost_scale }}))
{% endif %} {% endif %}
{%- if item_name in tech_table and tech_tree_information == 2 or original_tech_name in static_nodes -%} {%- if (tech_tree_information == 2 or original_tech_name in static_nodes) and item_name in base_tech_table -%}
{#- copy Factorio Technology Icon -#} {#- copy Factorio Technology Icon -#}
copy_factorio_icon(new_tree_copy, "{{ item_name }}") copy_factorio_icon(new_tree_copy, "{{ item_name }}")
{%- elif (tech_tree_information == 2 or original_tech_name in static_nodes) and item_name in progressive_technology_table -%}
copy_factorio_icon(new_tree_copy, "{{ progressive_technology_table[item_name][0] }}")
{%- else -%} {%- else -%}
{#- use default AP icon if no Factorio graphics exist -#} {#- use default AP icon if no Factorio graphics exist -#}
{% if advancement or not tech_tree_information %}set_ap_icon(new_tree_copy){% else %}set_ap_unimportant_icon(new_tree_copy){% endif %} {% if advancement or not tech_tree_information %}set_ap_icon(new_tree_copy){% else %}set_ap_unimportant_icon(new_tree_copy){% endif %}

View File

@ -5,10 +5,18 @@
{% endfor -%} {% endfor -%}
} }
{%- endmacro %} {%- endmacro %}
{% macro list_to_lua(list) -%}
{
{%- for key in list -%}
{{ variable_to_lua(key) }}{% if not loop.last %},{% endif %}
{% endfor -%}
}
{%- endmacro %}
{%- macro variable_to_lua(value) %} {%- macro variable_to_lua(value) %}
{%- if value is mapping -%}{{ dict_to_lua(value) }} {%- if value is mapping -%}{{ dict_to_lua(value) }}
{%- elif value is boolean -%}{{ value | string | lower }} {%- elif value is boolean -%}{{ value | string | lower }}
{%- elif value is string -%} "{{ value | safe }}" {%- elif value is string -%}"{{ value | safe }}"
{%- elif value is iterable -%}{{ list_to_lua(value) }}
{%- else -%} {{ value | safe }} {%- else -%} {{ value | safe }}
{%- endif -%} {%- endif -%}
{%- endmacro -%} {%- endmacro -%}

View File

@ -91,6 +91,9 @@ Factorio:
single_craft: 0 single_craft: 0
half_stack: 0 half_stack: 0
stack: 0 stack: 0
progressive:
on: 1
off: 0
tech_tree_information: tech_tree_information:
none: 0 none: 0
advancement: 0 # show which items are a logical advancement advancement: 0 # show which items are a logical advancement

View File

@ -32,7 +32,7 @@ assert len(lookup_any_location_name_to_id) == len(lookup_any_location_id_to_name
network_data_package = {"lookup_any_location_id_to_name": lookup_any_location_id_to_name, network_data_package = {"lookup_any_location_id_to_name": lookup_any_location_id_to_name,
"lookup_any_item_id_to_name": lookup_any_item_id_to_name, "lookup_any_item_id_to_name": lookup_any_item_id_to_name,
"version": 7} "version": 9}
@enum.unique @enum.unique

View File

@ -11,7 +11,8 @@ import Utils
import shutil import shutil
from . import Options from . import Options
from BaseClasses import MultiWorld from BaseClasses import MultiWorld
from .Technologies import tech_table, rocket_recipes, recipes, free_sample_blacklist from .Technologies import tech_table, rocket_recipes, recipes, free_sample_blacklist, progressive_technology_table, \
base_tech_table, tech_to_progressive_lookup, progressive_tech_table
template_env: Optional[jinja2.Environment] = None template_env: Optional[jinja2.Environment] = None
@ -70,6 +71,7 @@ def generate_mod(world: MultiWorld, player: int):
6: 10}[world.tech_cost[player].value] 6: 10}[world.tech_cost[player].value]
template_data = {"locations": locations, "player_names": player_names, "tech_table": tech_table, template_data = {"locations": locations, "player_names": player_names, "tech_table": tech_table,
"base_tech_table": base_tech_table, "tech_to_progressive_lookup": tech_to_progressive_lookup,
"mod_name": mod_name, "allowed_science_packs": world.max_science_pack[player].get_allowed_packs(), "mod_name": mod_name, "allowed_science_packs": world.max_science_pack[player].get_allowed_packs(),
"tech_cost_scale": tech_cost_scale, "custom_technologies": world.worlds[player].custom_technologies, "tech_cost_scale": tech_cost_scale, "custom_technologies": world.worlds[player].custom_technologies,
"tech_tree_layout_prerequisites": world.tech_tree_layout_prerequisites[player], "tech_tree_layout_prerequisites": world.tech_tree_layout_prerequisites[player],
@ -78,7 +80,9 @@ def generate_mod(world: MultiWorld, player: int):
"starting_items": world.starting_items[player], "recipes": recipes, "starting_items": world.starting_items[player], "recipes": recipes,
"random": world.slot_seeds[player], "static_nodes": world.worlds[player].static_nodes, "random": world.slot_seeds[player], "static_nodes": world.worlds[player].static_nodes,
"recipe_time_scale": recipe_time_scales[world.recipe_time[player].value], "recipe_time_scale": recipe_time_scales[world.recipe_time[player].value],
"free_sample_blacklist": {item : 1 for item in free_sample_blacklist}} "free_sample_blacklist": {item : 1 for item in free_sample_blacklist},
"progressive_technology_table": {tech.name : tech.progressive for tech in
progressive_technology_table.values()}}
for factorio_option in Options.factorio_options: for factorio_option in Options.factorio_options:
template_data[factorio_option] = getattr(world, factorio_option)[player].value template_data[factorio_option] = getattr(world, factorio_option)[player].value

View File

@ -96,5 +96,6 @@ factorio_options: typing.Dict[str, type(Option)] = {
"starting_items": FactorioStartItems, "starting_items": FactorioStartItems,
"recipe_time": RecipeTime, "recipe_time": RecipeTime,
"imported_blueprints": DefaultOnToggle, "imported_blueprints": DefaultOnToggle,
"world_gen": FactorioWorldGen "world_gen": FactorioWorldGen,
"progressive": DefaultOnToggle
} }

View File

@ -10,6 +10,7 @@ funnel_slice_sizes = {TechTreeLayout.option_small_funnels: 6,
TechTreeLayout.option_medium_funnels: 10, TechTreeLayout.option_medium_funnels: 10,
TechTreeLayout.option_large_funnels: 15} TechTreeLayout.option_large_funnels: 15}
def get_shapes(factorio_world) -> Dict[str, List[str]]: def get_shapes(factorio_world) -> Dict[str, List[str]]:
world = factorio_world.world world = factorio_world.world
player = factorio_world.player player = factorio_world.player

View File

@ -1,8 +1,9 @@
from __future__ import annotations from __future__ import annotations
# Factorio technologies are imported from a .json document in /data # Factorio technologies are imported from a .json document in /data
from typing import Dict, Set, FrozenSet from typing import Dict, Set, FrozenSet, Tuple
import os import os
import json import json
import string
import Utils import Utils
import logging import logging
@ -36,10 +37,11 @@ class FactorioElement():
class Technology(FactorioElement): # maybe make subclass of Location? class Technology(FactorioElement): # maybe make subclass of Location?
def __init__(self, name, ingredients, factorio_id): def __init__(self, name: str, ingredients: Set[str], factorio_id: int, progressive: Tuple[str] = ()):
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
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}")
@ -104,7 +106,6 @@ class Machine(FactorioElement):
# 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]
factorio_id += 1
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)
factorio_id += 1 factorio_id += 1
@ -118,7 +119,7 @@ for technology, data in raw.items():
recipe_sources.setdefault(recipe_name, set()).add(technology) recipe_sources.setdefault(recipe_name, set()).add(technology)
del (raw) del (raw)
lookup_id_to_name: Dict[int, str] = {item_id: item_name for item_name, item_id in tech_table.items()}
recipes = {} recipes = {}
all_product_sources: Dict[str, Set[Recipe]] = {"character": set()} all_product_sources: Dict[str, Set[Recipe]] = {"character": set()}
for recipe_name, recipe_data in raw_recipes.items(): for recipe_name, recipe_data in raw_recipes.items():
@ -255,3 +256,92 @@ rocket_recipes = {
Options.MaxSciencePack.option_automation_science_pack: Options.MaxSciencePack.option_automation_science_pack:
{"copper-cable": 10, "iron-plate": 10, "wood": 10} {"copper-cable": 10, "iron-plate": 10, "wood": 10}
} }
# progressive technologies
# auto-progressive
progressive_rows = {}
progressive_incs = set()
for tech_name in tech_table:
if tech_name.endswith("-1"):
progressive_rows[tech_name] = []
elif tech_name[-2] == "-" and tech_name[-1] in string.digits:
progressive_incs.add(tech_name)
for root, progressive in progressive_rows.items():
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)
# 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])
# no -1 start
base_starts = set()
for remnant in progressive_incs:
if remnant[-1] == "2":
base_starts.add(remnant[:-2])
for root in base_starts:
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)
# science packs
progressive_rows["progressive-science-pack"] = tuple(sorted(required_technologies,
key=lambda name: len(required_technologies[name]))[1:] +
["space-science-pack"])
# manual progressive
progressive_rows["progressive-processing"] = ("steel-processing",
"oil-processing", "sulfur-processing", "advanced-oil-processing",
"uranium-processing", "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-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")
base_tech_table = tech_table.copy() # without progressive techs
base_technology_table = technology_table.copy()
progressive_tech_table: Dict[str, int] = {}
progressive_technology_table: Dict[str, Technology] = {}
for root in sorted(progressive_rows):
progressive = progressive_rows[root]
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_tech_table[root] = progressive_technology.factorio_id
progressive_technology_table[root] = progressive_technology
if any(tech in advancement_technologies for tech in progressive):
advancement_technologies.add(root)
tech_to_progressive_lookup: Dict[str, str] = {}
for technology in progressive_technology_table.values():
for progressive in technology.progressive:
tech_to_progressive_lookup[progressive] = technology.name
tech_table.update(progressive_tech_table)
technology_table.update(progressive_technology_table)
# techs that are never progressive
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}
lookup_id_to_name: Dict[int, str] = {item_id: item_name for item_name, item_id in tech_table.items()}

View File

@ -1,8 +1,9 @@
from ..AutoWorld import World from ..AutoWorld import World
from BaseClasses import Region, Entrance, Location, MultiWorld, Item from BaseClasses import Region, Entrance, Location, MultiWorld, Item
from .Technologies import tech_table, recipe_sources, technology_table, advancement_technologies, \ from .Technologies import base_tech_table, recipe_sources, base_technology_table, advancement_technologies, \
all_ingredient_names, required_technologies, get_rocket_requirements, rocket_recipes all_ingredient_names, required_technologies, get_rocket_requirements, rocket_recipes, \
progressive_technology_table, common_tech_table, tech_to_progressive_lookup, progressive_tech_table
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 from .Options import factorio_options
@ -15,8 +16,16 @@ class Factorio(World):
victory_tech_names = get_rocket_requirements( victory_tech_names = get_rocket_requirements(
frozenset(rocket_recipes[self.world.max_science_pack[self.player].value])) frozenset(rocket_recipes[self.world.max_science_pack[self.player].value]))
for tech_name, tech_id in tech_table.items():
tech_item = Item(tech_name, tech_name in advancement_technologies or tech_name in victory_tech_names,
for tech_name, tech_id in base_tech_table.items():
if self.world.progressive and tech_name in tech_to_progressive_lookup:
item_name = tech_to_progressive_lookup[tech_name]
tech_id = progressive_tech_table[item_name]
else:
item_name = tech_name
tech_item = Item(item_name, item_name in advancement_technologies or item_name in victory_tech_names,
tech_id, self.player) tech_id, self.player)
tech_item.game = "Factorio" tech_item.game = "Factorio"
if tech_name in self.static_nodes: if tech_name in self.static_nodes:
@ -25,7 +34,7 @@ class Factorio(World):
self.world.itempool.append(tech_item) self.world.itempool.append(tech_item)
world_gen = self.world.world_gen[self.player].value world_gen = self.world.world_gen[self.player].value
if world_gen.get("seed", None) is None: # allow seed 0 if world_gen.get("seed", None) is None: # allow seed 0
world_gen["seed"] = self.world.slot_seeds[self.player].randint(0, 2**32-1) # 32 bit uint world_gen["seed"] = self.world.slot_seeds[self.player].randint(0, 2**32-1) # 32 bit uint
def generate_output(self): def generate_output(self):
generate_mod(self.world, self.player) generate_mod(self.world, self.player)
@ -38,7 +47,7 @@ class Factorio(World):
nauvis = Region("Nauvis", None, "Nauvis", player) nauvis = Region("Nauvis", None, "Nauvis", player)
nauvis.world = menu.world = self.world nauvis.world = menu.world = self.world
for tech_name, tech_id in tech_table.items(): for tech_name, tech_id in base_tech_table.items():
tech = Location(player, tech_name, tech_id, nauvis) tech = Location(player, tech_name, tech_id, nauvis)
nauvis.locations.append(tech) nauvis.locations.append(tech)
tech.game = "Factorio" tech.game = "Factorio"
@ -83,6 +92,15 @@ class Factorio(World):
world.completion_condition[player] = lambda state: state.has('Victory', player) world.completion_condition[player] = lambda state: state.has('Victory', player)
def collect(self, state, item) -> bool:
if item.advancement and item.name in progressive_technology_table:
prog_table = progressive_technology_table[item.name].progressive
for item_name in prog_table:
if not state.has(item_name, item.player):
state.prog_items[item_name, item.player] += 1
return True
return super(Factorio, self).collect(state, item)
def get_required_client_version(self) -> tuple: def get_required_client_version(self) -> tuple:
return max((0, 1, 4), super(Factorio, self).get_required_client_version()) return max((0, 1, 4), super(Factorio, self).get_required_client_version())
@ -91,6 +109,6 @@ class Factorio(World):
def set_custom_technologies(world: MultiWorld, player: int): def set_custom_technologies(world: MultiWorld, player: int):
custom_technologies = {} custom_technologies = {}
allowed_packs = world.max_science_pack[player].get_allowed_packs() allowed_packs = world.max_science_pack[player].get_allowed_packs()
for technology_name, technology in technology_table.items(): for technology_name, technology in base_technology_table.items():
custom_technologies[technology_name] = technology.get_custom(world, allowed_packs, player) custom_technologies[technology_name] = technology.get_custom(world, allowed_packs, player)
return custom_technologies return custom_technologies