mirror of
https://github.com/ComfyFactory/ComfyFactorio.git
synced 2025-01-06 00:23:49 +02:00
ff951394bb
Whenever collapse is active make sure that we don't fill with landtile below it.
366 lines
9.6 KiB
Lua
366 lines
9.6 KiB
Lua
local Public = {}
|
|
local Global = require 'utils.global'
|
|
local Collapse = require 'modules.collapse'
|
|
local this = {
|
|
explosives = {},
|
|
settings = {
|
|
check_growth_below_void = false
|
|
}
|
|
}
|
|
Global.register(
|
|
this,
|
|
function(tbl)
|
|
this = tbl
|
|
end
|
|
)
|
|
|
|
local math_abs = math.abs
|
|
local math_floor = math.floor
|
|
local math_sqrt = math.sqrt
|
|
local math_round = math.round
|
|
local math_random = math.random
|
|
local shuffle_table = table.shuffle_table
|
|
local speed = 3
|
|
local density = 1
|
|
local density_r = density * 0.5
|
|
local valid_container_types = {
|
|
['container'] = true,
|
|
['logistic-container'] = true,
|
|
['car'] = true,
|
|
['cargo-wagon'] = true
|
|
}
|
|
|
|
local function pos_to_key(position)
|
|
return tostring(position.x .. '_' .. position.y)
|
|
end
|
|
|
|
local function check_y_pos(position)
|
|
if not this.settings.check_growth_below_void then
|
|
return false
|
|
end
|
|
if not position or not position.y then
|
|
return false
|
|
end
|
|
local collapse_pos = Collapse.get_position()
|
|
|
|
local radius = 10
|
|
|
|
local dy = position.y - collapse_pos.y
|
|
if dy ^ 2 < radius ^ 2 then
|
|
return true
|
|
end
|
|
|
|
if position.y >= collapse_pos.y then
|
|
return true
|
|
else
|
|
return false
|
|
end
|
|
end
|
|
|
|
local function get_explosion_name(health)
|
|
if health < 2500 then
|
|
return 'explosion'
|
|
end
|
|
if health < 25000 then
|
|
return 'big-explosion'
|
|
end
|
|
return 'big-artillery-explosion'
|
|
end
|
|
|
|
local function cell_birth(surface_index, origin_position, origin_tick, position, health)
|
|
local key = pos_to_key(position)
|
|
|
|
--Merge cells that are overlapping.
|
|
if this.explosives.cells[key] then
|
|
this.explosives.cells[key].health = this.explosives.cells[key].health + health
|
|
return
|
|
end
|
|
|
|
--Spawn new cell.
|
|
this.explosives.cells[key] = {
|
|
surface_index = surface_index,
|
|
origin_position = origin_position,
|
|
origin_tick = origin_tick,
|
|
position = {x = position.x, y = position.y},
|
|
spawn_tick = game.tick + speed,
|
|
health = health
|
|
}
|
|
end
|
|
|
|
local function grow_cell(cell)
|
|
shuffle_table(this.explosives.vectors)
|
|
local radius = math_floor((game.tick - cell.origin_tick) / 9) + 2
|
|
local positions = {}
|
|
for i = 1, 4, 1 do
|
|
local position = {
|
|
x = cell.position.x + this.explosives.vectors[i][1],
|
|
y = cell.position.y + this.explosives.vectors[i][2]
|
|
}
|
|
if not this.explosives.cells[pos_to_key(position)] then
|
|
local distance = math_sqrt((cell.origin_position.x - position.x) ^ 2 + (cell.origin_position.y - position.y) ^ 2)
|
|
if distance < radius then
|
|
positions[#positions + 1] = position
|
|
end
|
|
end
|
|
end
|
|
|
|
if #positions == 0 then
|
|
positions[#positions + 1] = {
|
|
x = cell.position.x + this.explosives.vectors[1][1],
|
|
y = cell.position.y + this.explosives.vectors[1][2]
|
|
}
|
|
end
|
|
|
|
local new_cell_health = math_round(cell.health / #positions, 3) - this.explosives.damage_decay
|
|
|
|
--[[
|
|
if new_cell_health > 0 then
|
|
this.explosives.cells_damage_dealt = this.explosives.cells_damage_dealt + damage_decay * #positions
|
|
else
|
|
this.explosives.cells_damage_dealt = this.explosives.cells_damage_dealt + (new_cell_health + damage_decay) * #positions
|
|
end
|
|
]]
|
|
if new_cell_health <= 0 then
|
|
return
|
|
end
|
|
|
|
for _, p in pairs(positions) do
|
|
cell_birth(cell.surface_index, cell.origin_position, cell.origin_tick, p, new_cell_health)
|
|
end
|
|
end
|
|
|
|
local function damage_entity(entity, cell)
|
|
if not entity.valid then
|
|
return true
|
|
end
|
|
if not entity.health then
|
|
return true
|
|
end
|
|
if entity.health <= 0 then
|
|
return true
|
|
end
|
|
if not entity.destructible then
|
|
return true
|
|
end
|
|
|
|
if this.explosives.whitelist_entity[entity.name] then
|
|
return true
|
|
end
|
|
|
|
local damage_required = entity.health
|
|
for _ = 1, 4, 1 do
|
|
if damage_required > cell.health then
|
|
entity.damage(cell.health, 'player', 'explosion')
|
|
return false
|
|
end
|
|
local damage_dealt = entity.damage(damage_required, 'player', 'explosion')
|
|
cell.health = cell.health - damage_required
|
|
if not entity then
|
|
return true
|
|
end
|
|
if not entity.valid then
|
|
return true
|
|
end
|
|
if entity.health <= 0 then
|
|
return true
|
|
end
|
|
damage_required = math_floor(entity.health * (damage_required / damage_dealt)) + 1
|
|
end
|
|
end
|
|
|
|
local function damage_area(cell)
|
|
local surface = game.surfaces[cell.surface_index]
|
|
if not surface then
|
|
return
|
|
end
|
|
if not surface.valid then
|
|
return
|
|
end
|
|
|
|
if math_random(1, 4) == 1 then
|
|
surface.create_entity({name = get_explosion_name(cell.health), position = cell.position})
|
|
end
|
|
|
|
for _, entity in pairs(
|
|
surface.find_entities(
|
|
{
|
|
{cell.position.x - density_r, cell.position.y - density_r},
|
|
{cell.position.x + density_r, cell.position.y + density_r}
|
|
}
|
|
)
|
|
) do
|
|
if not damage_entity(entity, cell) then
|
|
return
|
|
end
|
|
end
|
|
|
|
local tile = surface.get_tile(cell.position)
|
|
if this.explosives.destructible_tiles[tile.name] then
|
|
local key = pos_to_key(tile.position)
|
|
if not this.explosives.tiles[key] then
|
|
this.explosives.tiles[key] = this.explosives.destructible_tiles[tile.name]
|
|
end
|
|
|
|
if cell.health > this.explosives.tiles[key] then
|
|
cell.health = cell.health - this.explosives.tiles[key]
|
|
this.explosives.tiles[key] = nil
|
|
if math_abs(tile.position.y) < surface.map_gen_settings.height * 0.5 and math_abs(tile.position.x) < surface.map_gen_settings.width * 0.5 then
|
|
if not check_y_pos(tile.position) then
|
|
surface.set_tiles({{name = 'landfill', position = tile.position}}, true)
|
|
end
|
|
end
|
|
else
|
|
this.explosives.tiles[key] = this.explosives.tiles[key] - cell.health
|
|
return
|
|
end
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
local function life_cycle(cell)
|
|
if not damage_area(cell) then
|
|
return
|
|
end
|
|
grow_cell(cell)
|
|
end
|
|
|
|
local function tick()
|
|
for key, cell in pairs(this.explosives.cells) do
|
|
if cell.spawn_tick < game.tick then
|
|
life_cycle(cell)
|
|
this.explosives.cells[key] = nil
|
|
end
|
|
end
|
|
if game.tick % 216000 == 0 then
|
|
this.explosives.tiles = {}
|
|
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
|
|
if this.explosives.surface_whitelist then
|
|
if not this.explosives.surface_whitelist[entity.surface.name] then
|
|
return
|
|
end
|
|
end
|
|
|
|
local inventory = defines.inventory.chest
|
|
if entity.type == 'car' 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
|
|
|
|
cell_birth(
|
|
entity.surface.index,
|
|
{x = entity.position.x, y = entity.position.y},
|
|
game.tick,
|
|
{x = entity.position.x, y = entity.position.y},
|
|
amount * this.explosives.damage_per_explosive
|
|
)
|
|
end
|
|
|
|
function Public.detonate_chest(entity)
|
|
if not entity or not entity.valid then
|
|
return false
|
|
end
|
|
if not valid_container_types[entity.type] then
|
|
return false
|
|
end
|
|
if this.explosives.surface_whitelist then
|
|
if not this.explosives.surface_whitelist[entity.surface.name] then
|
|
return false
|
|
end
|
|
end
|
|
|
|
local inventory = defines.inventory.chest
|
|
if entity.type == 'car' 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 false
|
|
end
|
|
if amount < 99 then
|
|
return false
|
|
end
|
|
|
|
cell_birth(
|
|
entity.surface.index,
|
|
{x = entity.position.x, y = entity.position.y},
|
|
game.tick,
|
|
{x = entity.position.x, y = entity.position.y},
|
|
amount * this.explosives.damage_per_explosive
|
|
)
|
|
return true
|
|
end
|
|
|
|
function Public.reset()
|
|
this.explosives.cells = {}
|
|
this.explosives.tiles = {}
|
|
if not this.explosives.vectors then
|
|
this.explosives.vectors = {{density, 0}, {density * -1, 0}, {0, density}, {0, density * -1}}
|
|
end
|
|
if not this.explosives.damage_per_explosive then
|
|
this.explosives.damage_per_explosive = 500
|
|
end
|
|
if not this.explosives.damage_decay then
|
|
this.explosives.damage_decay = 10
|
|
end
|
|
if not this.explosives.destructible_tiles then
|
|
this.explosives.destructible_tiles = {}
|
|
end
|
|
if not this.explosives.whitelist_entity then
|
|
this.explosives.whitelist_entity = {}
|
|
end
|
|
end
|
|
|
|
function Public.set_destructible_tile(tile_name, health)
|
|
this.explosives.destructible_tiles[tile_name] = health
|
|
end
|
|
|
|
function Public.set_whitelist_entity(entity)
|
|
if entity then
|
|
this.explosives.whitelist_entity[entity] = true
|
|
end
|
|
end
|
|
|
|
function Public.set_surface_whitelist(list)
|
|
this.explosives.surface_whitelist = list
|
|
end
|
|
|
|
function Public.get_table()
|
|
return this.explosives
|
|
end
|
|
|
|
function Public.check_growth_below_void(value)
|
|
this.settings.check_growth_below_void = value or false
|
|
end
|
|
|
|
local function on_init()
|
|
Public.reset()
|
|
end
|
|
|
|
local Event = require 'utils.event'
|
|
Event.on_init(on_init)
|
|
Event.on_nth_tick(speed, tick)
|
|
Event.add(defines.events.on_entity_died, on_entity_died)
|
|
|
|
return Public
|