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.
232 lines
9.1 KiB
232 lines
9.1 KiB
local EnergyBeamDefence = {}
|
|
|
|
--[[
|
|
The defence has a base power use.
|
|
It starts with full charge.
|
|
When under attack energy usage is increased based on the attack strength.
|
|
If the buffer has not recoverd sufficently between ticks then the structure is not providing defence.
|
|
|
|
|
|
Make a list of defences per zone
|
|
When an attack comes in, disrtibute the load of the attack on all enemy defences weighted by the defences current energy vs energy max.
|
|
Update once per second?
|
|
|
|
zone.energy_beams = {}
|
|
zone.energy_beam_defences = {}
|
|
beam.stress_factores = {beams}
|
|
Apply a share of the load (energy)
|
|
|
|
]]
|
|
EnergyBeamDefence.name_energy_beam_defence = mod_prefix.."energy-beam-defence"
|
|
EnergyBeamDefence.name_energy_beam_defence_glow = mod_prefix.."energy-beam-defence-glow"
|
|
EnergyBeamDefence.beam_defence_passive_draw = 10000000 --10MW
|
|
EnergyBeamDefence.beam_defence_buffer = 1000000000 --1GJ
|
|
EnergyBeamDefence.beam_defence_efficiency = 10 -- takes 1/10th the power of the emitter
|
|
EnergyBeamDefence.beam_defence_peak_flare_power = 2000000000 -- 2GW
|
|
EnergyBeamDefence.beam_defence_required = 0.5 --
|
|
|
|
function EnergyBeamDefence.zone_is_defended(zone, pressure_force_name)
|
|
-- force == nil == neutral
|
|
for force_name, forcedata in pairs(global.forces) do
|
|
local force = game.forces[force_name]
|
|
if pressure_force_name == nil or ((force_name ~= pressure_force_name) and (not (force.get_friend(pressure_force_name) or force.get_cease_fire(pressure_force_name)))) then
|
|
local zone_assets = Zone.get_force_assets(force_name, zone.index)
|
|
if zone_assets and zone_assets.energy_beam_defence then
|
|
for unit_number, defence in pairs(zone_assets.energy_beam_defence) do
|
|
--Log.trace(defence.entity.energy)
|
|
if defence.operational then
|
|
--Log.trace("defended")
|
|
return true
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
--Log.trace("not defended")
|
|
return false
|
|
end
|
|
|
|
function EnergyBeamDefence.zone_add_pressure(zone, pressure)
|
|
|
|
global.energy_beam_target_zones = global.energy_beam_target_zones or {}
|
|
global.energy_beam_target_zones[zone.index] = zone
|
|
zone.energy_beam_pressures = zone.energy_beam_pressures or {
|
|
solar = {},
|
|
emitters = {},
|
|
}
|
|
|
|
if pressure.type == "solar-flare" then
|
|
if not zone.energy_beam_pressures.solar[pressure.id] then
|
|
--TODO: print message to defenecs
|
|
zone.energy_beam_pressures.solar[pressure.id] = pressure
|
|
EnergyBeamDefence.defences_apply_pressure(zone)
|
|
end
|
|
else --if pressure.type == "energy-beam-emitter-tree" then -- restore later, legacy test is missing this property
|
|
if not zone.energy_beam_pressures.emitters[pressure.unit_number] then
|
|
--TODO: print message to defenecs
|
|
zone.energy_beam_pressures.emitters[pressure.unit_number] = pressure
|
|
EnergyBeamDefence.defences_apply_pressure(zone)
|
|
end
|
|
end
|
|
|
|
|
|
end
|
|
|
|
function EnergyBeamDefence.defences_apply_pressure(zone)
|
|
-- validate
|
|
if not zone.energy_beam_pressures then
|
|
global.energy_beam_target_zones[zone.index] = nil
|
|
return
|
|
end
|
|
|
|
-- gather and validate
|
|
local pressures_count = 0
|
|
local force_emitter_pressures = {}
|
|
|
|
for id, tick_task in pairs(zone.energy_beam_pressures.solar) do
|
|
if tick_task.valid then
|
|
pressures_count = pressures_count + 1
|
|
if not force_emitter_pressures["-"] then
|
|
force_emitter_pressures["-"] = 0
|
|
end
|
|
force_emitter_pressures["-"] = force_emitter_pressures["-"] + (0.1 + 0.9 * (tick_task.age_peak or 0.0001)) * EnergyBeamDefence.beam_defence_peak_flare_power * tick_task.power_multiplier
|
|
else
|
|
zone.energy_beam_pressures.solar[id] = nil
|
|
end
|
|
end
|
|
--Log.trace(table_size(zone.energy_beam_pressures.emitters))
|
|
for unit_number, emitter_tree in pairs(zone.energy_beam_pressures.emitters) do
|
|
--Log.trace(emitter_tree.last_temperature)
|
|
if emitter_tree.destination and emitter_tree.destination.zone and emitter_tree.destination.zone.index == zone.index and emitter_tree.emitter.valid and (emitter_tree.mode == "glaive" or emitter_tree.mode == "auto-glaive") then
|
|
pressures_count = pressures_count + 1
|
|
if not force_emitter_pressures[emitter_tree.force_name] then
|
|
force_emitter_pressures[emitter_tree.force_name] = 0
|
|
end
|
|
force_emitter_pressures[emitter_tree.force_name] = force_emitter_pressures[emitter_tree.force_name]
|
|
+ emitter_tree.last_temperature * emitter_tree.last_efficiency * EnergyBeam.specific_heat / EnergyBeamDefence.beam_defence_efficiency
|
|
else
|
|
zone.energy_beam_pressures.emitters[unit_number] = nil
|
|
end
|
|
end
|
|
|
|
for force_name, forcedata in pairs(global.forces) do
|
|
local zone_assets = Zone.get_force_assets(force_name, zone.index)
|
|
if zone_assets and zone_assets.energy_beam_defence then
|
|
for unit_number, defence in pairs(zone_assets.energy_beam_defence) do
|
|
if defence.entity and defence.entity.valid then
|
|
defence.pressure = 0
|
|
defence.operational = true
|
|
defence.entity.power_usage = EnergyBeamDefence.beam_defence_passive_draw/60
|
|
if defence.glow_id and rendering.is_valid(defence.glow_id) then
|
|
rendering.destroy(defence.glow_id)
|
|
defence.glow_id = nil
|
|
end
|
|
else
|
|
zone_assets.energy_beam_defence[unit_number] = nil
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
if pressures_count == 0 then
|
|
zone.energy_beam_pressures = nil
|
|
return
|
|
end
|
|
|
|
-- equalise
|
|
for pressure_force_name, pressure in pairs(force_emitter_pressures) do
|
|
|
|
local defences = {}
|
|
local defences_total_energy = 0
|
|
for force_name, forcedata in pairs(global.forces) do
|
|
local force = game.forces[force_name]
|
|
if pressure_force_name == "-" or ((force_name ~= pressure_force_name) and (not (force.get_friend(pressure_force_name) or force.get_cease_fire(pressure_force_name)))) then
|
|
local zone_assets = Zone.get_force_assets(force_name, zone.index)
|
|
if zone_assets and zone_assets.energy_beam_defence then
|
|
for unit_number, defence in pairs(zone_assets.energy_beam_defence) do
|
|
table.insert(defences, defence)
|
|
defences_total_energy = defences_total_energy + defence.entity.energy
|
|
end
|
|
end
|
|
end
|
|
end
|
|
for _, defence in pairs(defences) do
|
|
local defence_share = defences_total_energy > 0 and (defence.entity.energy / defences_total_energy) or 0.01
|
|
defence.pressure = defence.pressure + pressure * defence_share
|
|
end
|
|
end
|
|
|
|
for force_name, forcedata in pairs(global.forces) do
|
|
local force = game.forces[force_name]
|
|
local zone_assets = Zone.get_force_assets(force_name, zone.index)
|
|
if zone_assets and zone_assets.energy_beam_defence then
|
|
for unit_number, defence in pairs(zone_assets.energy_beam_defence) do
|
|
defence.entity.power_usage = (EnergyBeamDefence.beam_defence_passive_draw + defence.pressure)/60
|
|
defence.operational = defence.entity.energy / EnergyBeamDefence.beam_defence_buffer > EnergyBeamDefence.beam_defence_required
|
|
if defence.pressure > 0.001 then
|
|
defence.glow_id = rendering.draw_sprite{
|
|
sprite = EnergyBeamDefence.name_energy_beam_defence_glow,
|
|
target = defence.entity,
|
|
surface = defence.entity.surface
|
|
}
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
function EnergyBeamDefence.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 == EnergyBeamDefence.name_energy_beam_defence 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 force = entity.force
|
|
local force_name = force.name
|
|
local force_data = global.forces[force.name]
|
|
if force_data then
|
|
local zone_assets = Zone.get_force_assets(force_name, zone.index)
|
|
zone_assets.energy_beam_defence = zone_assets.energy_beam_defence or {}
|
|
local defence = {
|
|
type = "energy-beam-defence",
|
|
unit_number = entity.unit_number,
|
|
force_name = force_name,
|
|
entity = entity,
|
|
zone_index = zone.index,
|
|
pressures = {
|
|
solar = {},
|
|
emitters = {},
|
|
},
|
|
operational = false
|
|
}
|
|
zone_assets.energy_beam_defence[defence.unit_number] = defence
|
|
|
|
entity.power_usage = EnergyBeamDefence.beam_defence_passive_draw/60
|
|
entity.electric_buffer_size = EnergyBeamDefence.beam_defence_buffer
|
|
end
|
|
end
|
|
end
|
|
Event.addListener(defines.events.on_built_entity, EnergyBeamDefence.on_entity_created)
|
|
Event.addListener(defines.events.on_robot_built_entity, EnergyBeamDefence.on_entity_created)
|
|
Event.addListener(defines.events.script_raised_built, EnergyBeamDefence.on_entity_created)
|
|
Event.addListener(defines.events.script_raised_revive, EnergyBeamDefence.on_entity_created)
|
|
|
|
function EnergyBeamDefence.on_nth_tick_60()
|
|
if global.energy_beam_target_zones then
|
|
for zone_index, zone in pairs(global.energy_beam_target_zones) do
|
|
EnergyBeamDefence.defences_apply_pressure(zone)
|
|
end
|
|
end
|
|
end
|
|
Event.addListener("on_nth_tick_60", EnergyBeamDefence.on_nth_tick_60) -- 1 minute
|
|
|
|
return EnergyBeamDefence
|
|
|