2021-11-14 22:01:01 +02:00
local Public = require ' modules.wave_defense.core '
2020-12-05 19:10:53 +02:00
local Event = require ' utils.event '
2021-02-10 22:21:29 +02:00
local BiterHealthBooster = require ' modules.biter_health_booster_v2 '
2021-05-25 22:19:20 +02:00
local Difficulty = require ' modules.difficulty_vote_by_amount '
2020-06-07 13:33:24 +02:00
local Alert = require ' utils.alert '
2022-06-26 22:37:41 +02:00
local Server = require ' utils.server '
2020-10-30 23:05:05 +02:00
2021-11-28 21:42:38 +02:00
local random = math.random
local floor = math.floor
local sqrt = math.sqrt
local round = math.round
2019-11-09 14:18:30 +02:00
2019-10-08 01:17:00 +02:00
local function debug_print ( msg )
2021-11-14 22:01:01 +02:00
local debug = Public.get ( ' debug ' )
2020-08-17 20:18:06 +02:00
if not debug then
2020-08-09 20:23:45 +02:00
return
end
print ( ' WaveDefense: ' .. msg )
2019-10-08 01:17:00 +02:00
end
2021-11-14 14:02:00 +02:00
local function debug_print_health ( msg )
2021-11-14 22:01:01 +02:00
local debug = Public.get ( ' debug_health ' )
2021-11-14 14:02:00 +02:00
if not debug then
return
end
print ( ' [HEALTHBOOSTER]: ' .. msg )
end
2020-11-23 23:10:32 +02:00
local function valid ( userdata )
if not ( userdata and userdata.valid ) then
return false
end
return true
end
2020-11-18 16:24:22 +02:00
2021-11-11 02:56:03 +02:00
local function shuffle ( tbl )
local size = # tbl
for i = size , 1 , - 1 do
local rand = math.random ( size )
tbl [ i ] , tbl [ rand ] = tbl [ rand ] , tbl [ i ]
end
return tbl
end
2020-11-23 23:10:32 +02:00
local function find_initial_spot ( surface , position )
2021-11-14 22:01:01 +02:00
local spot = Public.get ( ' spot ' )
2020-11-23 23:10:32 +02:00
if not spot then
2021-11-13 03:09:19 +02:00
local pos = surface.find_non_colliding_position ( ' rocket-silo ' , position , 128 , 1 )
2020-12-05 19:10:53 +02:00
if not pos then
2021-11-13 03:09:19 +02:00
pos = surface.find_non_colliding_position ( ' rocket-silo ' , position , 148 , 1 )
2020-12-05 19:10:53 +02:00
end
if not pos then
2021-11-13 03:09:19 +02:00
pos = surface.find_non_colliding_position ( ' rocket-silo ' , position , 164 , 1 )
end
if not pos then
pos = surface.find_non_colliding_position ( ' rocket-silo ' , position , 200 , 1 )
2021-11-11 02:56:03 +02:00
end
if not pos then
pos = position
end
2021-11-28 21:42:38 +02:00
if random ( 1 , 2 ) == 1 then
2021-11-19 23:21:31 +02:00
local random_pos = {
{ x = pos.x - 10 , y = pos.y - 5 } ,
{ x = pos.x + 10 , y = pos.y + 5 } ,
{ x = pos.x - 10 , y = pos.y + 5 } ,
{ x = pos.x + 10 , y = pos.y - 5 }
}
2021-11-11 02:56:03 +02:00
local actual_pos = shuffle ( random_pos )
pos = { x = actual_pos [ 1 ] . x , y = actual_pos [ 1 ] . y }
2020-12-05 19:10:53 +02:00
end
2021-11-11 02:56:03 +02:00
2020-12-05 19:10:53 +02:00
if not pos then
pos = position
end
2021-11-14 22:01:01 +02:00
Public.set ( ' spot ' , pos )
2020-11-23 23:10:32 +02:00
return pos
else
2021-11-14 22:01:01 +02:00
spot = Public.get ( ' spot ' )
2020-11-23 23:10:32 +02:00
return spot
end
2020-10-22 13:32:18 +02:00
end
2020-11-18 16:24:22 +02:00
local function is_closer ( pos1 , pos2 , pos )
return ( ( pos1.x - pos.x ) ^ 2 + ( pos1.y - pos.y ) ^ 2 ) < ( ( pos2.x - pos.x ) ^ 2 + ( pos2.y - pos.y ) ^ 2 )
2020-11-17 16:03:14 +02:00
end
2020-10-22 13:32:18 +02:00
local function shuffle_distance ( tbl , position )
local size = # tbl
for i = size , 1 , - 1 do
2021-11-28 21:42:38 +02:00
local rand = random ( size )
2020-10-22 13:32:18 +02:00
if is_closer ( tbl [ i ] . position , tbl [ rand ] . position , position ) and i > rand then
tbl [ i ] , tbl [ rand ] = tbl [ rand ] , tbl [ i ]
end
end
return tbl
end
2020-11-23 23:10:32 +02:00
local function is_position_near ( pos_to_check , check_against )
local function inside ( pos )
return pos.x >= pos_to_check.x and pos.y >= pos_to_check.y and pos.x <= pos_to_check.x and pos.y <= pos_to_check.y
end
if inside ( check_against ) then
return true
end
return false
end
2020-08-04 12:10:15 +02:00
local function remove_trees ( entity )
2020-11-23 23:10:32 +02:00
if not valid ( entity ) then
return
end
2020-08-09 20:23:45 +02:00
local surface = entity.surface
2020-11-18 16:24:22 +02:00
local radius = 10
2020-08-09 20:23:45 +02:00
local pos = entity.position
local area = { { pos.x - radius , pos.y - radius } , { pos.x + radius , pos.y + radius } }
local trees = surface.find_entities_filtered { area = area , type = ' tree ' }
if # trees > 0 then
2022-05-12 22:19:00 +02:00
for _ , tree in pairs ( trees ) do
2020-08-09 20:23:45 +02:00
if tree and tree.valid then
tree.destroy ( )
end
end
end
2020-08-04 12:10:15 +02:00
end
local function remove_rocks ( entity )
2020-11-23 23:10:32 +02:00
if not valid ( entity ) then
return
end
2020-08-09 20:23:45 +02:00
local surface = entity.surface
2020-11-18 16:24:22 +02:00
local radius = 10
2020-08-09 20:23:45 +02:00
local pos = entity.position
local area = { { pos.x - radius , pos.y - radius } , { pos.x + radius , pos.y + radius } }
local rocks = surface.find_entities_filtered { area = area , type = ' simple-entity ' }
if # rocks > 0 then
2022-05-12 22:19:00 +02:00
for _ , rock in pairs ( rocks ) do
2020-08-09 20:23:45 +02:00
if rock and rock.valid then
rock.destroy ( )
end
end
end
end
2020-10-30 23:05:05 +02:00
2020-11-23 23:10:32 +02:00
local function fill_tiles ( entity , size )
if not valid ( entity ) then
return
end
2020-11-18 16:24:22 +02:00
local surface = entity.surface
2020-11-23 23:10:32 +02:00
local radius = size or 10
2020-11-18 16:24:22 +02:00
local pos = entity.position
local t = {
' water ' ,
' water-green ' ,
' water-mud ' ,
' water-shallow ' ,
' deepwater ' ,
' deepwater-green '
}
local area = { { pos.x - radius , pos.y - radius } , { pos.x + radius , pos.y + radius } }
local tiles = surface.find_tiles_filtered { area = area , name = t }
if # tiles > 0 then
for _ , tile in pairs ( tiles ) do
surface.set_tiles ( { { name = ' sand-1 ' , position = tile.position } } , true )
end
end
2020-11-23 23:10:32 +02:00
debug_print ( ' fill_tiles - filled tiles cause we found non-placable tiles. ' )
end
local function get_spawn_pos ( )
2021-11-14 22:01:01 +02:00
local surface_index = Public.get ( ' surface_index ' )
2020-11-23 23:10:32 +02:00
local surface = game.surfaces [ surface_index ]
if not surface then
return debug_print ( ' get_spawn_pos - surface was not valid? ' )
end
local c = 0
:: retry ::
2021-11-14 22:01:01 +02:00
local initial_position = Public.get ( ' spawn_position ' )
2020-11-23 23:10:32 +02:00
2021-03-01 22:49:30 +02:00
local located_position = find_initial_spot ( surface , initial_position )
2021-11-13 03:09:19 +02:00
local valid_position = surface.find_non_colliding_position ( ' stone-furnace ' , located_position , 32 , 1 )
2021-11-14 22:01:01 +02:00
local debug = Public.get ( ' debug ' )
2021-03-01 22:49:30 +02:00
if debug then
if valid_position then
local x = valid_position.x
local y = valid_position.y
game.print ( ' [gps= ' .. x .. ' , ' .. y .. ' , ' .. surface.name .. ' ] ' )
end
end
if not valid_position then
2021-11-14 22:01:01 +02:00
local remove_entities = Public.get ( ' remove_entities ' )
2020-11-23 23:10:32 +02:00
if remove_entities then
c = c + 1
2021-11-14 22:01:01 +02:00
valid_position = Public.get ( ' spawn_position ' )
2021-03-01 22:49:30 +02:00
debug_print ( serpent.block ( ' valid_position - x: ' .. valid_position.x .. ' y: ' .. valid_position.y ) )
remove_trees ( { surface = surface , position = valid_position , valid = true } )
remove_rocks ( { surface = surface , position = valid_position , valid = true } )
fill_tiles ( { surface = surface , position = valid_position , valid = true } )
2021-11-14 22:01:01 +02:00
Public.set ( ' spot ' , ' nil ' )
2020-11-23 23:10:32 +02:00
if c == 5 then
return debug_print ( ' get_spawn_pos - we could not find a spawning pos? ' )
end
goto retry
else
return debug_print ( ' get_spawn_pos - we could not find a spawning pos? ' )
end
end
2021-03-01 22:49:30 +02:00
debug_print ( serpent.block ( ' valid_position - x: ' .. valid_position.x .. ' y: ' .. valid_position.y ) )
return valid_position
2020-11-18 16:24:22 +02:00
end
2019-10-15 04:20:40 +02:00
local function is_unit_valid ( biter )
2021-11-14 22:01:01 +02:00
local max_biter_age = Public.get ( ' max_biter_age ' )
2020-08-09 20:23:45 +02:00
if not biter.entity then
debug_print ( ' is_unit_valid - unit destroyed - does no longer exist ' )
return false
end
if not biter.entity . valid then
debug_print ( ' is_unit_valid - unit destroyed - invalid ' )
return false
end
if not biter.entity . unit_group then
debug_print ( ' is_unit_valid - unit destroyed - no unitgroup ' )
return false
end
2020-11-17 13:45:47 +02:00
if biter.spawn_tick + max_biter_age < game.tick then
2020-08-09 20:23:45 +02:00
debug_print ( ' is_unit_valid - unit destroyed - timed out ' )
return false
end
return true
2019-10-07 22:40:05 +02:00
end
2019-10-25 08:09:39 +02:00
local function refresh_active_unit_threat ( )
2021-11-14 22:01:01 +02:00
local active_biter_threat = Public.get ( ' active_biter_threat ' )
2021-11-28 21:42:38 +02:00
local generated_units = Public.get ( ' generated_units ' )
2020-11-17 13:45:47 +02:00
debug_print ( ' refresh_active_unit_threat - current value ' .. active_biter_threat )
local biter_threat = 0
2021-11-28 21:42:38 +02:00
for k , biter in pairs ( generated_units.active_biters ) do
2020-11-23 23:10:32 +02:00
if valid ( biter.entity ) then
2021-11-14 22:01:01 +02:00
biter_threat = biter_threat + Public.threat_values [ biter.entity . name ]
2020-11-23 23:10:32 +02:00
else
2021-11-28 21:42:38 +02:00
generated_units.active_biters [ k ] = nil
2020-08-09 20:23:45 +02:00
end
end
2021-02-10 22:21:29 +02:00
local biter_health_boost = BiterHealthBooster.get ( ' biter_health_boost ' )
2021-11-28 21:42:38 +02:00
Public.set ( ' active_biter_threat ' , round ( biter_threat * biter_health_boost , 2 ) )
2020-11-17 13:45:47 +02:00
debug_print ( ' refresh_active_unit_threat - new value ' .. active_biter_threat )
2021-11-28 21:42:38 +02:00
if generated_units.unit_group_pos . index > 500 then
generated_units.unit_group_pos . positions = { }
generated_units.unit_group_pos . index = 0
2021-11-19 23:21:31 +02:00
end
2019-10-25 08:09:39 +02:00
end
2019-10-14 06:52:17 +02:00
local function time_out_biters ( )
2021-11-28 21:42:38 +02:00
local generated_units = Public.get ( ' generated_units ' )
2021-11-14 22:01:01 +02:00
local active_biter_count = Public.get ( ' active_biter_count ' )
local active_biter_threat = Public.get ( ' active_biter_threat ' )
2020-11-23 23:10:32 +02:00
2021-11-28 21:42:38 +02:00
if active_biter_count >= 100 and # generated_units.active_biters <= 10 then
2021-11-14 22:01:01 +02:00
Public.set ( ' active_biter_count ' , 50 )
2020-11-23 23:10:32 +02:00
end
2021-02-10 22:21:29 +02:00
local biter_health_boost = BiterHealthBooster.get ( ' biter_health_boost ' )
2021-11-28 21:42:38 +02:00
for k , biter in pairs ( generated_units.active_biters ) do
2020-08-09 20:23:45 +02:00
if not is_unit_valid ( biter ) then
2021-11-14 22:01:01 +02:00
Public.set ( ' active_biter_count ' , active_biter_count - 1 )
2020-11-23 23:10:32 +02:00
if biter.entity then
if biter.entity . valid then
2021-11-28 21:42:38 +02:00
Public.set ( ' active_biter_threat ' , active_biter_threat - round ( Public.threat_values [ biter.entity . name ] * biter_health_boost , 2 ) )
2020-11-23 23:10:32 +02:00
if biter.entity . force.index == 2 then
biter.entity . destroy ( )
end
debug_print ( ' time_out_biters: ' .. k .. ' got deleted. ' )
2020-08-09 20:23:45 +02:00
end
end
2021-11-28 21:42:38 +02:00
generated_units.active_biters [ k ] = nil
2020-08-09 20:23:45 +02:00
end
end
2019-10-07 04:37:23 +02:00
end
2020-10-22 12:44:14 +02:00
local function get_random_close_spawner ( )
2021-11-28 21:42:38 +02:00
local generated_units = Public.get ( ' generated_units ' )
2021-11-14 22:01:01 +02:00
local target = Public.get ( ' target ' )
local get_random_close_spawner_attempts = Public.get ( ' get_random_close_spawner_attempts ' )
2020-11-17 13:45:47 +02:00
local center = target.position
2020-10-22 12:44:14 +02:00
local spawner
2020-11-18 16:24:22 +02:00
local retries = 0
2022-04-18 01:17:16 +02:00
for _ = 1 , get_random_close_spawner_attempts , 1 do
2020-10-22 12:44:14 +02:00
:: retry ::
2021-11-28 21:42:38 +02:00
if # generated_units.nests < 1 then
2020-10-22 12:44:14 +02:00
return false
end
2021-11-28 21:42:38 +02:00
local k = random ( 1 , # generated_units.nests )
local spawner_2 = generated_units.nests [ k ]
2020-10-22 17:39:23 +02:00
if not spawner_2 or not spawner_2.valid then
2021-11-28 21:42:38 +02:00
generated_units.nests [ k ] = nil
2020-11-18 16:24:22 +02:00
retries = retries + 1
if retries == 5 then
break
end
2020-10-22 12:44:14 +02:00
goto retry
end
2022-04-18 01:17:16 +02:00
if not spawner or ( 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
2020-08-09 20:23:45 +02:00
spawner = spawner_2
2021-11-12 19:09:06 +02:00
if spawner and spawner.position then
debug_print ( ' get_random_close_spawner - Found at x ' .. spawner.position . x .. ' y ' .. spawner.position . y )
end
2020-08-09 20:23:45 +02:00
end
end
return spawner
2019-10-07 01:46:26 +02:00
end
2020-11-17 13:45:47 +02:00
local function get_random_character ( )
2020-08-09 20:23:45 +02:00
local characters = { }
2021-11-14 22:01:01 +02:00
local surface_index = Public.get ( ' surface_index ' )
2020-10-22 12:44:14 +02:00
local p = game.connected_players
for _ , player in pairs ( p ) do
2020-08-09 20:23:45 +02:00
if player.character then
if player.character . valid then
2020-11-17 13:45:47 +02:00
if player.character . surface.index == surface_index then
2020-08-09 20:23:45 +02:00
characters [ # characters + 1 ] = player.character
end
end
end
end
if not characters [ 1 ] then
return
end
2021-11-28 21:42:38 +02:00
return characters [ random ( 1 , # characters ) ]
2020-01-01 15:05:49 +02:00
end
2019-10-25 08:09:39 +02:00
local function set_main_target ( )
2021-11-14 22:01:01 +02:00
local target = Public.get ( ' target ' )
2020-11-17 13:45:47 +02:00
if target then
if target.valid then
2020-08-09 20:23:45 +02:00
return
end
end
2021-11-14 22:01:01 +02:00
local unit_groups_size = Public.get ( ' unit_groups_size ' )
2021-11-11 02:56:03 +02:00
if unit_groups_size < 0 then
unit_groups_size = 0
end
2021-11-14 22:01:01 +02:00
Public.set ( ' unit_groups_size ' , unit_groups_size )
2021-11-11 02:56:03 +02:00
2021-11-14 22:01:01 +02:00
local sec_target = Public.get_side_target ( )
2020-11-17 13:45:47 +02:00
if not sec_target then
sec_target = get_random_character ( )
2020-08-09 20:23:45 +02:00
end
2020-11-17 13:45:47 +02:00
if not sec_target then
2020-08-09 20:23:45 +02:00
return
end
2021-11-14 22:01:01 +02:00
Public.set ( ' target ' , sec_target )
2022-04-18 01:17:16 +02:00
debug_print ( ' set_main_target -- New main target ' .. sec_target.name .. ' at position x ' .. sec_target.position . x .. ' y ' .. sec_target.position . y .. ' selected. ' )
2019-10-25 08:09:39 +02:00
end
2019-10-12 04:06:48 +02:00
local function set_group_spawn_position ( surface )
2020-10-22 12:44:14 +02:00
local spawner = get_random_close_spawner ( )
2020-08-09 20:23:45 +02:00
if not spawner then
return
end
2020-11-23 23:10:32 +02:00
local position = surface.find_non_colliding_position ( ' behemoth-biter ' , spawner.position , 128 , 1 )
2020-08-09 20:23:45 +02:00
if not position then
return
end
2021-11-14 22:01:01 +02:00
Public.set ( ' spawn_position ' , { x = position.x , y = position.y } )
2020-11-18 16:24:22 +02:00
local spawn_position = get_spawn_pos ( )
2020-11-17 13:45:47 +02:00
debug_print ( ' set_group_spawn_position -- Changed position to x ' .. spawn_position.x .. ' y ' .. spawn_position.y .. ' . ' )
2019-10-07 01:46:26 +02:00
end
local function set_enemy_evolution ( )
2021-11-14 22:01:01 +02:00
local wave_number = Public.get ( ' wave_number ' )
2021-11-28 21:42:38 +02:00
local generated_units = Public.get ( ' generated_units ' )
2021-11-14 22:01:01 +02:00
local threat = Public.get ( ' threat ' )
2020-11-17 13:45:47 +02:00
local evolution_factor = wave_number * 0.001
2021-05-23 17:03:52 +02:00
local enemy = game.forces . enemy
2021-11-19 23:21:31 +02:00
local biter_health_boost = 1
2020-08-09 20:23:45 +02:00
if evolution_factor > 1 then
evolution_factor = 1
end
2021-11-28 21:42:38 +02:00
if not next ( generated_units.active_biters ) then
2021-11-19 23:21:31 +02:00
Public.set ( ' active_biter_count ' , 0 )
2020-10-25 18:02:37 +02:00
end
2021-11-19 23:21:31 +02:00
if threat > 50000 then
2021-11-28 21:42:38 +02:00
biter_health_boost = round ( biter_health_boost + ( threat - 50000 ) * 0.000033 , 3 )
2020-10-30 23:05:05 +02:00
end
2020-08-09 20:23:45 +02:00
2021-11-19 23:21:31 +02:00
BiterHealthBooster.set ( ' biter_health_boost ' , biter_health_boost )
2021-11-13 03:09:19 +02:00
2021-05-23 17:03:52 +02:00
if enemy.evolution_factor == 1 and evolution_factor == 1 then
return
end
enemy.evolution_factor = evolution_factor
2019-10-25 08:09:39 +02:00
end
local function can_units_spawn ( )
2021-11-14 22:01:01 +02:00
local threat = Public.get ( ' threat ' )
2020-11-17 13:45:47 +02:00
if threat <= 0 then
2020-08-09 20:23:45 +02:00
debug_print ( ' can_units_spawn - threat too low ' )
2020-11-23 23:10:32 +02:00
time_out_biters ( )
2020-08-09 20:23:45 +02:00
return false
end
2020-11-17 13:45:47 +02:00
2021-11-14 22:01:01 +02:00
local active_biter_count = Public.get ( ' active_biter_count ' )
local max_active_biters = Public.get ( ' max_active_biters ' )
2020-11-17 13:45:47 +02:00
if active_biter_count >= max_active_biters then
2020-08-09 20:23:45 +02:00
debug_print ( ' can_units_spawn - active biter count too high ' )
2020-11-23 23:10:32 +02:00
time_out_biters ( )
2020-08-09 20:23:45 +02:00
return false
end
2020-11-17 13:45:47 +02:00
2021-11-14 22:01:01 +02:00
local active_biter_threat = Public.get ( ' active_biter_threat ' )
2020-11-17 13:45:47 +02:00
if active_biter_threat >= threat then
debug_print ( ' can_units_spawn - active biter threat too high ( ' .. active_biter_threat .. ' ) ' )
2020-11-23 23:10:32 +02:00
time_out_biters ( )
2020-08-09 20:23:45 +02:00
return false
end
return true
2019-10-25 08:09:39 +02:00
end
local function get_active_unit_groups_count ( )
2021-11-28 21:42:38 +02:00
local generated_units = Public.get ( ' generated_units ' )
2020-08-09 20:23:45 +02:00
local count = 0
2020-11-23 23:10:32 +02:00
2021-11-28 21:42:38 +02:00
for k , g in pairs ( generated_units.unit_groups ) do
2020-08-09 20:23:45 +02:00
if g.valid then
if # g.members > 0 then
count = count + 1
else
g.destroy ( )
2021-11-28 21:42:38 +02:00
generated_units.unit_groups [ k ] = nil
2021-11-14 22:01:01 +02:00
local unit_groups_size = Public.get ( ' unit_groups_size ' )
Public.set ( ' unit_groups_size ' , unit_groups_size - 1 )
2020-08-09 20:23:45 +02:00
end
2020-11-23 23:10:32 +02:00
else
2021-11-28 21:42:38 +02:00
generated_units.unit_groups [ k ] = nil
generated_units.unit_group_pos . positions [ k ] = nil
2021-11-14 22:01:01 +02:00
local unit_groups_size = Public.get ( ' unit_groups_size ' )
Public.set ( ' unit_groups_size ' , unit_groups_size - 1 )
2021-11-28 21:42:38 +02:00
if generated_units.unit_group_last_command [ k ] then
generated_units.unit_group_last_command [ k ] = nil
2020-11-23 23:10:32 +02:00
end
2020-08-09 20:23:45 +02:00
end
end
debug_print ( ' Active unit group count: ' .. count )
return count
2019-10-07 01:46:26 +02:00
end
2021-11-28 21:42:38 +02:00
local function spawn_biter ( surface , position , forceSpawn , is_boss_biter , unit_settings )
2021-11-11 02:56:03 +02:00
if not forceSpawn then
if not is_boss_biter then
if not can_units_spawn ( ) then
return
end
2020-08-09 20:23:45 +02:00
end
end
2021-02-10 22:21:29 +02:00
local boosted_health = BiterHealthBooster.get ( ' biter_health_boost ' )
2020-11-17 13:45:47 +02:00
2020-08-09 20:23:45 +02:00
local name
2021-11-28 21:42:38 +02:00
if random ( 1 , 100 ) > 73 then
2021-11-14 22:01:01 +02:00
name = Public.wave_defense_roll_spitter_name ( )
2020-08-09 20:23:45 +02:00
else
2021-11-14 22:01:01 +02:00
name = Public.wave_defense_roll_biter_name ( )
2020-08-09 20:23:45 +02:00
end
2021-11-11 02:56:03 +02:00
local old_position = position
2021-11-23 21:28:23 +02:00
position = surface.find_non_colliding_position ( ' steel-chest ' , position , 3 , 1 )
2021-11-11 02:56:03 +02:00
if not position then
2021-11-23 21:28:23 +02:00
position = old_position
2021-11-11 02:56:03 +02:00
end
2020-11-17 13:45:47 +02:00
2020-11-18 16:24:22 +02:00
local biter = surface.create_entity ( { name = name , position = position , force = ' enemy ' } )
2020-08-09 20:23:45 +02:00
biter.ai_settings . allow_destroy_when_commands_fail = true
2021-11-11 02:56:03 +02:00
biter.ai_settings . allow_try_return_to_spawner = false
2020-08-21 13:56:01 +02:00
biter.ai_settings . do_separation = true
2020-11-17 13:45:47 +02:00
2021-11-14 22:01:01 +02:00
local increase_health_per_wave = Public.get ( ' increase_health_per_wave ' )
2021-12-18 15:03:22 +02:00
local boost_units_when_wave_is_above = Public.get ( ' boost_units_when_wave_is_above ' )
local boost_bosses_when_wave_is_above = Public.get ( ' boost_bosses_when_wave_is_above ' )
local wave_number = Public.get ( ' wave_number ' )
2021-02-10 22:21:29 +02:00
2021-12-18 15:03:22 +02:00
if ( increase_health_per_wave and ( wave_number >= boost_units_when_wave_is_above ) ) and not is_boss_biter then
2021-11-14 22:01:01 +02:00
local modified_unit_health = Public.get ( ' modified_unit_health ' )
2021-11-28 21:42:38 +02:00
local final_health = round ( modified_unit_health.current_value * unit_settings.scale_units_by_health [ biter.name ] , 3 )
2021-12-06 11:19:08 +02:00
if final_health < 1 then
final_health = 1
end
2021-11-28 21:42:38 +02:00
debug_print_health ( ' final_health - unit: ' .. biter.name .. ' with h-m: ' .. final_health )
BiterHealthBooster.add_unit ( biter , final_health )
2021-02-10 22:21:29 +02:00
end
2021-12-18 15:03:22 +02:00
if is_boss_biter and ( wave_number >= boost_bosses_when_wave_is_above ) then
2021-11-14 22:01:01 +02:00
local increase_boss_health_per_wave = Public.get ( ' increase_boss_health_per_wave ' )
2021-02-10 22:21:29 +02:00
if increase_boss_health_per_wave then
2021-11-14 22:01:01 +02:00
local modified_boss_unit_health = Public.get ( ' modified_boss_unit_health ' )
2021-11-19 23:21:31 +02:00
BiterHealthBooster.add_boss_unit ( biter , modified_boss_unit_health.current_value , 0.55 )
2020-11-17 13:45:47 +02:00
else
local sum = boosted_health * 5
debug_print ( ' Boss Health Boosted: ' .. sum )
BiterHealthBooster.add_boss_unit ( biter , sum , 0.55 )
end
2020-08-09 20:23:45 +02:00
end
2021-02-10 22:21:29 +02:00
2021-11-28 21:42:38 +02:00
local generated_units = Public.get ( ' generated_units ' )
generated_units.active_biters [ biter.unit_number ] = { entity = biter , spawn_tick = game.tick }
2021-11-14 22:01:01 +02:00
local active_biter_count = Public.get ( ' active_biter_count ' )
Public.set ( ' active_biter_count ' , active_biter_count + 1 )
local active_biter_threat = Public.get ( ' active_biter_threat ' )
2021-11-28 21:42:38 +02:00
Public.set ( ' active_biter_threat ' , active_biter_threat + round ( Public.threat_values [ name ] * boosted_health , 2 ) )
2020-08-09 20:23:45 +02:00
return biter
2019-10-07 01:46:26 +02:00
end
2020-12-05 19:10:53 +02:00
local function increase_biter_damage ( )
2021-11-14 22:01:01 +02:00
local increase_damage_per_wave = Public.get ( ' increase_damage_per_wave ' )
2021-02-04 21:18:31 +02:00
if not increase_damage_per_wave then
return
end
2020-12-05 19:10:53 +02:00
local e = game.forces . enemy
2022-07-10 19:42:07 +02:00
local new = Difficulty.get ( ' value ' ) * 0.04
2021-02-14 22:43:31 +02:00
local melee = new
local bio = new - 0.02
2020-12-05 19:10:53 +02:00
local e_old_melee = e.get_ammo_damage_modifier ( ' melee ' )
local e_old_biological = e.get_ammo_damage_modifier ( ' biological ' )
2021-02-14 22:43:31 +02:00
debug_print ( ' Melee: ' .. melee + e_old_melee )
debug_print ( ' Biological: ' .. bio + e_old_biological )
e.set_ammo_damage_modifier ( ' melee ' , melee + e_old_melee )
e.set_ammo_damage_modifier ( ' biological ' , bio + e_old_biological )
2020-12-05 19:10:53 +02:00
end
2021-02-10 22:21:29 +02:00
local function increase_biters_health ( )
2021-11-14 22:01:01 +02:00
local increase_health_per_wave = Public.get ( ' increase_health_per_wave ' )
2021-02-10 22:21:29 +02:00
if not increase_health_per_wave then
return
end
2021-11-19 23:21:31 +02:00
-- local boosted_health = BiterHealthBooster.get('biter_health_boost')
-- local wave_number = Public.get('wave_number')
2021-02-10 22:21:29 +02:00
-- this sets normal units health
2021-11-14 22:01:01 +02:00
local modified_unit_health = Public.get ( ' modified_unit_health ' )
2021-02-15 23:37:15 +02:00
if modified_unit_health.current_value > modified_unit_health.limit_value then
modified_unit_health.current_value = modified_unit_health.limit_value
2021-02-10 22:21:29 +02:00
end
2021-11-14 14:02:00 +02:00
debug_print_health ( ' modified_unit_health.current_value: ' .. modified_unit_health.current_value )
2021-11-14 22:01:01 +02:00
Public.set ( ' modified_unit_health ' ) . current_value = modified_unit_health.current_value + modified_unit_health.health_increase_per_boss_wave
2021-02-10 22:21:29 +02:00
-- this sets boss units health
2021-11-19 23:21:31 +02:00
-- if boosted_health == 1 then
-- boosted_health = 1.25
-- end
2021-11-14 14:02:00 +02:00
2021-11-28 21:42:38 +02:00
-- boosted_health = round(boosted_health * (wave_number * 0.04), 3)
2021-11-19 23:21:31 +02:00
-- debug_print_health('boosted_health: ' .. boosted_health)
-- if boosted_health >= 300 then
-- boosted_health = 300
-- end
-- Public.set('modified_boss_unit_health', boosted_health)
2021-02-10 22:21:29 +02:00
2021-11-19 23:21:31 +02:00
-- this sets boss units health
local modified_boss_unit_health = Public.get ( ' modified_boss_unit_health ' )
if modified_boss_unit_health.current_value > modified_boss_unit_health.limit_value then
modified_boss_unit_health.current_value = modified_boss_unit_health.limit_value
end
debug_print_health ( ' modified_boss_unit_health.current_value: ' .. modified_boss_unit_health.current_value )
Public.set ( ' modified_boss_unit_health ' ) . current_value = modified_boss_unit_health.current_value + modified_boss_unit_health.health_increase_per_boss_wave
2021-02-10 22:21:29 +02:00
end
2019-10-07 22:40:05 +02:00
local function set_next_wave ( )
2021-11-14 22:01:01 +02:00
local wave_number = Public.get ( ' wave_number ' )
Public.set ( ' wave_number ' , wave_number + 1 )
wave_number = Public.get ( ' wave_number ' )
2020-11-17 13:45:47 +02:00
2021-11-14 22:01:01 +02:00
local threat_gain_multiplier = Public.get ( ' threat_gain_multiplier ' )
2020-11-17 13:45:47 +02:00
local threat_gain = wave_number * threat_gain_multiplier
if wave_number > 1000 then
threat_gain = threat_gain * ( wave_number * 0.001 )
end
if wave_number % 25 == 0 then
2020-12-05 19:10:53 +02:00
increase_biter_damage ( )
2021-02-10 22:21:29 +02:00
increase_biters_health ( )
2021-11-14 22:01:01 +02:00
Public.set ( ' boss_wave ' , true )
Public.set ( ' boss_wave_warning ' , true )
local alert_boss_wave = Public.get ( ' alert_boss_wave ' )
2020-11-18 16:24:22 +02:00
local spawn_position = get_spawn_pos ( )
2020-11-17 13:45:47 +02:00
if alert_boss_wave then
local msg = ' Boss Wave: ' .. wave_number
2020-08-09 20:23:45 +02:00
local pos = {
2020-11-17 13:45:47 +02:00
position = spawn_position
2020-08-09 20:23:45 +02:00
}
Alert.alert_all_players_location ( pos , msg , { r = 0.8 , g = 0.1 , b = 0.1 } )
end
threat_gain = threat_gain * 2
else
2021-11-14 22:01:01 +02:00
local boss_wave_warning = Public.get ( ' boss_wave_warning ' )
2020-11-17 13:45:47 +02:00
if boss_wave_warning then
2021-11-14 22:01:01 +02:00
Public.set ( ' boss_wave_warning ' , false )
2020-08-09 20:23:45 +02:00
end
end
2022-06-26 22:37:41 +02:00
local log_wave_to_discord = Public.get ( ' log_wave_to_discord ' )
if wave_number % 100 == 0 and log_wave_to_discord then
Server.to_discord_embed ( ' Current wave: ' .. wave_number )
end
2021-11-14 22:01:01 +02:00
local threat = Public.get ( ' threat ' )
2021-11-28 21:42:38 +02:00
Public.set ( ' threat ' , threat + floor ( threat_gain ) )
2020-11-17 13:45:47 +02:00
2021-11-14 22:01:01 +02:00
local wave_enforced = Public.get ( ' wave_enforced ' )
local next_wave = Public.get ( ' next_wave ' )
local wave_interval = Public.get ( ' wave_interval ' )
2020-11-17 13:45:47 +02:00
if not wave_enforced then
2021-11-14 22:01:01 +02:00
Public.set ( ' last_wave ' , next_wave )
Public.set ( ' next_wave ' , game.tick + wave_interval )
2020-10-24 14:46:14 +02:00
end
2019-10-07 22:40:05 +02:00
end
2020-04-27 15:50:18 +02:00
local function reform_group ( group )
2021-11-14 22:01:01 +02:00
local unit_group_command_step_length = Public.get ( ' unit_group_command_step_length ' )
2020-08-09 20:23:45 +02:00
local group_position = { x = group.position . x , y = group.position . y }
2020-11-17 13:45:47 +02:00
local step_length = unit_group_command_step_length
2021-11-28 21:42:38 +02:00
local generated_units = Public.get ( ' generated_units ' )
2020-08-09 20:23:45 +02:00
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 }
2022-04-18 01:17:16 +02:00
for _ , biter in pairs ( group.members ) do
2020-08-09 20:23:45 +02:00
new_group.add_member ( biter )
end
debug_print ( ' Creating new unit group, because old one was stuck. ' )
2021-11-28 21:42:38 +02:00
generated_units.unit_groups [ new_group.group_number ] = new_group
2021-11-14 22:01:01 +02:00
local unit_groups_size = Public.get ( ' unit_groups_size ' )
Public.set ( ' unit_groups_size ' , unit_groups_size + 1 )
2020-10-22 12:44:14 +02:00
2020-08-09 20:23:45 +02:00
return new_group
else
debug_print ( ' Destroying stuck group. ' )
2021-11-28 21:42:38 +02:00
if generated_units.unit_groups [ group.group_number ] then
if generated_units.unit_group_last_command [ group.group_number ] then
generated_units.unit_group_last_command [ group.group_number ] = nil
2020-10-22 12:44:14 +02:00
end
2021-11-28 21:42:38 +02:00
local positions = generated_units.unit_group_pos . positions
2020-11-23 23:10:32 +02:00
if positions [ group.group_number ] then
positions [ group.group_number ] = nil
end
2021-11-28 21:42:38 +02:00
table.remove ( generated_units.unit_groups , group.group_number )
2021-11-14 22:01:01 +02:00
local unit_groups_size = Public.get ( ' unit_groups_size ' )
Public.set ( ' unit_groups_size ' , unit_groups_size - 1 )
2020-10-22 12:44:14 +02:00
end
2020-08-09 20:23:45 +02:00
group.destroy ( )
end
return nil
2020-04-27 15:50:18 +02:00
end
2020-11-23 23:10:32 +02:00
local function get_side_targets ( group )
2021-11-14 22:01:01 +02:00
local unit_group_command_step_length = Public.get ( ' unit_group_command_step_length ' )
2020-11-23 23:10:32 +02:00
2020-08-09 20:23:45 +02:00
local commands = { }
local group_position = { x = group.position . x , y = group.position . y }
2020-11-17 13:45:47 +02:00
local step_length = unit_group_command_step_length
2020-08-09 20:23:45 +02:00
2021-11-14 22:01:01 +02:00
local side_target = Public.get_side_target ( )
2020-11-23 23:10:32 +02:00
local target_position = side_target.position
2021-11-28 21:42:38 +02:00
local distance_to_target = floor ( sqrt ( ( target_position.x - group_position.x ) ^ 2 + ( target_position.y - group_position.y ) ^ 2 ) )
local steps = floor ( distance_to_target / step_length ) + 1
2020-11-17 13:45:47 +02:00
2022-04-18 01:17:16 +02:00
for _ = 1 , steps , 1 do
2020-11-23 23:10:32 +02:00
local old_position = group_position
local obstacles =
group.surface . find_entities_filtered {
position = old_position ,
radius = step_length * 2 ,
type = { ' simple-entity ' , ' tree ' } ,
limit = 100
}
if obstacles then
for v = 1 , # obstacles , 1 do
if obstacles [ v ] . valid then
2020-10-30 23:05:05 +02:00
commands [ # commands + 1 ] = {
2020-11-23 23:10:32 +02:00
type = defines.command . attack ,
destination = obstacles [ v ] . position ,
2020-10-30 23:05:05 +02:00
distraction = defines.distraction . by_anything
}
end
end
2020-08-09 20:23:45 +02:00
end
2020-11-23 23:10:32 +02:00
commands [ # commands + 1 ] = {
type = defines.command . attack ,
target = side_target ,
distraction = defines.distraction . by_anything
}
2020-08-09 20:23:45 +02:00
end
2020-11-23 23:10:32 +02:00
return commands
end
local function get_main_command ( group )
2021-11-14 22:01:01 +02:00
local unit_group_command_step_length = Public.get ( ' unit_group_command_step_length ' )
2020-11-23 23:10:32 +02:00
local commands = { }
local group_position = { x = group.position . x , y = group.position . y }
local step_length = unit_group_command_step_length
2020-11-17 13:45:47 +02:00
2021-11-14 22:01:01 +02:00
local target = Public.get ( ' target ' )
2020-11-23 23:10:32 +02:00
if not valid ( target ) then
2020-11-17 13:45:47 +02:00
return
end
2020-11-23 23:10:32 +02:00
debug_print ( ' get_main_command - starting ' )
2020-11-17 13:45:47 +02:00
local target_position = target.position
2021-11-28 21:42:38 +02:00
local distance_to_target = floor ( sqrt ( ( target_position.x - group_position.x ) ^ 2 + ( target_position.y - group_position.y ) ^ 2 ) )
local steps = floor ( distance_to_target / step_length ) + 1
2020-11-23 23:10:32 +02:00
local vector = {
2021-11-28 21:42:38 +02:00
round ( ( target_position.x - group_position.x ) / steps , 3 ) ,
round ( ( target_position.y - group_position.y ) / steps , 3 )
2020-11-23 23:10:32 +02:00
}
debug_print ( ' get_commmands - to main target x ' .. target_position.x .. ' y ' .. target_position.y )
debug_print ( ' get_commmands - distance_to_target: ' .. distance_to_target .. ' steps: ' .. steps )
debug_print ( ' get_commmands - vector ' .. vector [ 1 ] .. ' _ ' .. vector [ 2 ] )
2020-08-09 20:23:45 +02:00
2022-04-18 01:17:16 +02:00
for _ = 1 , steps , 1 do
2020-11-23 23:10:32 +02:00
local old_position = group_position
group_position.x = group_position.x + vector [ 1 ]
group_position.y = group_position.y + vector [ 2 ]
2020-08-09 20:23:45 +02:00
local obstacles =
group.surface . find_entities_filtered {
2020-11-23 23:10:32 +02:00
position = old_position ,
2020-08-09 20:23:45 +02:00
radius = step_length / 2 ,
type = { ' simple-entity ' , ' tree ' } ,
2020-10-22 13:32:18 +02:00
limit = 50
2020-08-09 20:23:45 +02:00
}
if obstacles then
2020-11-23 23:10:32 +02:00
shuffle_distance ( obstacles , old_position )
2021-03-24 21:14:55 +02:00
for ii = 1 , # obstacles , 1 do
if obstacles [ ii ] . valid then
2020-08-09 20:23:45 +02:00
commands [ # commands + 1 ] = {
type = defines.command . attack ,
2021-03-24 21:14:55 +02:00
target = obstacles [ ii ] ,
2020-11-23 23:10:32 +02:00
distraction = defines.distraction . by_anything
2020-08-09 20:23:45 +02:00
}
end
end
end
2020-09-17 09:14:07 +02:00
local position = group.surface . find_non_colliding_position ( ' behemoth-biter ' , group_position , step_length , 1 )
2020-08-09 20:23:45 +02:00
if position then
commands [ # commands + 1 ] = {
type = defines.command . attack_area ,
destination = { x = position.x , y = position.y } ,
2020-11-23 23:10:32 +02:00
radius = 16 ,
2020-08-09 20:23:45 +02:00
distraction = defines.distraction . by_anything
}
end
end
commands [ # commands + 1 ] = {
type = defines.command . attack_area ,
destination = { x = target_position.x , y = target_position.y } ,
2020-11-23 23:10:32 +02:00
radius = 8 ,
distraction = defines.distraction . by_anything
2020-08-09 20:23:45 +02:00
}
commands [ # commands + 1 ] = {
type = defines.command . attack ,
2020-11-17 13:45:47 +02:00
target = target ,
2020-11-23 23:10:32 +02:00
distraction = defines.distraction . by_anything
2020-08-09 20:23:45 +02:00
}
return commands
2019-10-08 01:17:00 +02:00
end
2020-11-23 23:10:32 +02:00
local function command_to_main_target ( group , bypass )
if not valid ( group ) then
return
end
2021-11-28 21:42:38 +02:00
local generated_units = Public.get ( ' generated_units ' )
2021-11-14 22:01:01 +02:00
local unit_group_command_delay = Public.get ( ' unit_group_command_delay ' )
2020-11-23 23:10:32 +02:00
if not bypass then
2021-11-28 21:42:38 +02:00
if not generated_units.unit_group_last_command [ group.group_number ] then
generated_units.unit_group_last_command [ group.group_number ] = game.tick - ( unit_group_command_delay + 1 )
2020-11-23 23:10:32 +02:00
end
2021-11-28 21:42:38 +02:00
if generated_units.unit_group_last_command [ group.group_number ] then
if generated_units.unit_group_last_command [ group.group_number ] + unit_group_command_delay > game.tick then
2020-11-23 23:10:32 +02:00
return
end
end
end
2021-11-14 22:01:01 +02:00
local fill_tiles_so_biter_can_path = Public.get ( ' fill_tiles_so_biter_can_path ' )
2020-11-23 23:10:32 +02:00
if fill_tiles_so_biter_can_path then
fill_tiles ( group , 10 )
end
local tile = group.surface . get_tile ( group.position )
if tile.valid and tile.collides_with ( ' player-layer ' ) then
group = reform_group ( group )
end
if not valid ( group ) then
return
end
local commands = get_main_command ( group )
debug_print ( ' get_main_command - got commands ' )
2021-11-14 22:01:01 +02:00
local surface_index = Public.get ( ' surface_index ' )
2021-07-07 12:22:22 +02:00
if group.surface . index ~= surface_index then
return
end
2020-11-23 23:10:32 +02:00
group.set_command (
{
type = defines.command . compound ,
structure_type = defines.compound_command . return_last ,
commands = commands
}
)
debug_print ( ' get_main_command - sent commands ' )
if valid ( group ) then
2021-11-28 21:42:38 +02:00
generated_units.unit_group_last_command [ group.group_number ] = game.tick
2020-11-23 23:10:32 +02:00
end
end
local function command_to_side_target ( group )
2021-11-28 21:42:38 +02:00
local generated_units = Public.get ( ' generated_units ' )
2021-11-14 22:01:01 +02:00
local unit_group_command_delay = Public.get ( ' unit_group_command_delay ' )
2021-11-28 21:42:38 +02:00
if not generated_units.unit_group_last_command [ group.group_number ] then
generated_units.unit_group_last_command [ group.group_number ] = game.tick - ( unit_group_command_delay + 1 )
2020-08-09 20:23:45 +02:00
end
2020-10-18 12:45:18 +02:00
2021-11-28 21:42:38 +02:00
if generated_units.unit_group_last_command [ group.group_number ] then
if generated_units.unit_group_last_command [ group.group_number ] + unit_group_command_delay > game.tick then
2020-08-09 20:23:45 +02:00
return
end
end
2020-10-18 12:45:18 +02:00
2020-08-09 20:23:45 +02:00
local tile = group.surface . get_tile ( group.position )
if tile.valid and tile.collides_with ( ' player-layer ' ) then
group = reform_group ( group )
end
2020-11-23 23:10:32 +02:00
local commands = get_side_targets ( group )
2020-08-09 20:23:45 +02:00
group.set_command (
{
type = defines.command . compound ,
2020-10-22 13:32:18 +02:00
structure_type = defines.compound_command . return_last ,
2020-11-23 23:10:32 +02:00
commands = commands
2020-08-09 20:23:45 +02:00
}
)
2020-10-30 23:05:05 +02:00
2021-11-28 21:42:38 +02:00
generated_units.unit_group_last_command [ group.group_number ] = game.tick
2019-10-07 22:40:05 +02:00
end
2020-11-23 23:10:32 +02:00
local function give_side_commands_to_group ( )
2021-11-14 22:01:01 +02:00
local enable_side_target = Public.get ( ' enable_side_target ' )
2020-11-23 23:10:32 +02:00
if not enable_side_target then
2020-08-09 20:23:45 +02:00
return
end
2020-11-23 23:10:32 +02:00
2021-11-14 22:01:01 +02:00
local target = Public.get ( ' target ' )
2020-11-23 23:10:32 +02:00
if not valid ( target ) then
2020-08-09 20:23:45 +02:00
return
end
2020-11-17 13:45:47 +02:00
2021-11-28 21:42:38 +02:00
local generated_units = Public.get ( ' generated_units ' )
2022-04-18 01:17:16 +02:00
for _ , group in pairs ( generated_units.unit_groups ) do
2020-10-22 12:44:14 +02:00
if type ( group ) ~= ' number ' then
if group.valid then
2020-11-23 23:10:32 +02:00
command_to_side_target ( group )
else
get_active_unit_groups_count ( )
2020-10-22 12:44:14 +02:00
end
2020-08-09 20:23:45 +02:00
end
end
2019-10-07 04:37:23 +02:00
end
2020-11-23 23:10:32 +02:00
local function give_main_command_to_group ( )
2021-11-14 22:01:01 +02:00
local target = Public.get ( ' target ' )
2020-11-23 23:10:32 +02:00
if not valid ( target ) then
2020-11-18 16:24:22 +02:00
return
end
2021-11-28 21:42:38 +02:00
local generated_units = Public.get ( ' generated_units ' )
2022-04-18 01:17:16 +02:00
for _ , group in pairs ( generated_units.unit_groups ) do
2020-11-23 23:10:32 +02:00
if type ( group ) ~= ' number ' then
if group.valid then
2021-02-01 21:01:07 +02:00
if group.surface . index == target.surface . index then
command_to_main_target ( group )
end
2020-11-23 23:10:32 +02:00
else
get_active_unit_groups_count ( )
2020-11-18 16:24:22 +02:00
end
end
end
end
2021-11-14 22:01:01 +02:00
local function spawn_unit_group ( fs , only_bosses )
2021-11-11 02:56:03 +02:00
if fs then
debug_print ( ' spawn_unit_group - forcing new biters ' )
else
if not can_units_spawn ( ) then
debug_print ( ' spawn_unit_group - Cant spawn units? ' )
return
end
2020-08-09 20:23:45 +02:00
end
2021-11-14 22:01:01 +02:00
local target = Public.get ( ' target ' )
2020-11-23 23:10:32 +02:00
if not valid ( target ) then
2020-11-18 16:24:22 +02:00
debug_print ( ' spawn_unit_group - Target was not valid? ' )
2020-08-09 20:23:45 +02:00
return
end
2020-11-17 13:45:47 +02:00
2021-11-14 22:01:01 +02:00
local max_active_unit_groups = Public.get ( ' max_active_unit_groups ' )
2021-11-11 02:56:03 +02:00
if fs then
debug_print ( ' spawn_unit_group - forcing new biters ' )
else
if get_active_unit_groups_count ( ) >= max_active_unit_groups then
debug_print ( ' spawn_unit_group - unit_groups at max ' )
return
end
2020-08-09 20:23:45 +02:00
end
2021-11-14 22:01:01 +02:00
local surface_index = Public.get ( ' surface_index ' )
local remove_entities = Public.get ( ' remove_entities ' )
2020-11-23 23:10:32 +02:00
2020-11-17 13:45:47 +02:00
local surface = game.surfaces [ surface_index ]
2020-08-09 20:23:45 +02:00
set_group_spawn_position ( surface )
2020-11-18 16:24:22 +02:00
local spawn_position = get_spawn_pos ( )
2020-11-23 23:10:32 +02:00
if not spawn_position then
return
2020-08-09 20:23:45 +02:00
end
local radius = 10
2020-11-18 16:24:22 +02:00
local area = {
left_top = { spawn_position.x - radius , spawn_position.y - radius } ,
right_bottom = { spawn_position.x + radius , spawn_position.y + radius }
}
2022-04-18 01:17:16 +02:00
for _ , v in pairs ( surface.find_entities_filtered { area = area , name = ' land-mine ' } ) do
2020-08-09 20:23:45 +02:00
if v and v.valid then
2020-11-18 16:24:22 +02:00
debug_print ( ' spawn_unit_group - found land-mines ' )
2020-08-09 20:23:45 +02:00
v.die ( )
end
end
2020-11-23 23:10:32 +02:00
if remove_entities then
remove_trees ( { surface = surface , position = spawn_position , valid = true } )
remove_rocks ( { surface = surface , position = spawn_position , valid = true } )
fill_tiles ( { surface = surface , position = spawn_position , valid = true } )
end
2021-11-14 22:01:01 +02:00
local wave_number = Public.get ( ' wave_number ' )
Public.wave_defense_set_unit_raffle ( wave_number )
2020-08-09 20:23:45 +02:00
2020-11-17 13:45:47 +02:00
debug_print ( ' Spawning unit group at x ' .. spawn_position.x .. ' y ' .. spawn_position.y )
2020-08-09 20:23:45 +02:00
2021-11-28 21:42:38 +02:00
local generated_units = Public.get ( ' generated_units ' )
2021-11-11 02:56:03 +02:00
local unit_group = surface.create_unit_group ( { position = spawn_position , force = ' enemy ' } )
2021-11-28 21:42:38 +02:00
generated_units.unit_group_pos . index = generated_units.unit_group_pos . index + 1
generated_units.unit_group_pos . positions [ unit_group.group_number ] = { position = unit_group.position , index = 0 }
2021-11-14 22:01:01 +02:00
local average_unit_group_size = Public.get ( ' average_unit_group_size ' )
2021-11-28 21:42:38 +02:00
local unit_settings = Public.get ( ' unit_settings ' )
2021-12-18 15:03:22 +02:00
local group_size = floor ( average_unit_group_size * Public.group_size_modifier_raffle [ random ( 1 , Public.group_size_modifier_raffle_size ) ] )
2021-11-14 22:01:01 +02:00
if not only_bosses then
2021-12-18 15:03:22 +02:00
for _ = 1 , group_size , 1 do
2021-11-28 21:42:38 +02:00
local biter = spawn_biter ( surface , spawn_position , fs , false , unit_settings )
2021-11-14 22:01:01 +02:00
if not biter then
debug_print ( ' spawn_unit_group - No biters were found? ' )
break
end
unit_group.add_member ( biter )
2020-11-23 23:10:32 +02:00
2021-11-14 22:01:01 +02:00
-- command_to_side_target(unit_group)
end
2020-08-09 20:23:45 +02:00
end
2021-11-14 22:01:01 +02:00
local boss_wave = Public.get ( ' boss_wave ' )
if boss_wave or only_bosses then
2021-11-28 21:42:38 +02:00
local count = random ( 1 , floor ( wave_number * 0.01 ) + 2 )
2020-11-17 13:45:47 +02:00
if count > 16 then
count = 16
end
if count <= 1 then
count = 4
2020-08-09 20:23:45 +02:00
end
for _ = 1 , count , 1 do
2021-11-28 21:42:38 +02:00
local biter = spawn_biter ( surface , spawn_position , fs , true , unit_settings )
2020-08-09 20:23:45 +02:00
if not biter then
2020-11-18 16:24:22 +02:00
debug_print ( ' spawn_unit_group - No biters were found? ' )
2020-08-09 20:23:45 +02:00
break
end
unit_group.add_member ( biter )
end
2021-11-14 22:01:01 +02:00
Public.set ( ' boss_wave ' , false )
2020-11-17 13:45:47 +02:00
end
2021-11-28 21:42:38 +02:00
generated_units.unit_groups [ unit_group.group_number ] = unit_group
2021-11-14 22:01:01 +02:00
local unit_groups_size = Public.get ( ' unit_groups_size ' )
Public.set ( ' unit_groups_size ' , unit_groups_size + 1 )
2021-11-28 21:42:38 +02:00
if random ( 1 , 2 ) == 1 then
2021-11-14 22:01:01 +02:00
Public.set ( ' random_group ' , unit_group )
2020-10-22 12:44:14 +02:00
end
2021-11-14 22:01:01 +02:00
Public.set ( ' spot ' , ' nil ' )
2020-08-09 20:23:45 +02:00
return true
2019-10-27 20:26:55 +02:00
end
2020-11-23 23:10:32 +02:00
local function check_group_positions ( )
2021-11-28 21:42:38 +02:00
local generated_units = Public.get ( ' generated_units ' )
2021-11-14 22:01:01 +02:00
local target = Public.get ( ' target ' )
2020-11-23 23:10:32 +02:00
if not valid ( target ) then
return
end
2022-04-18 01:17:16 +02:00
for _ , group in pairs ( generated_units.unit_groups ) do
2020-11-23 23:10:32 +02:00
if group.valid then
2021-11-28 21:42:38 +02:00
local ugp = generated_units.unit_group_pos . positions
2020-11-23 23:10:32 +02:00
if group.state == defines.group_state . finished then
return command_to_main_target ( group , true )
end
if ugp [ group.group_number ] then
local success = is_position_near ( group.position , ugp [ group.group_number ] . position )
if success then
ugp [ group.group_number ] . index = ugp [ group.group_number ] . index + 1
if ugp [ group.group_number ] . index >= 2 then
command_to_main_target ( group , true )
fill_tiles ( group , 30 )
remove_rocks ( group )
remove_trees ( group )
2022-02-28 23:16:16 +02:00
if valid ( group ) and ugp [ group.group_number ] . index >= 4 then
2021-11-28 21:42:38 +02:00
generated_units.unit_group_pos . positions [ group.group_number ] = nil
2020-11-23 23:10:32 +02:00
reform_group ( group )
end
end
end
end
end
end
end
2019-10-28 14:29:15 +02:00
local function log_threat ( )
2021-11-14 22:01:01 +02:00
local threat_log_index = Public.get ( ' threat_log_index ' )
Public.set ( ' threat_log_index ' , threat_log_index + 1 )
local threat_log = Public.get ( ' threat_log ' )
local threat = Public.get ( ' threat ' )
threat_log_index = Public.get ( ' threat_log_index ' )
2020-11-17 13:45:47 +02:00
threat_log [ threat_log_index ] = threat
if threat_log_index > 900 then
threat_log [ threat_log_index - 901 ] = nil
2020-08-09 20:23:45 +02:00
end
end
2019-10-15 04:20:40 +02:00
local tick_tasks = {
2020-08-09 20:23:45 +02:00
[ 30 ] = set_main_target ,
[ 60 ] = set_enemy_evolution ,
2020-11-23 23:10:32 +02:00
[ 120 ] = give_main_command_to_group ,
2021-11-14 22:01:01 +02:00
[ 150 ] = Public.build_nest ,
[ 180 ] = Public.build_worm ,
2020-11-23 23:10:32 +02:00
[ 1200 ] = give_side_commands_to_group ,
2020-08-09 20:23:45 +02:00
[ 3600 ] = time_out_biters ,
2020-10-18 12:45:18 +02:00
[ 7200 ] = refresh_active_unit_threat
2019-10-15 04:20:40 +02:00
}
2021-11-28 21:42:38 +02:00
Public.spawn_unit_group = spawn_unit_group
2020-08-09 20:23:45 +02:00
2021-11-28 21:42:38 +02:00
Event.on_nth_tick (
30 ,
function ( )
local tick = game.tick
local game_lost = Public.get ( ' game_lost ' )
if game_lost then
return
2021-11-22 21:16:33 +02:00
end
2021-10-29 00:06:35 +02:00
2021-11-28 21:42:38 +02:00
local paused = Public.get ( ' paused ' )
if paused then
2022-04-18 01:17:16 +02:00
local players = game.connected_players
for _ , player in pairs ( players ) do
Public.update_gui ( player )
end
2021-11-28 21:42:38 +02:00
return
end
2022-04-18 01:17:16 +02:00
2021-11-28 21:42:38 +02:00
local enable_grace_time = Public.get ( ' enable_grace_time ' )
if enable_grace_time and ( not enable_grace_time.enabled ) then
if not enable_grace_time.set then
Public.set ( ' next_wave ' , game.tick + 100 )
enable_grace_time.set = true
end
end
2020-08-09 20:23:45 +02:00
2021-11-28 21:42:38 +02:00
local next_wave = Public.get ( ' next_wave ' )
if tick > next_wave then
set_next_wave ( )
end
2020-08-09 20:23:45 +02:00
2021-11-28 21:42:38 +02:00
local t = tick % 300
local t2 = tick % 18000
2020-08-09 20:23:45 +02:00
2021-11-28 21:42:38 +02:00
if tick_tasks [ t ] then
2022-05-12 22:19:00 +02:00
tick_tasks [ t ] ( )
2021-11-28 21:42:38 +02:00
end
if tick_tasks [ t2 ] then
2022-05-12 22:19:00 +02:00
tick_tasks [ t2 ] ( )
2020-11-23 23:10:32 +02:00
end
2021-11-28 21:42:38 +02:00
local resolve_pathing = Public.get ( ' resolve_pathing ' )
if resolve_pathing then
if tick % 60 == 0 then
check_group_positions ( )
end
2020-08-09 20:23:45 +02:00
end
2019-10-07 01:46:26 +02:00
2021-11-28 21:42:38 +02:00
local enable_threat_log = Public.get ( ' enable_threat_log ' )
if enable_threat_log then
if tick % 60 == 0 then
log_threat ( )
end
end
local players = game.connected_players
for _ , player in pairs ( players ) do
Public.update_gui ( player )
end
2021-11-11 02:56:03 +02:00
end
2021-11-28 21:42:38 +02:00
)
2021-11-11 02:56:03 +02:00
2021-11-28 21:42:38 +02:00
Event.on_nth_tick (
50 ,
function ( )
local tick_to_spawn_unit_groups = Public.get ( ' tick_to_spawn_unit_groups ' )
2021-12-18 15:03:22 +02:00
local tick = game.tick
local will_not_spawn = tick % tick_to_spawn_unit_groups ~= 0
2021-11-28 21:42:38 +02:00
if will_not_spawn then
return
end
2021-11-11 02:56:03 +02:00
2021-11-28 21:42:38 +02:00
local game_lost = Public.get ( ' game_lost ' )
if game_lost then
return
2021-11-14 22:01:01 +02:00
end
2021-11-11 02:56:03 +02:00
2021-11-28 21:42:38 +02:00
local paused = Public.get ( ' paused ' )
if paused then
return
end
2021-11-11 02:56:03 +02:00
2021-11-28 21:42:38 +02:00
spawn_unit_group ( )
end
)
2019-10-07 01:46:26 +02:00
2022-05-12 22:19:00 +02:00
Public.set_next_wave = set_next_wave
2020-04-08 20:28:02 +02:00
return Public