2018-11-25 17:04:57 +02:00
-- fish defender -- by mewmew --
2018-11-02 23:37:58 +02:00
local event = require ' utils.event '
2018-11-09 10:34:19 +02:00
require " maps.fish_defender_map_intro "
require " maps.fish_defender_kaboomsticks "
2018-11-07 22:48:03 +02:00
local map_functions = require " maps.tools.map_functions "
2018-11-02 23:37:58 +02:00
local math_random = math.random
local insert = table.insert
2018-11-27 08:09:49 +02:00
local wave_interval = 3600 --interval between waves in ticks
local biter_count_limit = 4000 --maximum biters on the east side of the map, next wave will not spawn if the maximum has been reached, if there are too biters the game might go slow
2018-11-02 23:37:58 +02:00
2018-11-03 19:16:59 +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
2018-11-06 01:07:35 +02:00
local function create_wave_gui ( player )
if player.gui . top [ " fish_defense_waves " ] then player.gui . top [ " fish_defense_waves " ] . destroy ( ) end
2018-11-07 02:50:14 +02:00
local frame = player.gui . top.add ( { type = " frame " , name = " fish_defense_waves " } )
frame.style . maximal_height = 38
2018-11-07 21:27:42 +02:00
2018-11-07 02:50:14 +02:00
local wave_count = 0
2018-11-20 15:46:13 +02:00
if global.wave_count then wave_count = global.wave_count end
2018-11-21 14:38:48 +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 }
local next_level_progress = game.tick % wave_interval / wave_interval
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
else
local time_remaining = math.floor ( ( ( global.wave_grace_period - ( game.tick % global.wave_grace_period ) ) / 60 ) / 60 )
if time_remaining <= 0 then
global.wave_grace_period = nil
2018-11-22 22:40:17 +02:00
return
2018-11-21 14:38:48 +02:00
end
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 }
end
2018-11-02 23:37:58 +02:00
end
2018-11-20 15:46:13 +02:00
local threat_values = {
[ " small_biter " ] = 1 ,
2018-11-27 08:09:49 +02:00
[ " medium_biter " ] = 3 ,
[ " big_biter " ] = 6 ,
[ " behemoth_biter " ] = 12 ,
2018-11-20 15:46:13 +02:00
[ " small_spitter " ] = 1 ,
2018-11-27 08:09:49 +02:00
[ " medium_spitter " ] = 3 ,
[ " big_spitter " ] = 6 ,
[ " behemoth_spitter " ] = 12
2018-11-20 15:46:13 +02:00
}
local function get_biter_initial_pool ( )
local biter_pool = { }
2018-11-27 08:09:49 +02:00
if global.wave_count > 2000 then
biter_pool = {
{ name = " big-biter " , threat = threat_values.big_biter , weight = 1 } ,
{ name = " behemoth-biter " , threat = threat_values.behemoth_biter , weight = 1 } ,
{ name = " behemoth-spitter " , threat = threat_values.behemoth_spitter , weight = 1 }
}
return biter_pool
end
2018-11-24 15:08:52 +02:00
if global.wave_count > 1000 then
biter_pool = {
{ name = " big-biter " , threat = threat_values.big_biter , weight = 3 } ,
{ name = " behemoth-biter " , threat = threat_values.behemoth_biter , weight = 2 } ,
{ name = " behemoth-spitter " , threat = threat_values.behemoth_spitter , weight = 1 }
}
return biter_pool
end
2018-11-20 15:46:13 +02:00
if game.forces . enemy.evolution_factor < 0.1 then
biter_pool = {
{ name = " small-biter " , threat = threat_values.small_biter , weight = 3 } ,
{ name = " small-spitter " , threat = threat_values.small_spitter , weight = 1 }
}
return biter_pool
end
2018-11-20 23:30:08 +02:00
if game.forces . enemy.evolution_factor < 0.2 then
2018-11-20 15:46:13 +02:00
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
2018-11-20 23:30:08 +02:00
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
2018-11-20 15:46:13 +02:00
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
2018-11-20 23:30:08 +02:00
if game.forces . enemy.evolution_factor < 0.5 then
2018-11-20 15:46:13 +02:00
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
2018-11-20 23:30:08 +02:00
if game.forces . enemy.evolution_factor < 0.6 then
biter_pool = {
{ 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
2018-11-20 15:46:13 +02:00
if game.forces . enemy.evolution_factor < 0.8 then
biter_pool = {
{ name = " behemoth-biter " , threat = threat_values.small_biter , weight = 2 } ,
2018-11-20 23:30:08 +02:00
{ name = " medium-biter " , threat = threat_values.medium_biter , weight = 4 } ,
2018-11-20 15:46:13 +02:00
{ name = " big-biter " , threat = threat_values.big_biter , weight = 10 } ,
{ name = " behemoth-spitter " , threat = threat_values.small_spitter , weight = 1 } ,
2018-11-20 23:30:08 +02:00
{ name = " medium-spitter " , threat = threat_values.medium_spitter , weight = 2 } ,
2018-11-20 15:46:13 +02:00
{ name = " big-spitter " , threat = threat_values.big_spitter , weight = 5 }
}
return biter_pool
end
2018-11-20 23:30:08 +02:00
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
end
2018-11-20 15:46:13 +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
end
end
local function get_biter_pool ( )
2018-11-21 14:38:48 +02:00
local surface = game.surfaces [ " fish_defender " ]
2018-11-20 15:46:13 +02:00
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 } )
2018-11-03 19:16:59 +02:00
end
2018-11-07 21:27:42 +02:00
end
2018-11-20 15:46:13 +02:00
return biter_raffle
end
local function spawn_biter_attack_group ( pos , amount_of_biters )
if global.attack_wave_threat < 1 then return false end
2018-11-21 14:38:48 +02:00
local surface = game.surfaces [ " fish_defender " ]
2018-11-20 15:46:13 +02:00
local biter_pool = get_biter_pool ( )
2018-11-27 08:09:49 +02:00
local unit_group = surface.create_unit_group ( { position = pos } )
2018-11-20 15:46:13 +02:00
while global.attack_wave_threat > 0 do
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 , 50 , 0.5 )
unit_group.add_member ( surface.create_entity ( { name = biter_pool [ 1 ] . name , position = valid_pos } ) )
amount_of_biters = amount_of_biters - 1
if amount_of_biters == 0 then break end
end
return unit_group
2018-11-03 19:16:59 +02:00
end
2018-11-27 08:09:49 +02:00
local function spawn_biter ( pos , biter_pool )
if global.attack_wave_threat < 1 then return false end
local surface = game.surfaces [ " fish_defender " ]
biter_pool = shuffle ( biter_pool )
global.attack_wave_threat = global.attack_wave_threat - biter_pool [ 1 ] . threat
2018-11-28 22:43:32 +02:00
local valid_pos = surface.find_non_colliding_position ( biter_pool [ 1 ] . name , pos , 100 , 0.75 )
2018-11-27 08:09:49 +02:00
local biter = surface.create_entity ( { name = biter_pool [ 1 ] . name , position = valid_pos } )
return biter
end
local attack_group_count_thresholds = {
{ 0 , 1 } ,
2018-11-28 22:43:32 +02:00
{ 50 , 2 } ,
{ 100 , 3 } ,
{ 150 , 4 } ,
{ 200 , 5 } ,
{ 1000 , 6 } ,
{ 2000 , 7 } ,
{ 3000 , 8 }
2018-11-27 08:09:49 +02:00
}
local function get_number_of_attack_groups ( )
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
2018-11-03 19:16:59 +02:00
local function biter_attack_wave ( )
2018-11-09 10:34:19 +02:00
if not global.market then return end
2018-11-21 14:38:48 +02:00
if global.wave_grace_period then return end
local surface = game.surfaces [ " fish_defender " ]
2018-11-27 08:09:49 +02:00
if surface.count_entities_filtered ( { type = " unit " , area = { { - 128 , - 256 } , { 360 , 256 } } } ) > biter_count_limit then
game.print ( " Biter limit reached, wave stalled. " , { r = 0.7 , g = 0.1 , b = 0.1 } )
return
end
2018-11-02 23:37:58 +02:00
if not global.wave_count then
2018-11-20 15:46:13 +02:00
global.wave_count = 1
2018-11-02 23:37:58 +02:00
else
2018-11-20 15:46:13 +02:00
global.wave_count = global.wave_count + 1
2018-11-02 23:37:58 +02:00
end
2018-11-21 14:38:48 +02:00
2018-11-20 15:46:13 +02:00
global.attack_wave_threat = global.wave_count * 5
2018-11-27 08:09:49 +02:00
if global.attack_wave_threat > 25000 then global.attack_wave_threat = 25000 end
2018-11-20 15:46:13 +02:00
local evolution = global.wave_count * 0.00125
2018-11-12 05:11:06 +02:00
if evolution > 1 then evolution = 1 end
game.forces . enemy.evolution_factor = evolution
2018-11-24 15:08:52 +02:00
if game.forces . enemy.evolution_factor == 1 then
2018-11-07 21:27:42 +02:00
if not global.endgame_modifier then
2018-11-24 15:08:52 +02:00
global.endgame_modifier = 1
2018-11-07 21:27:42 +02:00
game.print ( " Endgame enemy evolution reached. Biter damage is rising... " , { r = 0.7 , g = 0.1 , b = 0.1 } )
else
2018-11-24 15:08:52 +02:00
global.endgame_modifier = global.endgame_modifier + 1
2018-11-07 21:27:42 +02:00
end
end
2018-11-24 15:08:52 +02:00
local units = surface.find_entities_filtered ( { type = " unit " , area = { { 192 , - 256 } , { 360 , 256 } } } )
for _ , unit in pairs ( units ) do
2018-11-28 22:43:32 +02:00
unit.set_command ( {
type = defines.command . compound ,
structure_type = defines.compound_command . return_last ,
commands = {
{
type = defines.command . attack_area ,
destination = { x = 32 , y = 0 } ,
radius = 16 ,
distraction = defines.distraction . by_anything
} ,
{
type = defines.command . attack ,
target = global.market ,
distraction = defines.distraction . by_enemy
}
}
} )
2018-11-24 15:08:52 +02:00
end
2018-11-28 22:43:32 +02:00
2018-11-24 15:08:52 +02:00
local units = surface.find_entities_filtered ( { force = " player " , area = { { 160 , - 256 } , { 360 , 256 } } } )
for _ , unit in pairs ( units ) do
if unit.health then
unit.health = unit.health - math_random ( 75 , 125 )
surface.create_entity ( { name = " water-splash " , position = unit.position } )
if unit.health <= 0 then unit.die ( " enemy " ) end
else
if unit.type == " entity-ghost " then
unit.destroy ( )
end
end
2018-11-20 23:30:08 +02:00
end
2018-11-24 15:08:52 +02:00
2018-11-11 14:04:38 +02:00
local spawn_x = 242
2018-11-27 08:09:49 +02:00
local target_x = 32
local group_coords = { }
2018-11-28 22:43:32 +02:00
for a = - 80 , 80 , 16 do
2018-11-27 08:09:49 +02:00
insert ( group_coords , { spawn = { x = spawn_x , y = a * 2 } , target = { x = target_x , y = a } } )
end
2018-11-07 21:27:42 +02:00
group_coords = shuffle ( group_coords )
2018-11-20 15:46:13 +02:00
2018-11-27 08:09:49 +02:00
local unit_groups = { }
2018-11-28 22:43:32 +02:00
if global.wave_count > 100 and math_random ( 1 , 3 ) == 1 then
for i = 1 , # group_coords , 1 do
2018-11-27 08:09:49 +02:00
unit_groups [ i ] = surface.create_unit_group ( { position = group_coords [ i ] . spawn } )
end
else
for i = 1 , get_number_of_attack_groups ( ) , 1 do
unit_groups [ i ] = surface.create_unit_group ( { position = group_coords [ i ] . spawn } )
end
end
local biter_pool = get_biter_pool ( )
while global.attack_wave_threat > 0 do
for i = 1 , # unit_groups , 1 do
local biter = spawn_biter ( unit_groups [ i ] . position , biter_pool )
if biter then
unit_groups [ i ] . add_member ( biter )
else
break
end
end
end
for i = 1 , # unit_groups , 1 do
unit_groups [ i ] . set_command ( {
type = defines.command . compound ,
structure_type = defines.compound_command . return_last ,
commands = {
{
type = defines.command . attack_area ,
destination = group_coords [ i ] . target ,
radius = 16 ,
distraction = defines.distraction . by_anything
} ,
{
type = defines.command . attack ,
target = global.market ,
distraction = defines.distraction . by_enemy
}
}
} )
end
2018-11-09 10:34:19 +02:00
end
2018-11-07 21:27:42 +02:00
2018-11-20 15:46:13 +02:00
local function refresh_market_offers ( )
if not global.market then return end
for i = 1 , 100 , 1 do
local a = global.market . remove_market_item ( 1 )
if a == false then break end
end
2018-11-21 14:38:48 +02:00
local str1 = " Gun Turret Slot for " .. tostring ( global.entity_limits [ " gun-turret " ] . limit * global.entity_limits [ " gun-turret " ] . slot_price )
2018-11-20 15:46:13 +02:00
str1 = str1 .. " Coins. "
2018-11-21 14:38:48 +02:00
2018-11-20 15:46:13 +02:00
local str2 = " Laser Turret Slot for " .. tostring ( global.entity_limits [ " laser-turret " ] . limit * global.entity_limits [ " laser-turret " ] . slot_price )
str2 = str2 .. " Coins. "
2018-11-21 14:38:48 +02:00
2018-11-24 15:08:52 +02:00
local str3 = " Artillery Slot for " .. tostring ( global.entity_limits [ " artillery-turret " ] . limit * global.entity_limits [ " artillery-turret " ] . slot_price )
2018-11-20 15:46:13 +02:00
str3 = str3 .. " Coins. "
2018-11-21 14:38:48 +02:00
2018-11-24 15:08:52 +02:00
local current_limit = 1
if global.entity_limits [ " flamethrower-turret " ] . limit ~= 0 then current_limit = current_limit + global.entity_limits [ " flamethrower-turret " ] . limit end
local str4 = " Flamethrower Turret Slot for " .. tostring ( current_limit * global.entity_limits [ " flamethrower-turret " ] . slot_price )
2018-11-20 23:30:08 +02:00
str4 = str4 .. " Coins. "
2018-11-20 15:46:13 +02:00
2018-11-24 15:08:52 +02:00
local str5 = " Landmine Slot for " .. tostring ( global.entity_limits [ " land-mine " ] . limit * global.entity_limits [ " land-mine " ] . slot_price )
str5 = str5 .. " Coins. "
2018-11-20 15:46:13 +02:00
local market_items = {
{ price = { } , offer = { type = ' nothing ' , effect_description = str1 } } ,
{ price = { } , offer = { type = ' nothing ' , effect_description = str2 } } ,
{ price = { } , offer = { type = ' nothing ' , effect_description = str3 } } ,
2018-11-20 23:30:08 +02:00
{ price = { } , offer = { type = ' nothing ' , effect_description = str4 } } ,
2018-11-24 15:08:52 +02:00
{ price = { } , offer = { type = ' nothing ' , effect_description = str5 } } ,
2018-11-20 15:46:13 +02:00
{ price = { { " coin " , 3 } } , offer = { type = ' give-item ' , item = " raw-fish " , count = 1 } } ,
2018-11-24 15:08:52 +02:00
{ price = { { " coin " , 1 } } , offer = { type = ' give-item ' , item = ' raw-wood ' , count = 8 } } ,
2018-11-27 08:09:49 +02:00
{ price = { { " coin " , 9 } } , offer = { type = ' give-item ' , item = ' grenade ' , count = 1 } } ,
2018-11-24 15:08:52 +02:00
{ price = { { " coin " , 32 } } , offer = { type = ' give-item ' , item = ' cluster-grenade ' , count = 1 } } ,
2018-11-27 08:09:49 +02:00
{ price = { { " coin " , 1 } } , offer = { type = ' give-item ' , item = ' land-mine ' , count = 1 } } ,
2018-11-20 15:46:13 +02:00
{ price = { { " coin " , 80 } } , offer = { type = ' give-item ' , item = ' car ' , count = 1 } } ,
2018-11-27 08:09:49 +02:00
{ price = { { " coin " , 1200 } } , offer = { type = ' give-item ' , item = ' tank ' , count = 1 } } ,
2018-11-21 14:38:48 +02:00
{ price = { { " coin " , 3 } } , offer = { type = ' give-item ' , item = ' cannon-shell ' , count = 1 } } ,
2018-11-24 15:08:52 +02:00
{ price = { { " coin " , 7 } } , offer = { type = ' give-item ' , item = ' explosive-cannon-shell ' , count = 1 } } ,
2018-11-20 23:30:08 +02:00
{ price = { { " coin " , 50 } } , offer = { type = ' give-item ' , item = ' gun-turret ' , count = 1 } } ,
2018-11-24 15:08:52 +02:00
{ price = { { " coin " , 350 } } , offer = { type = ' give-item ' , item = ' laser-turret ' , count = 1 } } ,
{ price = { { " coin " , 500 } } , offer = { type = ' give-item ' , item = ' artillery-turret ' , count = 1 } } ,
{ price = { { " coin " , 12 } } , offer = { type = ' give-item ' , item = ' artillery-shell ' , count = 1 } } ,
{ price = { { " coin " , 25 } } , offer = { type = ' give-item ' , item = ' artillery-targeting-remote ' , count = 1 } } ,
2018-11-20 15:46:13 +02:00
{ price = { { " coin " , 1 } } , offer = { type = ' give-item ' , item = ' firearm-magazine ' , count = 1 } } ,
{ price = { { " coin " , 4 } } , offer = { type = ' give-item ' , item = ' piercing-rounds-magazine ' , count = 1 } } ,
2018-11-20 23:30:08 +02:00
{ price = { { " coin " , 2 } } , offer = { type = ' give-item ' , item = ' shotgun-shell ' , count = 1 } } ,
{ price = { { " coin " , 6 } } , offer = { type = ' give-item ' , item = ' piercing-shotgun-shell ' , count = 1 } } ,
2018-11-21 14:38:48 +02:00
{ price = { { " coin " , 30 } } , offer = { type = ' give-item ' , item = " submachine-gun " , count = 1 } } ,
2018-11-20 15:46:13 +02:00
{ price = { { " coin " , 250 } } , offer = { type = ' give-item ' , item = ' combat-shotgun ' , count = 1 } } ,
2018-11-24 15:08:52 +02:00
{ price = { { " coin " , 650 } } , offer = { type = ' give-item ' , item = ' flamethrower ' , count = 1 } } ,
{ price = { { " coin " , 35 } } , offer = { type = ' give-item ' , item = ' flamethrower-ammo ' , count = 1 } } ,
2018-11-20 15:46:13 +02:00
{ price = { { " coin " , 125 } } , offer = { type = ' give-item ' , item = ' rocket-launcher ' , count = 1 } } ,
2018-11-24 15:08:52 +02:00
{ price = { { " coin " , 2 } } , offer = { type = ' give-item ' , item = ' rocket ' , count = 1 } } ,
{ price = { { " coin " , 7 } } , offer = { type = ' give-item ' , item = ' explosive-rocket ' , count = 1 } } ,
2018-11-20 23:30:08 +02:00
{ price = { { " coin " , 750 } } , offer = { type = ' give-item ' , item = ' atomic-bomb ' , count = 1 } } ,
{ price = { { " coin " , 90 } } , offer = { type = ' give-item ' , item = ' railgun ' , count = 1 } } ,
2018-11-20 15:46:13 +02:00
{ price = { { " coin " , 5 } } , offer = { type = ' give-item ' , item = ' railgun-dart ' , count = 1 } } ,
2018-11-28 22:43:32 +02:00
{ price = { { " coin " , 40 } } , offer = { type = ' give-item ' , item = ' poison-capsule ' , count = 1 } } ,
2018-11-20 15:46:13 +02:00
{ price = { { " coin " , 8 } } , offer = { type = ' give-item ' , item = ' defender-capsule ' , count = 1 } } ,
{ price = { { " coin " , 10 } } , offer = { type = ' give-item ' , item = ' light-armor ' , count = 1 } } ,
{ price = { { " coin " , 150 } } , offer = { type = ' give-item ' , item = ' heavy-armor ' , count = 1 } } ,
{ price = { { " coin " , 350 } } , offer = { type = ' give-item ' , item = ' modular-armor ' , count = 1 } } ,
{ price = { { " coin " , 1500 } } , offer = { type = ' give-item ' , item = ' power-armor ' , count = 1 } } ,
2018-11-24 15:08:52 +02:00
{ price = { { " coin " , 12500 } } , offer = { type = ' give-item ' , item = ' power-armor-mk2 ' , count = 1 } } ,
{ price = { { " coin " , 50 } } , offer = { type = ' give-item ' , item = ' solar-panel-equipment ' , count = 1 } } ,
{ price = { { " coin " , 2250 } } , offer = { type = ' give-item ' , item = ' fusion-reactor-equipment ' , count = 1 } } ,
{ price = { { " coin " , 100 } } , offer = { type = ' give-item ' , item = ' battery-equipment ' , count = 1 } } ,
2018-11-20 23:30:08 +02:00
{ price = { { " coin " , 200 } } , offer = { type = ' give-item ' , item = ' energy-shield-equipment ' , count = 1 } } ,
{ price = { { " coin " , 750 } } , offer = { type = ' give-item ' , item = ' personal-laser-defense-equipment ' , count = 1 } } ,
2018-11-20 15:46:13 +02:00
{ price = { { " coin " , 175 } } , offer = { type = ' give-item ' , item = ' exoskeleton-equipment ' , count = 1 } } ,
{ price = { { " coin " , 125 } } , offer = { type = ' give-item ' , item = ' night-vision-equipment ' , count = 1 } } ,
2018-11-24 15:08:52 +02:00
{ price = { { " coin " , 250 } } , offer = { type = ' give-item ' , item = ' belt-immunity-equipment ' , count = 1 } } ,
2018-11-20 15:46:13 +02:00
{ price = { { " coin " , 250 } } , offer = { type = ' give-item ' , item = ' personal-roboport-equipment ' , count = 1 } } ,
{ price = { { " coin " , 40 } } , offer = { type = ' give-item ' , item = ' construction-robot ' , count = 1 } }
}
for _ , item in pairs ( market_items ) do
global.market . add_market_item ( item )
end
end
2018-11-09 10:34:19 +02:00
local function get_sorted_list ( column_name , score_list )
for x = 1 , # score_list , 1 do
for y = 1 , # score_list , 1 do
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
end
end
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
table.insert ( score_list , { name = p.name , killscore = killscore , deaths = deaths , built_entities = built_entities , mined_entities = mined_entities } )
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
2018-11-02 23:37:58 +02:00
end
local function is_game_lost ( )
if global.market then return end
2018-11-07 21:27:42 +02:00
2018-11-02 23:37:58 +02:00
for _ , player in pairs ( game.connected_players ) do
2018-11-07 02:50:14 +02:00
if player.gui . left [ " fish_defense_game_lost " ] then return end
2018-11-09 10:34:19 +02:00
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 }
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 }
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
local mvp = get_mvps ( )
if mvp then
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 }
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 }
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 }
local l = t.add ( { type = " label " , caption = mvp.deaths . name .. " died " .. mvp.deaths . score .. " times " } )
l.style . font = " default-bold "
l.style . font_color = { r = 0.33 , g = 0.66 , b = 0.9 }
end
2018-11-03 19:16:59 +02:00
for _ , player in pairs ( game.connected_players ) do
2018-11-07 02:50:14 +02:00
player.play_sound { path = " utility/game_lost " , volume_modifier = 1 }
2018-11-03 19:16:59 +02:00
end
2018-11-02 23:37:58 +02:00
end
2018-11-07 21:27:42 +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
2018-11-02 23:37:58 +02:00
end
2018-11-10 05:57:26 +02:00
local biter_building_inhabitants = {
[ 1 ] = { { " small-biter " , 8 , 16 } } ,
[ 2 ] = { { " small-biter " , 12 , 24 } } ,
[ 3 ] = { { " small-biter " , 8 , 16 } , { " medium-biter " , 1 , 2 } } ,
[ 4 ] = { { " small-biter " , 4 , 8 } , { " medium-biter " , 4 , 8 } } ,
[ 5 ] = { { " small-biter " , 3 , 5 } , { " medium-biter " , 8 , 12 } } ,
[ 6 ] = { { " small-biter " , 3 , 5 } , { " medium-biter " , 5 , 7 } , { " big-biter " , 1 , 2 } } ,
[ 7 ] = { { " medium-biter " , 6 , 8 } , { " big-biter " , 3 , 5 } } ,
[ 8 ] = { { " medium-biter " , 2 , 4 } , { " big-biter " , 6 , 8 } } ,
[ 9 ] = { { " medium-biter " , 2 , 3 } , { " big-biter " , 7 , 9 } } ,
[ 10 ] = { { " big-biter " , 4 , 8 } , { " behemoth-biter " , 3 , 4 } }
}
2018-11-06 01:07:35 +02:00
2018-11-07 02:50:14 +02:00
local function damage_entities_in_radius ( position , radius , damage )
2018-11-21 14:38:48 +02:00
local entities_to_damage = game.surfaces [ " fish_defender " ] . find_entities_filtered ( { area = { { position.x - radius , position.y - radius } , { position.x + radius , position.y + radius } } } )
2018-11-07 02:50:14 +02:00
for _ , entity in pairs ( entities_to_damage ) do
if entity.health then
if entity.force . name ~= " enemy " then
if entity.name == " player " then
entity.damage ( damage , " enemy " )
else
entity.health = entity.health - damage
2018-11-24 15:08:52 +02:00
entity.surface . create_entity ( { name = " explosion " , position = entity.position } )
2018-11-07 02:50:14 +02:00
if entity.health <= 0 then entity.die ( " enemy " ) end
2018-11-07 21:27:42 +02:00
end
2018-11-07 02:50:14 +02:00
end
end
end
end
2018-11-09 10:34:19 +02:00
local coin_earnings = {
[ " small-biter " ] = 1 ,
[ " medium-biter " ] = 2 ,
[ " big-biter " ] = 3 ,
[ " behemoth-biter " ] = 5 ,
[ " small-spitter " ] = 1 ,
[ " medium-spitter " ] = 2 ,
[ " big-spitter " ] = 3 ,
2018-11-26 17:50:30 +02:00
[ " behemoth-spitter " ] = 5 ,
[ " spitter-spawner " ] = 32 ,
[ " biter-spawner " ] = 32
2018-11-09 10:34:19 +02:00
}
2018-11-28 22:43:32 +02:00
local entities_that_earn_coins = {
[ " artillery-turret " ] = true
--["defender"] = true,
-- ["distractor"] = true,
-- ["destroyer"] = true
}
2018-11-02 23:37:58 +02:00
local function on_entity_died ( event )
2018-11-03 19:16:59 +02:00
if event.entity . force.name == " enemy " then
2018-11-21 14:38:48 +02:00
local players_to_reward = { }
2018-11-26 17:50:30 +02:00
local reward_has_been_given = false
if event.cause then
if event.entity . type == " unit " or event.entity . type == " unit-spawner " then
if event.cause . name == " player " then
insert ( players_to_reward , event.cause )
reward_has_been_given = true
end
if event.cause . type == " car " then
player = event.cause . get_driver ( )
passenger = event.cause . get_passenger ( )
if player then insert ( players_to_reward , player.player ) end
if passenger then insert ( players_to_reward , passenger.player ) end
reward_has_been_given = true
end
if event.cause . type == " locomotive " then
train_passengers = event.cause . train.passengers
if train_passengers then
for _ , passenger in pairs ( train_passengers ) do
insert ( players_to_reward , passenger )
end
reward_has_been_given = true
2018-11-11 02:26:24 +02:00
end
end
2018-11-26 17:50:30 +02:00
for _ , player in pairs ( players_to_reward ) do
player.insert ( { name = " coin " , count = coin_earnings [ event.entity . name ] } )
end
2018-11-28 22:43:32 +02:00
if entities_that_earn_coins [ event.cause . name ] then
2018-11-26 17:50:30 +02:00
event.entity . surface.spill_item_stack ( event.cause . position , { name = " coin " , count = coin_earnings [ event.entity . name ] } , true )
reward_has_been_given = true
2018-11-28 22:43:32 +02:00
end
2018-11-11 02:26:24 +02:00
end
2018-11-10 05:57:26 +02:00
end
2018-11-26 17:50:30 +02:00
2018-11-28 22:43:32 +02:00
if reward_has_been_given == false and coin_earnings [ event.entity . name ] then
event.entity . surface.spill_item_stack ( event.entity . position , { name = " coin " , count = coin_earnings [ event.entity . name ] } , true )
2018-11-21 14:38:48 +02:00
end
2018-11-06 01:07:35 +02:00
if event.entity . name == " biter-spawner " or event.entity . name == " spitter-spawner " then
2018-11-07 21:27:42 +02:00
local e = math.ceil ( game.forces . enemy.evolution_factor * 10 , 0 )
for _ , t in pairs ( biter_building_inhabitants [ e ] ) do
2018-11-06 01:07:35 +02:00
for x = 1 , math.random ( t [ 2 ] , t [ 3 ] ) , 1 do
2018-11-07 21:27:42 +02:00
local p = event.entity . surface.find_non_colliding_position ( t [ 1 ] , event.entity . position , 6 , 1 )
2018-11-06 01:07:35 +02:00
if p then event.entity . surface.create_entity { name = t [ 1 ] , position = p } end
end
end
end
2018-11-07 21:27:42 +02:00
2018-11-06 01:07:35 +02:00
if event.entity . name == " medium-biter " then
event.entity . surface.create_entity ( { name = " explosion " , position = event.entity . position } )
2018-11-07 21:27:42 +02:00
local damage = 25
2018-11-24 15:08:52 +02:00
if global.endgame_modifier then damage = 25 + math.ceil ( ( global.endgame_modifier * 0.05 ) , 0 ) end
damage_entities_in_radius ( event.entity . position , 1 + math.floor ( global.wave_count * 0.001 ) , damage )
2018-11-06 01:07:35 +02:00
end
2018-11-07 21:27:42 +02:00
2018-11-06 01:07:35 +02:00
if event.entity . name == " big-biter " then
event.entity . surface.create_entity ( { name = " uranium-cannon-shell-explosion " , position = event.entity . position } )
2018-11-09 10:34:19 +02:00
local damage = 35
2018-11-24 15:08:52 +02:00
if global.endgame_modifier then damage = 50 + math.ceil ( ( global.endgame_modifier * 0.1 ) , 0 ) end
damage_entities_in_radius ( event.entity . position , 2 + math.floor ( global.wave_count * 0.001 ) , damage )
2018-11-06 01:07:35 +02:00
end
2018-11-07 21:27:42 +02:00
2018-11-24 15:08:52 +02:00
if event.entity . name == " behemoth-biter " then
local spawn_entity = false
if global.wave_count >= 1000 then
spawn_entity = " small-worm-turret "
end
if global.wave_count >= 1500 then
spawn_entity = " medium-worm-turret "
end
if global.wave_count >= 2000 then
spawn_entity = " big-worm-turret "
end
if spawn_entity then
local surface = event.entity . surface
if surface.count_entities_filtered ( { area = { { event.entity . position.x - 3 , event.entity . position.y - 3 } , { event.entity . position.x + 3 , event.entity . position.y + 3 } } , name = spawn_entity } ) == 0 then
surface.create_entity ( { name = " blood-explosion-huge " , position = event.entity . position } )
surface.create_entity ( { name = spawn_entity , position = event.entity . position } )
end
end
end
2018-11-03 19:16:59 +02:00
return
end
2018-11-20 23:30:08 +02:00
2018-11-02 23:37:58 +02:00
if event.entity == global.market then
global.market = nil
global.market_age = game.tick
is_game_lost ( )
end
2018-11-12 05:11: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
end
2018-11-02 23:37:58 +02:00
end
local function on_entity_damaged ( event )
2018-11-07 02:50:14 +02:00
if event.cause then
if event.cause . name == " big-spitter " then
local surface = event.cause . surface
local area = { { event.entity . position.x - 3 , event.entity . position.y - 3 } , { event.entity . position.x + 3 , event.entity . position.y + 3 } }
if surface.count_entities_filtered ( { area = area , name = " small-biter " , limit = 3 } ) < 3 then
local pos = surface.find_non_colliding_position ( " small-biter " , event.entity . position , 3 , 1 )
surface.create_entity ( { name = " small-biter " , position = pos } )
end
end
2018-11-07 21:27:42 +02:00
if event.cause . name == " behemoth-spitter " then
local surface = event.cause . surface
local area = { { event.entity . position.x - 3 , event.entity . position.y - 3 } , { event.entity . position.x + 3 , event.entity . position.y + 3 } }
if surface.count_entities_filtered ( { area = area , name = " medium-biter " , limit = 3 } ) < 3 then
local pos = surface.find_non_colliding_position ( " medium-biter " , event.entity . position , 3 , 1 )
surface.create_entity ( { name = " medium-biter " , position = pos } )
end
end
2018-11-07 02:50:14 +02:00
if event.cause . force.name == " enemy " then
2018-11-07 21:27:42 +02:00
if global.endgame_modifier then
2018-11-24 15:08:52 +02:00
event.entity . health = event.entity . health - ( event.final_damage_amount * global.endgame_modifier * 0.002 )
2018-11-12 05:11:06 +02:00
if event.entity . health <= 0 then event.entity . die ( ) end
2018-11-07 21:27:42 +02:00
end
2018-11-07 02:50:14 +02:00
end
end
2018-11-24 15:08:52 +02:00
if event.entity . valid then
if event.entity . name == " market " then
2018-11-26 17:50:30 +02:00
if event.cause then
if event.cause . force.name == " enemy " then return end
end
2018-11-24 15:08:52 +02:00
event.entity . health = event.entity . health + event.final_damage_amount
end
2018-11-02 23:37:58 +02:00
end
end
local function on_player_joined_game ( event )
local player = game.players [ event.player_index ]
2018-11-07 21:27:42 +02:00
2018-11-21 14:38:48 +02:00
if not global.fish_defense_init_done then
local map_gen_settings = { }
map_gen_settings.water = " small "
map_gen_settings.cliff_settings = { cliff_elevation_interval = 22 , cliff_elevation_0 = 22 }
map_gen_settings.autoplace_controls = {
[ " coal " ] = { frequency = " normal " , size = " normal " , richness = " normal " } ,
[ " stone " ] = { frequency = " normal " , size = " normal " , richness = " normal " } ,
[ " copper-ore " ] = { frequency = " normal " , size = " normal " , richness = " normal " } ,
[ " iron-ore " ] = { frequency = " normal " , size = " normal " , richness = " normal " } ,
[ " crude-oil " ] = { frequency = " high " , size = " big " , richness = " normal " } ,
[ " trees " ] = { frequency = " normal " , size = " normal " , richness = " normal " } ,
[ " enemy-base " ] = { frequency = " none " , size = " none " , richness = " none " } ,
[ " grass " ] = { frequency = " normal " , size = " normal " , richness = " normal " } ,
[ " sand " ] = { frequency = " normal " , size = " normal " , richness = " normal " } ,
[ " desert " ] = { frequency = " normal " , size = " normal " , richness = " normal " } ,
[ " dirt " ] = { frequency = " normal " , size = " normal " , richness = " normal " }
}
game.create_surface ( " fish_defender " , map_gen_settings )
local surface = game.surfaces [ " fish_defender " ]
local radius = 256
game.forces . player.chart ( surface , { { x = - 1 * radius , y = - 1 * radius } , { x = radius , y = radius } } )
2018-11-07 02:50:14 +02:00
game.map_settings . enemy_expansion.enabled = false
2018-11-12 05:11:06 +02:00
game.map_settings . enemy_evolution.destroy_factor = 0
game.map_settings . enemy_evolution.time_factor = 0
2018-11-24 15:08:52 +02:00
game.map_settings . enemy_evolution.pollution_factor = 0
2018-11-22 22:40:17 +02:00
game.forces [ " player " ] . set_turret_attack_modifier ( " flamethrower-turret " , - 0.75 )
2018-11-02 23:37:58 +02:00
game.forces . player.set_ammo_damage_modifier ( " shotgun-shell " , 0.5 )
2018-11-21 14:38:48 +02:00
2018-11-20 15:46:13 +02:00
global.entity_limits = {
2018-11-28 22:43:32 +02:00
[ " gun-turret " ] = { placed = 1 , limit = 1 , str = " gun turret " , slot_price = 150 } ,
[ " laser-turret " ] = { placed = 0 , limit = 1 , str = " laser turret " , slot_price = 350 } ,
2018-11-24 15:08:52 +02:00
[ " artillery-turret " ] = { placed = 0 , limit = 1 , str = " artillery turret " , slot_price = 500 } ,
[ " flamethrower-turret " ] = { placed = 0 , limit = 0 , str = " flamethrower turret " , slot_price = 50000 } ,
2018-11-28 22:43:32 +02:00
[ " land-mine " ] = { placed = 0 , limit = 1 , str = " landmine " , slot_price = 3 }
2018-11-20 15:46:13 +02:00
}
2018-11-21 14:38:48 +02:00
global.wave_grace_period = wave_interval * 21
2018-11-09 10:34:19 +02:00
2018-11-02 23:37:58 +02:00
global.fish_defense_init_done = true
end
2018-11-07 21:27:42 +02:00
2018-11-02 23:37:58 +02:00
if player.online_time < 1 then
player.insert ( { name = " pistol " , count = 1 } )
2018-11-06 01:07:35 +02:00
player.insert ( { name = " iron-axe " , count = 1 } )
player.insert ( { name = " raw-fish " , count = 3 } )
player.insert ( { name = " firearm-magazine " , count = 32 } )
2018-11-09 10:34:19 +02:00
player.insert ( { name = " iron-plate " , count = 64 } )
if global.show_floating_killscore then global.show_floating_killscore [ player.name ] = false end
2018-11-02 23:37:58 +02:00
end
2018-11-21 14:38:48 +02:00
2018-11-22 22:40:17 +02:00
local surface = game.surfaces [ " fish_defender " ]
if player.online_time < 5 and surface.is_chunk_generated ( { 0 , 0 } ) then
player.teleport ( surface.find_non_colliding_position ( " player " , { - 10 , 0 } , 2 , 1 ) , " fish_defender " )
else
if player.online_time < 5 then
player.teleport ( { 16 , 0 } , " fish_defender " )
end
end
2018-11-21 14:38:48 +02:00
if global.wave_grace_period then
global.wave_grace_period = global.wave_grace_period - 3600
if global.wave_grace_period <= 0 then global.wave_grace_period = nil end
end
2018-11-25 17:04:57 +02:00
create_wave_gui ( player )
if game.tick > 900 then
is_game_lost ( )
end
2018-11-02 23:37:58 +02:00
end
local map_height = 96
2018-11-07 22:48:03 +02:00
2018-11-02 23:37:58 +02:00
local function on_chunk_generated ( event )
2018-11-21 14:38:48 +02:00
local surface = game.surfaces [ " fish_defender " ]
2018-11-22 22:40:17 +02:00
2018-11-23 12:30:57 +02:00
if not surface then return end
if surface.name ~= event.surface . name then return end
2018-11-02 23:37:58 +02:00
local area = event.area
local left_top = area.left_top
2018-11-07 21:27:42 +02:00
2018-11-02 23:37:58 +02:00
local entities = surface.find_entities_filtered ( { area = area , force = " enemy " } )
for _ , entity in pairs ( entities ) do
entity.destroy ( )
2018-11-07 22:48:03 +02:00
end
2018-11-22 22:40:17 +02:00
if left_top.x >= 192 then
if not global.spawn_ores_generated then
local pos = surface.find_non_colliding_position ( " market " , { - 8 , 0 } , 50 , 1 )
global.market = surface.create_entity ( { name = " market " , position = pos , force = " player " } )
global.market . minable = false
refresh_market_offers ( )
local pos = surface.find_non_colliding_position ( " gun-turret " , { - 6 , 1 } , 50 , 1 )
local turret = surface.create_entity ( { name = " gun-turret " , position = pos , force = " player " } )
turret.insert ( { name = " firearm-magazine " , count = 32 } )
surface.create_entity ( { name = " electric-beam " , position = { 160 , - 95 } , source = { 160 , - 95 } , target = { 160 , 96 } } )
local pos = surface.find_non_colliding_position ( " player " , { - 10 , 0 } , 50 , 1 )
game.forces [ " player " ] . set_spawn_position ( pos , surface )
2018-11-09 10:34:19 +02:00
2018-11-22 22:40:17 +02:00
local tiles = { }
2018-11-09 10:34:19 +02:00
local replacement_tile = surface.get_tile ( global.market . position )
2018-11-22 22:40:17 +02:00
local water_tiles = surface.find_tiles_filtered ( { name = { " water " , " deepwater " } } )
for _ , tile in pairs ( water_tiles ) do
insert ( tiles , { name = replacement_tile.name , position = { tile.position . x , tile.position . y } } )
end
2018-11-09 10:34:19 +02:00
surface.set_tiles ( tiles , true )
2018-11-22 22:40:17 +02:00
local entities = surface.find_entities_filtered ( { type = " resource " } )
for _ , entity in pairs ( entities ) do
entity.destroy ( )
end
2018-11-07 22:48:03 +02:00
map_functions.draw_smoothed_out_ore_circle ( { x = - 64 , y = - 64 } , " copper-ore " , surface , 15 , 2500 )
map_functions.draw_smoothed_out_ore_circle ( { x = - 64 , y = - 32 } , " iron-ore " , surface , 15 , 2500 )
map_functions.draw_smoothed_out_ore_circle ( { x = - 64 , y = 32 } , " coal " , surface , 15 , 1500 )
2018-11-22 22:40:17 +02:00
map_functions.draw_smoothed_out_ore_circle ( { x = - 64 , y = 64 } , " stone " , surface , 15 , 1500 )
2018-11-20 23:30:08 +02:00
map_functions.draw_noise_tile_circle ( { x = - 32 , y = 0 } , " water " , surface , 16 )
2018-11-22 22:40:17 +02:00
map_functions.draw_oil_circle ( { x = - 64 , y = 0 } , " crude-oil " , surface , 8 , 200000 )
local decorative_names = { }
for k , v in pairs ( game.decorative_prototypes ) do
if v.autoplace_specification then
decorative_names [ # decorative_names + 1 ] = k
end
end
for x = - 4 , 4 , 1 do
for y = - 3 , 3 , 1 do
surface.regenerate_decorative ( decorative_names , { { x , y } } )
end
end
2018-11-07 22:48:03 +02:00
global.spawn_ores_generated = true
2018-11-25 17:04:57 +02:00
end
end
2018-11-26 17:50:30 +02:00
if left_top.x <= - 352 then
if math_random ( 1 , 32 ) == 1 then
2018-11-25 17:04:57 +02:00
local positions = { }
for x = 0 , 31 , 1 do
for y = 0 , 31 , 1 do
insert ( positions , { x = left_top.x + x , y = left_top.y + y } )
end
end
positions = shuffle ( positions )
for _ , pos in pairs ( positions ) do
if surface.can_place_entity ( { name = " biter-spawner " , force = " enemy " , position = pos } ) then
if math_random ( 1 , 4 ) == 1 then
local entity = surface.create_entity ( { name = " spitter-spawner " , force = " enemy " , position = pos } )
else
local entity = surface.create_entity ( { name = " biter-spawner " , force = " enemy " , position = pos } )
end
break
end
end
end
2018-11-07 22:48:03 +02:00
end
2018-11-02 23:37:58 +02:00
local tiles = { }
2018-11-07 21:27:42 +02:00
local hourglass_center_piece_length = 64
2018-11-07 22:48:03 +02:00
2018-11-07 21:27:42 +02:00
for x = 0 , 31 , 1 do
for y = 0 , 31 , 1 do
2018-11-07 02:50:14 +02:00
local pos = { x = left_top.x + x , y = left_top.y + y }
if pos.y >= map_height then
if pos.y > pos.x - hourglass_center_piece_length and pos.x > 0 then
insert ( tiles , { name = " out-of-map " , position = pos } )
end
if pos.y > ( pos.x + hourglass_center_piece_length ) * - 1 and pos.x <= 0 then
insert ( tiles , { name = " out-of-map " , position = pos } )
end
2018-11-07 21:27:42 +02:00
end
2018-11-07 02:50:14 +02:00
if pos.y < map_height * - 1 then
if pos.y < ( pos.x - hourglass_center_piece_length ) * - 1 and pos.x > 0 then
insert ( tiles , { name = " out-of-map " , position = pos } )
end
if pos.y < pos.x + hourglass_center_piece_length and pos.x <= 0 then
insert ( tiles , { name = " out-of-map " , position = pos } )
end
2018-11-02 23:37:58 +02:00
end
end
end
2018-11-07 21:27:42 +02:00
2018-11-02 23:37:58 +02:00
surface.set_tiles ( tiles , false )
2018-11-07 21:27:42 +02:00
if left_top.x < 160 then return end
2018-11-03 19:16:59 +02:00
local entities = surface.find_entities_filtered ( { area = area , type = " tree " } )
for _ , entity in pairs ( entities ) do
entity.destroy ( )
end
2018-11-07 21:27:42 +02:00
2018-11-03 19:16:59 +02:00
local entities = surface.find_entities_filtered ( { area = area , type = " cliff " } )
for _ , entity in pairs ( entities ) do
entity.destroy ( )
end
2018-11-07 21:27:42 +02:00
2018-11-07 02:50:14 +02:00
local entities = surface.find_entities_filtered ( { area = area , type = " resource " } )
for _ , entity in pairs ( entities ) do
surface.create_entity ( { name = " uranium-ore " , position = entity.position , amount = math_random ( 200 , 8000 ) } )
entity.destroy ( )
end
2018-11-07 21:27:42 +02:00
2018-11-07 02:50:14 +02:00
local tiles = { }
2018-11-07 21:27:42 +02:00
for x = 0 , 31 , 1 do
for y = 0 , 31 , 1 do
2018-11-02 23:37:58 +02:00
local pos = { x = left_top.x + x , y = left_top.y + y }
2018-11-07 21:27:42 +02:00
2018-11-07 02:50:14 +02:00
local tile = surface.get_tile ( pos )
if tile.name ~= " out-of-map " then
2018-11-20 15:46:13 +02:00
if pos.x > 312 then
insert ( tiles , { name = " out-of-map " , position = pos } )
else
2018-11-24 15:08:52 +02:00
insert ( tiles , { name = " dirt-7 " , position = pos } )
2018-11-20 15:46:13 +02:00
end
2018-11-24 15:08:52 +02:00
if pos.x > 296 and pos.x < 312 and math_random ( 1 , 128 ) == 1 then
2018-11-20 15:46:13 +02:00
2018-11-02 23:37:58 +02:00
if surface.can_place_entity ( { name = " biter-spawner " , force = " enemy " , position = pos } ) then
if math_random ( 1 , 4 ) == 1 then
2018-11-24 15:08:52 +02:00
local entity = surface.create_entity ( { name = " spitter-spawner " , force = " enemy " , position = pos } )
entity.active = false
else
local entity = surface.create_entity ( { name = " biter-spawner " , force = " enemy " , position = pos } )
entity.active = false
2018-11-02 23:37:58 +02:00
end
end
2018-11-20 15:46:13 +02:00
end
end
2018-11-02 23:37:58 +02:00
end
end
2018-11-07 02:50:14 +02:00
surface.set_tiles ( tiles , true )
2018-11-07 21:27:42 +02:00
2018-11-07 02:50:14 +02:00
local decorative_names = { }
for k , v in pairs ( game.decorative_prototypes ) do
if v.autoplace_specification then
decorative_names [ # decorative_names + 1 ] = k
2018-11-06 01:07:35 +02:00
end
2018-11-07 21:27:42 +02:00
end
surface.regenerate_decorative ( decorative_names , { { x = math.floor ( event.area . left_top.x / 32 ) , y = math.floor ( event.area . left_top.y / 32 ) } } )
2018-11-02 23:37:58 +02:00
end
local function on_built_entity ( event )
2018-11-12 05:11:06 +02:00
local entity = event.created_entity
if global.entity_limits [ entity.name ] then
local surface = entity.surface
if global.entity_limits [ entity.name ] . placed < global.entity_limits [ entity.name ] . limit then
global.entity_limits [ entity.name ] . placed = global.entity_limits [ entity.name ] . placed + 1
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 } }
)
2018-11-07 21:27:42 +02:00
else
2018-11-12 05:11:06 +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 ]
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
2018-11-07 02:50:14 +02:00
end
end
2018-11-12 05:11:06 +02:00
end
entity.destroy ( )
2018-11-07 02:50:14 +02:00
end
end
2018-11-12 05:11:06 +02:00
end
2018-11-07 21:27:42 +02:00
2018-11-12 05:11:06 +02:00
local function on_robot_built_entity ( event )
local entity = event.created_entity
if global.entity_limits [ entity.name ] then
2018-11-20 23:30:08 +02:00
local surface = entity.surface
2018-11-12 05:11:06 +02:00
if global.entity_limits [ entity.name ] . placed < global.entity_limits [ entity.name ] . limit then
global.entity_limits [ entity.name ] . placed = global.entity_limits [ entity.name ] . placed + 1
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 } }
)
2018-11-07 21:27:42 +02:00
else
2018-11-12 05:11:06 +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 inventory = event.robot . get_inventory ( defines.inventory . robot_cargo )
inventory.insert ( { name = entity.name , count = 1 } )
entity.destroy ( )
2018-11-07 02:50:14 +02:00
end
2018-11-02 23:37:58 +02:00
end
end
local function on_tick ( )
2018-11-22 22:40:17 +02:00
if game.tick % 30 == 0 then
2018-11-07 02:50:14 +02:00
if global.market then
2018-11-07 21:27:42 +02:00
for _ , player in pairs ( game.connected_players ) do
create_wave_gui ( player )
2018-11-21 14:38:48 +02:00
end
end
if game.tick % 180 == 0 then
2018-11-23 12:30:57 +02:00
if game.surfaces [ " fish_defender " ] then
game.forces . player.chart ( game.surfaces [ " fish_defender " ] , { { x = 0 , y = - 256 } , { x = 288 , y = 256 } } )
end
2018-11-07 02:50:14 +02:00
end
2018-11-21 14:38:48 +02:00
if global.market_age then
if not global.game_restart_timer then
global.game_restart_timer = 7200
else
if global.game_restart_timer < 0 then return end
global.game_restart_timer = global.game_restart_timer - 30
end
if global.game_restart_timer % 900 == 0 then
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 )
end
end
2018-11-20 15:46:13 +02:00
end
2018-11-02 23:37:58 +02:00
end
2018-11-07 21:27:42 +02:00
2018-11-07 02:50:14 +02:00
if game.tick % wave_interval == wave_interval - 1 then
2018-11-02 23:37:58 +02:00
biter_attack_wave ( )
2018-11-07 21:27:42 +02:00
end
2018-11-02 23:37:58 +02:00
end
2018-11-07 02:50:14 +02:00
local function on_player_changed_position ( event )
local player = game.players [ event.player_index ]
if player.position . x >= 160 then
2018-11-21 14:38:48 +02:00
player.teleport ( { player.position . x - 1 , player.position . y } , game.surfaces [ " fish_defender " ] )
2018-11-07 21:27:42 +02:00
if player.position . y > map_height or player.position . y < map_height * - 1 then
2018-11-21 14:38:48 +02:00
player.teleport ( { player.position . x , 0 } , game.surfaces [ " fish_defender " ] )
2018-11-07 21:27:42 +02:00
end
2018-11-07 02:50:14 +02:00
if player.character then
2018-11-07 21:27:42 +02:00
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
2018-11-07 02:50:14 +02:00
end
end
end
2018-11-12 05:11:06 +02:00
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
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
end
end
2018-11-20 15:46:13 +02:00
local function on_market_item_purchased ( event )
local player = game.players [ event.player_index ]
local market = event.market
local offer_index = event.offer_index
local offers = market.get_market_items ( )
local bought_offer = offers [ offer_index ] . offer
if bought_offer.type ~= " nothing " then return end
local slot_upgrade_offers = {
[ 1 ] = { " gun-turret " , " gun turret " } ,
2018-11-21 14:38:48 +02:00
[ 2 ] = { " laser-turret " , " laser turret " } ,
2018-11-24 15:08:52 +02:00
[ 3 ] = { " artillery-turret " , " artillery turret " } ,
[ 4 ] = { " flamethrower-turret " , " flamethrower turret " } ,
[ 5 ] = { " land-mine " , " land mine " }
2018-11-20 15:46:13 +02:00
}
2018-11-24 15:08:52 +02:00
for x = 1 , 5 , 1 do
2018-11-21 14:38:48 +02:00
if offer_index == x then
2018-11-20 15:46:13 +02:00
local price = global.entity_limits [ slot_upgrade_offers [ x ] [ 1 ] ] . limit * global.entity_limits [ slot_upgrade_offers [ x ] [ 1 ] ] . slot_price
2018-11-21 14:38:48 +02:00
if slot_upgrade_offers [ x ] [ 1 ] == " flamethrower-turret " then
price = ( global.entity_limits [ slot_upgrade_offers [ x ] [ 1 ] ] . limit + 1 ) * global.entity_limits [ slot_upgrade_offers [ x ] [ 1 ] ] . slot_price
end
2018-11-20 15:46:13 +02:00
local coins_removed = player.remove_item ( { name = " coin " , count = price } )
if coins_removed ~= price then
if coins_removed > 0 then
player.insert ( { name = " coin " , count = coins_removed } )
end
player.print ( " Not enough coins. " , { r = 0.22 , g = 0.77 , b = 0.44 } )
return
end
global.entity_limits [ slot_upgrade_offers [ x ] [ 1 ] ] . limit = global.entity_limits [ slot_upgrade_offers [ x ] [ 1 ] ] . limit + 1
game.print ( player.name .. " has bought a " .. slot_upgrade_offers [ x ] [ 2 ] .. " slot for " .. price .. " coins! " , { r = 0.22 , g = 0.77 , b = 0.44 } )
refresh_market_offers ( )
end
end
end
2018-11-12 05:11:06 +02:00
2018-11-02 23:37:58 +02:00
event.add ( defines.events . on_tick , on_tick )
2018-11-20 15:46:13 +02:00
event.add ( defines.events . on_market_item_purchased , on_market_item_purchased )
2018-11-07 02:50:14 +02:00
event.add ( defines.events . on_player_changed_position , on_player_changed_position )
2018-11-02 23:37:58 +02:00
event.add ( defines.events . on_built_entity , on_built_entity )
event.add ( defines.events . on_robot_built_entity , on_robot_built_entity )
2018-11-12 05:11:06 +02:00
event.add ( defines.events . on_player_mined_entity , on_player_mined_entity )
event.add ( defines.events . on_robot_mined_entity , on_robot_mined_entity )
2018-11-02 23:37:58 +02:00
event.add ( defines.events . on_entity_died , on_entity_died )
event.add ( defines.events . on_entity_damaged , on_entity_damaged )
event.add ( defines.events . on_chunk_generated , on_chunk_generated )
2018-11-20 23:30:08 +02:00
event.add ( defines.events . on_player_joined_game , on_player_joined_game )