1
0
mirror of https://github.com/ComfyFactory/ComfyFactorio.git synced 2025-02-09 13:37:02 +02:00

wave defense table lookups

This commit is contained in:
Gerkiz 2020-11-17 12:45:47 +01:00
parent 88f46983af
commit dc3b62ed85
7 changed files with 519 additions and 420 deletions

View File

@ -1,105 +1,129 @@
local WD = require "modules.wave_defense.table"
local WD = require 'modules.wave_defense.table'
local Public = {}
function Public.wave_defense_roll_biter_name()
local wave_defense_table = WD.get_table()
local max_chance = 0
for k, v in pairs(wave_defense_table.biter_raffle) do
max_chance = max_chance + v
end
local r = math.random(0, math.floor(max_chance))
local current_chance = 0
for k, v in pairs(wave_defense_table.biter_raffle) do
current_chance = current_chance + v
if r <= current_chance then return k end
end
local biter_raffle = WD.get('biter_raffle')
local max_chance = 0
for k, v in pairs(biter_raffle) do
max_chance = max_chance + v
end
local r = math.random(0, math.floor(max_chance))
local current_chance = 0
for k, v in pairs(biter_raffle) do
current_chance = current_chance + v
if r <= current_chance then
return k
end
end
end
function Public.wave_defense_roll_spitter_name()
local wave_defense_table = WD.get_table()
local max_chance = 0
for k, v in pairs(wave_defense_table.spitter_raffle) do
max_chance = max_chance + v
end
local r = math.random(0, math.floor(max_chance))
local current_chance = 0
for k, v in pairs(wave_defense_table.spitter_raffle) do
current_chance = current_chance + v
if r <= current_chance then return k end
end
local spitter_raffle = WD.get('biter_raffle')
local max_chance = 0
for k, v in pairs(spitter_raffle) do
max_chance = max_chance + v
end
local r = math.random(0, math.floor(max_chance))
local current_chance = 0
for k, v in pairs(spitter_raffle) do
current_chance = current_chance + v
if r <= current_chance then
return k
end
end
end
function Public.wave_defense_set_unit_raffle(level)
local wave_defense_table = WD.get_table()
wave_defense_table.biter_raffle = {
["small-biter"] = 1000 - level * 1.75,
["medium-biter"] = level,
["big-biter"] = 0,
["behemoth-biter"] = 0,
}
wave_defense_table.spitter_raffle = {
["small-spitter"] = 1000 - level * 1.75,
["medium-spitter"] = level,
["big-spitter"] = 0,
["behemoth-spitter"] = 0,
}
if level > 500 then
wave_defense_table.biter_raffle["medium-biter"] = 500 - (level - 500)
wave_defense_table.spitter_raffle["medium-spitter"] = 500 - (level - 500)
wave_defense_table.biter_raffle["big-biter"] = (level - 500) * 2
wave_defense_table.spitter_raffle["big-spitter"] = (level - 500) * 2
end
if level > 800 then
wave_defense_table.biter_raffle["behemoth-biter"] = (level - 800) * 2.75
wave_defense_table.spitter_raffle["behemoth-spitter"] = (level - 800) * 2.75
end
for k, v in pairs(wave_defense_table.biter_raffle) do
if wave_defense_table.biter_raffle[k] < 0 then wave_defense_table.biter_raffle[k] = 0 end
end
for k, v in pairs(wave_defense_table.spitter_raffle) do
if wave_defense_table.spitter_raffle[k] < 0 then wave_defense_table.spitter_raffle[k] = 0 end
end
WD.set(
'biter_raffle',
{
['small-biter'] = 1000 - level * 1.75,
['medium-biter'] = level,
['big-biter'] = 0,
['behemoth-biter'] = 0
}
)
WD.set(
'spitter_raffle',
{
['small-spitter'] = 1000 - level * 1.75,
['medium-spitter'] = level,
['big-spitter'] = 0,
['behemoth-spitter'] = 0
}
)
local biter_raffle = WD.get('biter_raffle')
local spitter_raffle = WD.get('spitter_raffle')
if level > 500 then
biter_raffle['medium-biter'] = 500 - (level - 500)
spitter_raffle['medium-spitter'] = 500 - (level - 500)
biter_raffle['big-biter'] = (level - 500) * 2
spitter_raffle['big-spitter'] = (level - 500) * 2
end
if level > 800 then
biter_raffle['behemoth-biter'] = (level - 800) * 2.75
spitter_raffle['behemoth-spitter'] = (level - 800) * 2.75
end
for k, _ in pairs(biter_raffle) do
if biter_raffle[k] < 0 then
biter_raffle[k] = 0
end
end
for k, _ in pairs(spitter_raffle) do
if spitter_raffle[k] < 0 then
spitter_raffle[k] = 0
end
end
end
function Public.wave_defense_roll_worm_name()
local wave_defense_table = WD.get_table()
local max_chance = 0
for k, v in pairs(wave_defense_table.worm_raffle) do
max_chance = max_chance + v
end
local r = math.random(0, math.floor(max_chance))
local current_chance = 0
for k, v in pairs(wave_defense_table.worm_raffle) do
current_chance = current_chance + v
if r <= current_chance then return k end
end
local worm_raffle = WD.get('worm_raffle')
local max_chance = 0
for k, v in pairs(worm_raffle) do
max_chance = max_chance + v
end
local r = math.random(0, math.floor(max_chance))
local current_chance = 0
for k, v in pairs(worm_raffle) do
current_chance = current_chance + v
if r <= current_chance then
return k
end
end
end
function Public.wave_defense_set_worm_raffle(level)
local wave_defense_table = WD.get_table()
wave_defense_table.worm_raffle = {
["small-worm-turret"] = 1000 - level * 1.75,
["medium-worm-turret"] = level,
["big-worm-turret"] = 0,
["behemoth-worm-turret"] = 0,
}
if level > 500 then
wave_defense_table.worm_raffle["medium-worm-turret"] = 500 - (level - 500)
wave_defense_table.worm_raffle["big-worm-turret"] = (level - 500) * 2
end
if level > 800 then
wave_defense_table.worm_raffle["behemoth-worm-turret"] = (level - 800) * 3
end
for k, v in pairs(wave_defense_table.worm_raffle) do
if wave_defense_table.worm_raffle[k] < 0 then wave_defense_table.worm_raffle[k] = 0 end
end
WD.set(
'worm_raffle',
{
['small-worm-turret'] = 1000 - level * 1.75,
['medium-worm-turret'] = level,
['big-worm-turret'] = 0,
['behemoth-worm-turret'] = 0
}
)
local worm_raffle = WD.get('worm_raffle')
if level > 500 then
worm_raffle['medium-worm-turret'] = 500 - (level - 500)
worm_raffle['big-worm-turret'] = (level - 500) * 2
end
if level > 800 then
worm_raffle['behemoth-worm-turret'] = (level - 800) * 3
end
for k, _ in pairs(worm_raffle) do
if worm_raffle[k] < 0 then
worm_raffle[k] = 0
end
end
end
function Public.wave_defense_print_chances(tbl)
for k, v in pairs(tbl) do
game.print(k .. " chance = " .. v)
end
for k, v in pairs(tbl) do
game.print(k .. ' chance = ' .. v)
end
end
return Public
return Public

View File

@ -96,7 +96,7 @@ local function spawn_biters(data)
unit = surface.create_entity({name = BiterRolls.wave_defense_roll_biter_name(), position = position})
end
if random(1, 128) == 1 then
if random(1, 64) == 1 then
BiterHealthBooster.add_boss_unit(unit, boosted_health, 0.38)
end
end

View File

@ -29,15 +29,13 @@ local function create_gui(player)
label.style.left_padding = 4
label.style.font_color = {r = 150, g = 0, b = 255}
local label =
frame.add({type = 'label', caption = ' ', name = 'threat_value', tooltip = {'wave_defense.tooltip_1'}})
local label = frame.add({type = 'label', caption = ' ', name = 'threat_value', tooltip = {'wave_defense.tooltip_1'}})
label.style.font = 'default-bold'
label.style.right_padding = 1
label.style.minimal_width = 10
label.style.font_color = {r = 150, g = 0, b = 255}
local label =
frame.add({type = 'label', caption = ' ', name = 'threat_gains', tooltip = {'wave_defense.tooltip_2'}})
local label = frame.add({type = 'label', caption = ' ', name = 'threat_gains', tooltip = {'wave_defense.tooltip_2'}})
label.style.font = 'default'
label.style.left_padding = 1
label.style.right_padding = 1
@ -45,21 +43,17 @@ end
--display threat gain/loss per minute during last 15 minutes
local function get_threat_gain()
local wave_defense_table = WD.get_table()
local past_index = wave_defense_table.threat_log_index - 900
local threat_log_index = WD.get('threat_log_index')
local threat_log = WD.get('threat_log')
local past_index = threat_log_index - 900
if past_index < 1 then
past_index = 1
end
local gain =
math.floor(
(wave_defense_table.threat_log[wave_defense_table.threat_log_index] - wave_defense_table.threat_log[past_index]) /
15
)
local gain = math.floor((threat_log[threat_log_index] - threat_log[past_index]) / 15)
return gain
end
local function update_gui(player)
local wave_defense_table = WD.get_table()
if not player.gui.top.wave_defense then
create_gui(player)
end
@ -69,31 +63,38 @@ local function update_gui(player)
biter_health_boost = global.biter_health_boost
end
local wave_number = WD.get('wave_number')
local next_wave = WD.get('next_wave')
local last_wave = WD.get('last_wave')
local max_active_biters = WD.get('max_active_biters')
local threat = WD.get('threat')
local enable_threat_log = WD.get('enable_threat_log')
gui.label.caption = {'wave_defense.gui_2'}
gui.wave_number.caption = wave_defense_table.wave_number
if wave_defense_table.wave_number == 0 then
gui.wave_number.caption = wave_number
if wave_number == 0 then
gui.label.caption = {'wave_defense.gui_1'}
gui.wave_number.caption = math.floor((wave_defense_table.next_wave - game.tick) / 60) + 1
gui.wave_number.caption = math.floor((next_wave - game.tick) / 60) + 1
end
local interval = wave_defense_table.next_wave - wave_defense_table.last_wave
gui.progressbar.value = 1 - (wave_defense_table.next_wave - game.tick) / interval
local interval = next_wave - last_wave
gui.progressbar.value = 1 - (next_wave - game.tick) / interval
gui.threat.caption = {'wave_defense.gui_3'}
gui.threat.tooltip = {'wave_defense.tooltip_1', biter_health_boost * 100, wave_defense_table.max_active_biters}
gui.threat_value.caption = math.floor(wave_defense_table.threat)
gui.threat.tooltip = {'wave_defense.tooltip_1', biter_health_boost * 100, max_active_biters}
gui.threat_value.caption = math.floor(threat)
gui.threat_value.tooltip = {
'wave_defense.tooltip_1',
biter_health_boost * 100,
wave_defense_table.max_active_biters
max_active_biters
}
if wave_defense_table.wave_number == 0 then
if wave_number == 0 then
gui.threat_gains.caption = ''
return
end
if wave_defense_table.enable_threat_log then
if enable_threat_log then
local gain = get_threat_gain()
local d = wave_defense_table.wave_number / 75
local d = wave_number / 75
if gain >= 0 then
gui.threat_gains.caption = ' (+' .. gain .. ')'

View File

@ -94,7 +94,7 @@ local function remove_rocks(entity)
end
local function is_unit_valid(biter)
local this = WD.get()
local max_biter_age = WD.get('max_biter_age')
if not biter.entity then
debug_print('is_unit_valid - unit destroyed - does no longer exist')
return false
@ -107,7 +107,7 @@ local function is_unit_valid(biter)
debug_print('is_unit_valid - unit destroyed - no unitgroup')
return false
end
if biter.spawn_tick + this.max_biter_age < game.tick then
if biter.spawn_tick + max_biter_age < game.tick then
debug_print('is_unit_valid - unit destroyed - timed out')
return false
end
@ -115,54 +115,59 @@ local function is_unit_valid(biter)
end
local function refresh_active_unit_threat()
local this = WD.get()
debug_print('refresh_active_unit_threat - current value ' .. this.active_biter_threat)
local active_biter_threat = 0
for k, biter in pairs(this.active_biters) do
local active_biter_threat = WD.get('active_biter_threat')
local active_biters = WD.get('active_biters')
debug_print('refresh_active_unit_threat - current value ' .. active_biter_threat)
local biter_threat = 0
for k, biter in pairs(active_biters) do
if biter.entity then
if biter.entity.valid then
active_biter_threat = active_biter_threat + threat_values[biter.entity.name]
biter_threat = biter_threat + threat_values[biter.entity.name]
end
end
end
this.active_biter_threat = math_round(active_biter_threat * global.biter_health_boost, 2)
debug_print('refresh_active_unit_threat - new value ' .. this.active_biter_threat)
active_biter_threat = math_round(biter_threat * global.biter_health_boost, 2)
debug_print('refresh_active_unit_threat - new value ' .. active_biter_threat)
end
local function time_out_biters()
local this = WD.get()
for k, biter in pairs(this.active_biters) do
local active_biters = WD.get('active_biters')
local active_biter_count = WD.get('active_biter_count')
local active_biter_threat = WD.get('active_biter_threat')
for k, biter in pairs(active_biters) do
if not is_unit_valid(biter) then
this.active_biter_count = this.active_biter_count - 1
active_biter_count = active_biter_count - 1
if biter.entity then
if biter.entity.valid then
this.active_biter_threat =
this.active_biter_threat -
math_round(threat_values[biter.entity.name] * global.biter_health_boost, 2)
WD.set(
'active_biter_threat',
active_biter_threat - math_round(threat_values[biter.entity.name] * global.biter_health_boost, 2)
)
if biter.entity.force.index == 2 then
biter.entity.destroy()
end
end
end
this.active_biters[k] = nil
active_biters[k] = nil
end
end
end
local function get_random_close_spawner()
local this = WD.get()
local spawners = this.nests
local center = this.target.position
local nests = WD.get('nests')
local target = WD.get('target')
local get_random_close_spawner_attempts = WD.get('get_random_close_spawner_attempts')
local center = target.position
local spawner
for i = 1, this.get_random_close_spawner_attempts, 1 do
for i = 1, get_random_close_spawner_attempts, 1 do
::retry::
if #spawners < 1 then
if #nests < 1 then
return false
end
local k = math_random(1, #spawners)
local spawner_2 = spawners[k]
local k = math_random(1, #nests)
local spawner_2 = nests[k]
if not spawner_2 or not spawner_2.valid then
this.nests[k] = nil
nests[k] = nil
goto retry
end
if
@ -177,13 +182,14 @@ local function get_random_close_spawner()
return spawner
end
local function get_random_character(this)
local function get_random_character()
local characters = {}
local surface_index = WD.get('surface_index')
local p = game.connected_players
for _, player in pairs(p) do
if player.character then
if player.character.valid then
if player.character.surface.index == this.surface_index then
if player.character.surface.index == surface_index then
characters[#characters + 1] = player.character
end
end
@ -196,30 +202,29 @@ local function get_random_character(this)
end
local function set_main_target()
local this = WD.get()
if this.target then
if this.target.valid then
local target = WD.get('target')
if target then
if target.valid then
return
end
end
local target = SideTargets.get_side_target()
if not target then
target = get_random_character(this)
local sec_target = SideTargets.get_side_target()
if not sec_target then
sec_target = get_random_character()
end
if not target then
if not sec_target then
return
end
this.target = target
WD.set('target', sec_target)
debug_print(
'set_main_target -- New main target ' ..
target.name .. ' at position x' .. target.position.x .. ' y' .. target.position.y .. ' selected.'
sec_target.name .. ' at position x' .. sec_target.position.x .. ' y' .. sec_target.position.y .. ' selected.'
)
end
local function set_group_spawn_position(surface)
local this = WD.get()
local spawner = get_random_close_spawner()
if not spawner then
return
@ -228,62 +233,66 @@ local function set_group_spawn_position(surface)
if not position then
return
end
this.spawn_position = {x = position.x, y = position.y}
debug_print(
'set_group_spawn_position -- Changed position to x' ..
this.spawn_position.x .. ' y' .. this.spawn_position.y .. '.'
)
WD.set('spawn_position', {x = position.x, y = position.y})
local spawn_position = WD.get('spawn_position')
debug_print('set_group_spawn_position -- Changed position to x' .. spawn_position.x .. ' y' .. spawn_position.y .. '.')
end
local function set_enemy_evolution()
local this = WD.get()
local evolution_factor = this.wave_number * 0.001
local biter_health_boost = 1
local wave_number = WD.get('wave_number')
local biter_health_boost = WD.get('biter_health_boost')
local threat = WD.get('threat')
local evolution_factor = wave_number * 0.001
local biter_h_boost = 1
--local damage_increase = 0
if evolution_factor > 1 then
--damage_increase = damage_increase + (evolution_factor - 1)
--biter_health_boost = biter_health_boost + (evolution_factor - 1) * 2
evolution_factor = 1
end
if this.biter_health_boost then
biter_health_boost = math_round(this.biter_health_boost + (this.threat - 5000) * 0.000033, 3)
if biter_health_boost then
biter_h_boost = math_round(biter_health_boost + (threat - 5000) * 0.000033, 3)
else
biter_health_boost = math_round(biter_health_boost + (this.threat - 5000) * 0.000033, 3)
biter_h_boost = math_round(biter_h_boost + (threat - 5000) * 0.000033, 3)
end
if biter_health_boost <= 1 then
biter_health_boost = 1
if biter_h_boost <= 1 then
biter_h_boost = 1
end
--damage_increase = math_round(damage_increase + this.threat * 0.0000025, 3)
--damage_increase = math_round(damage_increase + threat * 0.0000025, 3)
global.biter_health_boost = biter_health_boost
global.biter_health_boost = biter_h_boost
--game.forces.enemy.set_ammo_damage_modifier("melee", damage_increase)
--game.forces.enemy.set_ammo_damage_modifier("biological", damage_increase)
game.forces.enemy.evolution_factor = evolution_factor
end
local function can_units_spawn()
local this = WD.get()
if this.threat <= 0 then
local threat = WD.get('threat')
if threat <= 0 then
debug_print('can_units_spawn - threat too low')
return false
end
if this.active_biter_count >= this.max_active_biters then
local active_biter_count = WD.get('active_biter_count')
local max_active_biters = WD.get('max_active_biters')
if active_biter_count >= max_active_biters then
debug_print('can_units_spawn - active biter count too high')
return false
end
if this.active_biter_threat >= this.threat then
debug_print('can_units_spawn - active biter threat too high (' .. this.active_biter_threat .. ')')
local active_biter_threat = WD.get('active_biter_threat')
if active_biter_threat >= threat then
debug_print('can_units_spawn - active biter threat too high (' .. active_biter_threat .. ')')
return false
end
return true
end
local function get_active_unit_groups_count()
local this = WD.get()
local unit_groups = WD.get('unit_groups')
local count = 0
for _, g in pairs(this.unit_groups) do
for _, g in pairs(unit_groups) do
if g.valid then
if #g.members > 0 then
count = count + 1
@ -297,70 +306,109 @@ local function get_active_unit_groups_count()
end
local function spawn_biter(surface, is_boss_biter)
local this = WD.get()
if not is_boss_biter then
if not can_units_spawn() then
return
end
end
local boosted_health = global.biter_health_boost
local name
if math_random(1, 100) > 73 then
name = BiterRolls.wave_defense_roll_spitter_name()
else
name = BiterRolls.wave_defense_roll_biter_name()
end
local position = this.spawn_position
local spawn_position = WD.get('spawn_position')
local position = spawn_position
local biter = surface.create_entity({name = name, position = position, force = 'enemy'})
biter.ai_settings.allow_destroy_when_commands_fail = true
biter.ai_settings.allow_try_return_to_spawner = false
biter.ai_settings.do_separation = true
if this.remove_entities then
biter.ai_settings.path_resolution_modifier = -5
local remove_entities = WD.get('remove_entities')
if remove_entities then
remove_trees(biter)
remove_rocks(biter)
end
if is_boss_biter then
BiterHealthBooster.add_boss_unit(biter, global.biter_health_boost * 5, 0.35)
local modified_boss_health = WD.get('modified_boss_health')
if modified_boss_health then
local wave_number = WD.get('wave_number')
if boosted_health == 1 then
boosted_health = 1.25
end
boosted_health = boosted_health * (wave_number * 0.05)
local sum = boosted_health * 5
debug_print('Boss Health Boosted: ' .. sum)
if sum >= 150 then
sum = 150
end
BiterHealthBooster.add_boss_unit(biter, sum, 0.55)
else
local sum = boosted_health * 5
debug_print('Boss Health Boosted: ' .. sum)
BiterHealthBooster.add_boss_unit(biter, sum, 0.55)
end
end
this.active_biters[biter.unit_number] = {entity = biter, spawn_tick = game.tick}
this.active_biter_count = this.active_biter_count + 1
this.active_biter_threat = this.active_biter_threat + math_round(threat_values[name] * global.biter_health_boost, 2)
WD.set('active_biters')[biter.unit_number] = {entity = biter, spawn_tick = game.tick}
local active_biter_count = WD.get('active_biter_count')
WD.set('active_biter_count', active_biter_count + 1)
local active_biter_threat = WD.get('active_biter_threat')
WD.set('active_biter_threat', active_biter_threat + math_round(threat_values[name] * boosted_health, 2))
return biter
end
local function set_next_wave()
local this = WD.get()
this.wave_number = this.wave_number + 1
local wave_number = WD.get('wave_number')
WD.set('wave_number', wave_number + 1)
wave_number = WD.get('wave_number')
local threat_gain = this.wave_number * this.threat_gain_multiplier
if this.wave_number > 1000 then
threat_gain = threat_gain * (this.wave_number * 0.001)
local threat_gain_multiplier = WD.get('threat_gain_multiplier')
local threat_gain = wave_number * threat_gain_multiplier
if wave_number > 1000 then
threat_gain = threat_gain * (wave_number * 0.001)
end
if this.wave_number % 25 == 0 then
this.boss_wave = true
this.boss_wave_warning = true
if this.alert_boss_wave then
local msg = 'Boss Wave: ' .. this.wave_number
if wave_number % 25 == 0 then
WD.set('boss_wave', true)
WD.set('boss_wave_warning', true)
local alert_boss_wave = WD.get('alert_boss_wave')
local spawn_position = WD.get('spawn_position')
if alert_boss_wave then
local msg = 'Boss Wave: ' .. wave_number
local pos = {
position = this.spawn_position
position = spawn_position
}
Alert.alert_all_players_location(pos, msg, {r = 0.8, g = 0.1, b = 0.1})
end
threat_gain = threat_gain * 2
else
if this.boss_wave_warning then
this.boss_wave_warning = false
local boss_wave_warning = WD.get('boss_wave_warning')
if boss_wave_warning then
WD.set('boss_wave_warning', false)
end
end
this.threat = this.threat + math_floor(threat_gain)
if not this.wave_enforced then
this.last_wave = this.next_wave
this.next_wave = game.tick + this.wave_interval
local threat = WD.get('threat')
WD.set('threat', threat + math_floor(threat_gain))
local wave_enforced = WD.get('wave_enforced')
local next_wave = WD.get('next_wave')
local wave_interval = WD.get('wave_interval')
if not wave_enforced then
WD.set('last_wave', next_wave)
WD.set('next_wave', game.tick + wave_interval)
end
if this.clear_corpses then
local surface = game.surfaces[this.surface_index]
local clear_corpses = WD.get('clear_corpses')
if clear_corpses then
local surface_index = WD.get('surface_index')
local surface = game.surfaces[surface_index]
for _, entity in pairs(surface.find_entities_filtered {type = 'corpse'}) do
if math_random(1, 2) == 1 then
entity.destroy()
@ -370,9 +418,9 @@ local function set_next_wave()
end
local function reform_group(group)
local this = WD.get()
local unit_group_command_step_length = WD.get('unit_group_command_step_length')
local group_position = {x = group.position.x, y = group.position.y}
local step_length = this.unit_group_command_step_length
local step_length = unit_group_command_step_length
local position = group.surface.find_non_colliding_position('biter-spawner', group_position, step_length, 4)
if position then
local new_group = group.surface.create_unit_group {position = position, force = group.force}
@ -380,17 +428,22 @@ local function reform_group(group)
new_group.add_member(biter)
end
debug_print('Creating new unit group, because old one was stuck.')
this.unit_groups[new_group.group_number] = new_group
this.index = this.index + 1
local unit_groups = WD.get('unit_groups')
unit_groups[new_group.group_number] = new_group
local index = WD.get('index')
WD.set('index', index + 1)
return new_group
else
debug_print('Destroying stuck group.')
if this.unit_groups[group.group_number] then
table.remove(this.unit_groups, group.group_number)
this.index = this.index - 1
if this.index <= 0 then
this.index = 0
local unit_groups = WD.get('unit_groups')
if unit_groups[group.group_number] then
table.remove(unit_groups, group.group_number)
local index = WD.get('index')
WD.set('index', index - 1)
index = WD.get('index')
if index <= 0 then
WD.set('index', 0)
end
end
group.destroy()
@ -399,29 +452,31 @@ local function reform_group(group)
end
local function get_commmands(group)
local this = WD.get()
local unit_group_command_step_length = WD.get('unit_group_command_step_length')
local enable_side_target = WD.get('enable_side_target')
local commands = {}
local group_position = {x = group.position.x, y = group.position.y}
local step_length = this.unit_group_command_step_length
local step_length = unit_group_command_step_length
if math_random(1, 2) == 1 then
if not enable_side_target then
goto continue
end
local side_target = SideTargets.get_side_target()
if side_target then
local target_position = side_target.position
local distance_to_target =
math_floor(
math_sqrt((target_position.x - group_position.x) ^ 2 + (target_position.y - group_position.y) ^ 2)
)
math_floor(math_sqrt((target_position.x - group_position.x) ^ 2 + (target_position.y - group_position.y) ^ 2))
local steps = math_floor(distance_to_target / step_length) + 1
local vector = {
math_round((target_position.x - group_position.x) / steps, 3),
math_round((target_position.y - group_position.y) / steps, 3)
}
if this.debug then
debug_print(
'get_commmands - to side_target x' .. side_target.position.x .. ' y' .. side_target.position.y
)
local d = WD.get('debug')
if d then
debug_print('get_commmands - to side_target x' .. side_target.position.x .. ' y' .. side_target.position.y)
debug_print('get_commmands - distance_to_target:' .. distance_to_target .. ' steps:' .. steps)
debug_print('get_commmands - vector ' .. vector[1] .. '_' .. vector[2])
end
@ -449,8 +504,7 @@ local function get_commmands(group)
end
end
end
local position =
group.surface.find_non_colliding_position('behemoth-biter', group_position, step_length, 4)
local position = group.surface.find_non_colliding_position('behemoth-biter', group_position, step_length, 4)
if position then
commands[#commands + 1] = {
type = defines.command.attack_area,
@ -489,7 +543,14 @@ local function get_commmands(group)
end
end
local target_position = this.target.position
::continue::
local target = WD.get('target')
if not (target and target.valid) then
return
end
local target_position = target.position
for i = 1, 4, 1 do
local obstacles =
@ -531,7 +592,7 @@ local function get_commmands(group)
commands[#commands + 1] = {
type = defines.command.attack,
target = this.target,
target = target,
distraction = defines.distraction.by_enemy
}
@ -539,13 +600,14 @@ local function get_commmands(group)
end
local function command_unit_group(group)
local this = WD.get()
if not this.unit_group_last_command[group.group_number] then
this.unit_group_last_command[group.group_number] = game.tick - (this.unit_group_command_delay + 1)
local unit_group_last_command = WD.get('unit_group_last_command')
local unit_group_command_delay = WD.get('unit_group_command_delay')
if not unit_group_last_command[group.group_number] then
unit_group_last_command[group.group_number] = game.tick - (unit_group_command_delay + 1)
end
if this.unit_group_last_command[group.group_number] then
if this.unit_group_last_command[group.group_number] + this.unit_group_command_delay > game.tick then
if unit_group_last_command[group.group_number] then
if unit_group_last_command[group.group_number] + unit_group_command_delay > game.tick then
return
end
end
@ -562,56 +624,60 @@ local function command_unit_group(group)
}
)
this.unit_group_last_command[group.group_number] = game.tick
unit_group_last_command[group.group_number] = game.tick
end
local function give_commands_to_unit_groups()
local this = WD.get()
if this.index == 0 then
local index = WD.get('index')
if index == 0 then
return
end
if not this.target then
local target = WD.get('target')
if not (target and target.valid) then
return
end
if not this.target.valid then
return
end
for k, group in pairs(this.unit_groups) do
local unit_groups = WD.get('unit_groups')
for k, group in pairs(unit_groups) do
if not group.valid then
this.unit_groups[k] = nil
this.index = this.index - 1
if this.index <= 0 then
this.index = 0
unit_groups[k] = nil
WD.set('index', index - 1)
index = WD.get('index')
if index <= 0 then
WD.set('index', 0)
end
if this.unit_group_last_command[k] then
this.unit_group_last_command[k] = nil
local unit_group_last_command = WD.get('unit_group_last_command')
if unit_group_last_command[k] then
unit_group_last_command[k] = nil
end
end
if type(group) ~= 'number' then
if group.valid then
command_unit_group(group, this)
command_unit_group(group)
end
end
end
end
local function spawn_unit_group()
local this = WD.get()
if not can_units_spawn() then
return
end
if not this.target then
local target = WD.get('target')
if not (target and target.valid) then
return
end
if not this.target.valid then
local max_active_unit_groups = WD.get('max_active_unit_groups')
if get_active_unit_groups_count() >= max_active_unit_groups then
return
end
if get_active_unit_groups_count() >= this.max_active_unit_groups then
return
end
local surface = game.surfaces[this.surface_index]
local surface_index = WD.get('surface_index')
local surface = game.surfaces[surface_index]
set_group_spawn_position(surface)
local pos = this.spawn_position
local spawn_position = WD.get('spawn_position')
local pos = spawn_position
if not surface.can_place_entity({name = 'behemoth-biter', position = pos}) then
return
end
@ -624,16 +690,15 @@ local function spawn_unit_group()
end
end
BiterRolls.wave_defense_set_unit_raffle(this.wave_number)
local wave_number = WD.get('wave_number')
BiterRolls.wave_defense_set_unit_raffle(wave_number)
debug_print('Spawning unit group at x' .. this.spawn_position.x .. ' y' .. this.spawn_position.y)
local position = this.spawn_position
debug_print('Spawning unit group at x' .. spawn_position.x .. ' y' .. spawn_position.y)
local position = spawn_position
local unit_group = surface.create_unit_group({position = position, force = 'enemy'})
local group_size =
math_floor(
this.average_unit_group_size * group_size_modifier_raffle[math_random(1, group_size_modifier_raffle_size)]
)
local average_unit_group_size = WD.get('average_unit_group_size')
local group_size = math_floor(average_unit_group_size * group_size_modifier_raffle[math_random(1, group_size_modifier_raffle_size)])
for _ = 1, group_size, 1 do
local biter = spawn_biter(surface)
if not biter then
@ -642,10 +707,14 @@ local function spawn_unit_group()
unit_group.add_member(biter)
end
if this.boss_wave then
local count = math_random(1, math_floor(this.wave_number * 0.01) + 2)
if count > 8 then
count = 8
local boss_wave = WD.get('boss_wave')
if boss_wave then
local count = math_random(1, math_floor(wave_number * 0.01) + 2)
if count > 16 then
count = 16
end
if count <= 1 then
count = 4
end
for _ = 1, count, 1 do
local biter = spawn_biter(surface, true)
@ -654,22 +723,32 @@ local function spawn_unit_group()
end
unit_group.add_member(biter)
end
this.boss_wave = false
WD.set('boss_wave', false)
end
this.unit_groups[unit_group.group_number] = unit_group
if unit_group then
unit_group.start_moving()
end
local unit_groups = WD.get('unit_groups')
unit_groups[unit_group.group_number] = unit_group
if math_random(1, 2) == 1 then
this.random_group = unit_group.group_number
WD.set('random_group', unit_group.group_number)
end
this.index = this.index + 1
local index = WD.get('index')
WD.set('index', index + 1)
return true
end
local function log_threat()
local this = WD.get()
this.threat_log_index = this.threat_log_index + 1
this.threat_log[this.threat_log_index] = this.threat
if this.threat_log_index > 900 then
this.threat_log[this.threat_log_index - 901] = nil
local threat_log_index = WD.get('threat_log_index')
WD.set('threat_log_index', threat_log_index + 1)
local threat_log = WD.get('threat_log')
local threat = WD.get('threat')
threat_log_index = WD.get('threat_log_index')
threat_log[threat_log_index] = threat
if threat_log_index > 900 then
threat_log[threat_log_index - 901] = nil
end
end
@ -685,17 +764,19 @@ local tick_tasks = {
}
local function on_tick()
local this = WD.get()
if this.game_lost then
local tick = game.tick
local game_lost = WD.get('game_lost')
if game_lost then
return
end
if game.tick > this.next_wave then
local next_wave = WD.get('next_wave')
if tick > next_wave then
set_next_wave()
end
local t = game.tick % 300
local t2 = game.tick % 18000
local t = tick % 300
local t2 = tick % 18000
if tick_tasks[t] then
tick_tasks[t]()
@ -704,8 +785,9 @@ local function on_tick()
tick_tasks[t2]()
end
if this.enable_threat_log then
if game.tick % 60 == 0 then
local enable_threat_log = WD.get('enable_threat_log')
if enable_threat_log then
if tick % 60 == 0 then
log_threat()
end
end

View File

@ -17,28 +17,35 @@ local side_target_types = {
['solar-panel'] = true
}
local function get_random_target(wave_defense_table)
local r = math.random(1, wave_defense_table.side_target_count)
if not wave_defense_table.side_targets[r] then
table.remove(wave_defense_table.side_targets, r)
wave_defense_table.side_target_count = wave_defense_table.side_target_count - 1
local function get_random_target()
local side_target_count = WD.get('side_target_count')
local side_targets = WD.get('side_targets')
local r = math.random(1, side_target_count)
if not side_targets[r] then
table.remove(side_targets, r)
WD.set('side_target_count', side_target_count - 1)
return
end
if not wave_defense_table.side_targets[r].valid then
table.remove(wave_defense_table.side_targets, r)
wave_defense_table.side_target_count = wave_defense_table.side_target_count - 1
if not side_targets[r].valid then
table.remove(side_targets, r)
WD.set('side_target_count', side_target_count - 1)
return
end
return wave_defense_table.side_targets[r]
side_targets = WD.get('side_targets')
return side_targets[r]
end
function Public.get_side_target()
local wave_defense_table = WD.get_table()
local enable_side_target = WD.get('enable_side_target')
if not enable_side_target then
return
end
local side_target_count = WD.get('side_target_count')
for _ = 1, 512, 1 do
if wave_defense_table.side_target_count == 0 then
if side_target_count == 0 then
return
end
local target = get_random_target(wave_defense_table)
local target = get_random_target()
if target then
return target
end
@ -46,19 +53,27 @@ function Public.get_side_target()
end
local function add_entity(entity)
local wave_defense_table = WD.get_table()
local enable_side_target = WD.get('enable_side_target')
if not enable_side_target then
return
end
local surface_index = WD.get('surface_index')
--skip entities that are on another surface
if entity.surface.index ~= wave_defense_table.surface_index then
return
end
if wave_defense_table.side_target_count >= 512 then
if entity.surface.index ~= surface_index then
return
end
local side_target_count = WD.get('side_target_count')
if side_target_count >= 512 then
return
end
local side_targets = WD.get('side_targets')
--add entity to the side target list
table.insert(wave_defense_table.side_targets, entity)
wave_defense_table.side_target_count = wave_defense_table.side_target_count + 1
table.insert(side_targets, entity)
WD.set('side_target_count', side_target_count + 1)
end
local function on_built_entity(event)

View File

@ -63,9 +63,11 @@ function Public.reset_wave_defense()
this.biter_health_boost = 1
this.alert_boss_wave = false
this.remove_entities = false
this.enable_side_target = false
this.enable_threat_log = true
this.disable_threat_below_zero = false
this.check_collapse_position = true
this.modified_boss_health = true
end
function Public.get(key)
@ -77,11 +79,11 @@ function Public.get(key)
end
function Public.set(key, value)
if key then
return this[key]
elseif key and value then
if key and (value or value == false) then
this[key] = value
return this[key]
elseif key then
return this[key]
else
return this
end
@ -90,10 +92,8 @@ end
Public.get_table = Public.get
function Public.clear_corpses(value)
if value then
if (value or value == false) then
this.clear_corpses = value
else
this.clear_corpses = false
end
return this.clear_corpses
end
@ -106,11 +106,9 @@ function Public.get_disable_threat_below_zero()
return this.disable_threat_below_zero
end
function Public.set_disable_threat_below_zero(value)
if value then
this.disable_threat_below_zero = value
else
this.disable_threat_below_zero = false
function Public.set_disable_threat_below_zero(boolean)
if (boolean or boolean == false) then
this.disable_threat_below_zero = boolean
end
return this.disable_threat_below_zero
end
@ -119,54 +117,60 @@ function Public.get_alert_boss_wave()
return this.get_alert_boss_wave
end
function Public.alert_boss_wave(value)
if value then
this.alert_boss_wave = value
else
this.alert_boss_wave = false
function Public.alert_boss_wave(boolean)
if (boolean or boolean == false) then
this.alert_boss_wave = boolean
end
return this.alert_boss_wave
end
function Public.set_spawn_position(value)
if type(value) == 'table' then
this.spawn_position = value
function Public.set_spawn_position(tbl)
if type(tbl) == 'table' then
this.spawn_position = tbl
else
error('Value must be of type table.')
error('Tbl must be of type table.')
end
return this.spawn_position
end
function Public.remove_entities(value)
if value then
this.remove_entities = value
else
this.remove_entities = false
function Public.remove_entities(boolean)
if (boolean or boolean == false) then
this.remove_entities = boolean
end
return this.remove_entities
end
function Public.enable_threat_log(value)
if value then
this.enable_threat_log = value
else
this.enable_threat_log = false
function Public.enable_threat_log(boolean)
if (boolean or boolean == false) then
this.enable_threat_log = boolean
end
return this.enable_threat_log
end
function Public.check_collapse_position(value)
if value then
this.check_collapse_position = value
else
this.check_collapse_position = false
function Public.check_collapse_position(boolean)
if (boolean or boolean == false) then
this.check_collapse_position = boolean
end
return this.check_collapse_position
end
function Public.set_biter_health_boost(value)
if value and type(value) == 'number' then
this.biter_health_boost = value
function Public.enable_side_target(boolean)
if (boolean or boolean == false) then
this.enable_side_target = boolean
end
return this.enable_side_target
end
function Public.modified_boss_health(boolean)
if (boolean or boolean == false) then
this.modified_boss_health = boolean
end
return this.modified_boss_health
end
function Public.set_biter_health_boost(number)
if number and type(number) == 'number' then
this.biter_health_boost = number
else
this.biter_health_boost = 1
end

View File

@ -1,14 +1,15 @@
local WD = require 'modules.wave_defense.table'
local threat_values = require 'modules.wave_defense.threat_values'
local Event = require 'utils.event'
local BiterRolls = require 'modules.wave_defense.biter_rolls'
local math_random = math.random
local Public = {}
local function remove_unit(entity)
local wave_defense_table = WD.get_table()
local active_biters = WD.get('active_biters')
local unit_number = entity.unit_number
if not wave_defense_table.active_biters[unit_number] then
if not active_biters[unit_number] then
return
end
local m = 1
@ -16,13 +17,17 @@ local function remove_unit(entity)
m = 1 / global.biter_health_boost_units[unit_number][2]
end
local active_threat_loss = math.round(threat_values[entity.name] * m, 2)
wave_defense_table.active_biter_threat = wave_defense_table.active_biter_threat - active_threat_loss
wave_defense_table.active_biter_count = wave_defense_table.active_biter_count - 1
wave_defense_table.active_biters[unit_number] = nil
local active_biter_threat = WD.get('active_biter_threat')
WD.set('active_biter_threat', active_biter_threat - active_threat_loss)
local active_biter_count = WD.get('active_biter_count')
WD.set('active_biter_count', active_biter_count - 1)
active_biters[unit_number] = nil
end
local function place_nest_near_unit_group(wave_defense_table)
local group = wave_defense_table.unit_groups[wave_defense_table.random_group]
local function place_nest_near_unit_group()
local unit_groups = WD.get('unit_groups')
local random_group = WD.get('random_group')
local group = unit_groups[random_group]
if not group then
return
end
@ -47,7 +52,7 @@ local function place_nest_near_unit_group(wave_defense_table)
if not position then
return
end
local r = wave_defense_table.nest_building_density
local r = WD.get('nest_building_density')
if
unit.surface.count_entities_filtered(
{
@ -60,42 +65,51 @@ local function place_nest_near_unit_group(wave_defense_table)
return
end
local spawner = unit.surface.create_entity({name = name, position = position, force = unit.force})
wave_defense_table.nests[#wave_defense_table.nests + 1] = spawner
local nests = WD.get('nests')
nests[#nests + 1] = spawner
unit.surface.create_entity({name = 'blood-explosion-huge', position = position})
unit.surface.create_entity({name = 'blood-explosion-huge', position = unit.position})
remove_unit(unit)
unit.destroy()
wave_defense_table.threat = wave_defense_table.threat - threat_values[name]
local threat = WD.get('threat')
WD.set('threat', threat - threat_values[name])
return true
end
function Public.build_nest()
local wave_defense_table = WD.get_table()
if wave_defense_table.threat < 1024 then
local threat = WD.get('threat')
if threat < 1024 then
return
end
if wave_defense_table.index == 0 then
local index = WD.get('index')
if index == 0 then
return
end
for _ = 1, 2, 1 do
if place_nest_near_unit_group(wave_defense_table) then
if place_nest_near_unit_group() then
return
end
end
end
function Public.build_worm()
local wave_defense_table = WD.get_table()
if wave_defense_table.threat < 512 then
local threat = WD.get('threat')
if threat < 512 then
return
end
if math_random(1, wave_defense_table.worm_building_chance) ~= 1 then
local worm_building_chance = WD.get('worm_building_chance')
if math_random(1, worm_building_chance) ~= 1 then
return
end
if wave_defense_table.index == 0 then
local index = WD.get('index')
if index == 0 then
return
end
local group = wave_defense_table.unit_groups[wave_defense_table.random_group]
local random_group = WD.get('random_group')
local unit_groups = WD.get('unit_groups')
local group = unit_groups[random_group]
if not group then
return
end
@ -112,13 +126,17 @@ function Public.build_worm()
if not unit.valid then
return
end
local wave_number = WD.get('wave_number')
local position = unit.surface.find_non_colliding_position('assembling-machine-1', unit.position, 8, 1)
BiterRolls.wave_defense_set_worm_raffle(wave_defense_table.wave_number)
BiterRolls.wave_defense_set_worm_raffle(wave_number)
local worm = BiterRolls.wave_defense_roll_worm_name()
if not position then
return
end
local r = wave_defense_table.worm_building_density
local worm_building_density = WD.get('worm_building_density')
local r = worm_building_density
if
unit.surface.count_entities_filtered(
{
@ -135,52 +153,12 @@ function Public.build_worm()
unit.surface.create_entity({name = 'blood-explosion-huge', position = unit.position})
remove_unit(unit)
unit.destroy()
wave_defense_table.threat = wave_defense_table.threat - threat_values[worm]
end
--[[
local function get_circle_vectors(radius)
local vectors = {}
for x = radius * -1, radius, 1 do
for y = radius * -1, radius, 1 do
if math.sqrt(x^2 + y^2) <= radius then
vectors[#vectors + 1] = {x, y}
end
end
end
return vectors
WD.set('threat', threat - threat_values[worm])
end
local acid_nova_entities = {
["small-biter"] = {projectile = "acid-stream-worm-small", vectors = get_circle_vectors(3), threat_cost = 32},
["medium-biter"] = {projectile = "acid-stream-worm-medium", vectors = get_circle_vectors(4), threat_cost = 64},
["big-biter"] = {projectile = "acid-stream-worm-big", vectors = get_circle_vectors(5), threat_cost = 96},
["behemoth-biter"] = {projectile = "acid-stream-worm-behemoth", vectors = get_circle_vectors(6), threat_cost = 128},
}
local function acid_nova(entity)
local wave_defense_table = WD.get_table()
if not acid_nova_entities[entity.name] then return end
if wave_defense_table.threat < 100000 then return end
if math.random(1, 32) ~= 1 then return end
for _ = 1, 8, 1 do
local i = math_random(1, #acid_nova_entities[entity.name].vectors)
entity.surface.create_entity({
name = acid_nova_entities[entity.name].projectile,
position = entity.position,
force = entity.force.name,
source = entity.position,
target = {x = entity.position.x + acid_nova_entities[entity.name].vectors[i][1], y = entity.position.y + acid_nova_entities[entity.name].vectors[i][2]},
max_range = 10,
speed = 0.001
})
end
wave_defense_table.threat = wave_defense_table.threat - acid_nova_entities[entity.name].threat_cost
return true
end
]]
local function shred_simple_entities(entity)
local wave_defense_table = WD.get_table()
if wave_defense_table.threat < 25000 then
local threat = WD.get('threat')
if threat < 25000 then
return
end
local simple_entities =
@ -196,7 +174,7 @@ local function shred_simple_entities(entity)
if #simple_entities > 1 then
table.shuffle_table(simple_entities)
end
local r = math.floor(wave_defense_table.threat * 0.00004)
local r = math.floor(threat * 0.00004)
if r < 1 then
r = 1
end
@ -217,71 +195,67 @@ local function shred_simple_entities(entity)
if damage_dealt == 0 then
return
end
local threat_cost = math.floor(damage_dealt * wave_defense_table.simple_entity_shredding_cost_modifier)
local simple_entity_shredding_cost_modifier = WD.get('simple_entity_shredding_cost_modifier')
local threat_cost = math.floor(damage_dealt * simple_entity_shredding_cost_modifier)
if threat_cost < 1 then
threat_cost = 1
end
wave_defense_table.threat = wave_defense_table.threat - threat_cost
WD.set('threat', threat - threat_cost)
end
local function spawn_unit_spawner_inhabitants(wave_defense_table, entity)
local function spawn_unit_spawner_inhabitants(entity)
if entity.type ~= 'unit-spawner' then
return
end
local count = 8 + math.floor(wave_defense_table.wave_number * 0.02)
local wave_number = WD.get('wave_number')
local count = 8 + math.floor(wave_number * 0.02)
if count > 128 then
count = 128
end
BiterRolls.wave_defense_set_unit_raffle(wave_defense_table.wave_number)
BiterRolls.wave_defense_set_unit_raffle(wave_number)
for _ = 1, count, 1 do
local position = {entity.position.x + (-4 + math.random(0, 8)), entity.position.y + (-4 + math.random(0, 8))}
if math.random(1, 4) == 1 then
entity.surface.create_entity(
{name = BiterRolls.wave_defense_roll_spitter_name(), position = position, force = 'enemy'}
)
entity.surface.create_entity({name = BiterRolls.wave_defense_roll_spitter_name(), position = position, force = 'enemy'})
else
entity.surface.create_entity(
{name = BiterRolls.wave_defense_roll_biter_name(), position = position, force = 'enemy'}
)
entity.surface.create_entity({name = BiterRolls.wave_defense_roll_biter_name(), position = position, force = 'enemy'})
end
end
end
local function on_entity_died(event)
local wave_defense_table = WD.get_table()
local entity = event.entity
if not entity.valid then
return
end
local disable_threat_below_zero = WD.get('disable_threat_below_zero')
if entity.type == 'unit' then
--acid_nova(entity)
if not threat_values[entity.name] then
return
end
if wave_defense_table.disable_threat_below_zero then
if wave_defense_table.threat <= 0 then
wave_defense_table.threat = 0
if disable_threat_below_zero then
local threat = WD.get('threat')
if threat <= 0 then
WD.set('threat', 0)
threat = WD.get('threat')
end
wave_defense_table.threat =
math.round(wave_defense_table.threat - threat_values[entity.name] * global.biter_health_boost, 2)
WD.set('threat', math.round(threat - threat_values[entity.name] * global.biter_health_boost, 2))
remove_unit(entity)
else
wave_defense_table.threat =
math.round(wave_defense_table.threat - threat_values[entity.name] * global.biter_health_boost, 2)
local threat = WD.get('threat')
WD.set('threat', math.round(threat - threat_values[entity.name] * global.biter_health_boost, 2))
remove_unit(entity)
end
else
if entity.force.index == 2 then
if entity.health then
if threat_values[entity.name] then
wave_defense_table.threat =
math.round(
wave_defense_table.threat - threat_values[entity.name] * global.biter_health_boost,
2
)
local threat = WD.get('threat')
WD.set('threat', math.round(threat - threat_values[entity.name] * global.biter_health_boost, 2))
end
spawn_unit_spawner_inhabitants(wave_defense_table, entity)
spawn_unit_spawner_inhabitants(entity)
end
end
end
@ -297,7 +271,6 @@ local function on_entity_died(event)
end
end
local event = require 'utils.event'
event.add(defines.events.on_entity_died, on_entity_died)
Event.add(defines.events.on_entity_died, on_entity_died)
return Public