2019-04-15 02:44:06 +02:00
-- fish defender -- by mewmew --
2019-09-13 13:10:41 +02:00
require " maps.fish_defender.terrain "
2019-04-15 09:02:51 +02:00
require " maps.fish_defender.map_intro "
2019-04-19 09:12:22 +02:00
require " maps.fish_defender.market "
2019-04-15 20:19:32 +02:00
require " maps.fish_defender.shotgun_buff "
2019-04-19 09:12:22 +02:00
require " maps.fish_defender.on_entity_damaged "
2019-04-15 20:19:32 +02:00
2019-04-15 02:44:06 +02:00
require " modules.rocket_launch_always_yields_science "
require " modules.launch_fish_to_win "
require " modules.biters_yield_coins "
require " modules.dynamic_landfill "
require " modules.dangerous_goods "
require " modules.custom_death_messages "
require " modules.biter_evasion_hp_increaser "
2019-09-13 13:10:41 +02:00
require " modules.rocks_yield_ore "
2019-10-12 22:54:00 +02:00
require " modules.rpg "
2019-04-15 02:44:06 +02:00
local event = require ' utils.event '
2019-05-22 00:17:00 +02:00
local boss_biter = require " maps.fish_defender.boss_biters "
2019-09-08 07:21:19 +02:00
require " functions.boss_unit "
2019-04-15 02:44:06 +02:00
local math_random = math.random
local insert = table.insert
local enable_start_grace_period = true
2019-09-13 13:10:41 +02:00
map_height = 96
2019-08-15 12:38:24 +02:00
local biter_count_limit = 1024 --maximum biters on the east side of the map, next wave will be delayed if the maximum has been reached
2019-04-15 02:44:06 +02:00
local boss_waves = {
[ 50 ] = { { name = " big-biter " , count = 3 } } ,
[ 100 ] = { { name = " behemoth-biter " , count = 1 } } ,
[ 150 ] = { { name = " behemoth-spitter " , count = 4 } , { name = " big-spitter " , count = 16 } } ,
[ 200 ] = { { name = " behemoth-biter " , count = 4 } , { name = " behemoth-spitter " , count = 2 } , { name = " big-biter " , count = 32 } } ,
[ 250 ] = { { name = " behemoth-biter " , count = 8 } , { name = " behemoth-spitter " , count = 4 } , { name = " big-spitter " , count = 32 } } ,
2019-06-07 11:15:16 +02:00
[ 300 ] = { { name = " behemoth-biter " , count = 16 } , { name = " behemoth-spitter " , count = 8 } }
2019-04-15 02:44:06 +02:00
}
2019-08-15 12:38:24 +02:00
local difficulties_votes = {
2019-09-17 07:30:16 +02:00
[ 1 ] = { wave_interval = 4500 , amount_modifier = 0.52 , strength_modifier = 0.40 , boss_modifier = 3.0 } ,
[ 2 ] = { wave_interval = 4100 , amount_modifier = 0.76 , strength_modifier = 0.65 , boss_modifier = 4.0 } ,
[ 3 ] = { wave_interval = 3800 , amount_modifier = 0.92 , strength_modifier = 0.85 , boss_modifier = 5.0 } ,
[ 4 ] = { wave_interval = 3600 , amount_modifier = 1.00 , strength_modifier = 1.00 , boss_modifier = 6.0 } ,
[ 5 ] = { wave_interval = 3400 , amount_modifier = 1.08 , strength_modifier = 1.25 , boss_modifier = 7.0 } ,
[ 6 ] = { wave_interval = 3100 , amount_modifier = 1.24 , strength_modifier = 1.75 , boss_modifier = 8.0 } ,
[ 7 ] = { wave_interval = 2700 , amount_modifier = 1.48 , strength_modifier = 2.50 , boss_modifier = 9.0 }
2019-08-15 12:38:24 +02:00
}
2019-04-15 02:44:06 +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
local function create_wave_gui ( player )
if player.gui . top [ " fish_defense_waves " ] then player.gui . top [ " fish_defense_waves " ] . destroy ( ) end
local frame = player.gui . top.add ( { type = " frame " , name = " fish_defense_waves " , tooltip = " Click to show map info " } )
frame.style . maximal_height = 38
local wave_count = 0
if global.wave_count then wave_count = global.wave_count end
2019-06-07 11:15:16 +02:00
2019-04-15 02:44:06 +02:00
if not global.wave_grace_period then
local label = frame.add ( { type = " label " , caption = " Wave: " .. wave_count } )
label.style . font_color = { r = 0.88 , g = 0.88 , b = 0.88 }
label.style . font = " default-listbox "
label.style . left_padding = 4
label.style . right_padding = 4
label.style . minimal_width = 68
label.style . font_color = { r = 0.33 , g = 0.66 , b = 0.9 }
2019-08-15 12:38:24 +02:00
local next_level_progress = game.tick % global.wave_interval / global.wave_interval
2019-04-15 02:44:06 +02:00
local progressbar = frame.add ( { type = " progressbar " , value = next_level_progress } )
progressbar.style . minimal_width = 120
progressbar.style . maximal_width = 120
progressbar.style . top_padding = 10
2019-06-07 11:15:16 +02:00
else
local time_remaining = math.floor ( ( ( global.wave_grace_period - ( game.tick % global.wave_grace_period ) ) / 60 ) / 60 )
2019-04-15 02:44:06 +02:00
if time_remaining <= 0 then
global.wave_grace_period = nil
return
end
2019-06-07 11:15:16 +02:00
2019-04-15 02:44:06 +02:00
local label = frame.add ( { type = " label " , caption = " Waves will start in " .. time_remaining .. " minutes. " } )
label.style . font_color = { r = 0.88 , g = 0.88 , b = 0.88 }
label.style . font = " default-listbox "
label.style . left_padding = 4
label.style . right_padding = 4
label.style . font_color = { r = 0.33 , g = 0.66 , b = 0.9 }
if not enable_start_grace_period then global.wave_grace_period = nil return end
end
end
2019-06-07 11:15:16 +02:00
local function show_fd_stats ( player )
local gui_id = " fd-stats "
local table_id = gui_id .. " table "
if player.gui . left [ gui_id ] then
player.gui . left [ gui_id ] . destroy ( )
end
local frame = player.gui . left.add {
type = " frame " ,
name = gui_id
}
local table = frame.add {
type = " table " ,
name = table_id ,
column_count = 2 ,
}
local table_header = { " Building " , " Placed " .. ' / ' .. " Limit " }
for k , v in pairs ( table_header ) do
local h = table.add { type = " label " , caption = v }
h.style . font = " heading-2 "
end
for k , v in pairs ( global.entity_limits ) do
local name = v.str
local placed = v.placed
local limit = v.limit
local entry = { name , placed .. ' / ' .. limit }
for k , v in pairs ( entry ) do
table.add {
type = " label " ,
caption = v
}
end
end
end
local function update_fd_stats ( )
for _ , player in pairs ( game.connected_players ) do
if player.gui . left [ " fd-stats " ] then
show_fd_stats ( player )
end
end
end
local function add_fd_stats_button ( player )
local button_id = " fd-stats-button "
if player.gui . top [ button_id ] then
player.gui . top [ button_id ] . destroy ( )
end
local button = player.gui . top.add {
type = " sprite-button " ,
name = button_id ,
sprite = " item/submachine-gun "
}
end
local function on_gui_click ( event )
2019-06-10 15:31:51 +02:00
if not event.element . valid then
return
end
2019-06-07 11:15:16 +02:00
if event.element . name ~= " fd-stats-button " then
return
end
local player = game.players [ event.player_index ]
local frame = player.gui . left [ " fd-stats " ]
if frame == nil then
show_fd_stats ( player )
else
frame.destroy ( )
end
end
2019-06-07 15:43:44 +02:00
local function on_market_item_purchased ( event )
update_fd_stats ( )
end
2019-06-07 11:15:16 +02:00
2019-04-15 02:44:06 +02:00
local threat_values = {
[ " small_biter " ] = 1 ,
[ " medium_biter " ] = 3 ,
[ " big_biter " ] = 5 ,
[ " behemoth_biter " ] = 10 ,
[ " small_spitter " ] = 1 ,
[ " medium_spitter " ] = 3 ,
[ " big_spitter " ] = 5 ,
[ " behemoth_spitter " ] = 10
}
local function get_biter_initial_pool ( )
local biter_pool = { }
if global.wave_count > 1750 then
2019-06-07 11:15:16 +02:00
biter_pool = {
{ name = " behemoth-biter " , threat = threat_values.behemoth_biter , weight = 2 } ,
2019-04-15 02:44:06 +02:00
{ name = " behemoth-spitter " , threat = threat_values.behemoth_spitter , weight = 1 }
}
return biter_pool
end
if global.wave_count > 1500 then
biter_pool = {
{ name = " big-biter " , threat = threat_values.big_biter , weight = 1 } ,
2019-06-07 11:15:16 +02:00
{ name = " behemoth-biter " , threat = threat_values.behemoth_biter , weight = 2 } ,
2019-04-15 02:44:06 +02:00
{ name = " behemoth-spitter " , threat = threat_values.behemoth_spitter , weight = 1 }
}
return biter_pool
end
if global.wave_count > 1250 then
biter_pool = {
{ name = " big-biter " , threat = threat_values.big_biter , weight = 2 } ,
2019-06-07 11:15:16 +02:00
{ name = " behemoth-biter " , threat = threat_values.behemoth_biter , weight = 2 } ,
2019-04-15 02:44:06 +02:00
{ name = " behemoth-spitter " , threat = threat_values.behemoth_spitter , weight = 1 }
}
return biter_pool
end
if global.wave_count > 1000 then
biter_pool = {
{ name = " big-biter " , threat = threat_values.big_biter , weight = 3 } ,
2019-06-07 11:15:16 +02:00
{ name = " behemoth-biter " , threat = threat_values.behemoth_biter , weight = 2 } ,
2019-04-15 02:44:06 +02:00
{ name = " behemoth-spitter " , threat = threat_values.behemoth_spitter , weight = 1 }
}
return biter_pool
end
if game.forces . enemy.evolution_factor < 0.1 then
biter_pool = {
2019-06-07 11:15:16 +02:00
{ name = " small-biter " , threat = threat_values.small_biter , weight = 3 } ,
{ name = " small-spitter " , threat = threat_values.small_spitter , weight = 1 }
2019-04-15 02:44:06 +02:00
}
return biter_pool
end
if game.forces . enemy.evolution_factor < 0.2 then
biter_pool = {
{ name = " small-biter " , threat = threat_values.small_biter , weight = 10 } ,
{ name = " medium-biter " , threat = threat_values.medium_biter , weight = 2 } ,
{ name = " small-spitter " , threat = threat_values.small_spitter , weight = 5 } ,
{ name = " medium-spitter " , threat = threat_values.medium_spitter , weight = 1 }
}
return biter_pool
end
if game.forces . enemy.evolution_factor < 0.3 then
biter_pool = {
{ name = " small-biter " , threat = threat_values.small_biter , weight = 18 } ,
{ name = " medium-biter " , threat = threat_values.medium_biter , weight = 6 } ,
{ name = " small-spitter " , threat = threat_values.small_spitter , weight = 8 } ,
{ name = " medium-spitter " , threat = threat_values.medium_spitter , weight = 3 } ,
{ name = " big-biter " , threat = threat_values.big_biter , weight = 1 }
}
return biter_pool
end
if game.forces . enemy.evolution_factor < 0.4 then
biter_pool = {
{ name = " small-biter " , threat = threat_values.small_biter , weight = 2 } ,
{ name = " medium-biter " , threat = threat_values.medium_biter , weight = 8 } ,
{ name = " big-biter " , threat = threat_values.big_biter , weight = 2 } ,
{ name = " small-spitter " , threat = threat_values.small_spitter , weight = 1 } ,
{ name = " medium-spitter " , threat = threat_values.medium_spitter , weight = 4 } ,
{ name = " big-spitter " , threat = threat_values.big_spitter , weight = 1 }
}
return biter_pool
end
if game.forces . enemy.evolution_factor < 0.5 then
biter_pool = {
{ name = " small-biter " , threat = threat_values.small_biter , weight = 2 } ,
{ name = " medium-biter " , threat = threat_values.medium_biter , weight = 4 } ,
{ name = " big-biter " , threat = threat_values.big_biter , weight = 8 } ,
{ name = " small-spitter " , threat = threat_values.small_spitter , weight = 1 } ,
{ name = " medium-spitter " , threat = threat_values.medium_spitter , weight = 2 } ,
{ name = " big-spitter " , threat = threat_values.big_spitter , weight = 4 }
}
return biter_pool
end
if game.forces . enemy.evolution_factor < 0.6 then
2019-06-07 11:15:16 +02:00
biter_pool = {
2019-04-15 02:44:06 +02:00
{ name = " medium-biter " , threat = threat_values.medium_biter , weight = 4 } ,
{ name = " big-biter " , threat = threat_values.big_biter , weight = 8 } ,
{ name = " medium-spitter " , threat = threat_values.medium_spitter , weight = 2 } ,
{ name = " big-spitter " , threat = threat_values.big_spitter , weight = 4 }
}
return biter_pool
end
if game.forces . enemy.evolution_factor < 0.7 then
biter_pool = {
{ name = " behemoth-biter " , threat = threat_values.small_biter , weight = 2 } ,
{ name = " medium-biter " , threat = threat_values.medium_biter , weight = 12 } ,
{ name = " big-biter " , threat = threat_values.big_biter , weight = 20 } ,
{ name = " behemoth-spitter " , threat = threat_values.small_spitter , weight = 1 } ,
{ name = " medium-spitter " , threat = threat_values.medium_spitter , weight = 6 } ,
{ name = " big-spitter " , threat = threat_values.big_spitter , weight = 10 }
}
return biter_pool
end
if game.forces . enemy.evolution_factor < 0.8 then
biter_pool = {
{ name = " behemoth-biter " , threat = threat_values.small_biter , weight = 2 } ,
{ name = " medium-biter " , threat = threat_values.medium_biter , weight = 4 } ,
{ name = " big-biter " , threat = threat_values.big_biter , weight = 10 } ,
{ name = " behemoth-spitter " , threat = threat_values.small_spitter , weight = 1 } ,
{ name = " medium-spitter " , threat = threat_values.medium_spitter , weight = 2 } ,
{ name = " big-spitter " , threat = threat_values.big_spitter , weight = 5 }
}
return biter_pool
end
if game.forces . enemy.evolution_factor <= 0.9 then
biter_pool = {
{ name = " big-biter " , threat = threat_values.big_biter , weight = 12 } ,
{ name = " behemoth-biter " , threat = threat_values.behemoth_biter , weight = 2 } ,
{ name = " big-spitter " , threat = threat_values.big_spitter , weight = 6 } ,
{ name = " behemoth-spitter " , threat = threat_values.behemoth_spitter , weight = 1 }
}
return biter_pool
2019-06-07 11:15:16 +02:00
end
2019-04-15 02:44:06 +02:00
if game.forces . enemy.evolution_factor <= 1 then
biter_pool = {
{ name = " big-biter " , threat = threat_values.big_biter , weight = 4 } ,
{ name = " behemoth-biter " , threat = threat_values.behemoth_biter , weight = 2 } ,
{ name = " big-spitter " , threat = threat_values.big_spitter , weight = 2 } ,
{ name = " behemoth-spitter " , threat = threat_values.behemoth_spitter , weight = 1 }
}
return biter_pool
2019-06-07 11:15:16 +02:00
end
2019-04-15 02:44:06 +02:00
end
local function get_biter_pool ( )
local surface = game.surfaces [ " fish_defender " ]
local biter_pool = get_biter_initial_pool ( )
local biter_raffle = { }
for _ , biter_type in pairs ( biter_pool ) do
for x = 1 , biter_type.weight , 1 do
insert ( biter_raffle , { name = biter_type.name , threat = biter_type.threat } )
end
end
return biter_raffle
end
local function spawn_biter ( pos , biter_pool )
if global.attack_wave_threat < 1 then return false end
2019-06-07 11:15:16 +02:00
local surface = game.surfaces [ " fish_defender " ]
2019-04-15 02:44:06 +02:00
biter_pool = shuffle ( biter_pool )
global.attack_wave_threat = global.attack_wave_threat - biter_pool [ 1 ] . threat
local valid_pos = surface.find_non_colliding_position ( biter_pool [ 1 ] . name , pos , 100 , 2 )
2019-06-07 11:15:16 +02:00
local biter = surface.create_entity ( { name = biter_pool [ 1 ] . name , position = valid_pos } )
2019-09-16 18:18:21 +02:00
biter.ai_settings . allow_destroy_when_commands_fail = false
biter.ai_settings . allow_try_return_to_spawner = false
2019-04-15 02:44:06 +02:00
return biter
end
2019-09-16 18:18:21 +02:00
local function get_y_coord_raffle_table ( )
local t = { }
for y = - 96 , 96 , 8 do
t [ # t + 1 ] = y
end
table.shuffle_table ( t )
return t
end
2019-04-15 02:44:06 +02:00
local attack_group_count_thresholds = {
{ 0 , 1 } ,
{ 50 , 2 } ,
{ 100 , 3 } ,
{ 150 , 4 } ,
{ 200 , 5 } ,
{ 1000 , 6 } ,
{ 2000 , 7 } ,
{ 3000 , 8 }
}
2019-06-07 11:15:16 +02:00
local function get_number_of_attack_groups ( )
2019-04-15 02:44:06 +02:00
local n = 1
for _ , entry in pairs ( attack_group_count_thresholds ) do
if global.wave_count >= entry [ 1 ] then
n = entry [ 2 ]
end
end
return n
end
local function clear_corpses ( surface )
if not global.wave_count then return end
local chance = 4
if global.wave_count > 250 then chance = 3 end
2019-06-07 11:15:16 +02:00
if global.wave_count > 500 then chance = 2 end
for _ , entity in pairs ( surface.find_entities_filtered { type = " corpse " } ) do
2019-04-15 02:44:06 +02:00
if math_random ( 1 , chance ) == 1 then
entity.destroy ( )
end
end
end
local boss_wave_names = {
[ 50 ] = " The Big Biter Gang " ,
[ 100 ] = " Biterzilla " ,
[ 150 ] = " The Spitter Squad " ,
[ 200 ] = " The Wall Nibblers " ,
[ 250 ] = " Conveyor Munchers " ,
[ 300 ] = " Furnace Freezers " ,
2019-06-07 11:15:16 +02:00
[ 350 ] = " Cable Chewers " ,
2019-04-15 02:44:06 +02:00
[ 400 ] = " Power Pole Thieves " ,
[ 450 ] = " Assembler Annihilators " ,
[ 500 ] = " Inserter Crunchers " ,
[ 550 ] = " Engineer Eaters " ,
[ 600 ] = " Belt Unbalancers " ,
[ 650 ] = " Turret Devourers " ,
[ 700 ] = " Pipe Perforators " ,
[ 750 ] = " Desync Bros " ,
[ 800 ] = " Ratio Randomizers " ,
[ 850 ] = " Wire Chompers " ,
[ 900 ] = " The Bus Mixers " ,
[ 950 ] = " Roundabout Deadlockers " ,
2019-06-07 11:15:16 +02:00
[ 1000 ] = " Happy Tree Friends " ,
2019-04-15 02:44:06 +02:00
[ 1050 ] = " Uranium Digesters " ,
[ 1100 ] = " Bot Banishers " ,
[ 1150 ] = " Chest Crushers " ,
[ 1200 ] = " Cargo Wagon Scratchers " ,
[ 1250 ] = " Transport Belt Surfers " ,
[ 1300 ] = " Pumpjack Pulverizers " ,
[ 1350 ] = " Radar Ravagers " ,
[ 1400 ] = " Mall Deconstrutors " ,
[ 1450 ] = " Lamp Dimmers " ,
[ 1500 ] = " Roboport Disablers " ,
[ 1550 ] = " Signal Spammers " ,
[ 1600 ] = " Brick Tramplers " ,
[ 1650 ] = " Drill Destroyers " ,
[ 1700 ] = " Gearwheel Grinders " ,
[ 1750 ] = " Silo Seekers " ,
[ 1800 ] = " Circuit Breakers " ,
[ 1850 ] = " Bullet Absorbers " ,
[ 1900 ] = " Oil Guzzlers " ,
[ 1950 ] = " Belt Rotators " ,
[ 2000 ] = " Bluescreen Factor "
}
2019-09-16 18:18:21 +02:00
local function send_unit_group ( unit_group )
local commands = { }
for x = unit_group.position . x , global.market . position.x , - 48 do
local destination = unit_group.surface . find_non_colliding_position ( " stone-wall " , { x = x , y = unit_group.position . y } , 32 , 4 )
if destination then
commands [ # commands + 1 ] = {
type = defines.command . attack_area ,
destination = destination ,
radius = 16 ,
distraction = defines.distraction . by_enemy
}
end
end
commands [ # commands + 1 ] = {
type = defines.command . attack_area ,
destination = { x = global.market . position.x , y = unit_group.position . y } ,
radius = 16 ,
distraction = defines.distraction . by_enemy
}
commands [ # commands + 1 ] = {
type = defines.command . attack ,
target = global.market ,
distraction = defines.distraction . by_enemy
}
unit_group.set_command ( {
type = defines.command . compound ,
structure_type = defines.compound_command . logical_and ,
commands = commands
} )
end
2019-04-15 02:44:06 +02:00
local function spawn_boss_units ( surface )
if boss_wave_names [ global.wave_count ] then
game.print ( " Boss Wave " .. global.wave_count .. " - - " .. boss_wave_names [ global.wave_count ] , { r = 0.8 , g = 0.1 , b = 0.1 } )
else
game.print ( " Boss Wave " .. global.wave_count , { r = 0.8 , g = 0.1 , b = 0.1 } )
end
2019-06-07 11:15:16 +02:00
2019-04-15 02:44:06 +02:00
if not boss_waves [ global.wave_count ] then
2019-09-16 18:18:21 +02:00
local amount = global.wave_count
if amount > 1000 then amount = 1000 end
boss_waves [ global.wave_count ] = { { name = " behemoth-biter " , count = math.floor ( amount / 20 ) } , { name = " behemoth-spitter " , count = math.floor ( amount / 40 ) } }
2019-06-07 11:15:16 +02:00
end
2019-09-16 18:18:21 +02:00
2019-09-17 07:30:16 +02:00
local health_factor = difficulties_votes [ global.difficulty_vote_index ] . boss_modifier
if global.wave_count == 100 then health_factor = health_factor * 2 end
2019-09-16 18:18:21 +02:00
2019-04-15 02:44:06 +02:00
local position = { x = 216 , y = 0 }
local biter_group = surface.create_unit_group ( { position = position } )
for _ , entry in pairs ( boss_waves [ global.wave_count ] ) do
for x = 1 , entry.count , 1 do
local pos = surface.find_non_colliding_position ( entry.name , position , 64 , 3 )
if pos then
local biter = surface.create_entity ( { name = entry.name , position = pos } )
2019-09-16 18:18:21 +02:00
biter.ai_settings . allow_destroy_when_commands_fail = false
biter.ai_settings . allow_try_return_to_spawner = false
2019-05-22 00:17:00 +02:00
global.boss_biters [ biter.unit_number ] = biter
2019-09-16 18:18:21 +02:00
add_boss_unit ( biter , global.biter_evasion_health_increase_factor * health_factor , 0.55 )
2019-04-15 02:44:06 +02:00
biter_group.add_member ( biter )
end
end
2019-06-07 11:15:16 +02:00
end
2019-09-16 18:18:21 +02:00
send_unit_group ( biter_group )
2019-04-15 02:44:06 +02:00
end
2019-06-07 11:15:16 +02:00
local function wake_up_the_biters ( surface )
2019-04-15 02:44:06 +02:00
if not global.market then return end
2019-06-07 11:15:16 +02:00
2019-04-15 02:44:06 +02:00
local units = surface.find_entities_filtered ( { type = " unit " } )
units = shuffle ( units )
local unit_groups = { }
2019-09-16 18:18:21 +02:00
local y_raffle = get_y_coord_raffle_table ( )
2019-04-15 02:44:06 +02:00
for i = 1 , 2 , 1 do
if not units [ i ] then break end
if not units [ i ] . valid then break end
2019-09-16 18:18:21 +02:00
local x = units [ i ] . position.x
if x > 256 then x = 256 end
local y = units [ i ] . position.y
if y > 96 or y < - 96 then y = y_raffle [ i ] end
unit_groups [ i ] = surface.create_unit_group ( { position = { x = x , y = y } } )
2019-04-15 02:44:06 +02:00
local biters = surface.find_enemy_units ( units [ i ] . position , 24 , " player " )
for _ , biter in pairs ( biters ) do
unit_groups [ i ] . add_member ( biter )
2019-06-07 11:15:16 +02:00
end
2019-04-15 02:44:06 +02:00
end
2019-06-07 11:15:16 +02:00
2019-04-15 02:44:06 +02:00
for i = 1 , # unit_groups , 1 do
if unit_groups [ i ] . valid then
2019-06-07 11:15:16 +02:00
if # unit_groups [ i ] . members > 0 then
2019-09-16 18:18:21 +02:00
send_unit_group ( unit_groups [ i ] )
2019-04-15 02:44:06 +02:00
else
unit_groups [ i ] . destroy ( )
end
end
2019-06-07 11:15:16 +02:00
end
2019-04-15 02:44:06 +02:00
surface.set_multi_command ( {
command = {
type = defines.command . attack ,
target = global.market ,
distraction = defines.distraction . none
} ,
unit_count = 16 ,
force = " enemy " ,
unit_search_distance = 24
} )
end
2019-04-15 20:19:32 +02:00
local function damage_entity_outside_of_fence ( e )
if not e.health then return end
if e.force . name == " neutral " then return end
if e.type == " unit " or e.type == " unit-spawner " then return end
2019-06-07 11:15:16 +02:00
2019-04-15 20:19:32 +02:00
e.surface . create_entity ( { name = " water-splash " , position = e.position } )
2019-06-07 11:15:16 +02:00
2019-04-15 20:19:32 +02:00
if e.type == " entity-ghost " then e.destroy ( ) return end
2019-06-07 11:15:16 +02:00
2019-04-15 20:19:32 +02:00
e.health = e.health - math_random ( math.floor ( e.prototype . max_health * 0.05 ) , math.floor ( e.prototype . max_health * 0.1 ) )
if e.health <= 0 then e.die ( " enemy " ) end
end
2019-04-15 02:44:06 +02:00
local function biter_attack_wave ( )
2019-06-07 11:15:16 +02:00
if not global.market then return end
2019-04-15 02:44:06 +02:00
if global.wave_grace_period then return end
local surface = game.surfaces [ " fish_defender " ]
2019-06-07 11:15:16 +02:00
2019-04-15 02:44:06 +02:00
clear_corpses ( surface )
wake_up_the_biters ( surface )
2019-06-07 11:15:16 +02:00
2019-04-15 02:44:06 +02:00
if surface.count_entities_filtered ( { type = " unit " } ) > biter_count_limit then
2019-06-07 11:15:16 +02:00
--game.print("Biter limit reached, wave delayed.", {r = 0.7, g = 0.1, b = 0.1})
return
2019-04-15 02:44:06 +02:00
end
2019-06-07 11:15:16 +02:00
2019-04-15 02:44:06 +02:00
if not global.wave_count then
global.wave_count = 1
else
global.wave_count = global.wave_count + 1
end
2019-08-15 12:38:24 +02:00
local m = 0.0015
if global.difficulty_vote_index then
m = m * difficulties_votes [ global.difficulty_vote_index ] . strength_modifier
end
game.forces . enemy.set_ammo_damage_modifier ( " melee " , global.wave_count * m )
game.forces . enemy.set_ammo_damage_modifier ( " biological " , global.wave_count * m )
global.biter_evasion_health_increase_factor = 1 + ( global.wave_count * ( m * 2 ) )
local m = 4
if global.difficulty_vote_index then
m = m * difficulties_votes [ global.difficulty_vote_index ] . amount_modifier
end
2019-06-07 11:15:16 +02:00
if global.wave_count % 50 == 0 then
2019-09-13 13:10:41 +02:00
global.attack_wave_threat = math.floor ( global.wave_count * ( m * 1.5 ) )
2019-04-15 02:44:06 +02:00
spawn_boss_units ( surface )
2019-09-08 07:21:19 +02:00
if global.attack_wave_threat > 10000 then global.attack_wave_threat = 10000 end
2019-04-15 02:44:06 +02:00
else
2019-08-15 12:38:24 +02:00
global.attack_wave_threat = math.floor ( global.wave_count * m )
2019-09-08 07:21:19 +02:00
if global.attack_wave_threat > 10000 then global.attack_wave_threat = 10000 end
2019-06-07 11:15:16 +02:00
end
2019-08-15 12:38:24 +02:00
2019-04-15 02:44:06 +02:00
local evolution = global.wave_count * 0.00125
if evolution > 1 then evolution = 1 end
game.forces . enemy.evolution_factor = evolution
2019-06-07 11:15:16 +02:00
2019-09-16 18:18:21 +02:00
--if game.forces.enemy.evolution_factor == 1 then
-- if not global.endgame_modifier then
-- global.endgame_modifier = 1
-- game.print("Endgame enemy evolution reached.", {r = 0.7, g = 0.1, b = 0.1})
-- else
-- global.endgame_modifier = global.endgame_modifier + 1
-- end
--end
2019-06-07 11:15:16 +02:00
2019-04-15 20:19:32 +02:00
for _ , e in pairs ( surface.find_entities_filtered ( { area = { { 160 , - 256 } , { 360 , 256 } } } ) ) do
2019-06-07 11:15:16 +02:00
damage_entity_outside_of_fence ( e )
end
2019-09-16 18:18:21 +02:00
local y_raffle = get_y_coord_raffle_table ( )
2019-06-07 11:15:16 +02:00
2019-04-15 02:44:06 +02:00
local unit_groups = { }
2019-09-16 18:18:21 +02:00
if global.wave_count > 50 and math_random ( 1 , 8 ) == 1 then
for i = 1 , 10 , 1 do
unit_groups [ i ] = surface.create_unit_group ( { position = { x = 256 , y = y_raffle [ i ] } } )
2019-04-15 02:44:06 +02:00
end
2019-06-07 11:15:16 +02:00
else
2019-04-15 02:44:06 +02:00
for i = 1 , get_number_of_attack_groups ( ) , 1 do
2019-09-16 18:18:21 +02:00
unit_groups [ i ] = surface.create_unit_group ( { position = { x = 256 , y = y_raffle [ i ] } } )
2019-04-15 02:44:06 +02:00
end
end
2019-09-16 18:18:21 +02:00
2019-04-15 02:44:06 +02:00
local biter_pool = get_biter_pool ( )
2019-09-16 18:18:21 +02:00
--local spawners = surface.find_entities_filtered({type = "unit-spawner", area = {{160, -196},{512, 196}}})
--table.shuffle_table(spawners)
2019-04-15 02:44:06 +02:00
while global.attack_wave_threat > 0 do
for i = 1 , # unit_groups , 1 do
2019-09-16 18:18:21 +02:00
--local biter
--if spawners[i] then
--biter = spawn_biter(spawners[i].position, biter_pool)
--else
--biter = spawn_biter(unit_groups[i].position, biter_pool)
--end
2019-04-15 02:44:06 +02:00
local biter = spawn_biter ( unit_groups [ i ] . position , biter_pool )
if biter then
unit_groups [ i ] . add_member ( biter )
else
break
2019-06-07 11:15:16 +02:00
end
2019-04-15 02:44:06 +02:00
end
end
2019-06-07 11:15:16 +02:00
for i = 1 , # unit_groups , 1 do
2019-09-16 18:18:21 +02:00
send_unit_group ( unit_groups [ i ] )
2019-04-15 02:44:06 +02:00
end
end
2019-06-07 11:15:16 +02:00
local function get_sorted_list ( column_name , score_list )
2019-04-15 02:44:06 +02:00
for x = 1 , # score_list , 1 do
2019-06-07 11:15:16 +02:00
for y = 1 , # score_list , 1 do
2019-04-15 02:44:06 +02:00
if not score_list [ y + 1 ] then break end
if score_list [ y ] [ column_name ] < score_list [ y + 1 ] [ column_name ] then
local key = score_list [ y ]
score_list [ y ] = score_list [ y + 1 ]
score_list [ y + 1 ] = key
end
2019-06-07 11:15:16 +02:00
end
end
2019-04-15 02:44:06 +02:00
return score_list
end
local function get_mvps ( )
if not global.score [ " player " ] then return false end
local score = global.score [ " player " ]
local score_list = { }
for _ , p in pairs ( game.players ) do
local killscore = 0
if score.players [ p.name ] . killscore then killscore = score.players [ p.name ] . killscore end
local deaths = 0
if score.players [ p.name ] . deaths then deaths = score.players [ p.name ] . deaths end
local built_entities = 0
if score.players [ p.name ] . built_entities then built_entities = score.players [ p.name ] . built_entities end
local mined_entities = 0
if score.players [ p.name ] . mined_entities then mined_entities = score.players [ p.name ] . mined_entities end
2019-06-07 11:15:16 +02:00
table.insert ( score_list , { name = p.name , killscore = killscore , deaths = deaths , built_entities = built_entities , mined_entities = mined_entities } )
2019-04-15 02:44:06 +02:00
end
local mvp = { }
score_list = get_sorted_list ( " killscore " , score_list )
mvp.killscore = { name = score_list [ 1 ] . name , score = score_list [ 1 ] . killscore }
score_list = get_sorted_list ( " deaths " , score_list )
mvp.deaths = { name = score_list [ 1 ] . name , score = score_list [ 1 ] . deaths }
score_list = get_sorted_list ( " built_entities " , score_list )
mvp.built_entities = { name = score_list [ 1 ] . name , score = score_list [ 1 ] . built_entities }
return mvp
end
local function is_game_lost ( )
if global.market then return end
for _ , player in pairs ( game.connected_players ) do
if player.gui . left [ " fish_defense_game_lost " ] then return end
local f = player.gui . left.add ( { type = " frame " , name = " fish_defense_game_lost " , caption = " The fish market was overrun! The biters are having a feast :3 " , direction = " vertical " } )
f.style . font_color = { r = 0.65 , g = 0.1 , b = 0.99 }
2019-06-07 11:15:16 +02:00
2019-04-15 02:44:06 +02:00
local t = f.add ( { type = " table " , column_count = 2 } )
local l = t.add ( { type = " label " , caption = " Survival Time >> " } )
l.style . font = " default-listbox "
l.style . font_color = { r = 0.22 , g = 0.77 , b = 0.44 }
2019-06-07 11:15:16 +02:00
2019-04-15 02:44:06 +02:00
if global.market_age >= 216000 then
local l = t.add ( { type = " label " , caption = math.floor ( ( ( global.market_age / 60 ) / 60 ) / 60 ) .. " hours " .. math.ceil ( ( global.market_age % 216000 / 60 ) / 60 ) .. " minutes " } )
l.style . font = " default-bold "
l.style . font_color = { r = 0.33 , g = 0.66 , b = 0.9 }
else
local l = t.add ( { type = " label " , caption = math.ceil ( ( global.market_age % 216000 / 60 ) / 60 ) .. " minutes " } )
l.style . font = " default-bold "
l.style . font_color = { r = 0.33 , g = 0.66 , b = 0.9 }
end
2019-06-07 11:15:16 +02:00
local mvp = get_mvps ( )
2019-04-15 02:44:06 +02:00
if mvp then
2019-06-07 11:15:16 +02:00
2019-04-15 02:44:06 +02:00
local l = t.add ( { type = " label " , caption = " MVP Defender >> " } )
l.style . font = " default-listbox "
l.style . font_color = { r = 0.22 , g = 0.77 , b = 0.44 }
local l = t.add ( { type = " label " , caption = mvp.killscore . name .. " with a score of " .. mvp.killscore . score } )
l.style . font = " default-bold "
l.style . font_color = { r = 0.33 , g = 0.66 , b = 0.9 }
2019-06-07 11:15:16 +02:00
2019-04-15 02:44:06 +02:00
local l = t.add ( { type = " label " , caption = " MVP Builder >> " } )
l.style . font = " default-listbox "
l.style . font_color = { r = 0.22 , g = 0.77 , b = 0.44 }
local l = t.add ( { type = " label " , caption = mvp.built_entities . name .. " built " .. mvp.built_entities . score .. " things " } )
l.style . font = " default-bold "
l.style . font_color = { r = 0.33 , g = 0.66 , b = 0.9 }
2019-06-07 11:15:16 +02:00
2019-04-15 02:44:06 +02:00
local l = t.add ( { type = " label " , caption = " MVP Deaths >> " } )
l.style . font = " default-listbox "
l.style . font_color = { r = 0.22 , g = 0.77 , b = 0.44 }
2019-06-07 11:15:16 +02:00
local l = t.add ( { type = " label " , caption = mvp.deaths . name .. " died " .. mvp.deaths . score .. " times " } )
2019-04-15 02:44:06 +02:00
l.style . font = " default-bold "
l.style . font_color = { r = 0.33 , g = 0.66 , b = 0.9 }
2019-06-07 11:15:16 +02:00
2019-04-15 02:44:06 +02:00
if not global.results_sent then
local result = { }
insert ( result , ' MVP Defender: \\ n ' )
insert ( result , mvp.killscore . name .. " with a score of " .. mvp.killscore . score .. " \\ n " )
insert ( result , ' \\ n ' )
insert ( result , ' MVP Builder: \\ n ' )
insert ( result , mvp.built_entities . name .. " built " .. mvp.built_entities . score .. " things \\ n " )
insert ( result , ' \\ n ' )
insert ( result , ' MVP Deaths: \\ n ' )
2019-06-07 11:15:16 +02:00
insert ( result , mvp.deaths . name .. " died " .. mvp.deaths . score .. " times " )
2019-04-15 02:44:06 +02:00
local message = table.concat ( result )
server_commands.to_discord_embed ( message )
global.results_sent = true
end
end
2019-06-07 11:15:16 +02:00
2019-04-15 02:44:06 +02:00
for _ , player in pairs ( game.connected_players ) do
2019-05-03 09:47:16 +02:00
player.play_sound { path = " utility/game_lost " , volume_modifier = 0.75 }
2019-06-07 11:15:16 +02:00
end
2019-04-15 02:44:06 +02:00
end
2019-06-07 11:15:16 +02:00
2019-04-15 02:44:06 +02:00
game.map_settings . enemy_expansion.enabled = true
game.map_settings . enemy_expansion.max_expansion_distance = 15
game.map_settings . enemy_expansion.settler_group_min_size = 15
game.map_settings . enemy_expansion.settler_group_max_size = 30
game.map_settings . enemy_expansion.min_expansion_cooldown = 600
game.map_settings . enemy_expansion.max_expansion_cooldown = 600
end
local function damage_entities_in_radius ( surface , position , radius , damage )
local entities_to_damage = surface.find_entities_filtered ( { area = { { position.x - radius , position.y - radius } , { position.x + radius , position.y + radius } } } )
for _ , entity in pairs ( entities_to_damage ) do
2019-09-08 00:22:17 +02:00
if entity.valid then
if entity.health and entity.name ~= " land-mine " then
if entity.force . name ~= " enemy " then
if entity.name == " character " then
entity.damage ( damage , " enemy " )
else
entity.health = entity.health - damage
if entity.health <= 0 then entity.die ( " enemy " ) end
end
2019-04-15 02:44:06 +02:00
end
end
end
end
end
2019-04-15 09:02:51 +02:00
local function market_kill_visuals ( )
local m = 32
local m2 = m * 0.005
2019-06-07 11:15:16 +02:00
for i = 1 , 1024 , 1 do
2019-04-15 09:02:51 +02:00
global.market . surface.create_entity ( {
name = " branch-particle " ,
position = global.market . position ,
frame_speed = 0.1 ,
vertical_speed = 0.1 ,
height = 0.1 ,
movement = { m2 - ( math.random ( 0 , m ) * 0.01 ) , m2 - ( math.random ( 0 , m ) * 0.01 ) }
} )
end
for x = - 5 , 5 , 0.5 do
2019-06-07 11:15:16 +02:00
for y = - 5 , 5 , 0.5 do
2019-04-15 09:02:51 +02:00
if math_random ( 1 , 2 ) == 1 then
2019-06-07 11:15:16 +02:00
global.market . surface.create_trivial_smoke ( { name = " smoke-fast " , position = { global.market . position.x + ( x * 0.35 ) , global.market . position.y + ( y * 0.35 ) } } )
2019-04-15 09:02:51 +02:00
end
if math_random ( 1 , 3 ) == 1 then
2019-06-07 11:15:16 +02:00
global.market . surface.create_trivial_smoke ( { name = " train-smoke " , position = { global.market . position.x + ( x * 0.35 ) , global.market . position.y + ( y * 0.35 ) } } )
2019-04-15 09:02:51 +02:00
end
end
end
global.market . surface.spill_item_stack ( global.market . position , { name = " raw-fish " , count = 1024 } , true )
end
2019-04-15 02:44:06 +02:00
local biter_splash_damage = {
2019-09-16 18:18:21 +02:00
[ " medium-biter " ] = { visuals = { " blood-explosion-big " , " big-explosion " } , radius = 1.5 , damage_min = 50 , damage_max = 100 , chance = 32 } ,
[ " big-biter " ] = { visuals = { " blood-explosion-huge " , " ground-explosion " } , radius = 2 , damage_min = 75 , damage_max = 150 , chance = 48 } ,
[ " behemoth-biter " ] = { visuals = { " blood-explosion-huge " , " big-artillery-explosion " } , radius = 2.5 , damage_min = 100 , damage_max = 200 , chance = 64 }
2019-04-15 02:44:06 +02:00
}
local function on_entity_died ( event )
2019-09-16 18:18:21 +02:00
if not event.entity . valid then return end
2019-06-07 11:15:16 +02:00
if event.entity . force.name == " enemy " then
2019-04-15 02:44:06 +02:00
local surface = event.entity . surface
2019-06-07 11:15:16 +02:00
2019-09-16 18:18:21 +02:00
if global.boss_biters [ event.entity . unit_number ] then boss_biter.died ( event ) end
2019-06-07 11:15:16 +02:00
local splash = biter_splash_damage [ event.entity . name ]
if splash then
if math_random ( 1 , splash.chance ) == 1 then
2019-04-15 02:44:06 +02:00
for _ , visual in pairs ( splash.visuals ) do
surface.create_entity ( { name = visual , position = event.entity . position } )
end
damage_entities_in_radius ( surface , event.entity . position , splash.radius , math_random ( splash.damage_min , splash.damage_max ) )
return
end
end
2019-06-07 11:15:16 +02:00
if event.entity . name == " behemoth-biter " then
2019-04-15 02:44:06 +02:00
if math_random ( 1 , 16 ) == 1 then
local p = surface.find_non_colliding_position ( " big-biter " , event.entity . position , 3 , 0.5 )
if p then surface.create_entity { name = " big-biter " , position = p } end
end
for i = 1 , math_random ( 1 , 2 ) , 1 do
local p = surface.find_non_colliding_position ( " medium-biter " , event.entity . position , 3 , 0.5 )
if p then surface.create_entity { name = " medium-biter " , position = p } end
end
end
return
end
2019-09-16 18:18:21 +02:00
2019-04-15 02:44:06 +02:00
if event.entity == global.market then
2019-04-15 09:02:51 +02:00
market_kill_visuals ( )
2019-04-15 02:44:06 +02:00
global.market = nil
global.market_age = game.tick
is_game_lost ( )
end
2019-06-07 11:15:16 +02:00
2019-04-15 02:44:06 +02:00
if global.entity_limits [ event.entity . name ] then
global.entity_limits [ event.entity . name ] . placed = global.entity_limits [ event.entity . name ] . placed - 1
2019-06-07 11:15:16 +02:00
update_fd_stats ( )
2019-04-15 02:44:06 +02:00
end
end
local function on_player_joined_game ( event )
local player = game.players [ event.player_index ]
2019-09-16 18:18:21 +02:00
if player.online_time == 0 then
2019-04-15 02:44:06 +02:00
player.insert ( { name = " pistol " , count = 1 } )
--player.insert({name = "iron-axe", count = 1})
player.insert ( { name = " raw-fish " , count = 3 } )
player.insert ( { name = " firearm-magazine " , count = 16 } )
player.insert ( { name = " iron-plate " , count = 32 } )
if global.show_floating_killscore then global.show_floating_killscore [ player.name ] = false end
end
2019-06-07 11:15:16 +02:00
2019-04-15 02:44:06 +02:00
local surface = game.surfaces [ " fish_defender " ]
2019-06-07 11:15:16 +02:00
if player.online_time < 2 and surface.is_chunk_generated ( { 0 , 0 } ) then
2019-09-16 18:18:21 +02:00
player.teleport ( surface.find_non_colliding_position ( " character " , game.forces [ " player " ] . get_spawn_position ( surface ) , 50 , 1 ) , " fish_defender " )
2019-04-15 02:44:06 +02:00
else
if player.online_time < 2 then
2019-09-16 18:18:21 +02:00
player.teleport ( game.forces [ " player " ] . get_spawn_position ( surface ) , " fish_defender " )
2019-04-15 02:44:06 +02:00
end
end
2019-09-22 11:13:32 +02:00
2019-04-15 02:44:06 +02:00
create_wave_gui ( player )
2019-06-07 11:15:16 +02:00
add_fd_stats_button ( player )
2019-04-15 02:44:06 +02:00
if game.tick > 900 then
is_game_lost ( )
end
2019-09-22 11:13:32 +02:00
2019-09-27 17:31:33 +02:00
--if global.charting_done then return end
--game.forces.player.chart(game.surfaces["fish_defender"], {{-256, -512},{768, 512}})
--global.charting_done = true
2019-04-15 02:44:06 +02:00
end
local function on_built_entity ( event )
local entity = event.created_entity
if not entity.valid then return end
if global.entity_limits [ entity.name ] then
local surface = entity.surface
2019-06-07 11:15:16 +02:00
2019-04-15 02:44:06 +02:00
if global.entity_limits [ entity.name ] . placed < global.entity_limits [ entity.name ] . limit then
2019-06-07 11:15:16 +02:00
global.entity_limits [ entity.name ] . placed = global.entity_limits [ entity.name ] . placed + 1
2019-04-15 02:44:06 +02:00
surface.create_entity (
{ name = " flying-text " , position = entity.position , text = global.entity_limits [ entity.name ] . placed .. " / " .. global.entity_limits [ entity.name ] . limit .. " " .. global.entity_limits [ entity.name ] . str .. " s " , color = { r = 0.98 , g = 0.66 , b = 0.22 } }
)
2019-06-07 11:15:16 +02:00
update_fd_stats ( )
2019-04-15 02:44:06 +02:00
else
2019-06-07 11:15:16 +02:00
surface.create_entity ( { name = " flying-text " , position = entity.position , text = global.entity_limits [ entity.name ] . str .. " limit reached. " , color = { r = 0.82 , g = 0.11 , b = 0.11 } } )
local player = game.players [ event.player_index ]
2019-04-15 02:44:06 +02:00
player.insert ( { name = entity.name , count = 1 } )
if global.score then
if global.score [ player.force . name ] then
if global.score [ player.force . name ] . players [ player.name ] then
global.score [ player.force . name ] . players [ player.name ] . built_entities = global.score [ player.force . name ] . players [ player.name ] . built_entities - 1
end
end
2019-06-07 11:15:16 +02:00
end
2019-04-15 02:44:06 +02:00
entity.destroy ( )
end
end
end
local function on_robot_built_entity ( event )
local entity = event.created_entity
if global.entity_limits [ entity.name ] then
2019-06-07 11:15:16 +02:00
local surface = entity.surface
2019-04-15 02:44:06 +02:00
if global.entity_limits [ entity.name ] . placed < global.entity_limits [ entity.name ] . limit then
2019-06-07 11:15:16 +02:00
global.entity_limits [ entity.name ] . placed = global.entity_limits [ entity.name ] . placed + 1
2019-04-15 02:44:06 +02:00
surface.create_entity (
{ name = " flying-text " , position = entity.position , text = global.entity_limits [ entity.name ] . placed .. " / " .. global.entity_limits [ entity.name ] . limit .. " " .. global.entity_limits [ entity.name ] . str .. " s " , color = { r = 0.98 , g = 0.66 , b = 0.22 } }
)
2019-06-07 11:15:16 +02:00
update_fd_stats ( )
2019-04-15 02:44:06 +02:00
else
surface.create_entity ( { name = " flying-text " , position = entity.position , text = global.entity_limits [ entity.name ] . str .. " limit reached. " , color = { r = 0.82 , g = 0.11 , b = 0.11 } } )
local inventory = event.robot . get_inventory ( defines.inventory . robot_cargo )
inventory.insert ( { name = entity.name , count = 1 } )
2019-06-07 11:15:16 +02:00
entity.destroy ( )
2019-04-15 02:44:06 +02:00
end
end
end
local function on_tick ( )
2019-06-07 11:15:16 +02:00
if game.tick % 30 == 0 then
2019-04-15 02:44:06 +02:00
if global.market then
for _ , player in pairs ( game.connected_players ) do
if game.surfaces [ " fish_defender " ] . peaceful_mode == false then
2019-06-07 11:15:16 +02:00
create_wave_gui ( player )
end
end
2019-04-15 02:44:06 +02:00
end
if game.tick % 180 == 0 then
if game.surfaces [ " fish_defender " ] then
2019-09-27 17:31:33 +02:00
game.forces . player.chart ( game.surfaces [ " fish_defender " ] , { { - 160 , - 128 } , { 192 , 128 } } )
2019-08-15 12:38:24 +02:00
if global.difficulty_vote_index then
global.wave_interval = difficulties_votes [ global.difficulty_vote_index ] . wave_interval
end
2019-04-15 02:44:06 +02:00
end
end
2019-06-07 11:15:16 +02:00
2019-04-15 02:44:06 +02:00
if global.market_age then
if not global.game_restart_timer then
2019-08-15 12:38:24 +02:00
global.game_restart_timer = 10800
2019-04-15 02:44:06 +02:00
else
if global.game_restart_timer < 0 then return end
global.game_restart_timer = global.game_restart_timer - 30
end
2019-06-07 11:15:16 +02:00
if global.game_restart_timer % 1800 == 0 then
2019-04-15 02:44:06 +02:00
if global.game_restart_timer > 0 then game.print ( " Map will restart in " .. global.game_restart_timer / 60 .. " seconds! " , { r = 0.22 , g = 0.88 , b = 0.22 } ) end
if global.game_restart_timer == 0 then
game.print ( " Map is restarting! " , { r = 0.22 , g = 0.88 , b = 0.22 } )
--game.write_file("commandPipe", ":loadscenario --force", false, 0)
2019-06-07 11:15:16 +02:00
2019-04-15 02:44:06 +02:00
local message = ' Map is restarting! '
server_commands.to_discord_bold ( table.concat { ' *** ' , message , ' *** ' } )
server_commands.start_scenario ( ' Fish_Defender ' )
2019-06-07 11:15:16 +02:00
end
2019-04-15 02:44:06 +02:00
end
end
end
2019-08-15 12:38:24 +02:00
if game.tick % global.wave_interval == global.wave_interval - 1 then
2019-04-15 02:44:06 +02:00
if game.surfaces [ " fish_defender " ] . peaceful_mode == true then return end
biter_attack_wave ( )
end
end
local function on_player_changed_position ( event )
local player = game.players [ event.player_index ]
2019-09-13 13:10:41 +02:00
if player.position . x + player.position . y < 0 then return end
if player.position . x < player.position . y then return end
2019-04-15 02:44:06 +02:00
if player.position . x >= 160 then
player.teleport ( { player.position . x - 1 , player.position . y } , game.surfaces [ " fish_defender " ] )
if player.position . y > map_height or player.position . y < map_height * - 1 then
player.teleport ( { player.position . x , 0 } , game.surfaces [ " fish_defender " ] )
end
if player.character then
player.character . health = player.character . health - 25
player.character . surface.create_entity ( { name = " water-splash " , position = player.position } )
if player.character . health <= 0 then player.character . die ( " enemy " ) end
end
end
end
local function on_player_mined_entity ( event )
if global.entity_limits [ event.entity . name ] then
global.entity_limits [ event.entity . name ] . placed = global.entity_limits [ event.entity . name ] . placed - 1
2019-06-07 11:15:16 +02:00
update_fd_stats ( )
2019-04-15 02:44:06 +02:00
end
end
local function on_robot_mined_entity ( event )
if global.entity_limits [ event.entity . name ] then
global.entity_limits [ event.entity . name ] . placed = global.entity_limits [ event.entity . name ] . placed - 1
2019-06-07 11:15:16 +02:00
update_fd_stats ( )
2019-04-15 02:44:06 +02:00
end
end
local function on_research_finished ( event )
local research = event.research . name
if research ~= " tanks " then return end
game.forces [ " player " ] . technologies [ " artillery " ] . researched = true
game.forces . player.recipes [ " artillery-wagon " ] . enabled = false
end
local function on_player_respawned ( event )
if not global.market_age then return end
2019-06-07 11:15:16 +02:00
local player = game.players [ event.player_index ]
player.character . destructible = false
2019-04-15 02:44:06 +02:00
end
2019-08-15 12:38:24 +02:00
local function on_init ( event )
global.wave_interval = 3600 --interval between waves in ticks
2019-09-16 18:18:21 +02:00
global.wave_grace_period = 3600 * 20
global.difficulty_poll_closing_timeout = global.wave_grace_period
2019-08-15 12:38:24 +02:00
global.boss_biters = { }
global.acid_lines_delay = { }
2019-09-13 13:10:41 +02:00
global.entity_limits = {
[ " gun-turret " ] = { placed = 1 , limit = 1 , str = " gun turret " , slot_price = 75 } ,
[ " laser-turret " ] = { placed = 0 , limit = 1 , str = " laser turret " , slot_price = 300 } ,
[ " artillery-turret " ] = { placed = 0 , limit = 1 , str = " artillery turret " , slot_price = 500 } ,
[ " flamethrower-turret " ] = { placed = 0 , limit = 0 , str = " flamethrower turret " , slot_price = 50000 } ,
[ " land-mine " ] = { placed = 0 , limit = 1 , str = " mine " , slot_price = 1 } ,
}
2019-09-16 18:18:21 +02:00
local map_gen_settings = { }
2019-09-17 07:30:16 +02:00
map_gen_settings.height = 2048
map_gen_settings.water = 0.10
map_gen_settings.terrain_segmentation = 3
2019-09-22 11:13:32 +02:00
map_gen_settings.cliff_settings = { cliff_elevation_interval = 32 , cliff_elevation_0 = 32 }
2019-09-16 18:18:21 +02:00
map_gen_settings.autoplace_controls = {
[ " coal " ] = { frequency = 3 , size = 1.5 , richness = 1 } ,
[ " stone " ] = { frequency = 3 , size = 1.5 , richness = 1 } ,
[ " copper-ore " ] = { frequency = 3 , size = 1.5 , richness = 1 } ,
[ " iron-ore " ] = { frequency = 3 , size = 1.5 , richness = 1 } ,
[ " uranium-ore " ] = { frequency = 0 , size = 0 , richness = 0 } ,
[ " crude-oil " ] = { frequency = 5 , size = 1.25 , richness = 2 } ,
[ " trees " ] = { frequency = 2 , size = 1 , richness = 1 } ,
[ " enemy-base " ] = { frequency = " none " , size = " none " , richness = " none " }
}
game.create_surface ( " fish_defender " , map_gen_settings )
local surface = game.surfaces [ " fish_defender " ]
game.map_settings . enemy_expansion.enabled = false
game.map_settings . enemy_evolution.destroy_factor = 0
game.map_settings . enemy_evolution.time_factor = 0
game.map_settings . enemy_evolution.pollution_factor = 0
game.map_settings . pollution.enabled = false
game.forces [ " player " ] . technologies [ " atomic-bomb " ] . enabled = false
--game.forces["player"].technologies["landfill"].enabled = false
game.create_force ( " decoratives " )
game.forces [ " decoratives " ] . set_cease_fire ( " enemy " , true )
game.forces [ " enemy " ] . set_cease_fire ( " decoratives " , true )
game.forces [ " player " ] . set_cease_fire ( " decoratives " , true )
global.comfylatron_habitat = {
left_top = { x = - 1500 , y = - 1500 } ,
right_bottom = { x = - 80 , y = 1500 }
}
fish_eye ( surface , { x = - 2150 , y = - 300 } )
2019-09-22 11:13:32 +02:00
global.chunk_queue = { }
2019-08-15 12:38:24 +02:00
end
2019-06-07 11:15:16 +02:00
event.add ( defines.events . on_gui_click , on_gui_click )
2019-06-07 15:43:44 +02:00
event.add ( defines.events . on_market_item_purchased , on_market_item_purchased )
2019-04-15 02:44:06 +02:00
event.add ( defines.events . on_player_respawned , on_player_respawned )
event.add ( defines.events . on_built_entity , on_built_entity )
event.add ( defines.events . on_entity_died , on_entity_died )
2019-09-13 18:02:45 +02:00
event.add ( defines.events . on_player_changed_position , on_player_changed_position )
2019-04-15 02:44:06 +02:00
event.add ( defines.events . on_player_joined_game , on_player_joined_game )
event.add ( defines.events . on_player_mined_entity , on_player_mined_entity )
2019-06-07 11:15:16 +02:00
event.add ( defines.events . on_research_finished , on_research_finished )
2019-04-15 02:44:06 +02:00
event.add ( defines.events . on_robot_built_entity , on_robot_built_entity )
event.add ( defines.events . on_robot_mined_entity , on_robot_mined_entity )
event.add ( defines.events . on_tick , on_tick )
2019-08-15 12:38:24 +02:00
event.on_init ( on_init )
2019-10-12 09:35:00 +02:00
require " modules.difficulty_vote "
require " modules.rpg "