1
0
mirror of https://github.com/ComfyFactory/ComfyFactorio.git synced 2024-12-30 23:17:53 +02:00
ComfyFactorio/maps/mountain_fortress_v3/functions.lua
2020-11-23 22:10:45 +01:00

640 lines
16 KiB
Lua

local Token = require 'utils.token'
local Task = require 'utils.task'
local ICW = require 'maps.mountain_fortress_v3.icw.main'
local Event = require 'utils.event'
local Global = require 'utils.global'
local this = {
power_sources = {index = 1},
refill_turrets = {index = 1},
magic_crafters = {index = 1},
magic_fluid_crafters = {index = 1},
art_table = {index = 1},
surface_cleared = false
}
Global.register(
this,
function(t)
this = t
end
)
local Public = {}
local random = math.random
local floor = math.floor
local sqrt = math.sqrt
local magic_crafters_per_tick = 3
local magic_fluid_crafters_per_tick = 8
local artillery_target_entities = {
'character',
'tank',
'car',
'furnace',
'locomotive',
'cargo-wagon',
'fluid-wagon',
'artillery-wagon'
}
local function fast_remove(tbl, index)
local count = #tbl
if index > count then
return
elseif index < count then
tbl[index] = tbl[count]
end
tbl[count] = nil
end
local function do_refill_turrets()
local refill_turrets = this.refill_turrets
local index = refill_turrets.index
if index > #refill_turrets then
refill_turrets.index = 1
return
end
local turret_data = refill_turrets[index]
local turret = turret_data.turret
if not turret.valid then
fast_remove(refill_turrets, index)
return
end
refill_turrets.index = index + 1
local data = turret_data.data
if data.liquid then
turret.fluidbox[1] = data
elseif data then
turret.insert(data)
end
end
local function turret_died(event)
local entity = event.entity
if not entity or not entity.valid then
return
end
local number = entity.unit_number
if not number then
return
end
local power_sources = this.power_sources
local ps_data = power_sources[number]
if ps_data then
power_sources[number] = nil
local ps_entity = ps_data.entity
local ps_pole = ps_data.pole
if ps_entity and ps_entity.valid then
ps_entity.destroy()
end
if ps_pole and ps_pole.valid then
ps_pole.destroy()
end
end
end
local function do_magic_crafters()
local magic_crafters = this.magic_crafters
local limit = #magic_crafters
if limit == 0 then
return
end
local index = magic_crafters.index
for i = 1, magic_crafters_per_tick do
if index > limit then
index = 1
end
local data = magic_crafters[index]
local entity = data.entity
if not entity.valid then
fast_remove(magic_crafters, index)
limit = limit - 1
if limit == 0 then
return
end
else
index = index + 1
local tick = game.tick
local last_tick = data.last_tick
local rate = data.rate
local count = (tick - last_tick) * rate
local fcount = floor(count)
if fcount > 1 then
fcount = 1
end
if fcount > 0 then
entity.get_output_inventory().insert {name = data.item, count = fcount}
data.last_tick = tick - (count - fcount) / rate
end
end
end
magic_crafters.index = index
end
local function do_magic_fluid_crafters()
local magic_fluid_crafters = this.magic_fluid_crafters
local limit = #magic_fluid_crafters
if limit == 0 then
return
end
local index = magic_fluid_crafters.index
for i = 1, magic_fluid_crafters_per_tick do
if index > limit then
index = 1
end
local data = magic_fluid_crafters[index]
local entity = data.entity
if not entity.valid then
fast_remove(magic_fluid_crafters, index)
limit = limit - 1
if limit == 0 then
return
end
else
index = index + 1
local tick = game.tick
local last_tick = data.last_tick
local rate = data.rate
local count = (tick - last_tick) * rate
local fcount = floor(count)
if fcount > 0 then
local fluidbox_index = data.fluidbox_index
local fb = entity.fluidbox
local fb_data = fb[fluidbox_index] or {name = data.item, amount = 0}
fb_data.amount = fb_data.amount + fcount
fb[fluidbox_index] = fb_data
data.last_tick = tick - (count - fcount) / rate
end
end
end
magic_fluid_crafters.index = index
end
local artillery_target_callback =
Token.register(
function(data)
local position = data.position
local entity = data.entity
if not entity.valid then
return
end
local tx, ty = position.x, position.y
local pos = entity.position
local x, y = pos.x, pos.y
local dx, dy = tx - x, ty - y
local d = dx * dx + dy * dy
if d >= 1024 and d <= 441398 then -- 704 in depth~
entity.surface.create_entity {
name = 'artillery-projectile',
position = position,
target = entity,
force = 'enemy',
speed = 1.5
}
end
end
)
local function do_artillery_turrets_targets()
local art_table = this.art_table
local index = art_table.index
if index > #art_table then
art_table.index = 1
return
end
art_table.index = index + 1
local outpost = art_table[index]
local now = game.tick
if now - outpost.last_fire_tick < 480 then
return
end
local turrets = outpost.artillery_turrets
for i = #turrets, 1, -1 do
local turret = turrets[i]
if not turret.valid then
fast_remove(turrets, i)
end
end
local count = #turrets
if count == 0 then
fast_remove(art_table, index)
return
end
outpost.last_fire_tick = now
local turret = turrets[1]
local area = outpost.artillery_area
local surface = turret.surface
local entities = surface.find_entities_filtered {area = area, name = artillery_target_entities}
if #entities == 0 then
return
end
local position = turret.position
for i = 1, count do
local entity = entities[random(#entities)]
if entity and entity.valid then
local data = {position = position, entity = entity}
Task.set_timeout_in_ticks(i * 60, artillery_target_callback, data)
end
end
end
local function add_magic_crafter_output(entity, output, distance)
local magic_fluid_crafters = this.magic_fluid_crafters
local magic_crafters = this.magic_crafters
local rate = output.min_rate + output.distance_factor * distance
local fluidbox_index = output.fluidbox_index
local data = {
entity = entity,
last_tick = game.tick,
base_rate = rate,
rate = rate,
item = output.item,
fluidbox_index = fluidbox_index
}
if fluidbox_index then
magic_fluid_crafters[#magic_fluid_crafters + 1] = data
else
magic_crafters[#magic_crafters + 1] = data
end
end
local function tick()
do_refill_turrets()
do_magic_crafters()
do_magic_fluid_crafters()
do_artillery_turrets_targets()
end
Public.deactivate_callback =
Token.register(
function(entity)
if entity and entity.valid then
entity.active = false
entity.operable = false
entity.destructible = false
end
end
)
Public.neutral_force =
Token.register(
function(entity)
if entity and entity.valid then
entity.force = 'neutral'
end
end
)
Public.enemy_force =
Token.register(
function(entity)
if entity and entity.valid then
entity.force = 'enemy'
end
end
)
Public.active_not_destructible_callback =
Token.register(
function(entity)
if entity and entity.valid then
entity.active = true
entity.operable = false
entity.destructible = false
end
end
)
Public.disable_minable_callback =
Token.register(
function(entity)
if entity and entity.valid then
entity.minable = false
end
end
)
Public.disable_minable_and_ICW_callback =
Token.register(
function(entity)
if entity and entity.valid then
entity.minable = false
ICW.register_wagon(entity, true)
end
end
)
Public.disable_destructible_callback =
Token.register(
function(entity)
if entity and entity.valid then
entity.destructible = false
entity.minable = false
end
end
)
Public.disable_active_callback =
Token.register(
function(entity)
if entity and entity.valid then
entity.active = false
end
end
)
local disable_active_callback = Public.disable_active_callback
Public.refill_turret_callback =
Token.register(
function(turret, data)
local refill_turrets = this.refill_turrets
local callback_data = data.callback_data
turret.direction = 3
refill_turrets[#refill_turrets + 1] = {turret = turret, data = callback_data}
end
)
Public.refill_artillery_turret_callback =
Token.register(
function(turret, data)
local refill_turrets = this.refill_turrets
local art_table = this.art_table
local index = art_table.index
turret.direction = 3
refill_turrets[#refill_turrets + 1] = {turret = turret, data = data.callback_data}
local artillery_data = art_table[index]
if not artillery_data then
artillery_data = {}
end
local artillery_turrets = artillery_data.artillery_turrets
if not artillery_turrets then
artillery_turrets = {}
artillery_data.artillery_turrets = artillery_turrets
local pos = turret.position
local x, y = pos.x, pos.y
artillery_data.artillery_area = {{x - 112, y}, {x + 112, y + 212}}
artillery_data.last_fire_tick = 0
art_table[#art_table + 1] = artillery_data
end
artillery_turrets[#artillery_turrets + 1] = turret
end
)
Public.refill_liquid_turret_callback =
Token.register(
function(turret, data)
local refill_turrets = this.refill_turrets
local callback_data = data.callback_data
callback_data.liquid = true
refill_turrets[#refill_turrets + 1] = {turret = turret, data = callback_data}
end
)
Public.power_source_callback =
Token.register(
function(turret, data)
local power_sources = this.power_sources
local callback_data = data.callback_data
local power_source = turret.surface.create_entity {name = 'hidden-electric-energy-interface', position = turret.position}
power_source.electric_buffer_size = callback_data.buffer_size
power_source.power_production = callback_data.power_production
power_source.destructible = false
local power_pole =
turret.surface.create_entity {
name = 'small-electric-pole',
position = {x = turret.position.x, y = turret.position.y}
}
power_pole.destructible = false
power_pole.disconnect_neighbour()
power_sources[turret.unit_number] = {entity = power_source, pole = power_pole}
end
)
Public.magic_item_crafting_callback =
Token.register(
function(entity, data)
local callback_data = data.callback_data
entity.minable = false
entity.destructible = false
entity.operable = false
local recipe = callback_data.recipe
if recipe then
entity.set_recipe(recipe)
else
local furance_item = callback_data.furance_item
if furance_item then
local inv = entity.get_inventory(defines.inventory.furnace_result)
inv.insert(furance_item)
end
end
local p = entity.position
local x, y = p.x, p.y
local distance = sqrt(x * x + y * y)
local output = callback_data.output
if #output == 0 then
add_magic_crafter_output(entity, output, distance)
else
for i = 1, #output do
local o = output[i]
add_magic_crafter_output(entity, o, distance)
end
end
if not callback_data.keep_active then
Task.set_timeout_in_ticks(2, disable_active_callback, entity) -- causes problems with refineries.
end
end
)
Public.magic_item_crafting_callback_weighted =
Token.register(
function(entity, data)
local callback_data = data.callback_data
entity.minable = false
entity.destructible = false
entity.operable = false
local weights = callback_data.weights
local loot = callback_data.loot
local p = entity.position
local i = random() * weights.total
local index = table.binary_search(weights, i)
if (index < 0) then
index = bit32.bnot(index)
end
local stack = loot[index].stack
if not stack then
return
end
local recipe = stack.recipe
if recipe then
entity.set_recipe(recipe)
else
local furance_item = stack.furance_item
if furance_item then
local inv = entity.get_inventory(defines.inventory.furnace_result)
inv.insert(furance_item)
end
end
local x, y = p.x, p.y
local distance = sqrt(x * x + y * y)
local output = stack.output
if #output == 0 then
add_magic_crafter_output(entity, output, distance)
else
for o_i = 1, #output do
local o = output[o_i]
add_magic_crafter_output(entity, o, distance)
end
end
if not callback_data.keep_active then
Task.set_timeout_in_ticks(2, disable_active_callback, entity) -- causes problems with refineries.
end
end
)
function Public.prepare_weighted_loot(loot)
local total = 0
local weights = {}
for i = 1, #loot do
local v = loot[i]
total = total + v.weight
weights[#weights + 1] = total
end
weights.total = total
return weights
end
function Public.do_random_loot(entity, weights, loot)
if not entity.valid then
return
end
entity.operable = false
--entity.destructible = false
local i = random() * weights.total
local index = table.binary_search(weights, i)
if (index < 0) then
index = bit32.bnot(index)
end
local stack = loot[index].stack
if not stack then
return
end
local df = stack.distance_factor
local count
if df then
local p = entity.position
local x, y = p.x, p.y
local d = sqrt(x * x + y * y)
count = stack.count + d * df
else
count = stack.count
end
entity.insert {name = stack.name, count = count}
end
Public.firearm_magazine_ammo = {name = 'firearm-magazine', count = 200}
Public.piercing_rounds_magazine_ammo = {name = 'piercing-rounds-magazine', count = 200}
Public.uranium_rounds_magazine_ammo = {name = 'uranium-rounds-magazine', count = 200}
Public.light_oil_ammo = {name = 'light-oil', amount = 100}
Public.artillery_shell_ammo = {name = 'artillery-shell', count = 15}
Public.laser_turrent_power_source = {buffer_size = 2400000, power_production = 40000}
function Public.reset_table()
this.power_sources = {index = 1}
this.refill_turrets = {index = 1}
this.magic_crafters = {index = 1}
this.magic_fluid_crafters = {index = 1}
end
Event.on_nth_tick(10, tick)
--Event.add(defines.events.on_tick, tick)
Event.add(defines.events.on_entity_died, turret_died)
return Public