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.

336 lines
12 KiB

local Landingpad = {}
-- constants
Landingpad.name_rocket_landing_pad = mod_prefix.."rocket-landing-pad"
Landingpad.name_rocket_landing_pad_settings = mod_prefix.."rocket-landing-pad-settings"
---@class LandingPad All data necessary to maintain the state of a delivery cannon
--- Gets the Landingpad for this unit_number
---@param unit_number number
function Landingpad.from_unit_number (unit_number)
if not unit_number then Log.trace("Landingpad.from_unit_number: invalid unit_number: nil") return end
unit_number = tonumber(unit_number)
-- NOTE: only supports container as the entity
if global.rocket_landing_pads[unit_number] then
return global.rocket_landing_pads[unit_number]
else
Log.trace("Landingpad.from_unit_number: invalid unit_number: " .. unit_number)
end
end
--- Gets the Landingpad for this entity
---@param entity LuaEntity
function Landingpad.from_entity (entity)
if not(entity and entity.valid) then
Log.trace("Landingpad.from_entity: invalid entity")
return
end
-- NOTE: only suppors container as the entity
return Landingpad.from_unit_number(entity.unit_number)
end
-- returns the available struct
function Landingpad.get_force_landing_pads_availability(force_name, landing_pad_name)
local empty_landing_pads = {}
local filled_landing_pads = {}
local blocked_landing_pads = {}
if global.forces[force_name] and global.forces[force_name].rocket_landing_pad_names and global.forces[force_name].rocket_landing_pad_names[landing_pad_name] then
local landing_pads = global.forces[force_name].rocket_landing_pad_names[landing_pad_name]
for _, landing_pad in pairs(landing_pads) do
if landing_pad.container and landing_pad.container.valid then
if landing_pad.inbound_rocket then
table.insert(blocked_landing_pads, landing_pad)
elseif landing_pad.container.get_inventory(defines.inventory.chest).is_empty() then
table.insert(empty_landing_pads, landing_pad)
else
table.insert(filled_landing_pads, landing_pad)
end
else
Landingpad.destroy(landing_pad)
end
end
end
return {
empty_landing_pads = empty_landing_pads,
filled_landing_pads = filled_landing_pads,
blocked_landing_pads = blocked_landing_pads,
}
end
-- returns the available struct
function Landingpad.get_zone_landing_pads_availability(force_name, zone, landing_pad_name)
local empty_landing_pads = {}
local filled_landing_pads = {}
local blocked_landing_pads = {}
local zone_assets = Zone.get_force_assets(force_name, zone.index)
if zone_assets.rocket_landing_pad_names and zone_assets.rocket_landing_pad_names[landing_pad_name] then
local landing_pads = zone_assets.rocket_landing_pad_names[landing_pad_name]
for _, landing_pad in pairs(landing_pads) do
if landing_pad.container and landing_pad.container.valid then
if landing_pad.inbound_rocket then
table.insert(blocked_landing_pads, landing_pad)
elseif landing_pad.container.get_inventory(defines.inventory.chest).is_empty() then
table.insert(empty_landing_pads, landing_pad)
else
table.insert(filled_landing_pads, landing_pad)
end
else
Landingpad.destroy(landing_pad)
end
end
end
return {
empty_landing_pads = empty_landing_pads,
filled_landing_pads = filled_landing_pads,
blocked_landing_pads = blocked_landing_pads,
}
end
function Landingpad.on_entity_created(event)
local entity = util.get_entity_from_event(event)
if not entity then return end
if entity.name == Landingpad.name_rocket_landing_pad then
local zone = Zone.from_surface(entity.surface)
if not zone then
return cancel_entity_creation(entity, event.player_index, {"space-exploration.construction-denied"})
end
local fn = entity.force.name
local default_name = zone.name .. " Landing Pad"
local struct = {
type = Landingpad.name_rocket_landing_pad,
valid = true,
force_name = fn,
unit_number = entity.unit_number,
container = entity,
name = default_name,
zone = zone
}
global.rocket_landing_pads = global.rocket_landing_pads or {}
global.rocket_landing_pads[entity.unit_number] = struct
Landingpad.name(struct) -- assigns to zone_assets
-- set settings
local tags = util.get_tags_from_event(event, Landingpad.serialize)
if tags then
Landingpad.deserialize(entity, tags)
end
if event.player_index and game.players[event.player_index] and game.players[event.player_index].connected then
LandingpadGUI.gui_open(game.players[event.player_index], struct)
end
end
end
Event.addListener(defines.events.on_entity_cloned, Landingpad.on_entity_created)
Event.addListener(defines.events.on_built_entity, Landingpad.on_entity_created)
Event.addListener(defines.events.on_robot_built_entity, Landingpad.on_entity_created)
Event.addListener(defines.events.script_raised_built, Landingpad.on_entity_created)
Event.addListener(defines.events.script_raised_revive, Landingpad.on_entity_created)
function Landingpad.remove_struct_from_tables(struct)
-- force
local force_data = global.forces[struct.force_name]
force_data.rocket_landing_pad_names = force_data.rocket_landing_pad_names or {}
local force_type_table = force_data.rocket_landing_pad_names
if not force_type_table[struct.name] then return end
force_type_table[struct.name][struct.unit_number] = nil
local count_remaining = 0
for _, remaining in pairs(force_type_table[struct.name]) do
count_remaining = count_remaining + 1
end
if count_remaining == 0 then
force_type_table[struct.name] = nil
end
-- zone
local zone_assets = Zone.get_force_assets(struct.force_name, struct.zone.index)
zone_assets.rocket_landing_pad_names = zone_assets.rocket_landing_pad_names or {}
local zone_type_table = zone_assets.rocket_landing_pad_names
if not zone_type_table[struct.name] then return end
zone_type_table[struct.name][struct.unit_number] = nil
local count_remaining = 0
for _, remaining in pairs(zone_type_table[struct.name]) do
count_remaining = count_remaining + 1
end
if count_remaining == 0 then
zone_type_table[struct.name] = nil
end
end
function Landingpad.destroy_sub(struct, key)
if struct[key] and struct[key].valid then
struct[key].destroy()
struct[key] = nil
end
end
function Landingpad.destroy(struct)
if not struct then
Log.trace("Landingpad.destroy: no struct")
return
end
struct.valid = false
Landingpad.destroy_sub(struct, 'container')
Landingpad.remove_struct_from_tables(struct)
global.rocket_landing_pads[struct.unit_number] = nil
-- if a player has this gui open then close it
local gui_name = LandingpadGUI.name_rocket_landing_pad_gui_root
for _, player in pairs(game.connected_players) do
local root = player.gui.relative[gui_name]
if root and root.tags and root.tags.unit_number == struct.unit_number then
player.gui.relative[gui_name].destroy()
end
end
end
function Landingpad.name(struct, new_name)
struct.name = (new_name or struct.name)
-- force
local force_data = global.forces[struct.force_name]
force_data.rocket_landing_pad_names = force_data.rocket_landing_pad_names or {}
local force_type_table = force_data.rocket_landing_pad_names
force_type_table[struct.name] = force_type_table[struct.name] or {}
force_type_table[struct.name][struct.unit_number] = struct
local zone_assets = Zone.get_force_assets(struct.force_name, struct.zone.index)
zone_assets.rocket_landing_pad_names = zone_assets.rocket_landing_pad_names or {}
local zone_type_table = zone_assets.rocket_landing_pad_names
zone_type_table[struct.name] = zone_type_table[struct.name] or {}
zone_type_table[struct.name][struct.unit_number] = struct
end
function Landingpad.rename(struct, new_name)
local old_name = struct.name
Landingpad.remove_struct_from_tables(struct)
Landingpad.name(struct, new_name)
end
function Landingpad.dropdown_list_zone_landing_pad_names(force_name, zone, current)
local selected_index
local list = {} -- names with optional [count]
local values = {} -- raw names
table.insert(list, {"space-exploration.none_general_vicinity"})
table.insert(values, "") -- not sure if nil would work
if zone and zone.type ~= "spaceship" then
local zone_assets = Zone.get_force_assets(force_name, zone.index)
for name, sites in pairs(zone_assets["rocket_landing_pad_names"]) do
local count = 0
for _, struct in pairs(sites) do
count = count + 1
end
if count == 1 then
table.insert(list, name)
table.insert(values, name)
if name == current then selected_index = #list end
elseif count > 1 then
table.insert(list, name .. " ["..count.."]")
table.insert(values, name)
if name == current then selected_index = #list end
end
end
end
return list, (selected_index or 1), values
end
function Landingpad.dropdown_list_force_landing_pad_names(force_name, current)
local selected_index
local list = {} -- names with optional [count]
local values = {} -- raw names
table.insert(list, {"space-exploration.none_cannot_launch"})
table.insert(values, "") -- not sure if nil would work
local force_data = global.forces[force_name]
if force_data.rocket_landing_pad_names then
for name, sites in pairs(force_data.rocket_landing_pad_names) do
local count = 0
for _, struct in pairs(sites) do
count = count + 1
end
if count == 1 then
table.insert(list, name)
table.insert(values, name)
if name == current then selected_index = #list end
elseif count > 1 then
table.insert(list, name .. " ["..count.."]")
table.insert(values, name)
if name == current then selected_index = #list end
end
end
end
return list, (selected_index or 1), values
end
function Landingpad.on_entity_removed(event)
local entity = event.entity
if entity and entity.valid and entity.name == Landingpad.name_rocket_landing_pad then
Landingpad.destroy(Landingpad.from_entity(entity))
end
end
Event.addListener(defines.events.on_entity_died, Landingpad.on_entity_removed)
Event.addListener(defines.events.on_robot_mined_entity, Landingpad.on_entity_removed)
Event.addListener(defines.events.on_player_mined_entity, Landingpad.on_entity_removed)
Event.addListener(defines.events.script_raised_destroy, Landingpad.on_entity_removed)
function Landingpad.serialize(entity)
local landing_pad = Landingpad.from_entity(entity)
if landing_pad then
local tags = {}
tags.name = landing_pad.name
return tags
end
end
function Landingpad.deserialize(entity, tags)
local landing_pad = Landingpad.from_entity(entity)
if landing_pad then
Landingpad.rename(landing_pad, tags.name)
end
end
--- Handles the player creating a blueprint by setting tags to store the state of landing pads
---@param event any
function Landingpad.on_player_setup_blueprint(event)
util.setup_blueprint(event, Landingpad.name_rocket_landing_pad, Landingpad.serialize)
end
Event.addListener(defines.events.on_player_setup_blueprint, Landingpad.on_player_setup_blueprint)
--- Handles the player copy/pasting settings between landing pads
---@param event any
function Landingpad.on_entity_settings_pasted(event)
util.settings_pasted(event, Landingpad.name_rocket_landing_pad, Landingpad.serialize, Landingpad.deserialize)
end
Event.addListener(defines.events.on_entity_settings_pasted, Landingpad.on_entity_settings_pasted)
function Landingpad.on_init(event)
global.rocket_landing_pads = {} -- all landing pads sorted by struct[unit_unumber]
end
Event.addListener("on_init", Landingpad.on_init, true)
return Landingpad