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.

602 lines
27 KiB

local DeliveryCannon = {}
DeliveryCannon.variants = {
["logistic"] = {
name = mod_prefix.."delivery-cannon",
name_energy_interface = mod_prefix.."delivery-cannon-energy-interface",
name_beam = mod_prefix.."delivery-cannon-beam",
beam_offset = {x = -0.5, y = -5},
name_capsule = mod_prefix.."delivery-cannon-capsule",
name_capsule_projectile = mod_prefix.."delivery-cannon-capsule-projectile",
energy_per_delta_v = 50000,
},
["weapon"] = {
name = mod_prefix.."delivery-cannon-weapon",
name_energy_interface = mod_prefix.."delivery-cannon-weapon-energy-interface",
name_beam = mod_prefix.."delivery-cannon-weapon-beam",
beam_offset = {x = -1, y = -5},
name_capsule = mod_prefix.."delivery-cannon-weapon-capsule",
name_capsule_projectile = mod_prefix.."delivery-cannon-weapon-capsule-projectile",
energy_per_delta_v = 500000,
}
}
DeliveryCannon.name_delivery_cannon_chest = mod_prefix.."delivery-cannon-chest"
DeliveryCannon.name_delivery_cannon_capsule_shadow = mod_prefix.."delivery-cannon-capsule-shadow"
DeliveryCannon.name_delivery_cannon_capsule_explosion = mod_prefix.."delivery-cannon-capsule-explosion"
DeliveryCannon.name_delivery_cannon_targeter = mod_prefix.."delivery-cannon-targeter"
DeliveryCannon.name_target_activity_type = "delivery-cannon-target"
DeliveryCannon.capsule_fall_altitude = 100
DeliveryCannon.capsule_fall_time = 2 * 60
DeliveryCannon.name_event_copy_entity_settings = mod_prefix.."copy-entity-settings"
---@class DeliveryCannon All data necessary to maintain the state of a delivery cannon
--- Gets the DeliveryCannon for this unit_number
---@param unit_number number
function DeliveryCannon.from_unit_number (unit_number)
if not unit_number then Log.trace("DeliveryCannon.from_unit_number: invalid unit_number: nil") return end
unit_number = tonumber(unit_number)
-- NOTE: only supports container as the entity
if global.delivery_cannons[unit_number] then
return global.delivery_cannons[unit_number]
else
Log.trace("DeliveryCannon.from_unit_number: invalid unit_number: " .. unit_number)
end
end
--- Gets the DeliveryCannon for this entity
---@param entity LuaEntity
function DeliveryCannon.from_entity (entity)
if not(entity and entity.valid) then
Log.trace("DeliveryCannon.from_entity: invalid entity")
return
end
-- NOTE: only supports container as the entity
return DeliveryCannon.from_unit_number(entity.unit_number)
end
--- Computes the cost to launch a delivery cannon
---@param origin Zone launch zone
---@param destination Zone destination zone
function DeliveryCannon.get_delta_v(origin, destination)
if origin and destination then
return Zone.get_launch_delta_v(origin) + Zone.get_travel_delta_v(origin, destination)
end
end
--- Get the coordinate the delivery cannon is targetting
---@param delivery_cannon DeliveryCannon delivery cannon data
function DeliveryCannon.get_coordinate(delivery_cannon)
if delivery_cannon.destination and delivery_cannon.destination.coordinate then
return delivery_cannon.destination.coordinate
end
return nil
end
--- Does the delivery cannon have a destination set
---@param delivery_cannon DeliveryCannon delivery cannon data
function DeliveryCannon.has_destination(delivery_cannon)
return delivery_cannon and delivery_cannon.destination and delivery_cannon.destination.coordinate and delivery_cannon.destination.zone
end
--- Returns if this delivery cannon is valid
---@param delivery_cannon DeliveryCannon delivery cannon data
function DeliveryCannon.is_valid(delivery_cannon)
return delivery_cannon and delivery_cannon.main and delivery_cannon.main.valid
and delivery_cannon.energy_interface and delivery_cannon.energy_interface.valid
end
--- Returns if this delivery cannon can fire
---@param delivery_cannon DeliveryCannon delivery cannon data
function DeliveryCannon.can_fire(delivery_cannon)
return delivery_cannon and (not delivery_cannon.is_off)
and delivery_cannon.energy and delivery_cannon.required_energy
and delivery_cannon.energy >= delivery_cannon.required_energy
end
--- Gets the stack that this delivery cannon is ready to fire
---@param delivery_cannon any
function DeliveryCannon.get_stack(delivery_cannon)
if not delivery_cannon then return end
local recipe = delivery_cannon.main.get_recipe()
if not recipe then return end
if string.find(recipe.name, "se-delivery-cannon-weapon-pack-", 1, true) then
local ammo_name = Util.replace(recipe.name, "se-delivery-cannon-weapon-pack-", "")
local ammo = game.item_prototypes[ammo_name]
if ammo then
return {name = ammo_name, count = 1}
end
else
for _, ingredient in pairs(recipe.ingredients) do
if ingredient.name ~= DeliveryCannon.variants[delivery_cannon.variant].name_capsule then
local stack = ingredient
stack.count = stack.amount or stack.count
return stack
end
end
end
end
--- Displays a message that the delivery cannon projectile was destroyed by an opposing force
---@param delivery_cannon DeliveryCannon delivery cannon data
---@param defence_data any info about the destruction
---@param target_zone Zone the zone the delivery cannon was firing at
function DeliveryCannon.display_destroyed_projectile_message(delivery_cannon, defence_data, target_zone)
game.forces[delivery_cannon.force_name].print("Your delivery cannon canister from "..delivery_cannon.zone.name.." was destroyed by "..target_zone.name.." defences. ")
for force_name, shots_fired in pairs(defence_data) do
game.forces[force_name].print("Defences on "..target_zone.name
.." successfully shot down an enemy delivery cannon capsule. Shots fired: [img=item/se-meteor-defence] "
..shots_fired.defence_shots.." [img=item/se-meteor-point-defence] "..shots_fired.point_defence_shots)
end
end
--- Displays a message that the delivery cannon projectile was not destroyed by an opposing force
---@param delivery_cannon DeliveryCannon delivery cannon data
---@param defence_data any info about the (failed) destruction
---@param target_zone Zone the zone the delivery cannon was firing at
function DeliveryCannon.display_not_destroyed_projectile_message(delivery_cannon, defence_data, target_zone)
for force_name, shots_fired in pairs(defence_data) do
game.forces[force_name].print("[color=red]Defences on "..target_zone.name
.." failed to shoot down an enemy delivery cannon capsule. Shots fired: [img=item/se-meteor-defence] "
..shots_fired.defence_shots.." [img=item/se-meteor-point-defence] "..shots_fired.point_defence_shots.."[/color]")
end
end
--- Picks a new target for a delivery cannon
---@param delivery_cannon DeliveryCannon delivery cannon data
---@param target_zone Zone the zone to pick a target from
---@param target_surface LuaSurface the surface to pick a target from
function DeliveryCannon.pick_new_target(delivery_cannon, target_zone, target_surface)
local random_chunk = target_surface.get_random_chunk()
local position = {x = (random_chunk.x + math.random()) * 32, y = (random_chunk.y + math.random()) * 32}
if target_zone.radius and Util.vector_length(position) > target_zone.radius then
position = Util.vector_set_length(position, target_zone.radius * math.random())
end
if math.random() < 0.99 then
local enemy = find_enemy(game.forces[delivery_cannon.force_name], target_surface, position)
if enemy then
position = enemy.position
end
end
delivery_cannon.destination.coordinate = position
end
--- Adds a delivery cannon to the zone assets
---@param delivery_cannon DeliveryCannon delivery cannon data
function DeliveryCannon.add_delivery_cannon_to_table(delivery_cannon)
local type_table = DeliveryCannon.get_delivery_cannon_type_table(delivery_cannon)
type_table[delivery_cannon.unit_number] = delivery_cannon
end
--- Gets the delivery cannon zone assets
---@param delivery_cannon DeliveryCannon delivery cannon data
function DeliveryCannon.get_delivery_cannon_type_table(delivery_cannon)
local zone_assets = Zone.get_force_assets(delivery_cannon.force_name, delivery_cannon.zone.index)
zone_assets.delivery_cannons = zone_assets.delivery_cannons or {}
return zone_assets.delivery_cannons
end
--- Removes a delivery cannon from the zone assets
---@param delivery_cannon DeliveryCannon delivery cannon data
function DeliveryCannon.remove_delivery_cannon_from_table(delivery_cannon)
local type_table = DeliveryCannon.get_delivery_cannon_type_table(delivery_cannon)
if not type_table[delivery_cannon.unit_number] then return end
type_table[delivery_cannon.unit_number] = nil
end
--- Fires a delivery cannon if it's ready to fire
---@param delivery_cannon DeliveryCannon delivery cannon data
function DeliveryCannon.attempt_fire(delivery_cannon)
-- only fire cannons that are valid, have a valid destination, and have enough energy to fire at that destination
if not DeliveryCannon.is_valid(delivery_cannon) then DeliveryCannon.destroy(delivery_cannon) return end
if not DeliveryCannon.has_destination(delivery_cannon) then return end
delivery_cannon.energy = delivery_cannon.energy_interface.energy
if not delivery_cannon.required_energy then
delivery_cannon.required_energy = DeliveryCannon.variants[delivery_cannon.variant].energy_per_delta_v * DeliveryCannon.get_delta_v(delivery_cannon.zone, delivery_cannon.destination.zone)
end
if not DeliveryCannon.can_fire(delivery_cannon) then return end
-- only fire cannons with a valid payload ready
local cannon_inv = delivery_cannon.main.get_output_inventory()
delivery_cannon.payload_name = nil
delivery_cannon.payload_count = 0
for name, count in pairs(cannon_inv.get_contents()) do -- should only be 1
delivery_cannon.payload_name = name
delivery_cannon.payload_count = count
end
if not (delivery_cannon.payload_count > 0) then return end
-- fire the cannon
local target_zone = delivery_cannon.destination.zone
local target_surface = Zone.get_make_surface(target_zone)
local target_position = DeliveryCannon.get_coordinate(delivery_cannon)
if delivery_cannon.force_name then game.forces[delivery_cannon.force_name].chart(target_surface, Util.position_to_area(target_position, 64)) end
local stack = DeliveryCannon.get_stack(delivery_cannon)
if not stack then error("Delivery Cannon tried to fire invalid stack") return end
cannon_inv.remove({name=delivery_cannon.payload_name, count=1})
delivery_cannon.energy_interface.energy = delivery_cannon.energy_interface.energy - delivery_cannon.required_energy
delivery_cannon.main.surface.create_entity{
name = DeliveryCannon.variants[delivery_cannon.variant].name_beam,
position = Util.vectors_add(delivery_cannon.main.position, DeliveryCannon.variants[delivery_cannon.variant].beam_offset ),
target = Util.vectors_add(delivery_cannon.main.position, {x = 0, y = -100})
}
-- give opposing force's meteor defence a chance to destroy the projectile
local payload = {
variant = delivery_cannon.variant,
stack = stack,
target_zone = target_zone,
target_position = target_position,
force_name = delivery_cannon.force_name,
eta = game.tick + DeliveryCannon.capsule_fall_time,
health = 1
}
local defence_data = Meteor.defence_vs_projectile(payload)
if payload.health <= 0 then DeliveryCannon.display_destroyed_projectile_message(delivery_cannon, defence_data, target_zone) return end
-- the projectile went through
DeliveryCannon.display_not_destroyed_projectile_message(delivery_cannon, defence_data, target_zone)
global.delivery_cannon_payloads = global.delivery_cannon_payloads or {}
table.insert(global.delivery_cannon_payloads, payload)
local projectile_start_position = Util.vectors_add(target_position, {x = 0, y = -DeliveryCannon.capsule_fall_altitude})
local shadow_start_position = Util.vectors_add(target_position, {x = DeliveryCannon.capsule_fall_altitude, y = 0})
target_surface.create_entity{
name = DeliveryCannon.variants[delivery_cannon.variant].name_capsule_projectile,
position = projectile_start_position,
target = target_position,
force = delivery_cannon.force_name,
speed = DeliveryCannon.capsule_fall_altitude/DeliveryCannon.capsule_fall_time
}
target_surface.create_entity{
name = DeliveryCannon.name_delivery_cannon_capsule_shadow,
position = shadow_start_position,
target = target_position,
force = delivery_cannon.force_name,
speed = DeliveryCannon.capsule_fall_altitude/DeliveryCannon.capsule_fall_time
}
target_surface.request_to_generate_chunks(projectile_start_position)
target_surface.request_to_generate_chunks(shadow_start_position)
target_surface.request_to_generate_chunks(target_position)
-- select a new target if it automatic mode
if delivery_cannon.auto_select_targets then
DeliveryCannon.pick_new_target(delivery_cannon, target_zone, target_surface)
end
end
--- Performs the effect of a payload landing
--- If there is a delivery chest at the landing location, try to insert the payload item,
--- otherwise causes an explosion at the target and spills the items on the ground
---@param payload any the payload that is landing
function DeliveryCannon.do_payload_effect(payload)
local surface = Zone.get_make_surface(payload.target_zone)
local spill = payload.stack.count
local chest = surface.find_entity(DeliveryCannon.name_delivery_cannon_chest, payload.target_position)
if chest then
spill = spill - chest.insert(payload.stack)
end
if spill > 0 then
surface.create_entity{
name = DeliveryCannon.name_delivery_cannon_capsule_explosion,
position = payload.target_position,
force = payload.force_name
}
if payload.stack.name == "explosives" then -- double damage
surface.create_entity{
name = DeliveryCannon.name_delivery_cannon_capsule_explosion,
position = payload.target_position,
force = payload.force_name
}
end
local proto = game.item_prototypes[payload.stack.name]
local projectiles = {}
if proto.type == "ammo" then
local ammo_type = proto.get_ammo_type()
for _, action in pairs(ammo_type.action) do
for _, action_delivery in pairs(action.action_delivery) do
if action_delivery.type == "projectile" or action_delivery.type == "artillery" then
projectiles[action_delivery.projectile] = (projectiles[action_delivery.projectile] or 0) + 1
end
end
end
end
if proto.type == "capsule" then
local ammo_type = proto.capsule_action.attack_parameters.ammo_type
for _, action in pairs(ammo_type.action) do
for _, action_delivery in pairs(action.action_delivery) do
if action_delivery.type == "projectile" or action_delivery.type == "artillery" then
projectiles[action_delivery.projectile] = (projectiles[action_delivery.projectile] or 0) + 1
end
end
end
end
local no_items = false
for projectile_name, projectile_count in pairs(projectiles) do
no_items = true
surface.create_entity{
name = projectile_name,
position = payload.target_position,
target = payload.target_position,
speed = 0.1,
force = payload.force_name
}
end
if not no_items then
local spill_stack = table.deepcopy(payload.stack)
spill_stack.count = math.ceil(spill/4)
surface.spill_item_stack(payload.target_position, spill_stack, true, payload.force_name, true)
end
end
end
--- Updates all delivery cannons, potentially firing them or updating their guis
--- Checks are done infrequently, but still frequently enough that the cannon will never
--- get backed up while assembling at full speed
--- Updates all delivery cannons payloads, causing their effect when they hit
---@param delivery_cannon DeliveryCannon delivery cannon data
function DeliveryCannon.on_tick()
-- fire cannons
for _, delivery_cannon in pairs(global.delivery_cannons) do
if (game.tick + delivery_cannon.unit_number) % 60 == 0 then
DeliveryCannon.attempt_fire(delivery_cannon)
end
end
-- update guis
if game.tick % 60 == 0 then
for _, player in pairs(game.connected_players) do
DeliveryCannonGUI.gui_update(player)
end
end
-- process payloads
if global.delivery_cannon_payloads then
for i = #global.delivery_cannon_payloads, 1, -1 do
local payload = global.delivery_cannon_payloads[i]
if payload then
if game.tick >= payload.eta then
DeliveryCannon.do_payload_effect(payload)
table.remove(global.delivery_cannon_payloads, i)
end
end
end
end
end
Event.addListener(defines.events.on_tick, DeliveryCannon.on_tick)
--- When the player selects an area using the targeter, set the delivery cannon to target that location
---@param event any
function DeliveryCannon.on_player_selected_area(event)
if (event.item == DeliveryCannon.name_delivery_cannon_targeter) then
local player = game.players[event.player_index]
local playerdata = get_make_playerdata(player)
if playerdata.remote_view_activity and playerdata.remote_view_activity.type == DeliveryCannon.name_target_activity_type then
local delivery_cannon = playerdata.remote_view_activity.delivery_cannon
if delivery_cannon.main and delivery_cannon.main.valid then
delivery_cannon.destination.coordinate = {
x = (event.area.left_top.x + event.area.right_bottom.x) / 2,
y = (event.area.left_top.y + event.area.right_bottom.y) / 2
}
delivery_cannon.destination.zone = Zone.from_surface(player.surface)
player.print({"space-exploration.delivery-cannon-coordinates-set", math.floor(delivery_cannon.destination.coordinate.x), math.floor(delivery_cannon.destination.coordinate.y)})
-- reopen the gui and stop targetting
player.opened = delivery_cannon.main
player.cursor_stack.set_stack(nil)
end
end
end
end
Event.addListener(defines.events.on_player_selected_area, DeliveryCannon.on_player_selected_area)
function DeliveryCannon.get_make_energy_interface(entity, delivery_cannon)
local energy_interface = entity.surface.find_entity(DeliveryCannon.variants[delivery_cannon.variant].name_energy_interface, entity.position)
if energy_interface then return energy_interface end
local energy_interface_ghosts = entity.surface.find_entities_filtered{
ghost_name = DeliveryCannon.variants[delivery_cannon.variant].name_energy_interface,
position = entity.position
}
if energy_interface_ghosts[1] and energy_interface_ghosts[1].valid then
local collisions, energy_interface = energy_interface_ghosts[1].revive({})
if energy_interface then return energy_interface end
end
energy_interface = entity.surface.create_entity{
name = DeliveryCannon.variants[delivery_cannon.variant].name_energy_interface,
force = entity.force,
position = {entity.position.x, entity.position.y}
}
return energy_interface
end
function DeliveryCannon.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 then return end
if entity.name == DeliveryCannon.variants["logistic"].name or entity.name == DeliveryCannon.variants["weapon"].name then
if not RemoteView.is_unlocked_force(entity.force.name) then
return cancel_entity_creation(entity, event.player_index, {"space-exploration.generic-requires-satellite"})
end
local force_name = entity.force.name
local zone = Zone.from_surface(entity.surface)
if not zone then
return cancel_entity_creation(entity, event.player_index, "Invalid launch location")
end
local delivery_cannon = {
type = entity.name,
variant = entity.name == DeliveryCannon.variants["logistic"].name and "logistic" or "weapon",
valid = true,
force_name = force_name,
unit_number = entity.unit_number,
main = entity,
zone = zone,
is_off = true,
destination = {
zone = nil
},
launch_status = -1
}
global.delivery_cannons[entity.unit_number] = delivery_cannon
Log.trace("DeliveryCannon: delivery_cannon added")
DeliveryCannon.add_delivery_cannon_to_table(delivery_cannon) -- assigns to zone_assets
-- spawn energy interface
delivery_cannon.energy_interface = DeliveryCannon.get_make_energy_interface(entity, delivery_cannon)
delivery_cannon.energy_interface.destructible = false
-- set settings
if event.tags then
if event.tags.destination then
delivery_cannon.destination.coordinate = event.tags.destination.coordinate
delivery_cannon.destination.zone = Zone.from_name(event.tags.destination.zone_name)
end
delivery_cannon.is_off = event.tags.is_off
delivery_cannon.auto_selects_targets = event.tags.auto_selects_targets
end
if event.player_index and game.players[event.player_index] and game.players[event.player_index].connected then
DeliveryCannonGUI.gui_open(game.players[event.player_index], delivery_cannon)
end
end
end
Event.addListener(defines.events.on_entity_cloned, DeliveryCannon.on_entity_created)
Event.addListener(defines.events.on_built_entity, DeliveryCannon.on_entity_created)
Event.addListener(defines.events.on_robot_built_entity, DeliveryCannon.on_entity_created)
Event.addListener(defines.events.script_raised_built, DeliveryCannon.on_entity_created)
Event.addListener(defines.events.script_raised_revive, DeliveryCannon.on_entity_created)
function DeliveryCannon.destroy_sub(delivery_cannon, key)
if delivery_cannon[key] and delivery_cannon[key].valid then
delivery_cannon[key].destroy()
delivery_cannon[key] = nil
end
end
function DeliveryCannon.destroy(delivery_cannon, player_index)
if not delivery_cannon then
Log.trace("delivery_cannon_destroy: no delivery_cannon")
return
end
delivery_cannon.valid = false
DeliveryCannon.destroy_sub(delivery_cannon, 'main')
DeliveryCannon.destroy_sub(delivery_cannon, 'energy_interface')
DeliveryCannon.remove_delivery_cannon_from_table(delivery_cannon)
global.delivery_cannons[delivery_cannon.unit_number] = nil
-- if a player has this gui open then close it
local gui_name = DeliveryCannonGUI.name_delivery_cannon_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 == delivery_cannon.unit_number then
root.destroy()
end
end
end
function DeliveryCannon.on_entity_removed(event)
local entity = event.entity
if entity and entity.valid and
(entity.name == DeliveryCannon.variants["logistic"].name or entity.name == DeliveryCannon.variants["weapon"].name) then
DeliveryCannon.destroy(DeliveryCannon.from_entity(entity), event.player_index )
end
end
Event.addListener(defines.events.on_entity_died, DeliveryCannon.on_entity_removed)
Event.addListener(defines.events.on_robot_mined_entity, DeliveryCannon.on_entity_removed)
Event.addListener(defines.events.on_player_mined_entity, DeliveryCannon.on_entity_removed)
Event.addListener(defines.events.script_raised_destroy, DeliveryCannon.on_entity_removed)
--- Handles the player creating a blueprint by setting tags to store the state of delivery cannons
---@param event any
function DeliveryCannon.on_player_setup_blueprint(event)
local player_index = event.player_index
if player_index and game.players[player_index] and game.players[player_index].connected then
local player = game.players[player_index]
-- this setup code and checks is a workaround for the fact that the event doesn't specify the blueprint on the event
-- and the player.blueprint_to_setup isn't actually set in the case of copy/paste or blueprint library or select new contents
local blueprint = nil
if player and player.blueprint_to_setup and player.blueprint_to_setup.valid_for_read then blueprint = player.blueprint_to_setup
elseif player and player.cursor_stack.valid_for_read and player.cursor_stack.is_blueprint then blueprint = player.cursor_stack end
if blueprint and blueprint.is_blueprint_setup() then
local mapping = event.mapping.get()
local blueprint_entities = blueprint.get_blueprint_entities()
if blueprint_entities then
for _, blueprint_entity in pairs(blueprint_entities) do
if blueprint_entity.name == DeliveryCannon.variants["logistic"].name or blueprint_entity.name == DeliveryCannon.variants["weapon"].name then
local entity = mapping[blueprint_entity.entity_number]
if entity then
local delivery_cannon = DeliveryCannon.from_entity(entity)
if delivery_cannon then
local tags = {}
if delivery_cannon.destination then
tags.destination = {
coordinate = delivery_cannon.destination.coordinate,
zone_name = delivery_cannon.destination.zone and delivery_cannon.destination.zone.name
}
end
tags.is_off = delivery_cannon.is_off
tags.auto_select_targets = delivery_cannon.auto_selects_targets
blueprint.set_blueprint_entity_tags(blueprint_entity.entity_number, tags)
end
end
end
end
end
end
end
end
Event.addListener(defines.events.on_player_setup_blueprint, DeliveryCannon.on_player_setup_blueprint)
--- Handles the player copy/pasting settings between delivery cannons
---@param event any
function DeliveryCannon.on_entity_settings_pasted(event)
local player_index = event.player_index
if player_index and game.players[player_index] and game.players[player_index].connected
and event.source and event.source.valid and event.destination and event.destination.valid then
if not string.find(event.source.name, "delivery-cannon", 1, true) then return end
if not string.find(event.destination.name, "delivery-cannon", 1, true) then return end
local player = game.players[player_index]
local delivery_cannon_from = DeliveryCannon.from_entity(event.source)
local delivery_cannon_to = DeliveryCannon.from_entity(event.destination)
if delivery_cannon_from and delivery_cannon_to then
-- actual settings copy
delivery_cannon_to.destination.coordinate = table.deepcopy(delivery_cannon_from.destination.coordinate)
delivery_cannon_to.destination.zone = delivery_cannon_from.destination.zone
delivery_cannon_to.is_off = delivery_cannon_from.is_off
delivery_cannon_to.auto_select_targets = delivery_cannon_from.auto_select_targets
if delivery_cannon_to.destination.coordinate then
player.print({"space-exploration.delivery-cannon-coordinates-pasted", math.floor(delivery_cannon_to.destination.coordinate.x), math.floor(delivery_cannon_to.destination.coordinate.y)})
end
end
end
end
Event.addListener(defines.events.on_entity_settings_pasted, DeliveryCannon.on_entity_settings_pasted)
function DeliveryCannon.on_init(event)
global.delivery_cannons = {}
end
Event.addListener("on_init", DeliveryCannon.on_init, true)
return DeliveryCannon