You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2072 lines
75 KiB
2072 lines
75 KiB
require("stdlib/table")
|
|
require("stdlib/string")
|
|
mod_gui = require("__core__/lualib/mod-gui")
|
|
collision_mask_util_extended = require("__space-exploration__/collision-mask-util-extended/control/collision-mask-util-control")
|
|
|
|
version = 0005073 -- 0.5.073
|
|
local mod_display_name = "Space Exploration"
|
|
is_debug_mode = false
|
|
|
|
Util = require("scripts/util") util = Util
|
|
sha2 = require('scripts/sha2')
|
|
Essential = require('scripts/essential')
|
|
|
|
Log = require('scripts/log')
|
|
Event = require('scripts/event')
|
|
Profiler = require( 'scripts/profiler')
|
|
|
|
Shared = require("shared")
|
|
UniverseRaw = require("scripts/universe-raw")
|
|
Universe = require("scripts/universe")
|
|
Location = require('scripts/location')
|
|
Pin = require('scripts/pin')
|
|
RemoteView = require('scripts/remote-view')
|
|
SpaceshipObstacles = require('scripts/spaceship-obstacles')
|
|
MapView = require( 'scripts/map-view')
|
|
Respawn = require('scripts/respawn')
|
|
LaunchpadGUI = require('scripts/launchpad-gui')
|
|
Launchpad = require('scripts/launchpad')
|
|
LandingpadGUI = require('scripts/landingpad-gui')
|
|
Landingpad = require('scripts/landingpad')
|
|
Capsule = require('scripts/capsule')
|
|
Zone = require('scripts/zone')
|
|
Zonelist = require('scripts/zonelist')
|
|
Weapon = require('scripts/weapon')
|
|
Medpack = require('scripts/medpack')
|
|
SpaceshipClamp = require('scripts/spaceship-clamp')
|
|
SpaceshipClone = require('scripts/spaceship-clone')
|
|
SpaceshipGUI = require('scripts/spaceship-gui')
|
|
Spaceship = require('scripts/spaceship')
|
|
Coreminer = require('scripts/core-miner')
|
|
CondenserTurbine = require('scripts/condenser-turbine')
|
|
BigTurbine = require('scripts/big-turbine')
|
|
Meteor = require('scripts/meteor')
|
|
Beacon = require('scripts/beacon')
|
|
Lifesupport = require('scripts/lifesupport')
|
|
DeliveryCannonGUI = require('scripts/delivery-cannon-gui')
|
|
DeliveryCannon = require('scripts/delivery-cannon')
|
|
Composites = require('scripts/composites')
|
|
EnergyBeamGUI = require('scripts/energy-beam-gui.lua')
|
|
EnergyBeam = require('scripts/energy-beam')
|
|
EnergyBeamDefence = require('scripts/energy-beam-defence')
|
|
SolarFlare = require('scripts/solar-flare')
|
|
Nexus = require('scripts/nexus')
|
|
Arco = require('scripts/arco')
|
|
Interburbulator = require('scripts/interburbulator')
|
|
LinkedContainer = require('scripts/linked-container')
|
|
|
|
Ancient = require('scripts/ancient')
|
|
DAnchor = require('scripts/dimensional-anchor')
|
|
Ruin = require('scripts/ruin')
|
|
|
|
Informatron = require('scripts/informatron')
|
|
|
|
require('scripts/compatibility/miniloaders')
|
|
EntityMove = require('scripts/compatibility/entity-move')
|
|
AbandonedRuins = require('scripts/compatibility/abandoned-ruins')
|
|
|
|
Migrate = require('scripts/migrate')
|
|
|
|
sp_tile_scaffold = mod_prefix.."space-platform-scaffold"
|
|
sp_tile_plate = mod_prefix.."space-platform-plating"
|
|
name_space_tile = mod_prefix.."space"
|
|
name_out_of_map_tile = "out-of-map"
|
|
space_tiles = {
|
|
name_space_tile
|
|
}
|
|
name_asteroid_tile = mod_prefix.."asteroid"
|
|
|
|
tiles_allowed_in_space = {
|
|
name_out_of_map_tile,
|
|
name_space_tile,
|
|
name_asteroid_tile,
|
|
sp_tile_scaffold,
|
|
sp_tile_plate,
|
|
mod_prefix .. "spaceship-floor",
|
|
"transport-drone-road",
|
|
"transport-drone-proxy-tile",
|
|
}
|
|
|
|
name_fluid_rocket_fuel = mod_prefix.."liquid-rocket-fuel"
|
|
name_thermofluid_hot = mod_prefix.."space-coolant-hot"
|
|
name_thermofluid_supercooled = mod_prefix.."space-coolant-supercooled"
|
|
name_suffix_spaced = "-spaced"
|
|
name_suffix_grounded = "-grounded"
|
|
|
|
name_thruster_suits = {
|
|
mod_prefix.."thruster-suit",
|
|
mod_prefix.."thruster-suit-2",
|
|
mod_prefix.."thruster-suit-3",
|
|
mod_prefix.."thruster-suit-4",
|
|
}
|
|
base_space_thrust = 1
|
|
thruster_suit_thrust = {
|
|
[mod_prefix.."thruster-suit"] = 2,
|
|
[mod_prefix.."thruster-suit-2"] = 3,
|
|
[mod_prefix.."thruster-suit-3"] = 4,
|
|
[mod_prefix.."thruster-suit-4"] = 5,
|
|
}
|
|
|
|
first_starting_item_stacks = {
|
|
{name = mod_prefix.."medpack", count = 5},
|
|
{name = mod_prefix.."capsule-big-biter", count = 1},
|
|
}
|
|
starting_item_stacks = {
|
|
{name = mod_prefix.."medpack", count = 1}
|
|
}
|
|
|
|
suffocation_interval = 120
|
|
|
|
collision_player = mod_prefix.."collision-player"
|
|
collision_player_not_space = mod_prefix.."collision-player-not-space"
|
|
collision_rocket_destination_surface = mod_prefix.."collision-rocket-destination-surface"
|
|
collision_rocket_destination_orbit = mod_prefix.."collision-rocket-destination-orbital"
|
|
|
|
|
|
function get_make_playerdata(player)
|
|
global.playerdata = global.playerdata or {}
|
|
global.playerdata[player.index] = global.playerdata[player.index] or {}
|
|
return global.playerdata[player.index]
|
|
end
|
|
|
|
function player_set_dropdown_values(player, key, values)
|
|
local playerdata = get_make_playerdata(player)
|
|
playerdata.dropdown_values = playerdata.dropdown_values or {}
|
|
playerdata.dropdown_values[key] = values
|
|
end
|
|
|
|
function player_get_dropdown_value(player, key, index)
|
|
local playerdata = get_make_playerdata(player)
|
|
if playerdata.dropdown_values and playerdata.dropdown_values[key] then
|
|
return playerdata.dropdown_values[key][index]
|
|
end
|
|
end
|
|
|
|
function player_clear_dropdown_values(player, key)
|
|
local playerdata = get_make_playerdata(player)
|
|
if playerdata.dropdown_values then playerdata.dropdown_values[key] = nil end
|
|
end
|
|
|
|
function player_clear_all_dropdown_values(player)
|
|
local playerdata = get_make_playerdata(player)
|
|
playerdata.dropdown_values = nil
|
|
end
|
|
|
|
function player_get_character(player)
|
|
if player.character then return player.character end
|
|
local playerdata = get_make_playerdata(player)
|
|
if playerdata.character then
|
|
if playerdata.character.valid then
|
|
return playerdata.character
|
|
else
|
|
playerdata.character = nil
|
|
end
|
|
end
|
|
end
|
|
|
|
-- creation must contain position
|
|
-- returns entity, position
|
|
function create_non_colliding(surface, creation, radius, precision)
|
|
radius = radius or 32
|
|
precision = precision or 1
|
|
local try_pos = creation.position
|
|
local safe_pos = surface.find_non_colliding_position(creation.name, try_pos, radius, 1)or try_pos
|
|
creation.position = safe_pos
|
|
return surface.create_entity(creation), safe_pos
|
|
end
|
|
|
|
-- returns entity, position
|
|
function teleport_non_colliding(entity, position, radius, precision)
|
|
if entity then
|
|
radius = radius or 32
|
|
precision = precision or 1
|
|
local try_pos = position
|
|
local safe_pos = entity.surface.find_non_colliding_position(entity.name, try_pos, radius, 1) or try_pos
|
|
entity.teleport(safe_pos)
|
|
return entity, safe_pos
|
|
end
|
|
end
|
|
|
|
function teleport_non_colliding_player(player, position, surface, radius, precision)
|
|
surface = surface or player.surface
|
|
radius = radius or 32
|
|
precision = precision or 1
|
|
local try_pos = position
|
|
local safe_pos = surface.find_non_colliding_position(player.character.name, try_pos, radius, 1) or try_pos
|
|
player.teleport(safe_pos, surface)
|
|
return player, safe_pos
|
|
end
|
|
|
|
function teleport_character_to_surface(character, surface, position)
|
|
local try_pos = position
|
|
local safe_pos = surface.find_non_colliding_position(character.name, try_pos, 32, 1) or try_pos
|
|
if surface == character.surface then
|
|
-- easy
|
|
character.teleport(safe_pos)
|
|
return character, safe_pos
|
|
end
|
|
local zone = Zone.from_surface(surface)
|
|
if zone then
|
|
Zone.discover(character.force.name, zone)
|
|
end
|
|
if character.player then
|
|
-- use the player to do it
|
|
local player = character.player
|
|
player.teleport(safe_pos, surface) -- surface change breaks character reference
|
|
local playerdata = get_make_playerdata(player)
|
|
playerdata.last_position = nil
|
|
playerdata.set_postition = nil
|
|
playerdata.velocity = nil
|
|
return player.character, safe_pos
|
|
end
|
|
|
|
-- attach a player to do it
|
|
for player_index, playerdata in pairs(global.playerdata) do
|
|
local player = game.players[player_index]
|
|
if player and player.connected then
|
|
if RemoteView.is_active(player) and playerdata.character and playerdata.character == character then
|
|
local player_pos = player.position
|
|
local player_surface = player.surface
|
|
player.teleport(playerdata.character.position, playerdata.character.surface)
|
|
player.set_controller{type = defines.controllers.character, character = playerdata.character}
|
|
player.teleport(safe_pos, surface) -- surface change breaks character reference
|
|
playerdata.character = player.character
|
|
player.set_controller{type = defines.controllers.ghost}
|
|
--player.set_controller{type = defines.controllers.spectator}
|
|
player.teleport(player_pos, player_surface)
|
|
playerdata.last_position = nil
|
|
playerdata.set_postition = nil
|
|
playerdata.velocity = nil
|
|
Log.trace("character moved by reassociation")
|
|
return playerdata.character, safe_pos
|
|
end
|
|
end
|
|
end
|
|
|
|
-- clone the character and destroy the original
|
|
-- what could possibly go wrong?
|
|
surface.clone_entities{
|
|
entities = {character},
|
|
destination_offset = util.vectors_delta(character.position, safe_pos),
|
|
destination_surface = surface,
|
|
destination_force = character.force,
|
|
snap_to_grid = false
|
|
}
|
|
local candidate = surface.find_entity(character.name, safe_pos)
|
|
if candidate and candidate.player == nil
|
|
and candidate.color.r == character.color.r
|
|
and candidate.color.g == character.color.g
|
|
and candidate.color.b == character.color.b then
|
|
candidate.teleport(safe_pos)
|
|
for player_index, playerdata in pairs(global.playerdata) do
|
|
if playerdata.character and playerdata.character == character then
|
|
playerdata.character = candidate
|
|
end
|
|
end
|
|
character.destroy()
|
|
Log.trace("character moved by cloning")
|
|
return clone, safe_pos
|
|
end
|
|
local candidates = surface.find_entities_filtered{
|
|
type = character.type,
|
|
name = character.name,
|
|
force = character.force
|
|
}
|
|
for _, candidate in pairs(candidates) do
|
|
if candidate.player == nil
|
|
and candidate.color.r == character.color.r
|
|
and candidate.color.g == character.color.g
|
|
and candidate.color.b == character.color.b then
|
|
candidate.teleport(safe_pos)
|
|
|
|
for player_index, playerdata in pairs(global.playerdata) do
|
|
if playerdata.character and playerdata.character == character then
|
|
playerdata.character = candidate
|
|
end
|
|
end
|
|
character.destroy()
|
|
Log.trace("character moved by cloning")
|
|
return clone, safe_pos
|
|
end
|
|
end
|
|
|
|
Log.trace("character move by cloning but failed")
|
|
-- failed
|
|
return nil, safe_pos
|
|
end
|
|
|
|
function surface_set_area_tiles(data)
|
|
-- data.surface
|
|
-- data.name (tile type)
|
|
-- data.area
|
|
if not (data.surface and data.name and data.area) then return end
|
|
|
|
local tiles = {}
|
|
for y = data.area.left_top.y, data.area.right_bottom.y, 1 do
|
|
for x = data.area.left_top.x, data.area.right_bottom.x, 1 do
|
|
table.insert(tiles, {
|
|
name = data.name,
|
|
position = {x = x, y = y}})
|
|
end
|
|
end
|
|
data.surface.set_tiles(tiles, true)
|
|
end
|
|
|
|
function surface_set_space_tiles(data)
|
|
-- data.surface
|
|
-- data.area
|
|
if not (data.surface and data.area) then return end
|
|
|
|
local tiles = {}
|
|
for y = data.area.left_top.y, data.area.right_bottom.y, 1 do
|
|
for x = data.area.left_top.x, data.area.right_bottom.x, 1 do
|
|
table.insert(tiles, {
|
|
name = name_space_tile,
|
|
position = {x = x, y = y}})
|
|
end
|
|
end
|
|
data.surface.set_tiles(tiles, true)
|
|
end
|
|
|
|
function position_2d_array_add(array, position)
|
|
if not array[position.y] then array[position.y] = {} end
|
|
if not array[position.y][position.x] then array[position.y][position.x] = position end
|
|
end
|
|
|
|
function position_2d_array_add_range(array, position, range)
|
|
for y = position.y - range, position.y + range, 1 do
|
|
for x = position.x - range, position.x + range, 1 do
|
|
position_2d_array_add(array, {x = x, y = y})
|
|
end
|
|
end
|
|
end
|
|
|
|
function tile_is_space(tile)
|
|
for _, name in pairs(space_tiles) do
|
|
if tile.name == name then return true end
|
|
end
|
|
return false
|
|
end
|
|
|
|
function tile_is_space_platform(tile)
|
|
return tile.name == sp_tile_plate or tile.name == sp_tile_scaffold
|
|
end
|
|
|
|
function tile_is_space_platform(tile)
|
|
return tile.name == sp_tile_plate or tile.name == sp_tile_scaffold
|
|
end
|
|
|
|
|
|
--[[function on_player_created(event)
|
|
--local player = game.players[event.player_index]
|
|
--TODO: capsule crash sequence
|
|
end
|
|
Event.addListener(defines.events.on_player_created, on_player_created)]]--
|
|
|
|
function close_own_guis(player)
|
|
-- NOTE: don't close remote view gui here
|
|
Capsule.gui_close(player)
|
|
SpaceshipGUI.gui_close(player)
|
|
--player_clear_all_dropdown_values(player)
|
|
end
|
|
|
|
|
|
--[[
|
|
tag: {
|
|
surface_name (optional)
|
|
force_name
|
|
position
|
|
icon_type (item/virtual)
|
|
icon_name
|
|
text
|
|
chart_range (optional)
|
|
}
|
|
]]
|
|
function chart_tag_buffer_add(tag)
|
|
local surface = tag.surface
|
|
local force_name = tag.force_name
|
|
local force = game.forces[force_name]
|
|
local range = tag.chart_range or Zone.discovery_scan_radius
|
|
|
|
force.chart(surface, util.position_to_area(tag.position, range))
|
|
|
|
global.chart_tag_buffer = global.chart_tag_buffer or {}
|
|
global.chart_tag_next_id = (global.chart_tag_next_id or 0) + 1
|
|
global.chart_tag_buffer[global.chart_tag_next_id] = tag
|
|
end
|
|
|
|
function process_chart_tag_buffer()
|
|
if global.chart_tag_buffer then
|
|
local tags_remaining = 0
|
|
for _, tag in pairs(global.chart_tag_buffer) do
|
|
local surface = tag.surface
|
|
local force_name = tag.force_name
|
|
local force = game.forces[force_name]
|
|
if force then
|
|
local chart_tag = force.add_chart_tag(surface, {
|
|
icon = {type = tag.icon_type, name = tag.icon_name},
|
|
position = tag.position,
|
|
text = tag.text
|
|
})
|
|
if chart_tag then
|
|
global.chart_tag_buffer[_] = nil
|
|
else
|
|
tags_remaining = tags_remaining + 1
|
|
end
|
|
else
|
|
global.chart_tag_buffer[_] = nil
|
|
end
|
|
end
|
|
if tags_remaining == 0 then
|
|
-- cleanup
|
|
global.chart_tag_buffer = nil
|
|
global.chart_tag_next_id = nil
|
|
end
|
|
end
|
|
end
|
|
|
|
function player_capture_selected(player)
|
|
local playerdata = get_make_playerdata(player)
|
|
if playerdata.capture_text and rendering.is_valid(playerdata.capture_text) then
|
|
rendering.destroy(playerdata.capture_text)
|
|
end
|
|
local entity = player.selected
|
|
if entity and (entity.force.name == "capture" or entity.force.name == "conquest") and entity.type ~= "wall" then
|
|
local range = 1
|
|
local box = entity.bounding_box
|
|
local pos = player.position
|
|
if player.character and pos.x > box.left_top.x - range
|
|
and pos.x < box.right_bottom.x + range
|
|
and pos.y > box.left_top.y - range
|
|
and pos.y < box.right_bottom.y + range then
|
|
local blocker = entity.surface.find_nearest_enemy{position=entity.position, max_distance=32, force=player.force}
|
|
if blocker then
|
|
entity.surface.create_entity{
|
|
name = "flying-text",
|
|
position = entity.position,
|
|
text = {"space-exploration.capture-blocked"},
|
|
render_player_index = player.index,
|
|
}
|
|
else
|
|
entity.force = player.force
|
|
local zone = Zone.from_surface(entity.surface)
|
|
if zone then
|
|
local inventory = entity.get_inventory(defines.inventory.chest)
|
|
if inventory then
|
|
for _, item_name in pairs(Ruin.track_loot_items) do
|
|
local count = inventory.get_item_count(item_name)
|
|
if count > 0 then
|
|
zone.looted_items = zone.looted_items or {}
|
|
zone.looted_items[item_name] = (zone.looted_items[item_name] or 0) + count
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
else
|
|
if not Util.table_contains(
|
|
{"turret", "ammo-turret", "electric-turret", "fluid-turret", "artillery-turret",
|
|
"combat-robot", "logistic-robot", "construction-robot",
|
|
"wall", "gate"}, entity.type) then
|
|
playerdata.capture_text = rendering.draw_text{
|
|
text = {"space-exploration.touch-to-capture"},
|
|
surface = entity.surface,
|
|
target = entity,
|
|
target_offset = {0, -0.5},
|
|
players={player},
|
|
color={r=0.8,g=0.8,b=0.8,a=0.8},
|
|
alignment="center",
|
|
scale = (1 + box.right_bottom.x-box.left_top.x)/3,
|
|
}
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function on_selected_entity_changed(event)
|
|
local player = game.players[event.player_index]
|
|
player_capture_selected(player)
|
|
end
|
|
Event.addListener(defines.events.on_selected_entity_changed, on_selected_entity_changed)
|
|
|
|
|
|
function get_selected_index(array, current)
|
|
local i = 0
|
|
for _, item in ipairs(array) do
|
|
i = i + 1
|
|
if item == current then return i end
|
|
end
|
|
end
|
|
|
|
function get_dropdown_string(element, relevant_value)
|
|
if not relevant_value then relevant_value = 1 end
|
|
if element.selected_index and element.items[element.selected_index] then
|
|
local selected = element.items[element.selected_index]
|
|
if type(selected) == "string" then
|
|
return selected
|
|
elseif type(selected) == "table" and selected[relevant_value] then
|
|
return selected[relevant_value]
|
|
end
|
|
end
|
|
end
|
|
|
|
function selected_name_from_dropdown_preset(element, preset)
|
|
-- options eg: destination_type_options
|
|
|
|
local selected_string = get_dropdown_string(element)
|
|
for _, option in pairs(preset) do
|
|
if type(option.display) == "string" then
|
|
if option.display == selected_string then
|
|
return option.name
|
|
end
|
|
elseif type(option.display) == "table" and option.display[1] == selected_string then
|
|
return option.name
|
|
end
|
|
end
|
|
end
|
|
|
|
function dropdown_from_preset(preset, current)
|
|
-- options eg: destination_type_options
|
|
local selected_index
|
|
local list = {}
|
|
for _, option in pairs(preset) do
|
|
table.insert(list, option.display)
|
|
if option.name == current then selected_index = #list end
|
|
end
|
|
return list, selected_index
|
|
end
|
|
|
|
function count_inventory_slots_used(inv)
|
|
return #inv - inv.count_empty_stacks()
|
|
end
|
|
|
|
function gui_element_or_parent(element, name)
|
|
if not (element and element.valid) then return end
|
|
if element.name == name then
|
|
return element
|
|
elseif element.parent then
|
|
return gui_element_or_parent(element.parent, name)
|
|
end
|
|
end
|
|
|
|
function on_tick_player(player)
|
|
|
|
local playerdata = get_make_playerdata(player)
|
|
|
|
--on_tick_player_gui(player)
|
|
|
|
-- save position
|
|
playerdata.surface_positions = playerdata.surface_positions or {}
|
|
playerdata.surface_positions[player.surface.index] = player.position
|
|
end
|
|
|
|
function on_surface_deleted(event)
|
|
if global.playerdata then
|
|
for _, playerdata in pairs(global.playerdata) do
|
|
if playerdata.surface_positions then
|
|
playerdata.surface_positions[event.surface_index] = nil
|
|
end
|
|
end
|
|
end
|
|
Zone.rebuild_surface_index()
|
|
end
|
|
Event.addListener(defines.events.on_surface_deleted, on_surface_deleted)
|
|
|
|
|
|
function on_marked_for_deconstruction(event)
|
|
if event.entity and event.entity.valid and event.entity.type == "deconstructible-tile-proxy" then
|
|
local position = event.entity.position
|
|
local area = Util.tile_to_area(position)
|
|
local surface = event.entity.surface
|
|
local tile_under = surface.get_hidden_tile(position)
|
|
if tile_under then
|
|
local tile_proto = game.tile_prototypes[tile_under]
|
|
local collision_mask = {}
|
|
for name, blocks in pairs(tile_proto.collision_mask) do
|
|
if blocks then table.insert(collision_mask, name) end
|
|
end
|
|
local blocking_entities = 0
|
|
for _, entity in pairs(event.entity.surface.find_entities_filtered{area = area, collision_mask = collision_mask}) do
|
|
if entity.type ~= "deconstructible-tile-proxy" and entity.type ~= "corpse" then
|
|
blocking_entities = blocking_entities + 1
|
|
end
|
|
end
|
|
if blocking_entities > 0 then
|
|
event.entity.destroy()
|
|
--[[surface.create_entity{
|
|
name = "flying-text",
|
|
position = position,
|
|
text = "Blocked",
|
|
render_player_index = event.player_index,
|
|
}]]
|
|
end
|
|
end
|
|
end
|
|
end
|
|
Event.addListener(defines.events.on_marked_for_deconstruction, on_marked_for_deconstruction)
|
|
|
|
function is_character_passenger(character)
|
|
if character and character.vehicle then return true end
|
|
if global.tick_tasks then
|
|
for _, tick_task in pairs(global.tick_tasks) do
|
|
if tick_task.passengers then
|
|
for _, passenger in pairs(tick_task.passengers) do
|
|
if passenger == character then
|
|
return true
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
|
|
function on_player_changed_position(event)
|
|
local player = game.players[event.player_index]
|
|
if not player.character then return end
|
|
local playerdata = get_make_playerdata(player)
|
|
player_capture_selected(player)
|
|
local zone = Zone.from_surface(player.surface)
|
|
if zone then
|
|
if player.vehicle and player.vehicle.type == "spider-vehicle" then
|
|
local tile = player.surface.get_tile(player.vehicle.position)
|
|
if tile.name == "interior-divider" then
|
|
playerdata.interior_divider_collisions = (playerdata.interior_divider_collisions or 0) + 1
|
|
local max_health = player.vehicle.prototype.max_health
|
|
player.vehicle.health = math.min(max_health - max_health * playerdata.interior_divider_collisions / 10, player.vehicle.health - player.vehicle.health / 10)
|
|
if player.vehicle.health <= 1 then
|
|
player.vehicle.die()
|
|
playerdata.interior_divider_collisions = nil
|
|
teleport_non_colliding_player(player, player.position)
|
|
end
|
|
end
|
|
end
|
|
-- track visited
|
|
if not playerdata.visited_zone then playerdata.visited_zone = {} end
|
|
if zone.type ~= "spaceship" and not playerdata.visited_zone[zone.index] then playerdata.visited_zone[zone.index] = game.tick end
|
|
|
|
if (not playerdata.has_entered_anomaly) and zone.type == "anomaly" and player.character then
|
|
playerdata.has_entered_anomaly = true
|
|
player.print({"space-exploration.galaxy_ship_authenticated"})
|
|
for _, entity in pairs(player.surface.find_entities_filtered{force="ignore"}) do
|
|
entity.force = "friendly"
|
|
end
|
|
player.force.chart(player.surface, util.position_to_area(Ancient.galaxy_ship_default_position, 2))
|
|
player.force.chart_all(player.surface)
|
|
end
|
|
if zone.vault_pyramid_position then
|
|
if (not player.vehicle) then
|
|
if not (zone.vault_pyramid and zone.vault_pyramid.valid) then
|
|
-- make the pyramid again.
|
|
Ancient.make_vault_exterior(zone)
|
|
end
|
|
-- check if touching the pyramid
|
|
local x_test = Ancient.pyramid_width/2
|
|
local y_test = Ancient.pyramid_height/2
|
|
local buffer = 1
|
|
if player.position.x < zone.vault_pyramid_position.x + x_test + buffer
|
|
and player.position.x > zone.vault_pyramid_position.x - x_test - buffer
|
|
and player.position.y < zone.vault_pyramid_position.y + y_test + buffer
|
|
and player.position.y > zone.vault_pyramid_position.y - y_test - buffer then
|
|
if (not string.find(player.character.name, "jetpack", 1, true)) and (not is_character_passenger(player.character)) then
|
|
Ancient.make_vault_interior(zone)
|
|
local vault = global.glyph_vaults[zone.glyph][zone.index]
|
|
local vault_surface = game.surfaces[vault.surface_index]
|
|
player.teleport({0, Ancient.cartouche_path_end-2}, vault_surface)
|
|
local corpses = vault_surface.find_entities_filtered{type="corpse"}
|
|
for _, corpse in pairs(corpses) do corpse.destroy() end
|
|
if not playerdata.first_entered_vault then
|
|
playerdata.first_entered_vault = zone
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
else -- no zone
|
|
local vault = Ancient.vault_from_surface(player.surface)
|
|
if vault then
|
|
-- check if on the entrance/exit section
|
|
if player.position.x <=4 and player.position.x >= -4 and player.position.y > Ancient.cartouche_path_end -1 and player.position.y < Ancient.cartouche_path_end +1 then
|
|
local zone = Zone.from_zone_index(vault.zone_index)
|
|
local zone_surface = Zone.get_make_surface(zone)
|
|
local pos = table.deepcopy(zone.vault_pyramid_position) or {x = 0, y = 0}
|
|
pos.y = pos.y + Ancient.pyramid_height/2 + 1
|
|
teleport_character_to_surface(player.character, zone_surface, pos)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
Event.addListener(defines.events.on_player_changed_position, on_player_changed_position)
|
|
|
|
|
|
function on_trigger_created_entity(event)
|
|
if event.entity and event.entity.valid and event.entity.name == mod_prefix.."trigger-movable-debris" then
|
|
-- meteor and rocket fragments
|
|
|
|
local surface = event.entity.surface
|
|
local deconstruct = false
|
|
for force in pairs(game.forces) do
|
|
local networks = surface.find_logistic_networks_by_construction_area(event.entity.position, force)
|
|
if networks and #networks > 0 then
|
|
for _, network in pairs(networks) do
|
|
if network.storages and #network.storages > 1 then
|
|
local entities = surface.find_entities_filtered{position = event.entity.position, type = "simple-entity"}
|
|
for _, entity in pairs(entities) do
|
|
entity.order_deconstruction(force)
|
|
deconstruct = true
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
local tile = surface.get_tile(event.entity.position.x, event.entity.position.y)
|
|
local meteors = surface.find_entities_filtered{ type = "simple-entity", area = Util.position_to_area(event.entity.position, 1) }
|
|
for _, meteor in pairs(meteors) do
|
|
if string.find(meteor.name, "meteor", 1, true) then
|
|
if tile.collides_with("player-layer") or tile_is_space(tile) then
|
|
meteor.destroy()
|
|
else
|
|
-- This is a temporary solution. In the future the meteor swarm will be randomy assigned to be biological 30% of the time for vitamelange planets.
|
|
local zone = Zone.from_surface(surface)
|
|
if zone.controls and zone.controls["se-vitamelange"] and zone.controls["se-vitamelange"].richness > 0 then
|
|
local r = math.random()
|
|
if r < 0.1 then
|
|
surface.create_entity{name="behemoth-worm-turret", force="enemy", position=meteor.position}
|
|
elseif r < 0.5 then
|
|
surface.create_entity{name="spitter-spawner", force="enemy", position=meteor.position}
|
|
else
|
|
surface.create_entity{name="biter-spawner", force="enemy", position=meteor.position}
|
|
end
|
|
meteor.destroy()
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
Event.addListener(defines.events.on_trigger_created_entity, on_trigger_created_entity)
|
|
|
|
function cancel_entity_creation(entity, player_index, message)
|
|
-- put an item back in the inventory or drop to ground
|
|
-- display flying text
|
|
local player
|
|
if player_index then
|
|
player = game.players[player_index]
|
|
end
|
|
local inserted = 0
|
|
local item_to_place = entity.prototype.items_to_place_this[1]
|
|
local surface = entity.surface
|
|
local position = entity.position
|
|
if player then
|
|
if player.mine_entity(entity, false) then
|
|
inserted = 1
|
|
elseif item_to_place and item_to_place.name then
|
|
inserted = player.insert{name = item_to_place.name, count = 1}
|
|
end
|
|
-- play entity cannot build sound
|
|
player.play_sound{
|
|
path = "utility/cannot_build",
|
|
volume_modifier = 1.0
|
|
}
|
|
end
|
|
if inserted == 0 and item_to_place and item_to_place.name then
|
|
surface.create_entity{
|
|
name = "item-on-ground",
|
|
position = position,
|
|
stack = {name = item_to_place.name, count = 1}
|
|
}
|
|
end
|
|
surface.create_entity{
|
|
name = "flying-text",
|
|
position = position,
|
|
text = message,
|
|
render_player_index = player_index,
|
|
}
|
|
if entity and entity.valid then
|
|
entity.destroy()
|
|
end
|
|
end
|
|
|
|
function cancel_tile_placement(surface, tile, old_tiles, player_index, message)
|
|
-- put an item back in the inventory or drop to ground
|
|
-- display flying text
|
|
local player
|
|
if player_index then
|
|
player = game.players[player_index]
|
|
if player.controller_type == defines.controllers.editor then
|
|
-- tile placement could be allowed for testing but it will create errors further down the line so this should not be enabled.
|
|
-- e.g:
|
|
-- space platform on a spaceship surface will break cause errors.
|
|
-- water and/or land in space will cause entity problems.
|
|
-- space surfaces on planets will cause entity problems and maybe errors.
|
|
end
|
|
end
|
|
local set_tiles = {}
|
|
for i, old_tile in pairs(old_tiles) do
|
|
if tile.items_to_place_this and tile.items_to_place_this[1] then
|
|
local inserted = 0
|
|
if player then
|
|
inserted = player.insert{name = tile.items_to_place_this[1].name, count = 1}
|
|
end
|
|
if inserted == 0 then
|
|
surface.create_entity{
|
|
name = "item-on-ground",
|
|
position = old_tile.position,
|
|
--["item-entity"] = {name = tile.items_to_place_this[1].name, count = 1}
|
|
stack = {name = tile.items_to_place_this[1].name, count = 1}
|
|
}
|
|
end
|
|
end
|
|
if i == 1 then
|
|
surface.create_entity{
|
|
name = "flying-text",
|
|
position = old_tile.position,
|
|
text = message,
|
|
render_player_index = player_index,
|
|
}
|
|
end
|
|
local hidden = surface.get_hidden_tile(old_tile.position)
|
|
table.insert(set_tiles, {name = hidden or old_tile.old_tile.name, position = old_tile.position})
|
|
end
|
|
surface.set_tiles(set_tiles)
|
|
end
|
|
|
|
function swap_structure(entity, prototype_name)
|
|
local surface = entity.surface
|
|
local recipe = entity.get_recipe()
|
|
local clone = surface.create_entity{
|
|
name = prototype_name,
|
|
position = entity.position,
|
|
force = entity.force,
|
|
direction = entity.direction,
|
|
recipe = recipe and recipe.name
|
|
}
|
|
clone.operable = entity.operable
|
|
clone.active = entity.active
|
|
clone.destructible = entity.destructible
|
|
clone.rotatable = entity.rotatable
|
|
local inventories = {}
|
|
for _, inv_type in pairs({
|
|
defines.inventory.fuel,
|
|
defines.inventory.burnt_result,
|
|
defines.inventory.furnace_source,
|
|
defines.inventory.furnace_result,
|
|
defines.inventory.furnace_modules,
|
|
defines.inventory.assembling_machine_input,
|
|
defines.inventory.assembling_machine_output,
|
|
defines.inventory.assembling_machine_modules
|
|
}) do
|
|
inventories[inv_type] = inv_type -- no duplicate indexes
|
|
end
|
|
for _, inv_type in pairs(inventories) do
|
|
local inv_a = entity.get_inventory(inv_type)
|
|
local inv_b = clone.get_inventory(inv_type)
|
|
if inv_a and inv_b then
|
|
util.move_inventory_items(inv_a, inv_b)
|
|
end
|
|
end
|
|
entity.destroy()
|
|
clone.teleport(clone.position) -- reconnect pipes
|
|
return clone
|
|
end
|
|
|
|
function is_surface_space(surface)
|
|
local zone = Zone.from_surface(surface)
|
|
if zone and Zone.is_space(zone) then
|
|
return true
|
|
elseif surface and surface.name and string.starts(surface.name, "Space Factory") then -- Space Factorissimo compatibility
|
|
return true
|
|
end
|
|
return false
|
|
end
|
|
|
|
function on_entity_created(event)
|
|
local entity
|
|
if event.entity and event.entity.valid then
|
|
entity = event.entity
|
|
end
|
|
if event.created_entity and event.created_entity.valid then
|
|
entity = event.created_entity
|
|
end
|
|
if (not entity) or entity.type == "entity-ghost" or entity.type == "tile-ghost" then return end
|
|
|
|
if entity.type ~= "deconstructible-tile-proxy" and entity.type ~= "car" and entity.type ~= "spider-vehicle" then
|
|
local area = entity.bounding_box
|
|
local surface = entity.surface
|
|
local proxies = surface.find_entities_filtered{area = area, type = "deconstructible-tile-proxy"}
|
|
for _, proxy in pairs(proxies) do
|
|
proxy.destroy()
|
|
end
|
|
end
|
|
|
|
if is_surface_space(entity.surface) then
|
|
if (entity.type == "car")
|
|
and (not string.find(entity.name, mod_prefix.."space", 1, true))
|
|
and entity.prototype.effectivity > 0 then
|
|
return cancel_entity_creation(entity, event.player_index, {"space-exploration.construction-denied-vehicle-in-space"})
|
|
end
|
|
if game.entity_prototypes[entity.name..name_suffix_spaced] then
|
|
-- replace with spaced
|
|
return swap_structure(entity, entity.name..name_suffix_spaced)
|
|
end
|
|
if string.find(entity.name, name_suffix_grounded, 1, true) then
|
|
-- replace with non-grounded
|
|
return swap_structure(entity, util.replace(entity.name, name_suffix_grounded, ""))
|
|
end
|
|
if entity.type == "offshore-pump" then
|
|
return cancel_entity_creation(entity, event.player_index, {"space-exploration.construction-denied"})
|
|
end
|
|
else -- not space
|
|
if string.find(entity.name, name_suffix_spaced, 1, true) then
|
|
-- replace with non-spaced
|
|
return swap_structure(entity, util.replace(entity.name, name_suffix_spaced, ""))
|
|
end
|
|
if game.entity_prototypes[entity.name..name_suffix_grounded] then
|
|
-- replace with grounded
|
|
return swap_structure(entity, entity.name..name_suffix_grounded)
|
|
end
|
|
if zone and entity.name == "kr-atmospheric-condenser" and (not zone.is_homeworld) and zone.tags and util.table_contains(zone.tags, "water_none") then
|
|
return cancel_entity_creation(entity, event.player_index, {"space-exploration.construction-denied-no-water"})
|
|
end
|
|
if zone and entity.type == "offshore-pump" and (not zone.is_homeworld) and zone.tags and util.table_contains(zone.tags, "water_none") then
|
|
if entity.prototype.fluid == "water" then -- there is no water on this planet, send via rocket, cannon, or ship
|
|
return cancel_entity_creation(entity, event.player_index, {"space-exploration.construction-denied-no-water"})
|
|
end
|
|
end
|
|
end
|
|
|
|
end
|
|
Event.addListener(defines.events.on_robot_built_entity, on_entity_created)
|
|
Event.addListener(defines.events.on_built_entity, on_entity_created)
|
|
Event.addListener(defines.events.script_raised_built, on_entity_created)
|
|
Event.addListener(defines.events.script_raised_revive, on_entity_created)
|
|
|
|
--[[
|
|
When the player kills themself by placing water under themselves, the on_built_tile event does not fire.
|
|
Instead we listen to the on_player_died event, and replace any nearby water tiles with some non-water tile next to it.
|
|
]]
|
|
function on_pre_player_died(event)
|
|
local player = game.players[event.player_index]
|
|
local zone = Zone.from_surface(player.surface)
|
|
if (not zone) or Zone.is_solid(zone) then -- treat as land
|
|
if zone and (not zone.is_homeworld) and (zone.tags and (util.table_contains(zone.tags, "water_none"))) then
|
|
-- water should not be here
|
|
local area = {left_top = {player.position.x - 20, player.position.y - 20}, right_bottom = {player.position.x + 20, player.position.y + 20}}
|
|
local tick_task = new_tick_task("remove-water")
|
|
tick_task.delay_until = game.tick + 1
|
|
tick_task.surface = player.surface
|
|
tick_task.area = area
|
|
tick_task.position = player.position
|
|
end
|
|
end
|
|
end
|
|
Event.addListener(defines.events.on_pre_player_died, on_pre_player_died)
|
|
|
|
function remove_water_tiles(surface, area, position)
|
|
local bad_tiles = {}
|
|
local good_tile_name
|
|
for _, tile in pairs(surface.find_tiles_filtered({
|
|
area = area
|
|
})) do
|
|
if string.find(tile.name, "water", 1, true) then
|
|
table.insert(bad_tiles, tile)
|
|
else
|
|
good_tile_name = tile.name
|
|
end
|
|
end
|
|
if not good_tile_name then -- if we cant find a tile type to replace the water with use landfill as a default
|
|
good_tile_name = "landfill"
|
|
end
|
|
if #bad_tiles > 0 then
|
|
-- there is no water on this planet, send via rocket, cannon, or ship
|
|
surface.create_entity({
|
|
name = "flying-text",
|
|
position = position,
|
|
text = {"space-exploration.construction-denied-no-water"}
|
|
})
|
|
local tiles = {}
|
|
for _, tile in pairs(bad_tiles) do
|
|
table.insert(tiles, {
|
|
name = good_tile_name,
|
|
position = tile.position
|
|
})
|
|
end
|
|
surface.set_tiles(tiles)
|
|
end
|
|
end
|
|
|
|
function on_built_tile(event)
|
|
if not event.surface_index then return end
|
|
local surface = game.surfaces[event.surface_index]
|
|
if not surface then return end
|
|
local player
|
|
local tile = event.tile -- top left tile
|
|
local old_tiles = event.tiles -- all tiles over a large square
|
|
local stack = event.stack -- used to create, may be empty
|
|
|
|
for _, old_tile in pairs(old_tiles) do
|
|
if old_tile.old_tile.name == "interior-divider" then
|
|
if tile.name == "transport-drone-proxy-tile" then return error("Invalid map state") end
|
|
return cancel_tile_placement(surface, tile, old_tiles, event.player_index, {"space-exploration.construction-denied"})
|
|
end
|
|
end
|
|
--tile_is_space(tile)
|
|
local zone = Zone.from_surface(surface)
|
|
-- temp due to issue with transport drones script
|
|
if tile.name == "transport-drone-proxy-tile" then return end
|
|
|
|
if (not zone) or Zone.is_solid(zone) then -- treat as land
|
|
if Util.table_contains(tiles_allowed_in_space, tile.name) and tile.name ~= name_out_of_map_tile and tile.name ~= "transport-drone-road" and tile.name ~= "transport-drone-proxy-tile" then
|
|
if not (zone and Util.table_contains(Spaceship.names_spaceship_floors, tile.name)) then
|
|
return cancel_tile_placement(surface, tile, old_tiles, event.player_index, {"space-exploration.construction-denied"})
|
|
end
|
|
elseif string.find(tile.name, "water", 1, true) then
|
|
if zone and (not zone.is_homeworld) and (zone.tags and (util.table_contains(zone.tags, "water_none"))) then
|
|
-- should not be here
|
|
return cancel_tile_placement(surface, tile, old_tiles, event.player_index, {"space-exploration.construction-denied-no-water"})
|
|
end
|
|
end
|
|
else -- treat as space
|
|
if zone.type == "spaceship" and (not Util.table_contains(Spaceship.names_spaceship_floors, tile.name)) then
|
|
return cancel_tile_placement(surface, tile, old_tiles, event.player_index, {"space-exploration.construction-denied"})
|
|
elseif not Util.table_contains(tiles_allowed_in_space, tile.name) then
|
|
return cancel_tile_placement(surface, tile, old_tiles, event.player_index, {"space-exploration.construction-denied"})
|
|
end
|
|
end
|
|
end
|
|
Event.addListener(defines.events.on_player_built_tile, on_built_tile)
|
|
Event.addListener(defines.events.on_robot_built_tile, on_built_tile)
|
|
|
|
function on_script_raised_set_tiles(event)
|
|
if not event.surface_index then return end
|
|
local surface = game.surfaces[event.surface_index]
|
|
if not surface then return end
|
|
|
|
local zone = Zone.from_surface(surface)
|
|
local set_tiles = {}
|
|
for _, tile in pairs(event.tiles) do
|
|
if (not zone) or Zone.is_solid(zone) then -- treat as land
|
|
if Util.table_contains(tiles_allowed_in_space, tile.name) and tile.name ~= "transport-drone-road" and tile.name ~= "transport-drone-proxy-tile" then
|
|
if not (zone and Util.table_contains(Spaceship.names_spaceship_floors, tile.name)) then
|
|
table.insert(set_tiles, {name="mineral-black-dirt-1", position=tile.position})
|
|
end
|
|
elseif string.find(tile.name, "water", 1, true) then
|
|
if zone and (not zone.is_homeworld) and (zone.tags and (util.table_contains(zone.tags, "water_none"))) then
|
|
-- should not be here
|
|
table.insert(set_tiles, {name="mineral-black-dirt-1", position=tile.position})
|
|
end
|
|
end
|
|
else -- treat as space
|
|
if zone.type == "spaceship" and (not Util.table_contains(Spaceship.names_spaceship_floors, tile.name)) then
|
|
table.insert(set_tiles, {name=name_space_tile, position=tile.position})
|
|
elseif not Util.table_contains(tiles_allowed_in_space, tile.name) then
|
|
table.insert(set_tiles, {name=name_space_tile, position=tile.position})
|
|
end
|
|
end
|
|
end
|
|
if #set_tiles > 0 then
|
|
surface.set_tiles(set_tiles, true) -- DO NOT raise an event or it might cause a loop
|
|
end
|
|
end
|
|
Event.addListener(defines.events.script_raised_set_tiles, on_script_raised_set_tiles)
|
|
|
|
function spiral_next(input)
|
|
local x = input.x
|
|
local y = input.y
|
|
local output = table.deepcopy(input)
|
|
if x > y and x >= -y then
|
|
output.y = y + 1
|
|
elseif -y >= -x and -y > x then
|
|
output.x = x + 1
|
|
elseif -x > y and -x > -y then
|
|
output.y = y - 1
|
|
elseif y >= -x and y > x then
|
|
output.x = x - 1
|
|
else
|
|
output.x = x - 1
|
|
end
|
|
return output
|
|
end
|
|
|
|
function zigzag_next(input, y_limit)
|
|
local x = input.x
|
|
local y = input.y
|
|
local output = table.deepcopy(input)
|
|
if y > -y_limit then
|
|
output.y = y - 1
|
|
elseif x >= 0 then
|
|
output.x = -x - 1
|
|
output.y = y_limit
|
|
else
|
|
output.x = -x
|
|
output.y = y_limit
|
|
end
|
|
return output
|
|
end
|
|
|
|
function chart_position(force, surface, position)
|
|
force.chart(surface, {
|
|
{
|
|
x = position.x*32,
|
|
y = position.y*32
|
|
},
|
|
{
|
|
x = (position.x+0.5)*32, -- +1 actually scanes 4 chunks
|
|
y = (position.y+0.5)*32 -- +1 actually scanes 4 chunks
|
|
}
|
|
})
|
|
end
|
|
function process_force_scanning(forcedata, force)
|
|
if forcedata.is_scanning and forcedata.scanning_zone then
|
|
local y_limit = nil
|
|
if forcedata.scanning_zone.type == "asteroid-belt" or forcedata.scanning_zone.type == "orbit" then
|
|
y_limit = 8 -- changes spiral pattern to different method
|
|
if not forcedata.scanning_cursor then
|
|
forcedata.scanning_cursor = {x=0,y=16}
|
|
end
|
|
else
|
|
if not forcedata.scanning_cursor then
|
|
forcedata.scanning_cursor = {x=0,y=0}
|
|
end
|
|
end
|
|
local surface = Zone.get_surface(forcedata.scanning_zone)
|
|
if not surface then
|
|
forcedata.is_scanning = nil
|
|
forcedata.scanning_zone = nil
|
|
forcedata.scanning_cursor = nil
|
|
return
|
|
end
|
|
if forcedata.scanning_zone.radius and -- exit if out of bounds
|
|
((math.abs(forcedata.scanning_cursor.x) - 1.5)*32 > forcedata.scanning_zone.radius
|
|
or (math.abs(forcedata.scanning_cursor.y) - 1.5)*32 > forcedata.scanning_zone.radius) then
|
|
forcedata.is_scanning = nil
|
|
forcedata.scanning_zone = nil
|
|
forcedata.scanning_cursor = nil
|
|
return
|
|
end
|
|
local search_budget = settings.global["se-scan-search-budget"].value -- 1000
|
|
local searched = 0
|
|
local chart_budget = settings.global["se-scan-chart-budget"].value -- 10
|
|
local charted = 0
|
|
local cursor = table.deepcopy(forcedata.scanning_cursor)
|
|
while searched < search_budget and charted < chart_budget do
|
|
searched = searched + 1
|
|
if (not forcedata.scanning_zone.radius) or (Util.vector_length(cursor) - 1.5)*32 < forcedata.scanning_zone.radius then
|
|
if force.is_chunk_charted(surface, cursor) then
|
|
forcedata.scanning_cursor = cursor
|
|
else
|
|
charted = charted + 1
|
|
chart_position(force, surface, cursor)
|
|
end
|
|
else -- outside radius
|
|
if charted == 0 then -- skip ahead
|
|
forcedata.scanning_cursor = cursor
|
|
end
|
|
end
|
|
if y_limit then
|
|
cursor = zigzag_next(cursor, y_limit)
|
|
else
|
|
cursor = spiral_next(cursor)
|
|
end
|
|
end
|
|
|
|
if settings.global["se-scan-alert-interval"].value > 0 then
|
|
if game.tick % (60 * settings.global["se-scan-alert-interval"].value) == 0 then
|
|
force.print({"space-exploration.scan-progress-update", forcedata.scanning_zone.name, cursor.x, cursor.y})
|
|
end
|
|
end
|
|
|
|
end
|
|
end
|
|
|
|
function process_forces_scanning()
|
|
for force_name, forcedata in pairs(global.forces) do
|
|
local force = game.forces[force_name]
|
|
if not force then
|
|
global.forces[force_name] = nil
|
|
else
|
|
process_force_scanning(forcedata, force)
|
|
end
|
|
end
|
|
end
|
|
|
|
function on_tick()
|
|
|
|
process_chart_tag_buffer()
|
|
|
|
if game.tick % 60 == 0 then -- varaible rate
|
|
process_forces_scanning()
|
|
end
|
|
|
|
for _, player in pairs(game.connected_players) do
|
|
on_tick_player(player)
|
|
end
|
|
|
|
for _, tick_task in pairs(global.tick_tasks) do
|
|
if (not tick_task.delay_until) or game.tick >= tick_task.delay_until then
|
|
if tick_task.type == "chain-beam" then
|
|
Weapon.chain_beam(tick_task)
|
|
elseif tick_task.type == "plague-tick" then
|
|
Weapon.plague_tick(tick_task)
|
|
elseif tick_task.type == "cryogun-unfreeze" then
|
|
Weapon.cryogun_unfreeze(tick_task)
|
|
elseif tick_task.type == "bind-corpse" then
|
|
Respawn.tick_task_bind_corpse(tick_task)
|
|
elseif tick_task.type == "launchpad-journey" then
|
|
Launchpad.tick_journey(tick_task)
|
|
elseif tick_task.type == "grow_energy_tree" then
|
|
EnergyBeam.grow_energy_tree(tick_task)
|
|
elseif tick_task.type == "solar-flare" then
|
|
SolarFlare.tick_flare(tick_task)
|
|
elseif tick_task.type == "force-message" then
|
|
if tick_task.force_name then
|
|
local force = game.forces[tick_task.force_name]
|
|
if force then
|
|
force.print(tick_task.message)
|
|
end
|
|
end
|
|
tick_task.valid = false
|
|
elseif tick_task.type == "remove-water" then
|
|
remove_water_tiles(tick_task.surface, tick_task.area, tick_task.position)
|
|
tick_task.valid = false
|
|
else
|
|
tick_task.valid = false
|
|
end
|
|
if not tick_task.valid then
|
|
global.tick_tasks[tick_task.id] = nil
|
|
end
|
|
end
|
|
end
|
|
|
|
end
|
|
Event.addListener(defines.events.on_tick, on_tick)
|
|
|
|
function new_tick_task(type)
|
|
global.next_tick_task_id = global.next_tick_task_id or 1
|
|
local new_tick_task = {
|
|
id = global.next_tick_task_id,
|
|
valid = true,
|
|
type = type
|
|
}
|
|
global.tick_tasks[new_tick_task.id] = new_tick_task
|
|
global.next_tick_task_id = global.next_tick_task_id + 1
|
|
return new_tick_task
|
|
end
|
|
|
|
function on_entity_damaged (event)
|
|
if event.entity and event.entity.valid and event.entity.name ~= "shield-projector-barrier" then
|
|
if event.entity.health < 0 and event.entity.active == false then
|
|
event.entity.destroy()
|
|
end
|
|
end
|
|
end
|
|
Event.addListener(defines.events.on_entity_damaged, on_entity_damaged)
|
|
|
|
function build_satellite(force_name)
|
|
Log.debug_log("build_satellite: " .. force_name)
|
|
local home_zone = Zone.get_force_home_zone(force_name)
|
|
if not home_zone then home_zone = Zone.get_default() end
|
|
local zone = home_zone.orbit
|
|
local surface = Zone.get_make_surface(zone)
|
|
local satellite_position = Zone.find_zone_landing_position(zone, {
|
|
x = (-0.5+math.random()) * 256,
|
|
y = (-0.5+math.random()) * 64})
|
|
|
|
surface.request_to_generate_chunks(satellite_position, 2)
|
|
surface.force_generate_chunk_requests() -- must be generated to place
|
|
|
|
Ruin.build({
|
|
ruin_name = "satellite",
|
|
surface_index = surface.index,
|
|
position = satellite_position,
|
|
force_name_override = force_name
|
|
})
|
|
local range = Zone.discovery_scan_radius
|
|
game.forces[force_name].chart(surface, {
|
|
{satellite_position.x - range, satellite_position.y - range},
|
|
{satellite_position.x + range, satellite_position.y + range}
|
|
})
|
|
game.forces[force_name].print({"space-exploration.satellite-discovered-platform", zone.name})
|
|
chart_tag_buffer_add({
|
|
force_name = force_name,
|
|
surface = Zone.get_make_surface(zone),
|
|
position = satellite_position,
|
|
icon_type = "item",
|
|
icon_name = "satellite",
|
|
text = "Space Platform",
|
|
chart_range = Zone.discovery_scan_radius,
|
|
})
|
|
global.forces[force_name].nauvis_satellite = satellite_position
|
|
end
|
|
|
|
|
|
function on_satellite_launched(force_name, surface)
|
|
Log.debug_log("on_satellite_launched: " .. force_name)
|
|
local starting_zone = Zone.from_surface(surface)
|
|
if not starting_zone then
|
|
return game.forces[force_name].print({"space-exploration.satellite_invalid_launch_location"})
|
|
end
|
|
global.forces[force_name] = global.forces[force_name] or {}
|
|
global.forces[force_name].satellites_launched = (global.forces[force_name].satellites_launched or 0) + 1
|
|
|
|
-- discovery options are:
|
|
-- discover the satellite (always on 1st launch) either in orbit or deadsapce
|
|
-- discover a planet or moon (always on 1st - 5rd launches), 90% chance after
|
|
-- if nothing else discovered, discover an asteroid in deadpsace
|
|
|
|
local dicovered_something = false
|
|
if global.forces[force_name].satellites_launched == 1 then
|
|
-- nauvis satellite station
|
|
|
|
build_satellite(force_name)
|
|
Zone.discover_next_satellite(force_name, {"space-exploration.the_satellite"}, starting_zone)
|
|
dicovered_something = true
|
|
game.forces[force_name].print({"space-exploration.satellite-view-unlocked"})
|
|
--elseif global.forces[force_name].satellites_launched < 6
|
|
-- or math.random() < 0.9 then
|
|
else
|
|
dicovered_something = Zone.discover_next_satellite(force_name, {"space-exploration.satellite"}, starting_zone)
|
|
if not dicovered_something then
|
|
for _, player in pairs(game.forces[force_name].connected_players) do
|
|
if player.surface.index == surface.index then
|
|
if settings.get_player_settings(player)["se-print-satellite-discovered-nothing"].value then
|
|
player.print({"space-exploration.satellite-discovered-nothing"})
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
|
|
function on_rocket_launched(event)
|
|
game.set_game_state{game_finished=false, player_won=false, can_continue=true}
|
|
if event.rocket and event.rocket.valid then
|
|
if event.rocket.get_item_count("satellite") > 0 then
|
|
on_satellite_launched(event.rocket.force.name, event.rocket.surface)
|
|
end
|
|
end
|
|
end
|
|
Event.addListener(defines.events.on_rocket_launched, on_rocket_launched)
|
|
|
|
function on_rocket_launch_ordered(event)
|
|
if event.rocket and event.rocket.valid then
|
|
local zone = Zone.from_surface(event.rocket.surface)
|
|
if event.rocket.get_item_count(mod_prefix.."star-probe") > 0 then
|
|
if not (zone and zone.type == "orbit" and zone.parent.type == "star") then
|
|
event.rocket.remove_item({name=mod_prefix.."star-probe", count=1})
|
|
local tick_task = new_tick_task("force-message")
|
|
tick_task.force_name = event.rocket.force.name
|
|
tick_task.message = {"space-exploration.probe_invalid_launch_star"}
|
|
tick_task.delay_until = game.tick + 750 --5s
|
|
end
|
|
elseif event.rocket.get_item_count(mod_prefix.."belt-probe") > 0 then
|
|
if not (zone and zone.type == "asteroid-belt") then
|
|
event.rocket.remove_item({name=mod_prefix.."belt-probe", count=1})
|
|
game.print(event.rocket.get_item_count(mod_prefix.."belt-probe"))
|
|
local tick_task = new_tick_task("force-message")
|
|
tick_task.force_name = event.rocket.force.name
|
|
tick_task.message = {"space-exploration.probe_invalid_launch_belt"}
|
|
tick_task.delay_until = game.tick + 750 --5s
|
|
end
|
|
elseif event.rocket.get_item_count(mod_prefix.."void-probe") > 0 then
|
|
if not (zone and zone.type == "asteroid-field") then
|
|
event.rocket.remove_item({name=mod_prefix.."void-probe", count=1})
|
|
local tick_task = new_tick_task("force-message")
|
|
tick_task.force_name = event.rocket.force.name
|
|
tick_task.message = {"space-exploration.probe_invalid_launch_field"}
|
|
tick_task.delay_until = game.tick + 750 --5s
|
|
end
|
|
end
|
|
end
|
|
end
|
|
Event.addListener(defines.events.on_rocket_launch_ordered, on_rocket_launch_ordered)
|
|
|
|
function setup_force(force)
|
|
if is_system_force(force.name) then return end
|
|
|
|
local force_name = force.name
|
|
if global.forces[force_name] then return end
|
|
Log.debug_log("setup_force: "..force_name)
|
|
global.forces = global.forces or {}
|
|
global.forces[force_name] = {
|
|
force_name = force_name,
|
|
zones_discovered_count = 0, -- planets and moons discovered
|
|
zones_discovered = {}, -- name = ForceZoneData{discovered_at = tick discovered, marker = map marker}
|
|
satellites_launched = 0,
|
|
cargo_rockets_launched = 0,
|
|
cargo_rockets_crashed = 0,
|
|
zone_assets = {}, -- zone_index > (rocket_launch_pad_names/ rocket_landing_pad_names)
|
|
zone_priorities = {}
|
|
}
|
|
local homeworld = Zone.from_name("Nauvis")
|
|
global.forces[force_name].homeworld_index = homeworld.index
|
|
Zone.discover(force_name, homeworld)
|
|
Zone.discover(force_name, homeworld.parent)
|
|
for _, zone in pairs(global.zone_index) do
|
|
if zone.is_homeworld then
|
|
global.forces[force_name].zone_priorities[zone.index] = global.forces[force_name].zone_priorities[zone.index] or 1
|
|
end
|
|
end
|
|
|
|
local friendly = game.forces["friendly"]
|
|
if friendly then
|
|
friendly.set_friend(force, true)
|
|
force.set_friend(friendly, true)
|
|
end
|
|
|
|
local ignore = game.forces["ignore"]
|
|
if ignore then
|
|
ignore.set_cease_fire(force, true)
|
|
force.set_cease_fire(ignore, true)
|
|
end
|
|
|
|
local capture = game.forces["capture"]
|
|
if capture then
|
|
capture.set_cease_fire(force, true)
|
|
force.set_cease_fire(capture, true)
|
|
end
|
|
end
|
|
|
|
function allied_forces(force)
|
|
local allied_forces = {}
|
|
for _, oforce in pairs(game.forces) do
|
|
if oforce.name == force.name or force.get_friend(oforce) then
|
|
table.insert(allied_forces, oforce.name)
|
|
end
|
|
end
|
|
return allied_forces
|
|
end
|
|
|
|
function ceasefire_forces(force)
|
|
local ceasefire_forces = {}
|
|
for _, oforce in pairs(game.forces) do
|
|
if oforce.name == force.name or force.get_cease_fire(oforce) then
|
|
table.insert(ceasefire_forces, oforce.name)
|
|
end
|
|
end
|
|
return ceasefire_forces
|
|
end
|
|
|
|
function enemy_forces(force)
|
|
local enemy_forces = {}
|
|
for _, oforce in pairs(game.forces) do
|
|
if oforce ~= force and not force.get_cease_fire(oforce) then
|
|
if (not is_system_force(oforce.name)) or oforce.name == "enemy" or oforce.name == "conquest" then
|
|
table.insert(enemy_forces, oforce.name)
|
|
end
|
|
end
|
|
end
|
|
return enemy_forces
|
|
end
|
|
|
|
function find_enemy(force, surface, position)
|
|
local enemy_forces = enemy_forces(force)
|
|
|
|
for _, radius in pairs({8,32,256,1024}) do
|
|
local enemies = surface.find_entities_filtered{
|
|
force = enemy_forces,
|
|
type = {"unit-spawner", "turret"},
|
|
position = position,
|
|
radius = radius
|
|
}
|
|
if enemies and #enemies > 0 then return enemies[math.random(#enemies)] end
|
|
end
|
|
|
|
local enemy = surface.find_nearest_enemy{position=position, max_distance=20000, force=force}
|
|
if enemy then return enemy end
|
|
|
|
-- final try, anything enemy anywhere
|
|
local enemies = surface.find_entities_filtered{ force = enemy_forces, type = {
|
|
-- taken from https://wiki.factorio.com/Prototype/EntityWithHealth
|
|
"accumulator", "artillery-turret", "beacon", "boiler", "burner-generator", "character",
|
|
"arithmetic-combinator", "decider-combinator", "constant-combinator", "container",
|
|
"logistic-container", "infinity-container", "assembling-machine", "rocket-silo",
|
|
"furnace", "electric-energy-interface", "electric-pole", "unit-spawner",
|
|
--"fish",
|
|
"combat-robot", "construction-robot", "logistic-robot", "gate", "generator",
|
|
"heat-interface", "heat-pipe", "inserter", "lab", "lamp", "land-mine", "linked-container",
|
|
"market", "mining-drill", "offshore-pump", "pipe", "infinity-pipe", "pipe-to-ground",
|
|
"player-port", "power-switch", "programmable-speaker", "pump", "radar", "curved-rail",
|
|
"straight-rail", "rail-chain-signal", "rail-signal", "reactor", "roboport",
|
|
--"simple-entity",
|
|
"simple-entity-with-owner", "simple-entity-with-force", "solar-panel",
|
|
--"spider-leg",
|
|
"storage-tank", "train-stop", "linked-belt", "loader-1x1", "loader", "splitter",
|
|
"transport-belt", "underground-belt", "tree", "turret", "ammo-turret", "electric-turret",
|
|
"fluid-turret", "unit", "car", "artillery-wagon", "cargo-wagon", "fluid-wagon",
|
|
"locomotive", "spider-vehicle", "wall"
|
|
} }
|
|
if enemies and #enemies > 0 then
|
|
enemy = enemies[math.random(#enemies)]
|
|
if enemy.destructible then
|
|
return enemy
|
|
end
|
|
end
|
|
|
|
for _, enemy in pairs(enemies) do
|
|
if enemy.destructible then
|
|
return enemy
|
|
end
|
|
end
|
|
|
|
return false
|
|
end
|
|
|
|
--/c remote.call("space-exploration", "set_force_homeworld", {zone_name = "Arendel", force_name = "player-2", spawn_position = {x = 0, y = 0}, reset_discoveries = true})
|
|
function set_force_homeworld(data)
|
|
local zone = Zone.from_name(data.zone_name)
|
|
if not zone then return game.print({"space-exploration.no_zone_found"}) end
|
|
if not zone.is_homeworld then return game.print({"space-exploration.zone_must_be_a_homeworld"}) end
|
|
|
|
local force = game.forces[data.force_name]
|
|
if not force then return game.print({"space-exploration.no_force_found"}) end
|
|
|
|
local force_data = global.forces[data.force_name]
|
|
if not force_data then return game.print({"space-exploration.no_force_data_found"}) end
|
|
|
|
force_data.homeworld_index = zone.index
|
|
Zone.get_make_surface(zone) -- make sure the surface exists
|
|
force.set_spawn_position(data.spawn_position or {x = 0, y = 0}, zone.surface_index)
|
|
|
|
if data.reset_discoveries then
|
|
force_reset_discoveries(data.force_name)
|
|
end
|
|
end
|
|
|
|
function force_reset_discoveries(force_name)
|
|
local force_data = global.forces[force_name]
|
|
if not force_data then return end
|
|
game.print({"space-exploration.no_force_data_found", force_name})
|
|
force_data.zones_discovered_count = 0
|
|
force_data.zones_discovered = {}
|
|
force_data.satellites_launched = 0
|
|
force_data.zone_priorities = {}
|
|
local homeworld = Zone.from_name("Nauvis")
|
|
if force_data.homeworld_index then
|
|
homeworld = Zone.from_zone_index(force_data.homeworld_index)
|
|
end
|
|
Zone.discover(force_name, homeworld)
|
|
Zone.discover(force_name, homeworld.parent)
|
|
for _, zone in pairs(global.zone_index) do
|
|
if zone.is_homeworld then
|
|
global.forces[force_name].zone_priorities[zone.index] = global.forces[force_name].zone_priorities[zone.index] or 1
|
|
end
|
|
end
|
|
end
|
|
|
|
function is_system_force(force_name)
|
|
return force_name == "enemy"
|
|
or force_name == "neutral"
|
|
or force_name == "capture"
|
|
or force_name == "conquest"
|
|
or force_name == "ignore"
|
|
or force_name == "friendly"
|
|
end
|
|
|
|
function setup_util_forces()
|
|
|
|
if not game.forces["conquest"] then
|
|
game.create_force("conquest") -- will shoot at the player, does not show icons, cannot be deconstructed. Has capture mechanic but active entities must be destroyed.
|
|
end
|
|
local conquest = game.forces["conquest"]
|
|
conquest.ai_controllable = true
|
|
|
|
if not game.forces["ignore"] then
|
|
game.create_force("ignore") -- won't shoot at the player, does not show icons, cannot be deconstructed.
|
|
end
|
|
local ignore = game.forces["ignore"]
|
|
for _, force in pairs(game.forces) do
|
|
ignore.set_cease_fire(force, true)
|
|
force.set_cease_fire(ignore, true)
|
|
end
|
|
|
|
if not game.forces["capture"] then
|
|
game.create_force("capture") -- won't shoot at the player, does not show icons, cannot be deconstructed. Has capture mechanic.
|
|
end
|
|
local capture = game.forces["capture"]
|
|
for _, force in pairs(game.forces) do
|
|
capture.set_cease_fire(force, true)
|
|
force.set_cease_fire(capture, true)
|
|
end
|
|
|
|
if not game.forces["friendly"] then
|
|
game.create_force("friendly") -- acts like a player entity, displays power icons, can be deconstructured by player
|
|
end
|
|
local friendly = game.forces["friendly"]
|
|
for _, force in pairs(game.forces) do
|
|
friendly.set_friend(force, true)
|
|
force.set_friend(friendly, true)
|
|
end
|
|
|
|
local enemy = game.forces["enemy"]
|
|
enemy.set_friend(conquest, true)
|
|
conquest.set_friend(enemy, true)
|
|
|
|
capture.set_friend(conquest, true)
|
|
conquest.set_friend(capture, true)
|
|
capture.set_friend(ignore, true)
|
|
ignore.set_friend(capture, true)
|
|
capture.set_friend(enemy, true)
|
|
enemy.set_friend(capture, true)
|
|
|
|
ignore.set_friend(conquest, true)
|
|
conquest.set_friend(ignore, true)
|
|
ignore.set_friend(enemy, true)
|
|
enemy.set_friend(ignore, true)
|
|
end
|
|
|
|
function on_force_created(event)
|
|
setup_force(event.force)
|
|
end
|
|
Event.addListener(defines.events.on_force_created, on_force_created)
|
|
|
|
function setup_collision_layers()
|
|
|
|
collision_mask_util_extended.named_collision_mask_integrity_check() -- detect non-1 mask entities
|
|
|
|
global.named_collision_masks = {}
|
|
|
|
-- a full-height wall that you cannot fly though, such as the wall of an underground tunnel.
|
|
global.named_collision_masks.flying_layer = collision_mask_util_extended.get_named_collision_mask("flying-layer")
|
|
-- things that should block projectiles
|
|
global.named_collision_masks.projectile_collision_layer = collision_mask_util_extended.get_named_collision_mask("projectile-layer")
|
|
-- empty space only
|
|
global.named_collision_masks.empty_space_collision_layer = collision_mask_util_extended.get_named_collision_mask("empty-space-tile")
|
|
-- All space tiles have this
|
|
global.named_collision_masks.space_collision_layer = collision_mask_util_extended.get_named_collision_mask("space-tile")
|
|
-- Spaceship tiles move around
|
|
global.named_collision_masks.spaceship_collision_layer = collision_mask_util_extended.get_named_collision_mask("moving-tile")
|
|
|
|
end
|
|
|
|
function on_configuration_changed()
|
|
|
|
setup_collision_layers()
|
|
|
|
Essential.enable_critical_techs() -- needed after bad mod removal
|
|
|
|
AbandonedRuins.exclude_surfaces()
|
|
|
|
Migrate.migrations()
|
|
|
|
local zone = Zone.from_name("Nauvis")
|
|
zone.fragment_name = "se-core-fragment-omni"
|
|
zone.surface_index = 1
|
|
zone.inflated = true
|
|
|
|
if global.astronomical then
|
|
global.universe = global.astronomical
|
|
global.astronomical = nil
|
|
end
|
|
|
|
global.tick_tasks = global.tick_tasks or {}
|
|
|
|
if global.forces then
|
|
for force_name in pairs(global.forces) do
|
|
local forcedata = global.forces[force_name]
|
|
forcedata.force_name = force_name
|
|
if (not forcedata.homeworld_index) and not is_system_force(force_name) then
|
|
forcedata.homeworld_index = zone.index
|
|
end
|
|
end
|
|
end
|
|
|
|
for _, force in pairs(game.forces) do
|
|
force.reset_recipes()
|
|
if force.technologies["radar"] then
|
|
force.technologies["radar"].enabled = true
|
|
end
|
|
end
|
|
|
|
-- enable any recipes that should be unlocked.
|
|
-- mainly required for entity-update-externals as a migration file won't work
|
|
for _, force in pairs(game.forces) do
|
|
for _, tech in pairs(force.technologies) do
|
|
if tech.researched then
|
|
for _, effect in pairs(tech.effects) do
|
|
if effect.type == "unlock-recipe" and force.recipes[effect.recipe] then
|
|
force.recipes[effect.recipe].enabled = true
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- stop game from ending on launch and tracking of launches
|
|
local interface_name = "silo_script"
|
|
if remote.interfaces[interface_name] then
|
|
if remote.interfaces[interface_name]["set_finish_on_launch"] then
|
|
remote.call(interface_name, "set_finish_on_launch", false)
|
|
end
|
|
if remote.interfaces[interface_name]["set_show_launched_without_satellite"] then
|
|
remote.call(interface_name, "set_show_launched_without_satellite", false)
|
|
end
|
|
if remote.interfaces[interface_name]["remove_tracked_item"] then
|
|
remote.call(interface_name, "remove_tracked_item", "satellite")
|
|
end
|
|
end
|
|
|
|
if global.next_meteor_shower and
|
|
global.next_meteor_shower > game.tick + 60 * 60 * settings.global["se-meteor-interval"].value then
|
|
global.next_meteor_shower = game.tick + math.random() * 60 * 60 * settings.global["se-meteor-interval"].value
|
|
end
|
|
|
|
Zone.zones_fix_all_tiles()
|
|
|
|
Universe.load_resource_data()
|
|
|
|
local zone = Zone.from_name("Nauvis")
|
|
zone.fragment_name = "se-core-fragment-omni"
|
|
zone.surface_index = 1
|
|
zone.inflated = true
|
|
zone.resources = {}
|
|
zone.ticks_per_day = 25000
|
|
|
|
Coreminer.equalise_all()
|
|
|
|
global.cache_travel_delta_v = nil
|
|
|
|
if game.technology_prototypes[mod_prefix.."linked-container"] then
|
|
for _, force in pairs(game.forces) do
|
|
force.technologies[mod_prefix.."teleportation"].enabled = true
|
|
end
|
|
end
|
|
|
|
game.print({"space-exploration.please-consider-patreon"})
|
|
|
|
end
|
|
Event.addListener("on_configuration_changed", on_configuration_changed, true)
|
|
|
|
|
|
function on_init()
|
|
-- When creating a new game, script.on_init() will be called on each mod that has a control.lua file.
|
|
-- When loading a save game and the mod did not exist in that save game script.on_init() is called.
|
|
|
|
global.version = version
|
|
|
|
setup_collision_layers()
|
|
|
|
Essential.enable_critical_techs() -- needed after bad mod removal
|
|
|
|
-- Astronomical first
|
|
global.seed = game.surfaces[1].map_gen_settings.seed
|
|
global.next_tick_task_id = 1
|
|
global.tick_tasks = {}
|
|
|
|
AbandonedRuins.exclude_surfaces()
|
|
|
|
setup_util_forces()
|
|
|
|
Universe.build()
|
|
|
|
local zone = Zone.from_name("Nauvis")
|
|
zone.fragment_name = "se-core-fragment-omni"
|
|
zone.surface_index = 1
|
|
zone.inflated = true
|
|
zone.resources = {}
|
|
zone.ticks_per_day = 25000
|
|
game.surfaces[1].solar_power_multiplier = Zone.solar_multiplier
|
|
Zone.set_solar_and_daytime(zone)
|
|
local surface = game.surfaces[1]
|
|
for resource_name, resource_setting in pairs(global.resources_and_controls.resource_settings) do
|
|
surface.regenerate_entity(resource_name)
|
|
end
|
|
if settings.startup[mod_prefix.."spawn-small-resources"].value then
|
|
Zone.spawn_small_resources(surface)
|
|
end
|
|
|
|
global.zones_by_surface[zone.surface_index] = zone
|
|
if game.surfaces[1].map_gen_settings.autoplace_controls["planet-size"] then
|
|
-- planet_radius = 10000 / 6 * (6 + log(1/planet_frequency/6, 2))
|
|
-- planet_frequency = 1 / 6 / 2 ^ (planet_radius * 6 / 10000 - 6)
|
|
--zone.radius = 10000 / 6 * game.surfaces[1].map_gen_settings.autoplace_controls["planet-size"].frequency
|
|
zone.radius = 10000 / 6 * (6 + util.math_log(1/game.surfaces[1].map_gen_settings.autoplace_controls["planet-size"].frequency/6, 2))
|
|
Log.trace(zone.radius)
|
|
else
|
|
zone.radius = 10000 / 6 * (6 + util.math_log(1/1/6, 2))
|
|
end
|
|
|
|
if Log.debug_big_logs then
|
|
Log.log_universe_simplified()
|
|
Log.log_universe()
|
|
end
|
|
|
|
-- Other stuff second
|
|
global.playerdata = global.playerdata or {}
|
|
global.forces = global.forces or {}
|
|
|
|
for _, force in pairs(game.forces) do
|
|
setup_force(force)
|
|
force.reset_recipes()
|
|
|
|
-- enable any recipes that should be unlocked.
|
|
-- mainly required for entity-update-externals as a migration file won't work
|
|
for _, tech in pairs(force.technologies) do
|
|
if tech.researched then
|
|
for _, effect in pairs(tech.effects) do
|
|
if effect.type == "unlock-recipe" and force.recipes[effect.recipe] then
|
|
force.recipes[effect.recipe].enabled = true
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
for tech in pairs(force.technologies['rocket-silo'].prerequisites) do
|
|
force.technologies[tech].enabled = true
|
|
end
|
|
end
|
|
|
|
if remote.interfaces["freeplay"] and remote.interfaces["freeplay"]["set_created_items"] and remote.interfaces["freeplay"]["get_created_items"] then
|
|
local stacks = remote.call("freeplay", "get_created_items")
|
|
for _, starting_item_stack in pairs(first_starting_item_stacks) do
|
|
stacks[starting_item_stack.name] = starting_item_stack.count
|
|
end
|
|
remote.call("freeplay", "set_created_items", stacks)
|
|
end
|
|
|
|
|
|
end
|
|
Event.addListener("on_init", on_init, true)
|
|
|
|
function on_player_spawned(event)
|
|
local player = game.players[event.player_index]
|
|
if player and player.character then
|
|
for _, item_stack in pairs(starting_item_stacks) do
|
|
player.insert(item_stack)
|
|
end
|
|
end
|
|
local forcedata = global.forces[player.force.name]
|
|
if forcedata then
|
|
forcedata.has_players = true
|
|
end
|
|
update_overhead_buttons(player)
|
|
end
|
|
Event.addListener(defines.events.on_player_respawned, on_player_spawned)
|
|
|
|
function on_player_changed_force(event)
|
|
local player = game.players[event.player_index]
|
|
setup_force(player.force)
|
|
local forcedata = global.forces[player.force.name]
|
|
if forcedata then
|
|
forcedata.has_players = true
|
|
end
|
|
end
|
|
Event.addListener(defines.events.on_player_changed_force, on_player_changed_force)
|
|
|
|
function on_player_created(event)
|
|
local player = game.players[event.player_index]
|
|
if player and player.connected then
|
|
player.print({"space-exploration.please-consider-patreon"})
|
|
end
|
|
if not player.get_quick_bar_slot(10) then
|
|
player.set_quick_bar_slot(10, mod_prefix.."medpack")
|
|
end
|
|
on_player_spawned(event)
|
|
end
|
|
Event.addListener(defines.events.on_player_created, on_player_created)
|
|
|
|
function on_player_joined_game(event)
|
|
local player = game.players[event.player_index]
|
|
if player and player.connected then
|
|
player.print({"space-exploration.please-consider-patreon"})
|
|
end
|
|
local forcedata = global.forces[player.force.name]
|
|
if forcedata then
|
|
forcedata.has_players = true
|
|
end
|
|
update_overhead_buttons(player)
|
|
end
|
|
Event.addListener(defines.events.on_player_joined_game, on_player_joined_game)
|
|
|
|
function update_overhead_buttons(player)
|
|
-- Fix for Factorio 1.1
|
|
local button_flow = mod_gui.get_button_flow(player)
|
|
if button_flow["informatron_overhead"] then
|
|
local caption = button_flow["informatron_overhead"].caption
|
|
local tooltip = button_flow["informatron_overhead"].tooltip
|
|
local sprite = button_flow["informatron_overhead"].sprite
|
|
button_flow["informatron_overhead"].destroy()
|
|
button_flow.add{type="sprite-button", name="informatron_overhead", sprite = sprite, tooltip = tooltip}
|
|
end
|
|
|
|
if button_flow[RemoteView.name_button_overhead_satellite] then button_flow[RemoteView.name_button_overhead_satellite].destroy() end
|
|
RemoteView.update_overhead_button(player.index)
|
|
|
|
if button_flow[MapView.name_button_overhead_interstellar] then button_flow[MapView.name_button_overhead_interstellar].destroy() end
|
|
MapView.update_overhead_button(player.index)
|
|
|
|
if button_flow[Zonelist.name_button_overhead_explorer] then button_flow[Zonelist.name_button_overhead_explorer].destroy() end
|
|
Zonelist.update_overhead_button(player.index)
|
|
end
|
|
|
|
function on_pre_player_left_game(event)
|
|
local player = game.players[event.player_index]
|
|
if player then
|
|
RemoteView.stop(player)
|
|
end
|
|
end
|
|
Event.addListener(defines.events.on_pre_player_left_game, on_pre_player_left_game)
|
|
|
|
function on_forces_merged(event)
|
|
-- merge in all of an old force to a new force
|
|
-- add things like launch counts
|
|
-- merge things like zone assets
|
|
-- use a single value for things like satellite position
|
|
local source_forcedata = global.forces[event.source_name]
|
|
local destination_forcedata = global.forces[event.destination.name]
|
|
if source_forcedata and destination_forcedata then
|
|
-- zones_discovered
|
|
if source_forcedata.zones_discovered then
|
|
destination_forcedata.zones_discovered = destination_forcedata.zones_discovered or {}
|
|
for a, b in pairs(source_forcedata.zones_discovered) do
|
|
if not destination_forcedata.zones_discovered[a] then
|
|
destination_forcedata.zones_discovered[a] = b
|
|
end
|
|
end
|
|
destination_forcedata.zones_discovered_count = table_size(destination_forcedata.zones_discovered)
|
|
end
|
|
--zone_priorities
|
|
if source_forcedata.zone_priorities then
|
|
destination_forcedata.zone_priorities = destination_forcedata.zone_priorities or {}
|
|
for a, b in pairs(source_forcedata.zone_priorities) do
|
|
if not destination_forcedata.zone_priorities[a] then
|
|
destination_forcedata.zone_priorities[a] = b
|
|
else
|
|
destination_forcedata.zone_priorities[a] = math.max(destination_forcedata.zone_priorities[a], b)
|
|
end
|
|
end
|
|
end
|
|
--satellites_launched
|
|
if source_forcedata.satellites_launched then
|
|
destination_forcedata.satellites_launched = (destination_forcedata.satellites_launched or 0) + source_forcedata.satellites_launched
|
|
end
|
|
--cargo_rockets_launched
|
|
if source_forcedata.cargo_rockets_launched then
|
|
destination_forcedata.cargo_rockets_launched = (destination_forcedata.cargo_rockets_launched or 0) + source_forcedata.cargo_rockets_launched
|
|
end
|
|
--cargo_rockets_crashed
|
|
if source_forcedata.cargo_rockets_crashed then
|
|
destination_forcedata.cargo_rockets_crashed = (destination_forcedata.cargo_rockets_crashed or 0) + source_forcedata.cargo_rockets_crashed
|
|
end
|
|
--first_discovered_vault
|
|
if source_forcedata.first_discovered_vault and not destination_forcedata.first_discovered_vault then
|
|
destination_forcedata.first_discovered_vault = source_forcedata.first_discovered_vault
|
|
end
|
|
--first_entered_vault
|
|
if source_forcedata.first_entered_vault and not destination_forcedata.first_entered_vault then
|
|
destination_forcedata.first_entered_vault = source_forcedata.first_entered_vault
|
|
end
|
|
--nauvis_satellite
|
|
if source_forcedata.nauvis_satellite and not destination_forcedata.nauvis_satellite then
|
|
destination_forcedata.nauvis_satellite = source_forcedata.nauvis_satellite
|
|
end
|
|
--solar_flare
|
|
if source_forcedata.solar_flare and not destination_forcedata.solar_flare then
|
|
destination_forcedata.solar_flare = source_forcedata.solar_flare
|
|
end
|
|
|
|
--arcospheres
|
|
if source_forcedata.arcosphere_collectors_launched then
|
|
destination_forcedata.arcosphere_collectors_launched = (destination_forcedata.arcosphere_collectors_launched or 0) + source_forcedata.arcosphere_collectors_launched
|
|
end
|
|
if source_forcedata.arcospheres_collected then
|
|
destination_forcedata.arcospheres_collected = (destination_forcedata.arcospheres_collected or 0) + source_forcedata.arcospheres_collected
|
|
end
|
|
|
|
local single_depth_tables = {
|
|
"chart_tag_buffer",
|
|
"tick_tasks",
|
|
"gravimetrics_labs",
|
|
"space_capsule_launches",
|
|
"delivery_cannons",
|
|
"rocket_landing_pads",
|
|
"rocket_launch_pads",
|
|
"spaceships",
|
|
"nexus"
|
|
}
|
|
for _, table_name in pairs(single_depth_tables) do
|
|
if global[table_name] then
|
|
for _, thing in pairs(global[table_name]) do
|
|
if thing.force_name == event.source_name then
|
|
thing.force_name = event.destination.name
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Zones
|
|
for _, zone in pairs(global.zone_index) do
|
|
local single_depth_tables = {
|
|
"energy_transmitters",
|
|
}
|
|
for _, table_name in pairs(single_depth_tables) do
|
|
if source_forcedata.zone_assets[table_name] then
|
|
for _, thing in pairs(global[table_name]) do
|
|
if thing.force_name == event.source_name then
|
|
thing.force_name = event.destination.name
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
--zone_assets
|
|
if source_forcedata.zone_assets then
|
|
|
|
local single_depth_tables = {
|
|
"energy_beam_defence",
|
|
}
|
|
for _, table_name in pairs(single_depth_tables) do
|
|
if source_forcedata.zone_assets[table_name] then
|
|
for _, thing in pairs(global[table_name]) do
|
|
if thing.force_name == event.source_name then
|
|
thing.force_name = event.destination.name
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
destination_forcedata.zone_assets = destination_forcedata.zone_assets or {}
|
|
for a, b in pairs(source_forcedata.zone_assets) do
|
|
if not destination_forcedata.zone_assets[a] then
|
|
destination_forcedata.zone_assets[a] = b
|
|
else
|
|
for table_name, subtable in pairs(b) do
|
|
if not destination_forcedata.zone_assets[a][table_name] then
|
|
destination_forcedata.zone_assets[a][table_name] = subtable
|
|
elseif table_name == "rocket_launch_pad_names" or table_name == "rocket_landing_pad_names" then
|
|
for name, structs in pairs(subtable) do
|
|
destination_forcedata.zone_assets[a][table_name][name] = destination_forcedata.zone_assets[a][table_name][name] or {}
|
|
for unit_number, struct in pairs(structs) do
|
|
destination_forcedata.zone_assets[a][table_name][name][unit_number] = struct
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
destination_forcedata.zones_discovered_count = table_size(destination_forcedata.zones_discovered)
|
|
end
|
|
--zone_assets
|
|
if source_forcedata.rocket_landing_pad_names then
|
|
if not destination_forcedata.rocket_landing_pad_names then
|
|
destination_forcedata.rocket_landing_pad_names = source_forcedata.rocket_landing_pad_names
|
|
else
|
|
for name, structs in pairs(source_forcedata.rocket_landing_pad_names) do
|
|
destination_forcedata.rocket_landing_pad_names[name] = destination_forcedata.rocket_landing_pad_names[name] or {}
|
|
for unit_number, struct in pairs(structs) do
|
|
destination_forcedata.rocket_landing_pad_names[name][unit_number] = struct
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
Event.addListener(defines.events.on_forces_merged, on_forces_merged)
|
|
|
|
require('scripts/remote-interface')
|
|
|
|
--log( serpent.block( data.raw["projectile"], {comment = false, numformat = '%1.8g' } ) )
|
|
-- /c Log.trace(serpent.block( game.surfaces.nauvis.map_gen_settings.autoplace_controls, {comment = false, numformat = '%1.8g' }))
|
|
|