Factorio: add silo 'spawn' option
This commit is contained in:
parent
08beb5fbe6
commit
db0604f585
|
@ -97,6 +97,7 @@ Factorio:
|
||||||
silo:
|
silo:
|
||||||
vanilla: 1
|
vanilla: 1
|
||||||
randomize_recipe: 0
|
randomize_recipe: 0
|
||||||
|
spawn: 0 # spawn silo near player spawn point
|
||||||
free_samples:
|
free_samples:
|
||||||
none: 1
|
none: 1
|
||||||
single_craft: 0
|
single_craft: 0
|
||||||
|
|
|
@ -45,9 +45,10 @@ class TechCost(Choice):
|
||||||
|
|
||||||
|
|
||||||
class Silo(Choice):
|
class Silo(Choice):
|
||||||
"""Ingredients to craft rocket silo."""
|
"""Ingredients to craft rocket silo or auto-place if set to spawn."""
|
||||||
option_vanilla = 0
|
option_vanilla = 0
|
||||||
option_randomize_recipe = 1
|
option_randomize_recipe = 1
|
||||||
|
option_spawn = 2
|
||||||
default = 0
|
default = 0
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -278,8 +278,9 @@ for ingredient_name in all_ingredient_names:
|
||||||
@functools.lru_cache(10)
|
@functools.lru_cache(10)
|
||||||
def get_rocket_requirements(silo_recipe: Recipe, part_recipe: Recipe) -> Set[str]:
|
def get_rocket_requirements(silo_recipe: Recipe, part_recipe: Recipe) -> Set[str]:
|
||||||
techs = set()
|
techs = set()
|
||||||
for ingredient in silo_recipe.ingredients:
|
if silo_recipe:
|
||||||
techs |= recursively_get_unlocking_technologies(ingredient)
|
for ingredient in silo_recipe.ingredients:
|
||||||
|
techs |= recursively_get_unlocking_technologies(ingredient)
|
||||||
for ingredient in part_recipe.ingredients:
|
for ingredient in part_recipe.ingredients:
|
||||||
techs |= recursively_get_unlocking_technologies(ingredient)
|
techs |= recursively_get_unlocking_technologies(ingredient)
|
||||||
return {tech.name for tech in techs}
|
return {tech.name for tech in techs}
|
||||||
|
|
|
@ -7,7 +7,7 @@ from .Technologies import base_tech_table, recipe_sources, base_technology_table
|
||||||
get_science_pack_pools, Recipe, recipes, technology_table, tech_table
|
get_science_pack_pools, Recipe, recipes, technology_table, 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, Silo
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
@ -26,7 +26,10 @@ class Factorio(World):
|
||||||
location_name_to_id = base_tech_table
|
location_name_to_id = base_tech_table
|
||||||
|
|
||||||
def generate_basic(self):
|
def generate_basic(self):
|
||||||
|
skip_silo = self.world.silo[self.player].value == Silo.option_spawn
|
||||||
for tech_name in base_tech_table:
|
for tech_name in base_tech_table:
|
||||||
|
if skip_silo and tech_name == "rocket-silo":
|
||||||
|
continue
|
||||||
if self.world.progressive:
|
if self.world.progressive:
|
||||||
item_name = tech_to_progressive_lookup.get(tech_name, tech_name)
|
item_name = tech_to_progressive_lookup.get(tech_name, tech_name)
|
||||||
else:
|
else:
|
||||||
|
@ -49,7 +52,10 @@ class Factorio(World):
|
||||||
menu.exits.append(crash)
|
menu.exits.append(crash)
|
||||||
nauvis = Region("Nauvis", None, "Nauvis", player, self.world)
|
nauvis = Region("Nauvis", None, "Nauvis", player, self.world)
|
||||||
|
|
||||||
|
skip_silo = self.world.silo[self.player].value == Silo.option_spawn
|
||||||
for tech_name, tech_id in base_tech_table.items():
|
for tech_name, tech_id in base_tech_table.items():
|
||||||
|
if skip_silo and tech_name == "rocket-silo":
|
||||||
|
continue
|
||||||
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"
|
||||||
|
@ -92,7 +98,10 @@ class Factorio(World):
|
||||||
location.access_rule = lambda state, ingredient=ingredient: \
|
location.access_rule = lambda state, ingredient=ingredient: \
|
||||||
all(state.has(technology.name, player) for technology in required_technologies[ingredient])
|
all(state.has(technology.name, player) for technology in required_technologies[ingredient])
|
||||||
|
|
||||||
|
skip_silo = self.world.silo[self.player].value == Silo.option_spawn
|
||||||
for tech_name, technology in self.custom_technologies.items():
|
for tech_name, technology in self.custom_technologies.items():
|
||||||
|
if skip_silo and tech_name == "rocket-silo":
|
||||||
|
continue
|
||||||
location = world.get_location(tech_name, player)
|
location = world.get_location(tech_name, player)
|
||||||
Rules.set_rule(location, technology.build_rule(player))
|
Rules.set_rule(location, technology.build_rule(player))
|
||||||
prequisites = shapes.get(tech_name)
|
prequisites = shapes.get(tech_name)
|
||||||
|
@ -101,7 +110,8 @@ class Factorio(World):
|
||||||
Rules.add_rule(location, lambda state,
|
Rules.add_rule(location, lambda state,
|
||||||
locations=locations: all(state.can_reach(loc) for loc in locations))
|
locations=locations: all(state.can_reach(loc) for loc in locations))
|
||||||
|
|
||||||
silo_recipe = self.custom_recipes["rocket-silo"] \
|
silo_recipe = None if self.world.silo[self.player].value == Silo.option_spawn \
|
||||||
|
else self.custom_recipes["rocket-silo"] \
|
||||||
if "rocket-silo" in self.custom_recipes \
|
if "rocket-silo" in self.custom_recipes \
|
||||||
else next(iter(all_product_sources.get("rocket-silo")))
|
else next(iter(all_product_sources.get("rocket-silo")))
|
||||||
part_recipe = self.custom_recipes["rocket-part"]
|
part_recipe = self.custom_recipes["rocket-part"]
|
||||||
|
@ -230,7 +240,7 @@ class Factorio(World):
|
||||||
new_recipe.recursive_unlocking_technologies}
|
new_recipe.recursive_unlocking_technologies}
|
||||||
self.custom_recipes[pack] = new_recipe
|
self.custom_recipes[pack] = new_recipe
|
||||||
|
|
||||||
if self.world.silo[self.player]:
|
if self.world.silo[self.player].value == Silo.option_randomize_recipe:
|
||||||
valid_pool = []
|
valid_pool = []
|
||||||
for pack in self.world.max_science_pack[self.player].get_allowed_packs():
|
for pack in self.world.max_science_pack[self.player].get_allowed_packs():
|
||||||
valid_pool += sorted(science_pack_pools[pack])
|
valid_pool += sorted(science_pack_pools[pack])
|
||||||
|
|
|
@ -18,19 +18,56 @@ function set_permissions()
|
||||||
end
|
end
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
|
||||||
|
|
||||||
|
function check_spawn_silo(force)
|
||||||
|
if force.players and #force.players > 0 and force.get_entity_count("rocket-silo") < 1 then
|
||||||
|
local surface = game.get_surface(1)
|
||||||
|
local spawn_position = force.get_spawn_position(surface)
|
||||||
|
spawn_entity(surface, force, "rocket-silo", spawn_position.x, spawn_position.y, 80, true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function check_despawn_silo(force)
|
||||||
|
if not force.players or #force.players < 1 and force.get_entity_count("rocket-silo") > 0 then
|
||||||
|
local surface = game.get_surface(1)
|
||||||
|
local spawn_position = force.get_spawn_position(surface)
|
||||||
|
local x1 = spawn_position.x - 41
|
||||||
|
local x2 = spawn_position.x + 41
|
||||||
|
local y1 = spawn_position.y - 41
|
||||||
|
local y2 = spawn_position.y + 41
|
||||||
|
local silos = surface.find_entities_filtered{area = { {x1, y1}, {x2, y2} },
|
||||||
|
name = "rocket-silo",
|
||||||
|
force = force}
|
||||||
|
for i,silo in ipairs(silos) do
|
||||||
|
silo.destructible = true
|
||||||
|
silo.destroy()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
-- Initialize force data, either from it being created or already being part of the game when the mod was added.
|
-- Initialize force data, either from it being created or already being part of the game when the mod was added.
|
||||||
function on_force_created(event)
|
function on_force_created(event)
|
||||||
--event.force appears to be LuaForce.name, not LuaForce
|
local force = event.force
|
||||||
game.forces[event.force].research_queue_enabled = true
|
if type(event.force) == "string" then -- should be of type LuaForce
|
||||||
|
force = game.forces[force]
|
||||||
|
end
|
||||||
|
force.research_queue_enabled = true
|
||||||
local data = {}
|
local data = {}
|
||||||
data['earned_samples'] = {{ dict_to_lua(starting_items) }}
|
data['earned_samples'] = {{ dict_to_lua(starting_items) }}
|
||||||
data["victory"] = 0
|
data["victory"] = 0
|
||||||
global.forcedata[event.force] = data
|
global.forcedata[event.force] = data
|
||||||
|
{%- if silo == 2 %}
|
||||||
|
check_spawn_silo(force)
|
||||||
|
{%- endif %}
|
||||||
end
|
end
|
||||||
script.on_event(defines.events.on_force_created, on_force_created)
|
script.on_event(defines.events.on_force_created, on_force_created)
|
||||||
|
|
||||||
-- Destroy force data. This doesn't appear to be currently possible with the Factorio API, but here for completeness.
|
-- Destroy force data. This doesn't appear to be currently possible with the Factorio API, but here for completeness.
|
||||||
function on_force_destroyed(event)
|
function on_force_destroyed(event)
|
||||||
|
{%- if silo == 2 %}
|
||||||
|
check_despawn_silo(event.force)
|
||||||
|
{%- endif %}
|
||||||
global.forcedata[event.force.name] = nil
|
global.forcedata[event.force.name] = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -44,9 +81,21 @@ function on_player_created(event)
|
||||||
data['pending_samples'] = table.deepcopy(global.forcedata[player.force.name]['earned_samples'])
|
data['pending_samples'] = table.deepcopy(global.forcedata[player.force.name]['earned_samples'])
|
||||||
global.playerdata[player.index] = data
|
global.playerdata[player.index] = data
|
||||||
update_player(player.index) -- Attempt to send pending free samples, if relevant.
|
update_player(player.index) -- Attempt to send pending free samples, if relevant.
|
||||||
|
{%- if silo == 2 %}
|
||||||
|
check_spawn_silo(game.players[event.player_index].force)
|
||||||
|
{%- endif %}
|
||||||
end
|
end
|
||||||
script.on_event(defines.events.on_player_created, on_player_created)
|
script.on_event(defines.events.on_player_created, on_player_created)
|
||||||
|
|
||||||
|
-- Create/destroy silo for force if player switched force
|
||||||
|
function on_player_changed_force(event)
|
||||||
|
{%- if silo == 2 %}
|
||||||
|
check_despawn_silo(event.force)
|
||||||
|
check_spawn_silo(game.players[event.player_index].force)
|
||||||
|
{%- endif %}
|
||||||
|
end
|
||||||
|
script.on_event(defines.events.on_player_changed_force, on_player_changed_force)
|
||||||
|
|
||||||
function on_player_removed(event)
|
function on_player_removed(event)
|
||||||
global.playerdata[event.player_index] = nil
|
global.playerdata[event.player_index] = nil
|
||||||
end
|
end
|
||||||
|
@ -195,6 +244,98 @@ function chain_lookup(table, ...)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function spawn_entity(surface, force, name, x, y, radius, randomize)
|
||||||
|
local prototype = game.entity_prototypes[name]
|
||||||
|
local args = { -- For can_place_entity and place_entity
|
||||||
|
name = prototype.name,
|
||||||
|
position = {x = x, y = y},
|
||||||
|
force = force.name,
|
||||||
|
build_check_type = defines.build_check_type.blueprint_ghost,
|
||||||
|
forced = true
|
||||||
|
}
|
||||||
|
|
||||||
|
local box = prototype.selection_box
|
||||||
|
local dims = {
|
||||||
|
w = box.right_bottom.x - box.left_top.x,
|
||||||
|
h = box.right_bottom.y - box.left_top.y
|
||||||
|
}
|
||||||
|
local entity_radius = math.ceil(math.max(dims.w, dims.h) / math.sqrt(2) / 2)
|
||||||
|
local bounds = {
|
||||||
|
xmin = math.ceil(x - (radius - dims.w/2)),
|
||||||
|
xmax = math.floor(x + (radius - dims.w/2)),
|
||||||
|
ymin = math.ceil(y - (radius - dims.h/2)),
|
||||||
|
ymax = math.floor(y + (radius - dims.h/2))
|
||||||
|
}
|
||||||
|
|
||||||
|
local entity = nil
|
||||||
|
local attempts = 1000
|
||||||
|
for i = 1,attempts do -- Try multiple times
|
||||||
|
-- Find a position
|
||||||
|
if (randomize and i < attempts-3) or (not randomize and i ~= 1) then
|
||||||
|
args.position.x = math.random(bounds.xmin, bounds.xmax)
|
||||||
|
args.position.y = math.random(bounds.ymin, bounds.ymax)
|
||||||
|
elseif randomize then
|
||||||
|
args.position.x = x + (i + 3 - attempts) * dims.w
|
||||||
|
args.position.y = y + (i + 3 - attempts) * dims.h
|
||||||
|
end
|
||||||
|
-- Generate required chunks
|
||||||
|
local x1 = args.position.x + box.left_top.x
|
||||||
|
local x2 = args.position.x + box.right_bottom.x
|
||||||
|
local y1 = args.position.y + box.left_top.y
|
||||||
|
local y2 = args.position.y + box.right_bottom.y
|
||||||
|
if not surface.is_chunk_generated({x = x1, y = y1}) or
|
||||||
|
not surface.is_chunk_generated({x = x2, y = y1}) or
|
||||||
|
not surface.is_chunk_generated({x = x1, y = y2}) or
|
||||||
|
not surface.is_chunk_generated({x = x2, y = y2}) then
|
||||||
|
--player.print("Generating chunk at " .. serpent.line(args.position) .. ", radius=" .. entity_radius)
|
||||||
|
surface.request_to_generate_chunks(args.position, entity_radius)
|
||||||
|
surface.force_generate_chunk_requests()
|
||||||
|
end
|
||||||
|
-- Try to place entity
|
||||||
|
if surface.can_place_entity(args) then
|
||||||
|
-- Can hypothetically place this entity here. Destroy everything underneath it.
|
||||||
|
local collision_area = {
|
||||||
|
{
|
||||||
|
args.position.x + prototype.collision_box.left_top.x,
|
||||||
|
args.position.y + prototype.collision_box.left_top.x
|
||||||
|
},
|
||||||
|
{
|
||||||
|
args.position.x + prototype.collision_box.right_bottom.x,
|
||||||
|
args.position.y + prototype.collision_box.right_bottom.x
|
||||||
|
}
|
||||||
|
}
|
||||||
|
local entities = surface.find_entities_filtered {
|
||||||
|
area = collision_area,
|
||||||
|
collision_mask = prototype.collision_mask
|
||||||
|
}
|
||||||
|
local has_invalid_entities = false
|
||||||
|
for _, entity in pairs(entities) do
|
||||||
|
if entity.force and (entity.force.name ~= 'neutral') then
|
||||||
|
has_invalid_entities = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if not has_invalid_entities then
|
||||||
|
for _, entity in pairs(entities) do
|
||||||
|
entity.destroy({do_cliff_correction=true, raise_destroy=true})
|
||||||
|
end
|
||||||
|
args.build_check_type = defines.build_check_type.script
|
||||||
|
args.create_build_effect_smoke = false
|
||||||
|
entity = surface.create_entity(args)
|
||||||
|
if entity then
|
||||||
|
entity.destructible = false
|
||||||
|
entity.minable = false
|
||||||
|
entity.rotatable = false
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if entity == nil then
|
||||||
|
force.print("Failed to place " .. args.name .. " in " .. serpent.line({x = x, y = y, radius = radius}))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
-- add / commands
|
-- add / commands
|
||||||
commands.add_command("ap-sync", "Used by the Archipelago client to get progress information", function(call)
|
commands.add_command("ap-sync", "Used by the Archipelago client to get progress information", function(call)
|
||||||
local force
|
local force
|
||||||
|
@ -268,5 +409,13 @@ commands.add_command("ap-rcon-info", "Used by the Archipelago client to get info
|
||||||
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)
|
||||||
|
|
||||||
|
|
||||||
|
{% if allow_cheats -%}
|
||||||
|
commands.add_command("ap-spawn-silo", "Attempts to spawn a silo around 0,0", function(call)
|
||||||
|
spawn_entity(game.player.surface, game.player.force, "rocket-silo", 0, 0, 80, true)
|
||||||
|
end)
|
||||||
|
{% endif -%}
|
||||||
|
|
||||||
|
|
||||||
-- data
|
-- data
|
||||||
progressive_technologies = {{ dict_to_lua(progressive_technology_table) }}
|
progressive_technologies = {{ dict_to_lua(progressive_technology_table) }}
|
||||||
|
|
|
@ -106,4 +106,9 @@ data:extend{new_tree_copy}
|
||||||
adjust_energy("{{ recipe_name }}", {{ random.triangular(*recipe_time_scale) }})
|
adjust_energy("{{ recipe_name }}", {{ random.triangular(*recipe_time_scale) }})
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
{%- endfor -%}
|
{%- endfor -%}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{%- if silo==2 %}
|
||||||
|
-- disable silo research for pre-placed silo
|
||||||
|
technologies["rocket-silo"].hidden = true
|
||||||
|
{%- endif %}
|
||||||
|
|
Loading…
Reference in New Issue