mirror of
https://github.com/ComfyFactory/ComfyFactorio.git
synced 2025-01-04 00:15:45 +02:00
229 lines
6.2 KiB
Lua
229 lines
6.2 KiB
Lua
local Event = require 'utils.event'
|
|
local Global = require 'utils.global'
|
|
|
|
local Public = {}
|
|
local explosives = {}
|
|
|
|
Global.register(
|
|
explosives,
|
|
function(tbl)
|
|
explosives = tbl
|
|
end
|
|
)
|
|
|
|
local explosives_effects = {
|
|
'explosion',
|
|
'grenade-explosion',
|
|
'explosion',
|
|
'grenade-explosion',
|
|
'big-artillery-explosion',
|
|
'massive-explosion',
|
|
'land-mine-explosion',
|
|
'storage-tank-explosion'
|
|
}
|
|
local table_insert = table.insert
|
|
local table_remove = table.remove
|
|
local math_floor = math.floor
|
|
local math_sqrt = math.sqrt
|
|
local math_random = math.random
|
|
local speed = 6
|
|
local valid_container_types = {
|
|
['car'] = true,
|
|
['cargo-wagon'] = true,
|
|
['container'] = true,
|
|
['logistic-container'] = true,
|
|
['spider-vehicle'] = true
|
|
}
|
|
|
|
local maximum_radius = 64
|
|
local explosive_vectors = {}
|
|
for x = maximum_radius * -1, maximum_radius, 1 do
|
|
for y = maximum_radius * -1, maximum_radius, 1 do
|
|
local d = math_floor(math_sqrt(x ^ 2 + y ^ 2)) + 1
|
|
if d <= maximum_radius then
|
|
if not explosive_vectors[d] then
|
|
explosive_vectors[d] = {}
|
|
end
|
|
table_insert(explosive_vectors[d], {x, y})
|
|
end
|
|
end
|
|
end
|
|
|
|
local function draw_effects(surface, instance)
|
|
local vectors = explosive_vectors[instance.current_r]
|
|
if not vectors then
|
|
return
|
|
end
|
|
local center_position_x = instance.position.x
|
|
local center_position_y = instance.position.y
|
|
for _, v in pairs(vectors) do
|
|
if math_random(0, instance.current_r * 0.15 * (explosives.instance_count * 0.5)) == 0 then
|
|
local position = {center_position_x + v[1], center_position_y + v[2]}
|
|
local name = explosives_effects[math_random(1, 8)]
|
|
surface.create_entity({name = name, position = position, target = position})
|
|
end
|
|
end
|
|
end
|
|
|
|
local function damage_entity(entity, amount)
|
|
if not entity.valid then
|
|
return
|
|
end
|
|
if not entity.health then
|
|
return
|
|
end
|
|
if entity.health <= 0 then
|
|
return
|
|
end
|
|
if not entity.destructible then
|
|
return
|
|
end
|
|
entity.damage(amount, 'player', 'explosion')
|
|
return true
|
|
end
|
|
|
|
local function damage_entities(surface, instance)
|
|
local vectors = explosive_vectors[instance.current_r]
|
|
if not vectors then
|
|
return
|
|
end
|
|
local center_position_x = instance.position.x
|
|
local center_position_y = instance.position.y
|
|
for _, v in pairs(vectors) do
|
|
local position = {center_position_x + v[1], center_position_y + v[2]}
|
|
for _, entity in pairs(surface.find_entities_filtered({area = {position, {position[1] + 1, position[2] + 1}}, type = {'corpse', 'explosion'}, invert = true})) do
|
|
if instance.damage_remaining < 200 then
|
|
if damage_entity(entity, instance.damage_remaining) then
|
|
return
|
|
end
|
|
else
|
|
if damage_entity(entity, 200) then
|
|
instance.damage_remaining = instance.damage_remaining - 200
|
|
end
|
|
end
|
|
end
|
|
end
|
|
return true
|
|
end
|
|
|
|
local function damage_tiles(surface, instance)
|
|
local vectors = explosive_vectors[instance.current_r]
|
|
if not vectors then
|
|
return
|
|
end
|
|
local center_position_x = instance.position.x
|
|
local center_position_y = instance.position.y
|
|
local destructible_tiles = explosives.destructible_tiles
|
|
for _, v in pairs(vectors) do
|
|
local position = {center_position_x + v[1], center_position_y + v[2]}
|
|
local tile = surface.get_tile(position)
|
|
local tile_health = destructible_tiles[tile.name]
|
|
if tile_health then
|
|
if instance.damage_remaining < tile_health then
|
|
return
|
|
end
|
|
instance.damage_remaining = instance.damage_remaining - tile_health
|
|
surface.set_tiles({{name = 'nuclear-ground', position = position}}, true, false, false, false)
|
|
end
|
|
end
|
|
return true
|
|
end
|
|
|
|
local function process_explosion(instance)
|
|
local surface = game.surfaces[instance.surface_index]
|
|
if not surface then
|
|
return
|
|
end
|
|
if not surface.valid then
|
|
return
|
|
end
|
|
draw_effects(surface, instance)
|
|
if not damage_entities(surface, instance) then
|
|
return
|
|
end
|
|
if not damage_tiles(surface, instance) then
|
|
return
|
|
end
|
|
instance.current_r = instance.current_r + 1
|
|
if instance.current_r > instance.max_r then
|
|
return
|
|
end
|
|
return true
|
|
end
|
|
|
|
local function spawn_explosion(surface, position, amount)
|
|
if not explosives.instances then
|
|
explosives.instances = {}
|
|
end
|
|
table_insert(
|
|
explosives.instances,
|
|
{
|
|
surface_index = surface.index,
|
|
damage_remaining = amount * 500,
|
|
position = position,
|
|
current_r = 1,
|
|
max_r = math_floor(amount / 50) + 5
|
|
}
|
|
)
|
|
end
|
|
|
|
local function on_tick()
|
|
if not explosives.instances then
|
|
return
|
|
end
|
|
explosives.instance_count = #explosives.instances
|
|
for k, instance in pairs(explosives.instances) do
|
|
local success = process_explosion(instance)
|
|
if not success then
|
|
table_remove(explosives.instances, k)
|
|
end
|
|
end
|
|
if #explosives.instances == 0 then
|
|
explosives.instances = nil
|
|
end
|
|
end
|
|
|
|
local function on_entity_died(event)
|
|
local entity = event.entity
|
|
if not entity.valid then
|
|
return
|
|
end
|
|
if not valid_container_types[entity.type] then
|
|
return
|
|
end
|
|
|
|
local inventory = defines.inventory.chest
|
|
if entity.type == 'car' or entity.type == 'spider-vehicle' then
|
|
inventory = defines.inventory.car_trunk
|
|
end
|
|
|
|
local i = entity.get_inventory(inventory)
|
|
local amount = i.get_item_count('explosives')
|
|
if not amount then
|
|
return
|
|
end
|
|
if amount < 1 then
|
|
return
|
|
end
|
|
|
|
spawn_explosion(entity.surface, {x = entity.position.x, y = entity.position.y}, amount)
|
|
end
|
|
|
|
function Public.set_destructible_tile(tile_name, health)
|
|
explosives.destructible_tiles[tile_name] = health
|
|
end
|
|
|
|
function Public.get_table()
|
|
return explosives
|
|
end
|
|
|
|
local function on_init()
|
|
explosives.destructible_tiles = {}
|
|
end
|
|
|
|
Event.on_init(on_init)
|
|
Event.on_nth_tick(speed, on_tick)
|
|
Event.add(defines.events.on_entity_died, on_entity_died)
|
|
|
|
return Public
|