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.
945 lines
38 KiB
945 lines
38 KiB
-- Used for energy transmission and cross-surface energy beam weapons.
|
|
local EnergyBeam = {}
|
|
|
|
EnergyBeam.name_emitter = mod_prefix.."energy-transmitter-emitter"
|
|
EnergyBeam.name_chamber = mod_prefix.."energy-transmitter-chamber"
|
|
EnergyBeam.name_injector = mod_prefix.."energy-transmitter-injector"
|
|
EnergyBeam.name_injector_reactor = mod_prefix.."energy-transmitter-injector-reactor"
|
|
EnergyBeam.name_receiver = mod_prefix.."energy-receiver"
|
|
EnergyBeam.name_receiver_beam = mod_prefix.."energy-receiver-beam" -- projectile
|
|
EnergyBeam.name_glaive_beam = mod_prefix.."energy-glaive-beam" -- projectile
|
|
EnergyBeam.name_glaive_beam_sprite = mod_prefix.."energy-glaive-beam-sprite" -- sprite
|
|
EnergyBeam.name_glaive_path_fx = mod_prefix.."energy-glaive-path-fx"
|
|
EnergyBeam.name_glaive_damage_projectile = mod_prefix.."energy-glaive-damage-projectile"
|
|
EnergyBeam.name_glaive_damage_aoe = mod_prefix.."energy-glaive-damage-aoe"
|
|
EnergyBeam.name_glaive_damage_aoe_large = mod_prefix.."energy-glaive-damage-aoe-large"
|
|
EnergyBeam.name_glaive_damage_aoe_large_10 = mod_prefix.."energy-glaive-damage-aoe-large-10"
|
|
|
|
EnergyBeam.emitter_width = 10
|
|
EnergyBeam.chamber_box = {x=8, y=4}
|
|
EnergyBeam.injector_length = 5
|
|
|
|
EnergyBeam.name_transmitter_targeter = mod_prefix .. "energy-transmitter-targeter"
|
|
EnergyBeam.name_target_activity_type = "energy-transmitter-target"
|
|
EnergyBeam.name_transmitter_effect = mod_prefix .. "energy-transmitter-beam"
|
|
EnergyBeam.transfer_interval = 60
|
|
EnergyBeam.specific_heat = 1000000000 -- 1GJ
|
|
EnergyBeam.injector_donate_rate = 0.05
|
|
EnergyBeam.injector_waste_rate = 0.005
|
|
EnergyBeam.beam_speed_base = 0.05
|
|
EnergyBeam.beam_speed_temperature_multiplier = 0.06
|
|
EnergyBeam.beam_speed_temperature_exponent = 0.7
|
|
EnergyBeam.large_aoe_heat = 100
|
|
|
|
EnergyBeam.glaive_cost_aoe = 0.5
|
|
EnergyBeam.glaive_cost_aoe_large = 1.2
|
|
EnergyBeam.glaive_cost_aoe_large_10 = 12
|
|
|
|
--- Gets the EnergyBeam for this unit_number
|
|
---@param unit_number number
|
|
function EnergyBeam.from_unit_number (unit_number)
|
|
if not unit_number then Log.trace("EnergyBeam.from_unit_number: invalid unit_number: nil") return end
|
|
unit_number = tonumber(unit_number)
|
|
if global.energy_transmitters[unit_number] then
|
|
return global.energy_transmitters[unit_number]
|
|
else
|
|
Log.trace("EnergyBeam.from_unit_number: invalid unit_number: " .. unit_number)
|
|
end
|
|
end
|
|
|
|
--- Gets the EnergyBeam for this entity
|
|
---@param entity LuaEntity
|
|
function EnergyBeam.from_entity (entity)
|
|
if not(entity and entity.valid) then
|
|
Log.trace("EnergyBeam.from_entity: invalid entity")
|
|
return
|
|
end
|
|
return EnergyBeam.from_unit_number(entity.unit_number)
|
|
end
|
|
|
|
--- Does the enery beamer have a destination set
|
|
---@param tree any
|
|
function EnergyBeam.has_destination(tree)
|
|
return tree and tree.destination and tree.destination.coordinate and tree.destination.zone
|
|
end
|
|
|
|
function EnergyBeam.get_transmission_efficiency(origin, destination)
|
|
if origin and destination then
|
|
local delta_v = Zone.get_launch_delta_v(origin) + Zone.get_travel_delta_v(origin, destination)
|
|
local efficiency = 1- delta_v/(delta_v+10000)
|
|
|
|
local origin_stellar_position = Zone.get_stellar_position(origin)
|
|
local destination_stellar_position = Zone.get_stellar_position(destination)
|
|
|
|
if destination.type == "anomaly" or origin.type == "anomaly" then
|
|
efficiency = efficiency * 0.01
|
|
else
|
|
if origin_stellar_position and destination_stellar_position then -- interstellar less effective
|
|
if Util.vectors_delta_length(origin_stellar_position, destination_stellar_position) > 0.001 then
|
|
efficiency = efficiency * 0.5
|
|
end
|
|
else
|
|
efficiency = efficiency * 0.5
|
|
end
|
|
end
|
|
|
|
if Zone.is_solid(origin) then
|
|
efficiency = efficiency * 0.5
|
|
end
|
|
return efficiency
|
|
end
|
|
end
|
|
|
|
|
|
function EnergyBeam.get_coordinate(tree)
|
|
if tree.destination and tree.destination.coordinate then
|
|
return tree.destination.coordinate
|
|
end
|
|
--return tree.emitter.position -- return nil
|
|
end
|
|
|
|
function EnergyBeam.clear_end_beam(tree)
|
|
if tree.receiver_beam and tree.receiver_beam.valid then
|
|
tree.receiver_beam.destroy()
|
|
tree.receiver_beam = nil
|
|
end
|
|
if tree.glaive_beam and tree.glaive_beam.valid then
|
|
tree.glaive_beam.destroy()
|
|
tree.glaive_beam = nil
|
|
end
|
|
EnergyBeam.remove_markers(tree)
|
|
end
|
|
|
|
function EnergyBeam.collect_heat(tree, waste)
|
|
local temperature = 0
|
|
for _, injector_reactor in pairs(tree.injector_reactors) do
|
|
if injector_reactor.valid then
|
|
local heat = (injector_reactor.temperature - 15) * EnergyBeam.injector_donate_rate
|
|
if heat > 1 then heat = math.pow(heat, 0.5) end -- reduce overload charge efficiency
|
|
local remove = (injector_reactor.temperature - 15) * (waste and EnergyBeam.injector_waste_rate or EnergyBeam.injector_donate_rate)
|
|
injector_reactor.temperature = injector_reactor.temperature - remove
|
|
temperature = temperature + heat
|
|
end
|
|
end
|
|
return temperature
|
|
end
|
|
|
|
function EnergyBeam.beam_step_idle(tree)
|
|
EnergyBeam.clear_end_beam(tree)
|
|
if tree.emitter_beam and tree.emitter_beam.valid then
|
|
tree.emitter_beam.destroy()
|
|
end
|
|
|
|
local temperature = EnergyBeam.collect_heat(tree, true) -- waste
|
|
tree.last_temperature = temperature
|
|
|
|
if tree.destination and tree.destination.zone then
|
|
local efficiency = EnergyBeam.get_transmission_efficiency(tree.zone, tree.destination.zone)
|
|
tree.last_efficiency = efficiency
|
|
else
|
|
tree.last_efficiency = 0
|
|
end
|
|
end
|
|
|
|
function EnergyBeam.find_enemy(tree)
|
|
local destination_surface = Zone.get_make_surface(tree.destination.zone)
|
|
local position = tree.destination.coordinate or {x = 0, y = 0}
|
|
local force = game.forces[tree.force_name]
|
|
local enemy = find_enemy(force, destination_surface, position)
|
|
|
|
if enemy then
|
|
tree.destination.coordinate = enemy.position
|
|
tree.destination.enemy = enemy
|
|
force.chart(destination_surface, Util.position_to_area(enemy.position, 32))
|
|
return
|
|
end
|
|
-- nothing found
|
|
game.forces[tree.force_name].print({
|
|
"space-exploration.energy-transmitter-no-enemies-found",
|
|
"[gps="..math.floor(tree.emitter.position.x)..","..math.floor(tree.emitter.position.y)..","..destination_surface.name.."]"
|
|
})
|
|
tree.mode = "off"
|
|
end
|
|
|
|
function EnergyBeam.scale_glaive_sprite(tree)
|
|
local position = EnergyBeam.get_coordinate(tree)
|
|
if not position then
|
|
if not (tree.glaive_beam and tree.glaive_beam.valid) then return end
|
|
position = tree.glaive_beam.position
|
|
end
|
|
|
|
if not (tree.glaive_beam and tree.glaive_beam.valid) then
|
|
local destination_surface = Zone.get_make_surface(tree.destination.zone)
|
|
tree.glaive_beam = destination_surface.create_entity{
|
|
name = EnergyBeam.name_glaive_beam,
|
|
position = position,
|
|
target = Util.vectors_add(position, {x=0,y=-1}),
|
|
speed = 0,
|
|
force = tree.force_name
|
|
}
|
|
end
|
|
if not (tree.glaive_beam_sprite_id and rendering.is_valid(tree.glaive_beam_sprite_id)) then
|
|
tree.glaive_beam_sprite_id = rendering.draw_sprite{
|
|
target = tree.glaive_beam,
|
|
sprite = EnergyBeam.name_glaive_beam_sprite,
|
|
surface = tree.glaive_beam.surface,
|
|
}
|
|
end
|
|
rendering.set_y_scale(tree.glaive_beam_sprite_id, 0.5 + 1.5 * math.min(1, tree.last_temperature / 100))
|
|
rendering.set_x_scale(tree.glaive_beam_sprite_id, 0.4 + 2 * math.min(1, tree.last_temperature / 100))
|
|
rendering.set_color(tree.glaive_beam_sprite_id, {
|
|
r = 1,
|
|
g = 0.5 + 0.5 * math.min(1, tree.last_temperature / 100),
|
|
b = 0.5 + 0.5 * math.min(1, tree.last_temperature / 100) })
|
|
|
|
end
|
|
|
|
function EnergyBeam.remove_markers(tree)
|
|
if tree.markers then
|
|
for _, marker in pairs(tree.markers) do
|
|
if marker and marker.valid then
|
|
marker.destroy()
|
|
end
|
|
end
|
|
end
|
|
tree.markers = nil
|
|
end
|
|
|
|
function EnergyBeam.add_markers(tree)
|
|
EnergyBeam.remove_markers(tree)
|
|
if tree.glaive_beam and tree.glaive_beam.valid then
|
|
tree.markers = {}
|
|
for force_name, forcedata in pairs(global.forces) do
|
|
if force_name ~= "friendly" and force_name ~= "ignore" and force_name ~= "capture" then
|
|
tree.markers[force_name] = game.forces[force_name].add_chart_tag(tree.glaive_beam.surface, {
|
|
icon = {type = "virtual", name = mod_prefix.."heat"},
|
|
position = tree.glaive_beam.position,
|
|
text = "Energy Glaive"
|
|
})
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function EnergyBeam.beam_step(tree)
|
|
local mode = tree.mode or "off"
|
|
local position = EnergyBeam.get_coordinate(tree)
|
|
if position == nil and mode == "auto-glaive" then
|
|
EnergyBeam.find_enemy(tree)
|
|
position = EnergyBeam.get_coordinate(tree)
|
|
end
|
|
|
|
if mode == "off" or (not position) or not (tree.destination and tree.destination.zone) then
|
|
EnergyBeam.beam_step_idle(tree)
|
|
else
|
|
|
|
local zone = tree.zone
|
|
local efficiency = EnergyBeam.get_transmission_efficiency(zone, tree.destination.zone)
|
|
tree.last_efficiency = efficiency
|
|
local destination_surface = Zone.get_make_surface(tree.destination.zone)
|
|
local emitter_beam = false
|
|
|
|
if mode == "energise" then
|
|
local receiver = destination_surface.find_entity(EnergyBeam.name_receiver, position)
|
|
if receiver then
|
|
local temperature = EnergyBeam.collect_heat(tree)
|
|
tree.last_temperature = temperature
|
|
if temperature > 0.1 then
|
|
emitter_beam = true
|
|
if tree.glaive_beam then EnergyBeam.clear_end_beam(tree) end
|
|
receiver.temperature = receiver.temperature + temperature * efficiency
|
|
if not (tree.receiver_beam and tree.receiver_beam.valid) then
|
|
tree.receiver_beam = destination_surface.create_entity{
|
|
name = EnergyBeam.name_receiver_beam,
|
|
position = receiver.position,
|
|
target = Util.vectors_add(receiver.position, {x=0,y=-1}),
|
|
speed = 0
|
|
}
|
|
end
|
|
end
|
|
else
|
|
EnergyBeam.beam_step_idle(tree)
|
|
end
|
|
if emitter_beam == false then EnergyBeam.clear_end_beam(tree) end
|
|
|
|
elseif mode == "glaive" or mode == "auto-glaive" then
|
|
|
|
local temperature = EnergyBeam.collect_heat(tree)
|
|
tree.last_temperature = temperature
|
|
if temperature > 0.1 then
|
|
EnergyBeamDefence.zone_add_pressure(tree.destination.zone, tree)
|
|
|
|
if tree.receiver_beam then EnergyBeam.clear_end_beam(tree) end
|
|
tree.glaive_energy = (tree.glaive_energy or 0) + temperature * efficiency
|
|
if EnergyBeamDefence.zone_is_defended(tree.destination.zone, tree.force_name) then
|
|
-- the beam is blocked but pressure is being applied
|
|
if tree.glaive_beam and tree.glaive_beam.valid then
|
|
tree.glaive_beam.destroy()
|
|
tree.glaive_beam = nil
|
|
end
|
|
tree.glaive_energy = 0
|
|
emitter_beam = true
|
|
else
|
|
if tree.glaive_energy > 0.1 then
|
|
emitter_beam = true
|
|
end
|
|
if emitter_beam == false then
|
|
EnergyBeam.beam_move(tree) -- removes?
|
|
else
|
|
EnergyBeam.scale_glaive_sprite(tree)
|
|
if mode == "auto-glaive" then
|
|
-- find target
|
|
if tree.destination.coordinate == nil or Util.vectors_delta_length(tree.destination.coordinate, tree.glaive_beam.position) < 0.1 then
|
|
EnergyBeam.find_enemy(tree)
|
|
end
|
|
end
|
|
tree.glaive_beam.surface.create_entity{
|
|
name = "fire-flame-on-tree",
|
|
position = tree.glaive_beam.position,
|
|
force = tree.force_name
|
|
}
|
|
|
|
EnergyBeam.add_markers(tree)
|
|
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
if emitter_beam then
|
|
if not (tree.emitter_beam and tree.emitter_beam.valid) then
|
|
tree.emitter_beam = tree.emitter.surface.create_entity{
|
|
name = EnergyBeam.name_transmitter_effect,
|
|
position = tree.emitter.position,
|
|
target = {x = tree.emitter.position.x, y = tree.emitter.position.y - 1},
|
|
speed = 0}
|
|
end
|
|
else
|
|
if tree.emitter_beam and tree.emitter_beam.valid then
|
|
tree.emitter_beam.destroy()
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
function EnergyBeam.beam_move(tree)
|
|
if not tree.destination.zone then
|
|
tree.mode = "off"
|
|
EnergyBeam.beam_step_idle(tree)
|
|
return
|
|
end
|
|
local position = EnergyBeam.get_coordinate(tree)
|
|
if not position then
|
|
if not (tree.glaive_beam and tree.glaive_beam.valid) then return end
|
|
position = tree.glaive_beam.position
|
|
end
|
|
|
|
EnergyBeam.scale_glaive_sprite(tree)
|
|
local curent_position = tree.glaive_beam.position
|
|
|
|
local move_speed = EnergyBeam.beam_speed_base * (1 + math.pow(EnergyBeam.beam_speed_temperature_multiplier * tree.last_temperature, EnergyBeam.beam_speed_temperature_exponent))
|
|
local new_position = util.move_to(curent_position, position, move_speed, false)
|
|
tree.glaive_beam.teleport(new_position)
|
|
|
|
-- update the target position to a potentially moving enemy
|
|
local target_valid = tree.destination.enemy and tree.destination.enemy.valid and tree.destination.enemy.destructible
|
|
if target_valid then
|
|
tree.destination.coordinate = tree.destination.enemy.position
|
|
end
|
|
|
|
-- find a new enemy if we are at the destination and the enemy is not still alive
|
|
if Util.vectors_delta_length(new_position, position) < 0.1 and tree.mode == "auto-glaive" and not target_valid then
|
|
EnergyBeam.find_enemy(tree)
|
|
end
|
|
|
|
tree.glaive_energy_2 = tree.glaive_energy_2 or 0
|
|
if tree.glaive_energy_2 < tree.glaive_energy then
|
|
tree.glaive_energy_2 = tree.glaive_energy_2 + tree.glaive_energy / 600
|
|
tree.glaive_energy = tree.glaive_energy - tree.glaive_energy / 600
|
|
end
|
|
|
|
local energy_to_use = tree.glaive_energy_2 / 100
|
|
local energy_used = 0
|
|
--local cost_projectile = 0.05
|
|
|
|
if new_position.x ~= curent_position.x and new_position.y ~= curent_position.y and math.random() < 0.1 then
|
|
tree.glaive_beam.surface.create_entity{
|
|
name = "fire-flame-on-tree",
|
|
position = tree.glaive_beam.position,
|
|
force = tree.force_name
|
|
}
|
|
tree.glaive_beam.surface.create_entity{
|
|
name = EnergyBeam.name_glaive_path_fx,
|
|
position = tree.glaive_beam.position,
|
|
force = tree.force_name
|
|
}
|
|
end
|
|
|
|
while energy_used + EnergyBeam.glaive_cost_aoe_large <= energy_to_use do
|
|
if tree.last_temperature > EnergyBeam.large_aoe_heat then
|
|
if energy_used + EnergyBeam.glaive_cost_aoe_large_10 <= energy_to_use then
|
|
energy_used = energy_used + EnergyBeam.glaive_cost_aoe_large_10
|
|
tree.glaive_beam.surface.create_entity{
|
|
name = EnergyBeam.name_glaive_damage_aoe_large_10,
|
|
position = tree.glaive_beam.position,
|
|
force = tree.force_name
|
|
}
|
|
else
|
|
energy_used = energy_used + EnergyBeam.glaive_cost_aoe_large
|
|
tree.glaive_beam.surface.create_entity{
|
|
name = EnergyBeam.name_glaive_damage_aoe_large,
|
|
position = tree.glaive_beam.position,
|
|
force = tree.force_name
|
|
}
|
|
end
|
|
else
|
|
local r = math.random()
|
|
if r < tree.last_temperature/EnergyBeam.large_aoe_heat then -- transition the damage to lower direct dps but larger area as it gets towards 100 GW
|
|
energy_used = energy_used + EnergyBeam.glaive_cost_aoe_large
|
|
tree.glaive_beam.surface.create_entity{
|
|
name = EnergyBeam.name_glaive_damage_aoe_large,
|
|
position = tree.glaive_beam.position,
|
|
force = tree.force_name
|
|
}
|
|
else
|
|
energy_used = energy_used + EnergyBeam.glaive_cost_aoe
|
|
tree.glaive_beam.surface.create_entity{
|
|
name = EnergyBeam.name_glaive_damage_aoe,
|
|
position = tree.glaive_beam.position,
|
|
force = tree.force_name
|
|
}
|
|
end
|
|
end
|
|
--[[else
|
|
energy_used = energy_used + cost_projectile
|
|
tree.glaive_beam.surface.create_entity{
|
|
name = EnergyBeam.name_glaive_damage_projectile,
|
|
position = tree.glaive_beam.position,
|
|
target = Util.vectors_add(tree.glaive_beam.position, Util.orientation_to_vector(math.random(), 5)),
|
|
speed = 1,
|
|
max_range = 5,
|
|
force = tree.force_name
|
|
}
|
|
end]]
|
|
end
|
|
tree.glaive_energy_2 = tree.glaive_energy_2 - energy_used
|
|
end
|
|
|
|
function EnergyBeam.destroy(tree)
|
|
if not tree then
|
|
Log.trace("tree_destroy: no tree")
|
|
return
|
|
end
|
|
|
|
tree.valid = false
|
|
EnergyBeam.clear_end_beam(tree)
|
|
if tree.emitter_beam and tree.emitter_beam.valid then
|
|
tree.emitter_beam.destroy()
|
|
end
|
|
global.energy_transmitters[tree.unit_number] = nil
|
|
|
|
-- if a player has this gui open then close item-layer
|
|
local gui_name = EnergyBeamGUI.name_transmitter_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 == tree.unit_number then
|
|
root.destroy()
|
|
end
|
|
end
|
|
end
|
|
|
|
function EnergyBeam.on_tick(tree)
|
|
if global.energy_transmitters then
|
|
-- beam update
|
|
for _, tree in pairs(global.energy_transmitters) do
|
|
if (game.tick + tree.unit_number) % 60 == 0 then
|
|
EnergyBeam.beam_step(tree)
|
|
elseif tree.glaive_beam then
|
|
EnergyBeam.beam_move(tree)
|
|
end
|
|
end
|
|
|
|
-- gui update
|
|
if game.tick % 60 == 0 then
|
|
for _, player in pairs(game.connected_players) do
|
|
EnergyBeamGUI.gui_update(player)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
Event.addListener(defines.events.on_tick, EnergyBeam.on_tick)
|
|
|
|
function EnergyBeam.on_player_selected_area(event)
|
|
if (event.item == EnergyBeam.name_transmitter_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 == EnergyBeam.name_target_activity_type then
|
|
local tree = playerdata.remote_view_activity.tree
|
|
if tree.emitter and tree.emitter.valid then
|
|
tree.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
|
|
}
|
|
tree.destination.zone = Zone.from_surface(player.surface)
|
|
player.print({"space-exploration.energy-transmitter-coordinates-set", math.floor(tree.destination.coordinate.x), math.floor(tree.destination.coordinate.y)})
|
|
if tree.mode == "energise" then
|
|
EnergyBeam.clear_end_beam(tree)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
Event.addListener(defines.events.on_player_selected_area, EnergyBeam.on_player_selected_area)
|
|
|
|
function EnergyBeam.on_init(event)
|
|
global.energy_transmitters = {}
|
|
end
|
|
Event.addListener("on_init", EnergyBeam.on_init, true)
|
|
|
|
function EnergyBeam.chamber_connections(entity, update_neighbours)
|
|
local surface = entity.surface
|
|
local is_horizontal = entity.direction == defines.direction.east or entity.direction == defines.direction.west
|
|
local x = (is_horizontal and EnergyBeam.chamber_box.x or EnergyBeam.chamber_box.y)/2
|
|
local y = (is_horizontal and EnergyBeam.chamber_box.y or EnergyBeam.chamber_box.x)/2
|
|
|
|
local north = surface.find_entity(EnergyBeam.name_chamber, Util.vectors_add(entity.position, {x=0, y= -y -1}))
|
|
if north and north.position.x == entity.position.x then
|
|
if north.position.y == entity.position.y - y - EnergyBeam.chamber_box.y / 2 then -- north is connected by side
|
|
--Log.trace("north is connected by side")
|
|
if not is_horizontal then
|
|
surface.create_entity{
|
|
name=mod_prefix .. "energy-transmitter-chamber-addon-bottom",
|
|
position= Util.vectors_add(north.position, {x=0, y=1}),
|
|
surface=surface,
|
|
}
|
|
end
|
|
elseif north.position.y == entity.position.y - y - EnergyBeam.chamber_box.x / 2 then -- north is connected by end
|
|
--Log.trace("north is connected by end")
|
|
if is_horizontal then
|
|
surface.create_entity{
|
|
name=mod_prefix .. "energy-transmitter-chamber-addon-top",
|
|
position= Util.vectors_add(entity.position, {x=0, y=0.5}),
|
|
surface=surface,
|
|
}
|
|
end
|
|
end
|
|
end
|
|
local south = surface.find_entity(EnergyBeam.name_chamber, Util.vectors_add(entity.position, {x=0, y= y +1}))
|
|
if south and south.position.x == south.position.x then
|
|
if south.position.y == entity.position.y + y + EnergyBeam.chamber_box.y / 2 then -- south is connected by side
|
|
--Log.trace("south is connected by side")
|
|
if not is_horizontal then
|
|
surface.create_entity{
|
|
name=mod_prefix .. "energy-transmitter-chamber-addon-top",
|
|
position= Util.vectors_add(south.position, {x=0, y=0.5}),
|
|
surface=surface,
|
|
}
|
|
end
|
|
elseif south.position.y == entity.position.y + y + EnergyBeam.chamber_box.x / 2 then -- south is connected by end
|
|
--Log.trace("south is connected by end")
|
|
if is_horizontal then
|
|
surface.create_entity{
|
|
name=mod_prefix .. "energy-transmitter-chamber-addon-bottom",
|
|
position= Util.vectors_add(entity.position, {x=0, y=1}),
|
|
surface=surface,
|
|
}
|
|
end
|
|
end
|
|
end
|
|
local east = surface.find_entity(EnergyBeam.name_chamber, Util.vectors_add(entity.position, {x=x+1, y=0}))
|
|
if east and east.position.y == entity.position.y then
|
|
if east.position.x == entity.position.x + x + EnergyBeam.chamber_box.y / 2 then -- east is connected by side
|
|
--Log.trace("east is connected by side")
|
|
if is_horizontal then
|
|
surface.create_entity{
|
|
name=mod_prefix .. "energy-transmitter-chamber-addon-left",
|
|
position= Util.vectors_add(east.position, {x=-1, y=0.01}),
|
|
surface=surface,
|
|
}
|
|
end
|
|
elseif east.position.x == entity.position.x + x + EnergyBeam.chamber_box.x / 2 then -- east is connected by end
|
|
--Log.trace("east is connected by end")
|
|
if not is_horizontal then
|
|
surface.create_entity{
|
|
name=mod_prefix .. "energy-transmitter-chamber-addon-right",
|
|
position= Util.vectors_add(entity.position, {x=1, y=0}),
|
|
surface=surface,
|
|
}
|
|
end
|
|
end
|
|
end
|
|
local west = surface.find_entity(EnergyBeam.name_chamber, Util.vectors_add(entity.position, {x=-x-1, y=0}))
|
|
if west and west.position.y == entity.position.y then
|
|
if west.position.x == entity.position.x - x - EnergyBeam.chamber_box.y / 2 then -- west is connected by side
|
|
--Log.trace("west is connected by side")
|
|
if is_horizontal then
|
|
surface.create_entity{
|
|
name=mod_prefix .. "energy-transmitter-chamber-addon-right",
|
|
position= Util.vectors_add(west.position, {x=1, y=0}),
|
|
surface=surface,
|
|
}
|
|
end
|
|
elseif west.position.x == entity.position.x - x - EnergyBeam.chamber_box.x / 2 then -- west is connected by end
|
|
--Log.trace("west is connected by end")
|
|
if not is_horizontal then
|
|
surface.create_entity{
|
|
name=mod_prefix .. "energy-transmitter-chamber-addon-left",
|
|
position= Util.vectors_add(entity.position, {x=-1, y=0.01}),
|
|
surface=surface,
|
|
}
|
|
end
|
|
end
|
|
end
|
|
|
|
-- injector connections
|
|
local leaves
|
|
if is_horizontal then
|
|
leaves = surface.find_entities_filtered{
|
|
name = EnergyBeam.name_injector,
|
|
area = Util.area_add_position({{-EnergyBeam.chamber_box.x / 2 + 1, -EnergyBeam.chamber_box.y / 2 - 1}, {EnergyBeam.chamber_box.x / 2 - 1, EnergyBeam.chamber_box.y / 2 + 1}}, entity.position)
|
|
}
|
|
else
|
|
leaves = surface.find_entities_filtered{
|
|
name = EnergyBeam.name_injector,
|
|
area = Util.area_add_position({{-EnergyBeam.chamber_box.y / 2 - 1, -EnergyBeam.chamber_box.x / 2 + 1}, {EnergyBeam.chamber_box.y / 2 + 1, EnergyBeam.chamber_box.x / 2 - 1}}, entity.position)
|
|
}
|
|
end
|
|
for _, injector in pairs(leaves) do
|
|
-- update
|
|
EnergyBeam.remove_injector_connections(injector)
|
|
EnergyBeam.injector_connections(injector)
|
|
end
|
|
|
|
end
|
|
|
|
function EnergyBeam.remove_chamber_connections(entity)
|
|
local surface = entity.surface
|
|
local is_horizontal = entity.direction == defines.direction.east or entity.direction == defines.direction.west
|
|
local x = is_horizontal and (EnergyBeam.chamber_box.x / 2 + 1) or (EnergyBeam.chamber_box.y / 2)
|
|
local y = is_horizontal and (EnergyBeam.chamber_box.y / 2) or (EnergyBeam.chamber_box.x / 2 + 1)
|
|
local addons = surface.find_entities_filtered{
|
|
name = {
|
|
mod_prefix .. "energy-transmitter-chamber-addon-top",
|
|
mod_prefix .. "energy-transmitter-chamber-addon-bottom",
|
|
mod_prefix .. "energy-transmitter-chamber-addon-left",
|
|
mod_prefix .. "energy-transmitter-chamber-addon-right",
|
|
},
|
|
area = {{entity.position.x-x, entity.position.y-y}, {entity.position.x+x,entity.position.y+y+1.5}}
|
|
}
|
|
for _, addon in pairs(addons) do
|
|
addon.destroy()
|
|
end
|
|
end
|
|
|
|
function EnergyBeam.injector_connections(entity)
|
|
local surface = entity.surface
|
|
local direction = entity.direction
|
|
local is_horizontal = direction == defines.direction.east or direction == defines.direction.west
|
|
local vector = Util.direction_to_vector(direction)
|
|
|
|
local chamber = surface.find_entity(EnergyBeam.name_chamber, Util.vectors_add(entity.position, Util.vector_multiply(vector, (EnergyBeam.injector_length + 1)/2)))
|
|
if chamber then
|
|
local chamber_is_horizontal = chamber.direction == defines.direction.east or chamber.direction == defines.direction.west
|
|
if is_horizontal ~= chamber_is_horizontal then
|
|
local addon = surface.create_entity{
|
|
name = mod_prefix .. "energy-transmitter-injector-addon",
|
|
position = Util.vectors_add(entity.position, Util.vector_multiply(vector, (EnergyBeam.injector_length)/2))
|
|
}
|
|
addon.graphics_variation = (direction + 2) / 2
|
|
end
|
|
end
|
|
end
|
|
|
|
function EnergyBeam.remove_injector_connections(entity)
|
|
local surface = entity.surface
|
|
local direction = entity.direction
|
|
local addons
|
|
if entity.name == EnergyBeam.name_injector then
|
|
local vector = Util.direction_to_vector(direction)
|
|
addons = {surface.find_entity(mod_prefix .. "energy-transmitter-injector-addon", Util.vectors_add(entity.position, Util.vector_multiply(vector, (EnergyBeam.injector_length)/2)))}
|
|
elseif entity.name == EnergyBeam.name_chamber then
|
|
local is_horizontal = direction == defines.direction.east or direction == defines.direction.west
|
|
local x = (is_horizontal and EnergyBeam.chamber_box.x or EnergyBeam.chamber_box.y)/2+0.5
|
|
local y = (is_horizontal and EnergyBeam.chamber_box.y or EnergyBeam.chamber_box.x)/2+0.5
|
|
addons = surface.find_entities_filtered{
|
|
name = mod_prefix .. "energy-transmitter-injector-addon",
|
|
area = Util.area_add_position({{-x,-y},{x,y}}, entity.position)
|
|
}
|
|
end
|
|
if addons then
|
|
for _, addon in pairs(addons) do
|
|
addon.destroy()
|
|
end
|
|
end
|
|
end
|
|
|
|
function EnergyBeam.rebuild_trees(zone, immediate)
|
|
|
|
-- remove old tick tasks
|
|
if global.tick_tasks then
|
|
for _, tick_task in pairs(global.tick_tasks) do
|
|
if tick_task.type == "grow_energy_tree" and tick_task.zone == zone then
|
|
tick_task.valid = false
|
|
global.tick_tasks[tick_task.id] = nil
|
|
end
|
|
end
|
|
end
|
|
|
|
if zone then
|
|
local tick_task = new_tick_task("grow_energy_tree")
|
|
tick_task.zone = zone
|
|
|
|
if immediate then
|
|
EnergyBeam.grow_energy_tree(tick_task)
|
|
end
|
|
end
|
|
end
|
|
|
|
function EnergyBeam.grow_energy_tree(tick_task)
|
|
local zone = tick_task.zone
|
|
local surface = Zone.get_make_surface(zone)
|
|
|
|
if not tick_task.emitters then
|
|
-- init
|
|
zone.energy_transmitters = zone.energy_transmitters or {}
|
|
global.energy_transmitters = global.energy_transmitters or {}
|
|
for unit_number, tree in pairs(zone.energy_transmitters) do
|
|
if not tree.emitter.valid then
|
|
-- remove invalid trees
|
|
zone.energy_transmitters[unit_number] = nil
|
|
global.energy_transmitters[unit_number] = nil
|
|
|
|
else
|
|
tree.chamberes = {}
|
|
tree.leaves = {}
|
|
tree.injector_reactors = {}
|
|
tree.open = {tree.emitter}
|
|
end
|
|
end
|
|
|
|
tick_task.emitters = surface.find_entities_filtered{name = EnergyBeam.name_emitter}
|
|
for _, emitter in pairs(tick_task.emitters) do
|
|
if not zone.energy_transmitters[emitter.unit_number] then
|
|
zone.energy_transmitters[emitter.unit_number] = {
|
|
type = "energy-beam-emitter-tree",
|
|
unit_number = emitter.unit_number,
|
|
valid = true,
|
|
zone = zone,
|
|
force_name = emitter.force.name,
|
|
emitter = emitter,
|
|
chamberes = {},
|
|
leaves = {},
|
|
injector_reactors = {},
|
|
open = {emitter},
|
|
destination = {type = "zone", zone = zone}
|
|
}
|
|
global.energy_transmitters[emitter.unit_number] = zone.energy_transmitters[emitter.unit_number]
|
|
end
|
|
end
|
|
-- chamberes are moreved from the list as they are assigned to trees
|
|
tick_task.chamberes = surface.find_entities_filtered{name = EnergyBeam.name_chamber}
|
|
|
|
-- when a chamber is added to a tree, trach the tree for the chamber (so leaves can find the tree by finding the chamber)
|
|
tick_task.chamber_trees = {}
|
|
end
|
|
|
|
tick_task.valid = false -- end unless chamberes are found
|
|
|
|
for _, tree in pairs(zone.energy_transmitters) do
|
|
local open = tree.open
|
|
tree.open = {}
|
|
for _, entity in pairs(open) do
|
|
if entity.name == EnergyBeam.name_emitter then
|
|
-- find chamberes connected end-on
|
|
local extent = (EnergyBeam.emitter_width + EnergyBeam.chamber_box.x)/2
|
|
for i, chamber in pairs(tick_task.chamberes) do
|
|
if (chamber.position.x == entity.position.x and (chamber.position.y == entity.position.y + extent or chamber.position.y == entity.position.y - extent))
|
|
or (chamber.position.y == entity.position.y and (chamber.position.x == entity.position.x + extent or chamber.position.x == entity.position.x - extent)) then
|
|
tree.chamberes[chamber.unit_number] = chamber
|
|
tree.open[chamber.unit_number] = chamber
|
|
tick_task.chamber_trees[chamber.unit_number] = tree
|
|
tick_task.chamberes[i] = nil
|
|
tick_task.valid = true
|
|
end
|
|
end
|
|
elseif entity.name == EnergyBeam.name_chamber then
|
|
-- find chamberes connected
|
|
local extent_short = (EnergyBeam.chamber_box.x + EnergyBeam.chamber_box.y) / 2
|
|
local extent_long = (EnergyBeam.chamber_box.x + EnergyBeam.chamber_box.x) / 2
|
|
local is_horizontal = entity.direction == defines.direction.east or entity.direction == defines.direction.west
|
|
for i, chamber in pairs(tick_task.chamberes) do
|
|
local chamber_is_horizontal = chamber.direction == defines.direction.east or chamber.direction == defines.direction.west
|
|
if (is_horizontal ~= chamber_is_horizontal and ((chamber.position.x == entity.position.x and (chamber.position.y == entity.position.y + extent_short or chamber.position.y == entity.position.y - extent_short))
|
|
or (chamber.position.y == entity.position.y and (chamber.position.x == entity.position.x + extent_short or chamber.position.x == entity.position.x - extent_short))))
|
|
or (is_horizontal == chamber_is_horizontal and ((chamber.position.x == entity.position.x and (chamber.position.y == entity.position.y + extent_long or chamber.position.y == entity.position.y - extent_long))
|
|
or (chamber.position.y == entity.position.y and (chamber.position.x == entity.position.x + extent_long or chamber.position.x == entity.position.x - extent_long)))) then
|
|
tree.chamberes[chamber.unit_number] = chamber
|
|
tick_task.chamber_trees[chamber.unit_number] = tree
|
|
tree.open[chamber.unit_number] = chamber
|
|
tick_task.chamberes[i] = nil
|
|
tick_task.valid = true
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
if not tick_task.valid then -- finished the chamberes, add the leaves
|
|
for _, entity in pairs(surface.find_entities_filtered{name = EnergyBeam.name_injector}) do
|
|
local direction = entity.direction
|
|
local is_horizontal = direction == defines.direction.east or direction == defines.direction.west
|
|
local vector = Util.direction_to_vector(direction)
|
|
|
|
local chamber = surface.find_entity(EnergyBeam.name_chamber, Util.vectors_add(entity.position, Util.vector_multiply(vector, (EnergyBeam.injector_length + 1)/2)))
|
|
if chamber then
|
|
local chamber_is_horizontal = chamber.direction == defines.direction.east or chamber.direction == defines.direction.west
|
|
if is_horizontal ~= chamber_is_horizontal then
|
|
-- if the chamber is part of a tree
|
|
if tick_task.chamber_trees[chamber.unit_number] then
|
|
-- add the injector to the tree
|
|
local injector_reactor = surface.find_entity(EnergyBeam.name_injector_reactor, entity.position)
|
|
if injector_reactor then
|
|
tick_task.chamber_trees[chamber.unit_number].leaves[entity.unit_number] = entity
|
|
tick_task.chamber_trees[chamber.unit_number].injector_reactors[injector_reactor.unit_number] = injector_reactor
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
for _, tree in pairs(zone.energy_transmitters) do
|
|
Log.trace(table_size(tree.leaves))
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
|
|
function EnergyBeam.on_entity_created(event)
|
|
local entity = util.get_entity_from_event(event)
|
|
|
|
if not entity then return end
|
|
if entity.name == EnergyBeam.name_chamber or entity.name == EnergyBeam.name_injector or entity.name == EnergyBeam.name_emitter then
|
|
local zone = Zone.from_surface(entity.surface)
|
|
if zone and zone.type ~= "spaceship" then
|
|
if entity.name == EnergyBeam.name_chamber then
|
|
-- check connections
|
|
EnergyBeam.chamber_connections(entity, true)
|
|
elseif entity.name == EnergyBeam.name_injector then
|
|
-- check connections
|
|
EnergyBeam.injector_connections(entity, true)
|
|
local reactor = entity.surface.create_entity{ name = EnergyBeam.name_injector_reactor, position = entity.position, force = entity.force}
|
|
reactor.destructible = false
|
|
end
|
|
EnergyBeam.rebuild_trees(zone, true)
|
|
local tree = global.energy_transmitters[entity.unit_number]
|
|
|
|
-- set settings
|
|
local tags = util.get_tags_from_event(event, EnergyBeam.serialize)
|
|
if tags then
|
|
EnergyBeam.deserialize(entity, tags)
|
|
end
|
|
|
|
if tree and entity.name == EnergyBeam.name_emitter and event.player_index and game.players[event.player_index] and game.players[event.player_index].connected then
|
|
EnergyBeamGUI.gui_open(game.players[event.player_index], tree)
|
|
end
|
|
else
|
|
cancel_entity_creation(entity, event.player_index, {"space-explortion.construction-denied"})
|
|
return
|
|
end
|
|
end
|
|
|
|
end
|
|
Event.addListener(defines.events.on_entity_cloned, EnergyBeam.on_entity_created)
|
|
Event.addListener(defines.events.on_built_entity, EnergyBeam.on_entity_created)
|
|
Event.addListener(defines.events.on_robot_built_entity, EnergyBeam.on_entity_created)
|
|
Event.addListener(defines.events.script_raised_built, EnergyBeam.on_entity_created)
|
|
Event.addListener(defines.events.script_raised_revive, EnergyBeam.on_entity_created)
|
|
|
|
|
|
function EnergyBeam.on_entity_removed(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 == EnergyBeam.name_chamber then
|
|
EnergyBeam.remove_chamber_connections(entity, true)
|
|
EnergyBeam.remove_injector_connections(entity, true)
|
|
EnergyBeam.rebuild_trees(Zone.from_surface(entity.surface))
|
|
elseif entity.name == EnergyBeam.name_injector then
|
|
EnergyBeam.remove_injector_connections(entity, true)
|
|
EnergyBeam.rebuild_trees(Zone.from_surface(entity.surface))
|
|
local reactor = entity.surface.find_entity(EnergyBeam.name_injector_reactor, entity.position)
|
|
if reactor then reactor.destroy() end
|
|
elseif entity.name == EnergyBeam.name_emitter then
|
|
EnergyBeam.rebuild_trees(Zone.from_surface(entity.surface))
|
|
local tree = EnergyBeam.from_entity(entity)
|
|
if tree then
|
|
EnergyBeam.destroy(tree)
|
|
end
|
|
elseif entity.name == EnergyBeam.name_receiver then
|
|
local beam = entity.surface.find_entity(EnergyBeam.name_receiver_beam, entity.position)
|
|
if beam then beam.destroy() end
|
|
end
|
|
|
|
end
|
|
Event.addListener(defines.events.on_player_mined_entity, EnergyBeam.on_entity_removed)
|
|
Event.addListener(defines.events.on_robot_mined_entity, EnergyBeam.on_entity_removed)
|
|
Event.addListener(defines.events.on_entity_died, EnergyBeam.on_entity_removed)
|
|
Event.addListener(defines.events.script_raised_destroy, EnergyBeam.on_entity_removed)
|
|
|
|
function EnergyBeam.serialize(entity)
|
|
local tree = EnergyBeam.from_entity(entity)
|
|
if tree then
|
|
local tags = {}
|
|
if tree.destination then
|
|
tags.destination = {
|
|
coordinate = tree.destination.coordinate,
|
|
zone_name = tree.destination.zone and tree.destination.zone.name
|
|
}
|
|
end
|
|
tags.mode = tree.mode
|
|
return tags
|
|
end
|
|
end
|
|
|
|
function EnergyBeam.deserialize(entity, tags)
|
|
local tree = EnergyBeam.from_entity(entity)
|
|
if tree then
|
|
if tags.destination then
|
|
tree.destination = {
|
|
coordinate = table.deepcopy(tags.destination.coordinate),
|
|
zone = Zone.from_name(tags.destination.zone_name)
|
|
}
|
|
end
|
|
tree.mode = tags.mode
|
|
end
|
|
end
|
|
|
|
--- Handles the player creating a blueprint by setting tags to store the state of energy emitters
|
|
---@param event any
|
|
function EnergyBeam.on_player_setup_blueprint(event)
|
|
util.setup_blueprint(event, EnergyBeam.name_emitter, EnergyBeam.serialize)
|
|
end
|
|
Event.addListener(defines.events.on_player_setup_blueprint, EnergyBeam.on_player_setup_blueprint)
|
|
|
|
--- Handles the player copy/pasting settings between energy emitters
|
|
---@param event any
|
|
function EnergyBeam.on_entity_settings_pasted(event)
|
|
util.settings_pasted(event, EnergyBeam.name_emitter, EnergyBeam.serialize, EnergyBeam.deserialize,
|
|
function(entity, player_index)
|
|
local tree = EnergyBeam.from_entity(entity)
|
|
local player = game.players[player_index]
|
|
if tree and tree.destination and tree.destination.coordinate then
|
|
player.print({"space-exploration.energy-transmitter-coordinates-pasted", math.floor(tree.destination.coordinate.x), math.floor(tree.destination.coordinate.y)})
|
|
end
|
|
end)
|
|
end
|
|
Event.addListener(defines.events.on_entity_settings_pasted, EnergyBeam.on_entity_settings_pasted)
|
|
|
|
return EnergyBeam
|
|
|