1
0
mirror of https://github.com/ComfyFactory/ComfyFactorio.git synced 2025-01-10 00:43:27 +02:00
ComfyFactorio/modules/wave_defense.lua

250 lines
8.8 KiB
Lua
Raw Normal View History

2019-10-07 01:46:26 +02:00
local math_random = math.random
local threat_values = {
["behemoth-biter"] = 10,
["behemoth-spitter"] = 10,
["big-biter"] = 5,
["big-spitter"] = 5,
["medium-biter"] = 3,
["medium-spitter"] = 3,
["small-biter"] = 1,
["small-spitter"] = 1,
}
function roll_biter_name()
local max_chance = 0
for k, v in pairs(global.wave_defense.biter_raffle) do
max_chance = max_chance + v
end
local r = math.random(1, max_chance)
local current_chance = 0
for k, v in pairs(global.wave_defense.biter_raffle) do
current_chance = current_chance + v
if r <= current_chance then return k end
end
end
function set_biter_raffle(level)
global.wave_defense.biter_raffle = {
["small-biter"] = 1000 - level * 2,
["small-spitter"] = 1000 - level * 2,
2019-10-07 04:37:23 +02:00
["medium-biter"] = level,
["medium-spitter"] = level,
2019-10-07 01:46:26 +02:00
["big-biter"] = 0,
["big-spitter"] = 0,
["behemoth-biter"] = 0,
["behemoth-spitter"] = 0,
}
if level > 500 then
global.wave_defense.biter_raffle["big-biter"] = (level - 500) * 5
global.wave_defense.biter_raffle["big-spitter"] = (level - 500) * 5
end
if level > 800 then
global.wave_defense.biter_raffle["behemoth-biter"] = (level - 800) * 10
global.wave_defense.biter_raffle["behemoth-spitter"] = (level - 800) * 10
end
for k, v in pairs(global.wave_defense.biter_raffle) do
if global.wave_defense.biter_raffle[k] < 0 then global.wave_defense.biter_raffle[k] = 0 end
end
end
2019-10-07 04:37:23 +02:00
local function time_out_biters()
for k, biter in pairs(global.wave_defense.active_biters) do
if biter.spawn_tick + global.wave_defense.max_biter_age < game.tick then
global.wave_defense.threat = global.wave_defense.threat + threat_values[biter.entity.name]
biter.entity.destroy()
global.wave_defense.active_biters[k] = nil
end
end
end
2019-10-07 01:46:26 +02:00
local function get_random_close_spawner()
local spawners = global.wave_defense.surface.find_entities_filtered({type = "unit-spawner"})
if not spawners[1] then return false end
local center = global.wave_defense.target.position
local spawner = spawners[math_random(1,#spawners)]
for i = 1, 5, 1 do
local spawner_2 = spawners[math_random(1,#spawners)]
if (center.x - spawner_2.position.x) ^ 2 + (center.y - spawner_2.position.y) ^ 2 < (center.x - spawner.position.x) ^ 2 + (center.y - spawner.position.y) ^ 2 then spawner = spawner_2 end
end
return spawner
end
local function set_target()
if global.wave_defense.target then
if global.wave_defense.target.valid then return end
end
local characters = {}
for i = 1, #game.connected_players, 1 do
if game.connected_players[i].character then
if game.connected_players[i].character.valid then
characters[#characters + 1] = game.connected_players[i].character
end
end
end
global.wave_defense.target = characters[math_random(1, #characters)]
end
local function set_group_spawn_position()
local spawner = get_random_close_spawner()
if not spawner then return end
2019-10-07 04:37:23 +02:00
local position = global.wave_defense.surface.find_non_colliding_position("rocket-silo", spawner.position, 48, 1)
2019-10-07 01:46:26 +02:00
if not position then return end
global.wave_defense.spawn_position = position
end
local function set_enemy_evolution()
local evolution = global.wave_defense.wave_number * 0.001
if evolution > 1 then evolution = 1 end
game.forces.enemy.evolution_factor = evolution
end
local function spawn_biter()
if global.wave_defense.threat <= 0 then return false end
if global.wave_defense.active_biter_count >= global.wave_defense.max_active_biters then return false end
local name = roll_biter_name()
local position = global.wave_defense.surface.find_non_colliding_position(name, global.wave_defense.spawn_position, 32, 1)
if not position then return false end
local biter = global.wave_defense.surface.create_entity({name = name, position = position, force = "enemy"})
biter.ai_settings.allow_destroy_when_commands_fail = false
biter.ai_settings.allow_try_return_to_spawner = false
global.wave_defense.active_biters[biter.unit_number] = {entity = biter, spawn_tick = game.tick}
global.wave_defense.active_biter_count = global.wave_defense.active_biter_count + 1
global.wave_defense.threat = global.wave_defense.threat - threat_values[name]
return biter
end
local function spawn_unit_group()
if global.wave_defense.threat <= 0 then return false end
if global.wave_defense.active_biter_count >= global.wave_defense.max_active_biters then return false end
set_group_spawn_position()
local unit_group = global.wave_defense.surface.create_unit_group({position = global.wave_defense.spawn_position, force = "enemy"})
for a = 1, global.wave_defense.group_size, 1 do
local biter = spawn_biter()
if not biter then break end
unit_group.add_member(biter)
end
2019-10-07 04:37:23 +02:00
global.wave_defense.unit_groups[#global.wave_defense.unit_groups + 1] = unit_group
2019-10-07 01:46:26 +02:00
return true
end
local function spawn_wave()
2019-10-07 04:37:23 +02:00
if global.wave_defense.active_biter_count >= global.wave_defense.max_active_biters then return false end
2019-10-07 01:46:26 +02:00
global.wave_defense.wave_number = global.wave_defense.wave_number + 1
2019-10-07 04:37:23 +02:00
global.wave_defense.group_size = global.wave_defense.wave_number * 2
2019-10-07 01:46:26 +02:00
if global.wave_defense.group_size > global.wave_defense.max_group_size then global.wave_defense.group_size = global.wave_defense.max_group_size end
2019-10-07 04:37:23 +02:00
global.wave_defense.threat = global.wave_defense.threat + global.wave_defense.wave_number * 2
2019-10-07 01:46:26 +02:00
set_enemy_evolution()
set_biter_raffle(global.wave_defense.wave_number)
for a = 1, 16, 1 do
if not spawn_unit_group() then break end
end
end
2019-10-07 04:37:23 +02:00
local function give_commands_to_unit_groups()
if #global.wave_defense.unit_groups == 0 then return end
if not global.wave_defense.target then return end
if not global.wave_defense.target.valid then return end
for k, group in pairs(global.wave_defense.unit_groups) do
if group.valid then
group.set_command({
type = defines.command.compound,
structure_type = defines.compound_command.return_last,
commands = {
{
type = defines.command.attack_area,
destination = global.wave_defense.target.position,
radius = 16,
distraction = defines.distraction.by_enemy
},
{
type = defines.command.attack,
target = global.wave_defense.target,
distraction = defines.distraction.by_enemy
}
}
})
else
global.wave_defense.unit_groups[k] = nil
end
end
end
local function create_gui(player)
local frame = player.gui.top.add({ type = "frame", name = "wave_defense", tooltip = "Click to show map info"})
frame.style.maximal_height = 38
local label = frame.add({ type = "label", caption = " ", name = "label"})
label.style.font_color = {r=0.88, g=0.88, b=0.88}
label.style.font = "default-listbox"
label.style.left_padding = 4
label.style.right_padding = 4
label.style.minimal_width = 68
label.style.font_color = {r=0.33, g=0.66, b=0.9}
local progressbar = frame.add({ type = "progressbar", name = "progressbar", value = 0})
progressbar.style.minimal_width = 128
progressbar.style.maximal_width = 128
progressbar.style.top_padding = 10
end
local function update_gui(player)
if not player.gui.top.wave_defense then create_gui(player) end
player.gui.top.wave_defense.label.caption = "Wave: " .. global.wave_defense.wave_number
if global.wave_defense.wave_number == 0 then player.gui.top.wave_defense.label.caption = "First wave in " .. math.floor((global.wave_defense.next_wave - game.tick) / 60) + 1 end
player.gui.top.wave_defense.progressbar.value = 1 - math.round((global.wave_defense.next_wave - game.tick) / global.wave_defense.wave_interval, 3)
end
2019-10-07 01:46:26 +02:00
local function on_entity_died(event)
if not event.entity.valid then return end
if event.entity.type ~= "unit" then return end
if not global.wave_defense.active_biters[event.entity.unit_number] then return end
global.wave_defense.active_biters[event.entity.unit_number] = nil
global.wave_defense.active_biter_count = global.wave_defense.active_biter_count - 1
end
local function on_tick()
2019-10-07 04:37:23 +02:00
if global.wave_defense.game_lost then return end
for _, player in pairs(game.connected_players) do update_gui(player) end
if game.tick < global.wave_defense.next_wave then return end
if global.wave_defense.active_biter_count < global.wave_defense.max_active_biters then
global.wave_defense.next_wave = game.tick + global.wave_defense.wave_interval
time_out_biters()
2019-10-07 01:46:26 +02:00
set_target()
spawn_wave()
2019-10-07 04:37:23 +02:00
give_commands_to_unit_groups()
return
end
if game.tick % 3600 == 0 then
time_out_biters()
set_target()
give_commands_to_unit_groups()
end
2019-10-07 01:46:26 +02:00
end
local function on_init()
global.wave_defense = {
surface = game.surfaces["nauvis"],
active_biters = {},
2019-10-07 04:37:23 +02:00
unit_groups = {},
max_active_biters = 1024,
2019-10-07 01:46:26 +02:00
max_group_size = 256,
2019-10-07 04:37:23 +02:00
max_biter_age = 3600 * 30,
2019-10-07 01:46:26 +02:00
active_biter_count = 0,
spawn_position = {x = 0, y = 48},
2019-10-07 04:37:23 +02:00
next_wave = 3600 * 0.15,
wave_interval = 1800,
2019-10-07 01:46:26 +02:00
wave_number = 0,
2019-10-07 04:37:23 +02:00
game_lost = false,
2019-10-07 01:46:26 +02:00
threat = 0,
}
end
local event = require 'utils.event'
2019-10-07 04:37:23 +02:00
event.on_nth_tick(30, on_tick)
2019-10-07 01:46:26 +02:00
event.on_init(on_init)
event.add(defines.events.on_entity_died, on_entity_died)