Factorio: add Progressive Option
This commit is contained in:
parent
a11e840d36
commit
e58ae58e24
|
@ -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]))
|
||||||
|
|
|
@ -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)
|
||||||
|
@ -247,4 +263,7 @@ 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) }}
|
|
@ -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 %}
|
||||||
|
|
|
@ -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 -%}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
|
@ -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
|
||||||
|
|
|
@ -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()}
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue