mirror of
https://github.com/ComfyFactory/ComfyFactorio.git
synced 2025-01-10 00:43:27 +02:00
98c166ed82
Fused boss units into biter_health_booster. Unit evasion replaced with custom unit health pool. Boss Units no longer update their healthbar infinitely fast. Map Intro moved into the main panel. some globals to locals
1125 lines
40 KiB
Lua
1125 lines
40 KiB
Lua
-- fish defender -- by mewmew --
|
|
|
|
require "modules.rpg"
|
|
|
|
require "maps.fish_defender.terrain"
|
|
require "maps.fish_defender.market"
|
|
require "maps.fish_defender.shotgun_buff"
|
|
require "maps.fish_defender.on_entity_damaged"
|
|
|
|
require "modules.rocket_launch_always_yields_science"
|
|
require "modules.launch_fish_to_win"
|
|
require "modules.biters_yield_coins"
|
|
require "modules.dangerous_goods"
|
|
require "modules.custom_death_messages"
|
|
|
|
local Unit_health_booster = require "modules.biter_health_booster"
|
|
local Map = require "modules.map_info"
|
|
local event = require 'utils.event'
|
|
local Server = require 'utils.server'
|
|
local boss_biter = require "maps.fish_defender.boss_biters"
|
|
local math_random = math.random
|
|
local insert = table.insert
|
|
local enable_start_grace_period = true
|
|
map_height = 96
|
|
|
|
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
|
|
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}},
|
|
[300] = {{name = "behemoth-biter", count = 16}, {name = "behemoth-spitter", count = 8}}
|
|
}
|
|
|
|
local difficulties_votes = {
|
|
[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}
|
|
}
|
|
|
|
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
|
|
|
|
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 % global.wave_interval / global.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
|
|
return
|
|
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}
|
|
|
|
if not enable_start_grace_period then global.wave_grace_period = nil return end
|
|
end
|
|
end
|
|
|
|
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)
|
|
if not event.element.valid then
|
|
return
|
|
end
|
|
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
|
|
|
|
local function on_market_item_purchased(event)
|
|
update_fd_stats()
|
|
end
|
|
|
|
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
|
|
biter_pool = {
|
|
{name = "behemoth-biter", threat = threat_values.behemoth_biter, weight = 2},
|
|
{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},
|
|
{name = "behemoth-biter", threat = threat_values.behemoth_biter, weight = 2},
|
|
{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},
|
|
{name = "behemoth-biter", threat = threat_values.behemoth_biter, weight = 2},
|
|
{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},
|
|
{name = "behemoth-biter", threat = threat_values.behemoth_biter, weight = 2},
|
|
{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 = {
|
|
{name = "small-biter", threat = threat_values.small_biter, weight = 3},
|
|
{name = "small-spitter", threat = threat_values.small_spitter, weight = 1}
|
|
}
|
|
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
|
|
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
|
|
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
|
|
end
|
|
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()
|
|
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
|
|
local surface = game.surfaces["fish_defender"]
|
|
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)
|
|
local biter = surface.create_entity({name = biter_pool[1].name, position = valid_pos})
|
|
biter.ai_settings.allow_destroy_when_commands_fail = false
|
|
biter.ai_settings.allow_try_return_to_spawner = false
|
|
return biter
|
|
end
|
|
|
|
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
|
|
|
|
local attack_group_count_thresholds = {
|
|
{0, 1},
|
|
{50, 2},
|
|
{100, 3},
|
|
{150, 4},
|
|
{200, 5},
|
|
{1000, 6},
|
|
{2000, 7},
|
|
{3000, 8}
|
|
}
|
|
|
|
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
|
|
|
|
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
|
|
if global.wave_count > 500 then chance = 2 end
|
|
for _, entity in pairs(surface.find_entities_filtered{type = "corpse"}) do
|
|
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",
|
|
[350] = "Cable Chewers",
|
|
[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",
|
|
[1000] = "Happy Tree Friends",
|
|
[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"
|
|
}
|
|
|
|
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
|
|
|
|
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
|
|
|
|
if not boss_waves[global.wave_count] then
|
|
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)}}
|
|
end
|
|
|
|
local health_factor = difficulties_votes[global.difficulty_vote_index].boss_modifier
|
|
if global.wave_count == 100 then health_factor = health_factor * 2 end
|
|
|
|
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})
|
|
biter.ai_settings.allow_destroy_when_commands_fail = false
|
|
biter.ai_settings.allow_try_return_to_spawner = false
|
|
global.boss_biters[biter.unit_number] = biter
|
|
Unit_health_booster.add_boss_unit(biter, global.biter_health_boost * health_factor, 0.55)
|
|
biter_group.add_member(biter)
|
|
end
|
|
end
|
|
end
|
|
|
|
send_unit_group(biter_group)
|
|
end
|
|
|
|
local function wake_up_the_biters(surface)
|
|
if not global.market then return end
|
|
|
|
local units = surface.find_entities_filtered({type = "unit"})
|
|
units = shuffle(units)
|
|
local unit_groups = {}
|
|
local y_raffle = get_y_coord_raffle_table()
|
|
for i = 1, 2, 1 do
|
|
if not units[i] then break end
|
|
if not units[i].valid then break end
|
|
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}})
|
|
local biters = surface.find_enemy_units(units[i].position, 24, "player")
|
|
for _, biter in pairs(biters) do
|
|
unit_groups[i].add_member(biter)
|
|
end
|
|
end
|
|
|
|
for i = 1, #unit_groups, 1 do
|
|
if unit_groups[i].valid then
|
|
if #unit_groups[i].members > 0 then
|
|
send_unit_group(unit_groups[i])
|
|
else
|
|
unit_groups[i].destroy()
|
|
end
|
|
end
|
|
end
|
|
|
|
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
|
|
|
|
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
|
|
|
|
e.surface.create_entity({name = "water-splash", position = e.position})
|
|
|
|
if e.type == "entity-ghost" then e.destroy() return end
|
|
|
|
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
|
|
|
|
local function biter_attack_wave()
|
|
if not global.market then return end
|
|
if global.wave_grace_period then return end
|
|
local surface = game.surfaces["fish_defender"]
|
|
|
|
clear_corpses(surface)
|
|
wake_up_the_biters(surface)
|
|
|
|
if surface.count_entities_filtered({type = "unit"}) > biter_count_limit then
|
|
--game.print("Biter limit reached, wave delayed.", {r = 0.7, g = 0.1, b = 0.1})
|
|
return
|
|
end
|
|
|
|
if not global.wave_count then
|
|
global.wave_count = 1
|
|
else
|
|
global.wave_count = global.wave_count + 1
|
|
end
|
|
|
|
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_health_boost = 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
|
|
|
|
if global.wave_count % 50 == 0 then
|
|
global.attack_wave_threat = math.floor(global.wave_count * (m*1.5))
|
|
spawn_boss_units(surface)
|
|
if global.attack_wave_threat > 10000 then global.attack_wave_threat = 10000 end
|
|
else
|
|
global.attack_wave_threat = math.floor(global.wave_count * m)
|
|
if global.attack_wave_threat > 10000 then global.attack_wave_threat = 10000 end
|
|
end
|
|
|
|
local evolution = global.wave_count * 0.00125
|
|
if evolution > 1 then evolution = 1 end
|
|
game.forces.enemy.evolution_factor = evolution
|
|
|
|
--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
|
|
|
|
for _, e in pairs(surface.find_entities_filtered({area = {{160, -256},{360, 256}}})) do
|
|
damage_entity_outside_of_fence(e)
|
|
end
|
|
|
|
local y_raffle = get_y_coord_raffle_table()
|
|
|
|
local unit_groups = {}
|
|
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]}})
|
|
end
|
|
else
|
|
for i = 1, get_number_of_attack_groups(), 1 do
|
|
unit_groups[i] = surface.create_unit_group({position = {x = 256, y = y_raffle[i]}})
|
|
end
|
|
end
|
|
|
|
local biter_pool = get_biter_pool()
|
|
--local spawners = surface.find_entities_filtered({type = "unit-spawner", area = {{160, -196},{512, 196}}})
|
|
--table.shuffle_table(spawners)
|
|
|
|
while global.attack_wave_threat > 0 do
|
|
for i = 1, #unit_groups, 1 do
|
|
--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
|
|
|
|
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
|
|
send_unit_group(unit_groups[i])
|
|
end
|
|
end
|
|
|
|
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
|
|
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}
|
|
|
|
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}
|
|
|
|
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')
|
|
insert(result, mvp.deaths.name .. " died " .. mvp.deaths.score .. " times" )
|
|
local message = table.concat(result)
|
|
Server.to_discord_embed(message)
|
|
global.results_sent = true
|
|
end
|
|
end
|
|
|
|
for _, player in pairs(game.connected_players) do
|
|
player.play_sound{path="utility/game_lost", volume_modifier=0.75}
|
|
end
|
|
end
|
|
|
|
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
|
|
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
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local function market_kill_visuals()
|
|
local m = 32
|
|
local m2 = m * 0.005
|
|
for i = 1, 1024, 1 do
|
|
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
|
|
for y = -5, 5, 0.5 do
|
|
if math_random(1, 2) == 1 then
|
|
global.market.surface.create_trivial_smoke({name="smoke-fast", position={global.market.position.x + (x * 0.35), global.market.position.y + (y * 0.35)}})
|
|
end
|
|
if math_random(1, 3) == 1 then
|
|
global.market.surface.create_trivial_smoke({name="train-smoke", position={global.market.position.x + (x * 0.35), global.market.position.y + (y * 0.35)}})
|
|
end
|
|
end
|
|
end
|
|
global.market.surface.spill_item_stack(global.market.position,{name = "raw-fish", count = 1024}, true)
|
|
end
|
|
|
|
local biter_splash_damage = {
|
|
["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}
|
|
}
|
|
|
|
local function on_entity_died(event)
|
|
if not event.entity.valid then return end
|
|
|
|
if event.entity.force.name == "enemy" then
|
|
local surface = event.entity.surface
|
|
|
|
if global.boss_biters[event.entity.unit_number] then boss_biter.died(event) end
|
|
|
|
local splash = biter_splash_damage[event.entity.name]
|
|
if splash then
|
|
if math_random(1, splash.chance) == 1 then
|
|
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
|
|
|
|
if event.entity.name == "behemoth-biter" then
|
|
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
|
|
|
|
if event.entity == global.market then
|
|
market_kill_visuals()
|
|
global.market = nil
|
|
global.market_age = game.tick
|
|
is_game_lost()
|
|
end
|
|
|
|
if global.entity_limits[event.entity.name] then
|
|
global.entity_limits[event.entity.name].placed = global.entity_limits[event.entity.name].placed - 1
|
|
update_fd_stats()
|
|
end
|
|
end
|
|
|
|
local function on_player_joined_game(event)
|
|
local player = game.players[event.player_index]
|
|
|
|
if player.online_time == 0 then
|
|
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
|
|
|
|
local surface = game.surfaces["fish_defender"]
|
|
if player.online_time < 2 and surface.is_chunk_generated({0,0}) then
|
|
player.teleport(surface.find_non_colliding_position("character", game.forces["player"].get_spawn_position(surface), 50, 1), "fish_defender")
|
|
else
|
|
if player.online_time < 2 then
|
|
player.teleport(game.forces["player"].get_spawn_position(surface), "fish_defender")
|
|
end
|
|
end
|
|
|
|
create_wave_gui(player)
|
|
add_fd_stats_button(player)
|
|
|
|
if game.tick > 900 then
|
|
is_game_lost()
|
|
end
|
|
|
|
--if global.charting_done then return end
|
|
--game.forces.player.chart(game.surfaces["fish_defender"], {{-256, -512},{768, 512}})
|
|
--global.charting_done = true
|
|
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
|
|
|
|
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}}
|
|
)
|
|
update_fd_stats()
|
|
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 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
|
|
end
|
|
end
|
|
end
|
|
entity.destroy()
|
|
end
|
|
end
|
|
end
|
|
|
|
local function on_robot_built_entity(event)
|
|
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}}
|
|
)
|
|
update_fd_stats()
|
|
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})
|
|
entity.destroy()
|
|
end
|
|
end
|
|
end
|
|
|
|
local function on_tick()
|
|
if game.tick % 30 == 0 then
|
|
if global.market then
|
|
for _, player in pairs(game.connected_players) do
|
|
if game.surfaces["fish_defender"].peaceful_mode == false then
|
|
create_wave_gui(player)
|
|
end
|
|
end
|
|
end
|
|
if game.tick % 180 == 0 then
|
|
if game.surfaces["fish_defender"] then
|
|
game.forces.player.chart(game.surfaces["fish_defender"], {{-160, -128},{192, 128}})
|
|
if global.difficulty_vote_index then
|
|
global.wave_interval = difficulties_votes[global.difficulty_vote_index].wave_interval
|
|
end
|
|
end
|
|
end
|
|
|
|
if global.market_age then
|
|
if not global.game_restart_timer then
|
|
global.game_restart_timer = 10800
|
|
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 % 1800 == 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)
|
|
|
|
local message = 'Map is restarting! '
|
|
Server.to_discord_bold(table.concat{'*** ', message, ' ***'})
|
|
Server.start_scenario('Fish_Defender')
|
|
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
if game.tick % global.wave_interval == global.wave_interval - 1 then
|
|
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]
|
|
if player.position.x + player.position.y < 0 then return end
|
|
if player.position.x < player.position.y then return end
|
|
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
|
|
update_fd_stats()
|
|
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
|
|
update_fd_stats()
|
|
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
|
|
local player = game.players[event.player_index]
|
|
player.character.destructible = false
|
|
end
|
|
|
|
local function on_init(event)
|
|
global.wave_interval = 3600 --interval between waves in ticks
|
|
global.wave_grace_period = 3600 * 20
|
|
global.difficulty_poll_closing_timeout = global.wave_grace_period
|
|
global.boss_biters = {}
|
|
global.acid_lines_delay = {}
|
|
|
|
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},
|
|
}
|
|
|
|
local map_gen_settings = {}
|
|
map_gen_settings.height = 2048
|
|
map_gen_settings.water = 0.10
|
|
map_gen_settings.terrain_segmentation = 3
|
|
map_gen_settings.cliff_settings = {cliff_elevation_interval = 32, cliff_elevation_0 = 32}
|
|
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})
|
|
|
|
global.chunk_queue = {}
|
|
|
|
local T = Map.Pop_info()
|
|
T.main_caption = "--Fish Defender--"
|
|
T.sub_caption = "*blb blubby blub*"
|
|
T.text = [[
|
|
The biters have catched the scent of fish in the market.
|
|
Fend them off as long as possible!
|
|
This however will not be an easy task,
|
|
since their strength and resistance increases constantly over time.
|
|
|
|
Your ultimate goal is to evacuate all the fish to cat planet!
|
|
Put them in your rocket's cargo and launch them into space.
|
|
Don't worry, you will still get space science.
|
|
|
|
The Market will gladly take any coin you might find.
|
|
Additional turret slots can be bought at the market.
|
|
Several unique upgrades are available too.
|
|
|
|
Researching tanks will unlock the artillery technology early.
|
|
|
|
Any container bearing dangerous goods, like ammo, grenades or barrels,
|
|
causes heavy explosions when it breaks.
|
|
Maybe this can be used to our advantage.
|
|
]]
|
|
T.main_caption_color = {r=0.11, g=0.8, b=0.44}
|
|
T.sub_caption_color = {r=0.33, g=0.66, b=0.9}
|
|
end
|
|
|
|
event.add(defines.events.on_gui_click, on_gui_click)
|
|
event.add(defines.events.on_market_item_purchased, on_market_item_purchased)
|
|
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)
|
|
event.add(defines.events.on_player_changed_position, on_player_changed_position)
|
|
event.add(defines.events.on_player_joined_game, on_player_joined_game)
|
|
event.add(defines.events.on_player_mined_entity, on_player_mined_entity)
|
|
event.add(defines.events.on_research_finished, on_research_finished)
|
|
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)
|
|
event.on_init(on_init)
|
|
|
|
require "modules.difficulty_vote" |