mirror of
https://github.com/Refactorio/RedMew.git
synced 2024-12-12 10:04:40 +02:00
221 lines
5.4 KiB
Lua
221 lines
5.4 KiB
Lua
local Event = require 'utils.event'
|
|
local Global = require 'utils.global'
|
|
local Task = require 'utils.task'
|
|
local Token = require 'utils.token'
|
|
local register_on_object_destroyed = script.register_on_object_destroyed
|
|
|
|
local Public = {}
|
|
local turrets_map = {}
|
|
local primitives = { index = nil }
|
|
local Artillery = {
|
|
enabled = true,
|
|
turret_name = 'artillery-turret',
|
|
character_projectile = 'artillery-projectile',
|
|
structure_projectile = 'rocket',
|
|
target_force = 'player',
|
|
last_fire = 0,
|
|
fire_interval = 60, -- ticks
|
|
cooldown = 480, -- ticks
|
|
min_range = 32, -- tiles
|
|
max_range = 224, -- tiles
|
|
max_targeting_attempts = 10,
|
|
range_modifier = nil,
|
|
manual_range_modifier = nil,
|
|
creation_distance = 1.6,
|
|
target_offset = { -0.15625, -0.07812 },
|
|
target_entities = {
|
|
'artillery-turret',
|
|
'artillery-wagon',
|
|
'car',
|
|
'cargo-wagon',
|
|
'character',
|
|
'flamethrower-turret',
|
|
'fluid-wagon',
|
|
'furnace',
|
|
'gun-turret',
|
|
'lab',
|
|
'laser-turret',
|
|
'locomotive',
|
|
'radar',
|
|
'silo',
|
|
'spidertron',
|
|
'tank',
|
|
},
|
|
}
|
|
|
|
Global.register(
|
|
{
|
|
turrets_map = turrets_map,
|
|
primitives = primitives,
|
|
artillery = Artillery,
|
|
},
|
|
function(tbl)
|
|
turrets_map = tbl.turrets_map
|
|
primitives = tbl.primitives
|
|
Artillery = tbl.artillery
|
|
end)
|
|
|
|
local function distance(posA, posB)
|
|
return math.sqrt((posA.x - posB.x)^2 + (posA.y - posB.y)^2)
|
|
end
|
|
|
|
function Public.get_artillery_settings()
|
|
return Artillery
|
|
end
|
|
|
|
function Public.set_artillery_settings(key, value)
|
|
Artillery[key] = value
|
|
end
|
|
|
|
function Public.register(entity, refill_name)
|
|
if not (entity and entity.valid) then
|
|
return
|
|
end
|
|
|
|
if not refill_name then
|
|
return
|
|
end
|
|
|
|
local is_item = prototypes.item[refill_name] and true or false
|
|
local is_fluid = prototypes.fluid[refill_name] and true or false
|
|
local is_artillery = entity.prototype.type == Artillery.turret_name
|
|
|
|
if not (is_item or is_fluid or is_artillery) then
|
|
return
|
|
end
|
|
|
|
register_on_object_destroyed(entity)
|
|
local unit_id = entity.unit_number
|
|
|
|
local data = {
|
|
entity = entity,
|
|
refill = refill_name,
|
|
is_fluid = is_fluid,
|
|
is_artillery = is_artillery,
|
|
}
|
|
|
|
if data.is_artillery then
|
|
data.next_fire = game.tick
|
|
end
|
|
if data.is_fluid then
|
|
data.fluid_stack = {
|
|
name = data.refill,
|
|
amount = data.entity.fluidbox.get_capacity(1) or 100
|
|
}
|
|
else
|
|
data.item_stack = {
|
|
name = data.refill,
|
|
count = prototypes.item[data.refill].stack_size
|
|
}
|
|
end
|
|
|
|
turrets_map[unit_id] = data
|
|
end
|
|
|
|
function Public.remove(entity)
|
|
if not entity.unit_number then
|
|
return
|
|
end
|
|
turrets_map[entity.unit_number] = nil
|
|
end
|
|
|
|
function Public.reset()
|
|
for k, _ in pairs(turrets_map) do
|
|
turrets_map[k] = nil
|
|
end
|
|
end
|
|
|
|
local artillery_projectile_token = Token.register(function(data)
|
|
local surface = data.surface
|
|
local target = data.target
|
|
local source = data.source
|
|
if not (surface and surface.valid) then return end
|
|
if not (target and target.valid) then return end
|
|
if not (source and source.valid) then return end
|
|
surface.create_entity{
|
|
name = data.name,
|
|
position = data.position,
|
|
target = target,
|
|
source = source,
|
|
force = 'enemy',
|
|
speed = 1.5,
|
|
}
|
|
end)
|
|
|
|
local function simulate_automatic_artillery(data)
|
|
if data.next_fire > game.tick then
|
|
return
|
|
end
|
|
|
|
local entity = data.entity
|
|
local surface = entity.surface
|
|
local source_position = entity.position
|
|
local range_modifier = Artillery.range_modifier or entity.force.artillery_range_modifier or 0
|
|
local manual_range_modifier = Artillery.manual_range_modifier or entity.prototype.manual_range_modifier or 0
|
|
local params = {
|
|
position = source_position,
|
|
radius = Artillery.max_range * (1 + range_modifier) * (1 + manual_range_modifier),
|
|
name = Artillery.target_entities,
|
|
force = Artillery.target_force,
|
|
limit = Artillery.max_targeting_attempts,
|
|
}
|
|
local targets = surface.find_entities_filtered(params)
|
|
|
|
if #targets == 0 then
|
|
return
|
|
end
|
|
|
|
for i = 1, #targets do
|
|
local target = targets[i]
|
|
if distance(source_position, target.position) > Artillery.min_range then
|
|
Task.set_timeout_in_ticks(Artillery.fire_interval, artillery_projectile_token, {
|
|
surface = surface,
|
|
name = target.name == 'character' and Artillery.character_projectile or Artillery.structure_projectile,
|
|
position = target.position,
|
|
target = target,
|
|
source = entity,
|
|
force = 'enemy',
|
|
speed = 1.5,
|
|
})
|
|
data.next_fire = game.tick + Artillery.cooldown
|
|
Artillery.last_fire = game.tick
|
|
break
|
|
end
|
|
end
|
|
end
|
|
|
|
local function on_object_destroyed(event)
|
|
if not event.useful_id then
|
|
return
|
|
end
|
|
turrets_map[event.useful_id] = nil
|
|
end
|
|
Event.add(defines.events.on_object_destroyed, on_object_destroyed)
|
|
|
|
local function on_tick()
|
|
if primitives.index ~= nil and turrets_map[primitives.index] == nil then
|
|
primitives.index = nil
|
|
return
|
|
end
|
|
|
|
local idx, data = next(turrets_map, primitives.index)
|
|
if not (data and data.entity and data.entity.valid) then
|
|
primitives.index = nil
|
|
return
|
|
end
|
|
|
|
if Artillery.enabled and data.is_artillery and ((Artillery.last_fire + Artillery.fire_interval) < game.tick) then
|
|
simulate_automatic_artillery(data)
|
|
end
|
|
if data.is_fluid then
|
|
data.entity.insert_fluid(data.fluid_stack)
|
|
else
|
|
data.entity.insert(data.item_stack)
|
|
end
|
|
|
|
primitives.index = idx
|
|
end
|
|
Event.add(defines.events.on_tick, on_tick)
|
|
|
|
return Public
|