From edbef96f78f2226fbd98624005af7a5822f9ea74 Mon Sep 17 00:00:00 2001 From: Gerkiz Date: Sun, 12 Jul 2020 18:58:00 +0200 Subject: [PATCH 1/6] fixes --- antigrief.lua | 96 ----------------- comfy_panel/player_list.lua | 54 ++++++---- maps/fish_defender/commands.lua | 53 +++++++++ maps/fish_defender/main.lua | 34 ++++-- maps/fish_defender/table.lua | 3 +- maps/fish_defender/terrain.lua | 165 +++++++++++++++-------------- maps/mountain_fortress_v3/main.lua | 4 +- 7 files changed, 196 insertions(+), 213 deletions(-) diff --git a/antigrief.lua b/antigrief.lua index 2596cbe9..a601343d 100644 --- a/antigrief.lua +++ b/antigrief.lua @@ -26,7 +26,6 @@ local this = { players_warned = {}, log_tree_harvest = false, do_not_check_trusted = true, - protect_entities = true, enable_autokick = true, enable_autoban = false } @@ -53,52 +52,6 @@ local ammo_names = { ['rocket'] = true } -local protected = { - ['reactor'] = true, - ['roboport'] = true, - ['rocket-silo'] = true, - ['solar-panel'] = true, - ['generator'] = true, - ['splitter'] = true, - ['transport-belt'] = true, - ['underground-belt'] = true, - ['assembling-machine'] = true, - ['storage-tank'] = true, - ['pump'] = true, - ['mining-drill'] = true, - ['market'] = true, - ['accumulator'] = true, - ['ammo-turret'] = true, - ['artillery-turret'] = true, - ['artillery-wagon'] = true, - ['beacon'] = true, - ['boiler'] = true, - ['burner-generator'] = true, - ['car'] = true, - ['cargo-wagon'] = true, - ['constant-combinator'] = true, - ['straight-rail'] = true, - ['curved-rail'] = true, - ['decider-combinator'] = true, - ['electric-pole'] = true, - ['electric-turret'] = true, - ['fluid-turret'] = true, - ['fluid-wagon'] = true, - ['furnace'] = true, - ['gate'] = true, - ['heat-interface'] = true, - ['heat-pipe'] = true, - ['inserter'] = true, - ['lab'] = true, - ['lamp'] = true, - ['loader'] = true, - ['locomotive'] = true, - ['logistic-robot'] = true, - ['offshore-pump'] = true, - ['pipe-to-ground'] = true, - ['pipe'] = true -} - Global.register( this, function(t) @@ -704,46 +657,6 @@ local function on_player_cancelled_crafting(event) end end -local function protect_entities(event) - local entity = event.entity - - local function is_protected(e) - if protected[e.type] then - return true - end - - return false - end - - if is_protected(entity) then - entity.health = entity.health + event.final_damage_amount - end -end - ---- Protect entities from the player force ----@param event -local function on_entity_damaged(event) - if not this.protect_entities then - return - end - - local entity = event.entity - - if not entity or not entity.valid then - return - end - - if event.force.index ~= 1 then - return - end - - if entity.force.index ~= 1 then - return - end - - protect_entities(event) -end - local function on_init() local branch_version = '0.18.35' local sub = string.sub @@ -767,14 +680,6 @@ local function on_init() end end ---- Enabling this will protect all entities except for those in the not_protected table. ----@param boolean true/false -function Public.protect_entities(value) - if value then - this.protect_entities = value - end -end - --- This will reset the table of this function Public.reset_tables() this.landfill_history = {} @@ -833,6 +738,5 @@ Event.add(defines.events.on_player_used_capsule, on_player_used_capsule) Event.add(defines.events.on_player_cursor_stack_changed, on_player_cursor_stack_changed) Event.add(defines.events.on_player_cancelled_crafting, on_player_cancelled_crafting) Event.add(defines.events.on_player_joined_game, on_player_joined_game) -Event.add(defines.events.on_entity_damaged, on_entity_damaged) return Public diff --git a/comfy_panel/player_list.lua b/comfy_panel/player_list.lua index a5428044..d2716a7b 100644 --- a/comfy_panel/player_list.lua +++ b/comfy_panel/player_list.lua @@ -13,7 +13,8 @@ to your scenario control.lua. Minor changes by ~~~Gerkiz~~~ --]] local Event = require 'utils.event' -local play_time = require 'utils.session_data' +local Session = require 'utils.session_data' +local Jailed = require 'utils.jail_data' local Tabs = require 'comfy_panel.main' local symbol_asc = '▲' @@ -218,7 +219,7 @@ local function get_formatted_playtime(x) end local function get_rank(player) - local play_table = play_time.get_session_table() + local play_table = Session.get_session_table() local t = 0 if play_table then if play_table[player.name] then @@ -337,7 +338,7 @@ local function get_comparator(sort_by) end local function get_sorted_list(sort_by) - local play_table = play_time.get_session_table() + local play_table = Session.get_session_table() local player_list = {} for i, player in pairs(game.connected_players) do player_list[i] = {} @@ -369,12 +370,14 @@ local function player_list_show(player, frame, sort_by) -- Frame management frame.clear() frame.style.padding = 8 - local play_table = play_time.get_trusted_table() + local play_table = Session.get_trusted_table() + local jailed = Jailed.get_jailed_table() -- Header management local t = frame.add {type = 'table', name = 'player_list_panel_header_table', column_count = 5} - local column_widths = {tonumber(40), tonumber(240), tonumber(240), tonumber(150), tonumber(100)} - for _, w in ipairs(column_widths) do + local column_widths = {tonumber(40), tonumber(218), tonumber(220), tonumber(222), tonumber(50)} + local header_column_widths = {tonumber(40), tonumber(210), tonumber(220), tonumber(226), tonumber(50)} + for _, w in ipairs(header_column_widths) do local label = t.add {type = 'label', caption = ''} label.style.minimal_width = w label.style.maximal_width = w @@ -427,14 +430,14 @@ local function player_list_show(player, frame, sort_by) header_modifier[sort_by](headers) for k, v in ipairs(headers) do - local label = + local header_label = t.add { type = 'label', name = 'player_list_panel_header_' .. k, caption = v } - label.style.font = 'default-bold' - label.style.font_color = {r = 0.98, g = 0.66, b = 0.22} + header_label.style.font = 'default-bold' + header_label.style.font_color = {r = 0.98, g = 0.66, b = 0.22} end -- special style on first header @@ -476,6 +479,9 @@ local function player_list_show(player, frame, sort_by) if game.players[player_list[i].name].admin then trusted = '[color=red][A][/color]' tooltip = 'This player is an admin of this server.' + elseif jailed[player_list[i].name] then + trusted = '[color=orange][J][/color]' + tooltip = 'This player is currently jailed.' elseif play_table[player_list[i].name] then trusted = '[color=green][T][/color]' tooltip = 'This player is trusted.' @@ -485,41 +491,42 @@ local function player_list_show(player, frame, sort_by) end -- Name - local label = + local name_label = player_list_panel_table.add { type = 'label', name = 'player_list_panel_player_names_' .. i, caption = player_list[i].name .. ' ' .. trusted, tooltip = tooltip } - label.style.font = 'default' - label.style.font_color = { - r = .4 + game.players[player_list[i].player_index].color.r * 0.6, - g = .4 + game.players[player_list[i].player_index].color.g * 0.6, - b = .4 + game.players[player_list[i].player_index].color.b * 0.6 + local p_color = game.players[player_list[i].player_index] + name_label.style.font = 'default' + name_label.style.font_color = { + r = .4 + p_color.color.r * 0.6, + g = .4 + p_color.color.g * 0.6, + b = .4 + p_color.color.b * 0.6 } - label.style.minimal_width = column_widths[2] - label.style.maximal_width = column_widths[2] + name_label.style.minimal_width = column_widths[2] + name_label.style.maximal_width = column_widths[2] -- Total time - local label = + local total_label = player_list_panel_table.add { type = 'label', name = 'player_list_panel_player_total_time_played_' .. i, caption = player_list[i].total_played_time } - label.style.minimal_width = column_widths[3] - label.style.maximal_width = column_widths[3] + total_label.style.minimal_width = column_widths[3] + total_label.style.maximal_width = column_widths[3] -- Current time - local label = + local current_label = player_list_panel_table.add { type = 'label', name = 'player_list_panel_player_time_played_' .. i, caption = player_list[i].played_time } - label.style.minimal_width = column_widths[4] - label.style.maximal_width = column_widths[4] + current_label.style.minimal_width = column_widths[4] + current_label.style.maximal_width = column_widths[4] -- Poke local flow = player_list_panel_table.add {type = 'flow', name = 'button_flow_' .. i, direction = 'horizontal'} @@ -527,6 +534,7 @@ local function player_list_show(player, frame, sort_by) local button = flow.add {type = 'button', name = 'poke_player_' .. player_list[i].name, caption = player_list[i].pokes} button.style.font = 'default' + button.tooltip = 'Poke ' .. player_list[i].name .. ' with a random message!' label.style.font_color = {r = 0.83, g = 0.83, b = 0.83} button.style.minimal_height = 30 button.style.minimal_width = 30 diff --git a/maps/fish_defender/commands.lua b/maps/fish_defender/commands.lua index 439470f6..ad4dce2d 100644 --- a/maps/fish_defender/commands.lua +++ b/maps/fish_defender/commands.lua @@ -1,5 +1,6 @@ local Server = require 'utils.server' local FDT = require 'maps.fish_defender.table' +local Task = require 'utils.task' local mapkeeper = '[color=blue]Mapkeeper:[/color]' @@ -93,3 +94,55 @@ commands.add_command( end end ) + +commands.add_command( + 'set_queue_speed', + 'Usable only for admins - sets the queue speed of this map!', + function(cmd) + local p + local player = game.player + local param = tonumber(cmd.parameter) + + if player then + if player ~= nil then + p = player.print + if not player.admin then + p("[ERROR] You're not admin!", Color.fail) + return + end + if not param then + return + end + p('Queue speed set to: ' .. param) + Task.set_queue_speed(param) + else + p = log + p('Queue speed set to: ' .. param) + Task.set_queue_speed(param) + end + end + end +) + +commands.add_command( + 'get_queue_speed', + 'Usable only for admins - gets the queue speed of this map!', + function() + local p + local player = game.player + + if player then + if player ~= nil then + p = player.print + if not player.admin then + p("[ERROR] You're not admin!", Color.fail) + return + end + p(Task.get_queue_speed()) + else + p = log + p(Task.get_queue_speed()) + end + end + end +) diff --git a/maps/fish_defender/main.lua b/maps/fish_defender/main.lua index 90fcb96f..050d6820 100644 --- a/maps/fish_defender/main.lua +++ b/maps/fish_defender/main.lua @@ -13,6 +13,7 @@ require 'modules.dangerous_goods' require 'modules.custom_death_messages' local Terrain = require 'maps.fish_defender.terrain' +local Task = require 'utils.task' local Unit_health_booster = require 'modules.biter_health_booster' local Difficulty = require 'modules.difficulty_vote' local Map = require 'modules.map_info' @@ -40,14 +41,11 @@ local starting_items = { ['stone'] = 12 } -local function shuffle(t) - local tbl = {} - for i = 1, #t do - tbl[i] = t[i] - end - for i = #tbl, 2, -1 do - local j = math.random(i) - tbl[i], tbl[j] = tbl[j], tbl[i] +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 @@ -551,19 +549,30 @@ local function wake_up_the_biters(surface) ) end -local function damage_entity_outside_of_fence(e) +local function damage_entity_outside_and_inside_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 == 'land-mine' then + e.health = + e.health - math_random(math.floor(e.prototype.max_health * 0.2), math.floor(e.prototype.max_health * 0.4)) + if e.health <= 0 then + e.die('enemy') + end + return + end + if e.type == 'entity-ghost' then e.destroy() return @@ -646,8 +655,8 @@ local function biter_attack_wave() -- end --end - for _, e in pairs(surface.find_entities_filtered({area = {{160, -256}, {360, 256}}})) do - damage_entity_outside_of_fence(e) + for _, e in pairs(surface.find_entities_filtered({area = {{110, -256}, {360, 256}}})) do + damage_entity_outside_and_inside_of_fence(e) end local y_raffle = get_y_coord_raffle_table() @@ -1432,6 +1441,9 @@ function Public.reset_game() Terrain.fish_eye(surface, {x = -2150, y = -300}) + Task.get_task_queue(4) + Task.start_queue() + game.map_settings.enemy_expansion.enabled = false game.map_settings.enemy_evolution.destroy_factor = 0 game.map_settings.enemy_evolution.time_factor = 0 diff --git a/maps/fish_defender/table.lua b/maps/fish_defender/table.lua index 2e051a15..7ae96d72 100644 --- a/maps/fish_defender/table.lua +++ b/maps/fish_defender/table.lua @@ -25,6 +25,7 @@ function Public.reset_table() this.game_reset = false this.spawn_area_generated = false this.results_sent = false + this.explosive_bullets_unlocked = false this.bouncy_shells_unlocked = false this.trapped_capsules_unlocked = false @@ -49,7 +50,7 @@ function Public.reset_table() ['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 = 6} + ['land-mine'] = {placed = 0, limit = 1, str = 'mine', slot_price = 20} } this.difficulties_votes = { [1] = {wave_interval = 4500, amount_modifier = 0.52, strength_modifier = 0.40, boss_modifier = 3.0}, diff --git a/maps/fish_defender/terrain.lua b/maps/fish_defender/terrain.lua index b0ac800b..48d81680 100644 --- a/maps/fish_defender/terrain.lua +++ b/maps/fish_defender/terrain.lua @@ -2,10 +2,14 @@ local Event = require 'utils.event' local map_functions = require 'tools.map_functions' local simplex_noise = require 'utils.simplex_noise'.d2 local FDT = require 'maps.fish_defender.table' +local Task = require 'utils.task' +local Token = require 'utils.token' local math_random = math.random local math_abs = math.abs local math_floor = math.floor local math_sqrt = math.sqrt +local tiles_per_call = 16 +local total_calls = math.ceil(1024 / tiles_per_call) local Public = {} @@ -21,14 +25,11 @@ local rock_raffle = { 'rock-huge' } -local function shuffle(t) - local tbl = {} - for i = 1, #t do - tbl[i] = t[i] - end - for i = #tbl, 2, -1 do - local j = math.random(i) - tbl[i], tbl[j] = tbl[j], tbl[i] +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 @@ -287,76 +288,6 @@ local function plankton_territory(surface, position, seed) return 'water' end -local function process_chunk(left_top) - local this = FDT.get() - local surface = game.surfaces[this.active_surface_index] - if not surface or not surface.valid then - return - end - - local seed = game.surfaces[1].map_gen_settings.seed - - Public.generate_spawn_area(this, surface, left_top) - enemy_territory(surface, left_top) - fish_mouth(surface, left_top) - - local tiles = {} - - for x = 0, 31, 1 do - for y = 0, 31, 1 do - local pos = {x = left_top.x + x, y = left_top.y + y} - if is_out_of_map_tile(pos) then - --if not plankton_territory(surface, pos, seed) then surface.set_tiles({{name = "out-of-map", position = pos}}, true) end - local tile_to_set = plankton_territory(surface, pos, seed) - --local tile_to_set = "out-of-map" - tiles[#tiles + 1] = {name = tile_to_set, position = pos} - end - end - end - - surface.set_tiles(tiles, true) - - --if game.tick == 0 then return end - --if game.forces.player.is_chunk_charted(surface, {left_top.x / 32, left_top.y / 32}) then - game.forces.player.chart(surface, {{left_top.x, left_top.y}, {left_top.x + 31, left_top.y + 31}}) - --end - if this.market and this.market.valid then - this.game_reset = false - end -end - -local function process_chunk_queue() - local chunks = #global.chunk_queue - if chunks <= 0 then - return - end - - for k, left_top in pairs(global.chunk_queue) do - process_chunk(left_top) - global.chunk_queue[k] = nil - return - end -end - -local function on_chunk_generated(event) - local map_name = 'fish_defender' - - if string.sub(event.surface.name, 0, #map_name) ~= map_name then - return - end - local left_top = event.area.left_top - local this = FDT.get() - if this.game_has_ended then - return - end - - if game.tick == 0 or this.game_reset or this.force_chunk then - process_chunk(left_top) - else - global.chunk_queue[#global.chunk_queue + 1] = {x = left_top.x, y = left_top.y} - end -end - local function render_market_hp() local this = FDT.get() local surface = game.surfaces[this.active_surface_index] @@ -391,7 +322,7 @@ local function render_market_hp() } end -function Public.generate_spawn_area(this, surface) +local function generate_spawn_area(this, surface) if this.spawn_area_generated then return end @@ -541,6 +472,81 @@ function Public.generate_spawn_area(this, surface) this.spawn_area_generated = true end +local function process_chunk(left_top) + local this = FDT.get() + local surface = game.surfaces[this.active_surface_index] + if not surface or not surface.valid then + return + end + + local seed = game.surfaces[1].map_gen_settings.seed + + generate_spawn_area(this, surface, left_top) + enemy_territory(surface, left_top) + fish_mouth(surface, left_top) + + local tiles = {} + + for x = 0, 31, 1 do + for y = 0, 31, 1 do + local pos = {x = left_top.x + x, y = left_top.y + y} + if is_out_of_map_tile(pos) then + --if not plankton_territory(surface, pos, seed) then surface.set_tiles({{name = "out-of-map", position = pos}}, true) end + local tile_to_set = plankton_territory(surface, pos, seed) + --local tile_to_set = "out-of-map" + tiles[#tiles + 1] = {name = tile_to_set, position = pos} + end + end + end + + surface.set_tiles(tiles, true) + + --if game.tick == 0 then return end + --if game.forces.player.is_chunk_charted(surface, {left_top.x / 32, left_top.y / 32}) then + game.forces.player.chart(surface, {{left_top.x, left_top.y}, {left_top.x + 31, left_top.y + 31}}) + --end + if this.market and this.market.valid then + this.game_reset = false + end +end + +local process_chunk_queue = + Token.register( + function(data) + local chunk_queue = data.chunk_queue + + for i = 1, #chunk_queue do + local pos = {x = chunk_queue[i].x, y = chunk_queue[i].y} + process_chunk(pos) + chunk_queue[i] = nil + end + end +) + +local function on_chunk_generated(event) + local map_name = 'fish_defender' + + if string.sub(event.surface.name, 0, #map_name) ~= map_name then + return + end + local left_top = event.area.left_top + local this = FDT.get() + if this.game_has_ended then + return + end + + if game.tick == 0 or this.game_reset or this.force_chunk then + process_chunk(left_top) + else + global.chunk_queue[#global.chunk_queue + 1] = {x = left_top.x, y = left_top.y} + + local data = { + chunk_queue = global.chunk_queue + } + Task.set_timeout_in_ticks(total_calls, process_chunk_queue, data) + end +end + function Public.fish_eye(surface, position) surface.request_to_generate_chunks(position, 2) surface.force_generate_chunk_requests() @@ -567,7 +573,6 @@ function Public.fish_eye(surface, position) end end -Event.on_nth_tick(25, process_chunk_queue) Event.add(defines.events.on_chunk_generated, on_chunk_generated) return Public diff --git a/maps/mountain_fortress_v3/main.lua b/maps/mountain_fortress_v3/main.lua index e04ca01d..3170be18 100644 --- a/maps/mountain_fortress_v3/main.lua +++ b/maps/mountain_fortress_v3/main.lua @@ -265,7 +265,7 @@ function Public.reset_map() Collapse.set_direction('north') Collapse.start_now(false) - --[[ local x_value = rng(15, 25) + local x_value = rng(15, 25) local y_value = rng(50, 60) local data = { @@ -274,7 +274,7 @@ function Public.reset_map() ['fluid-wagon'] = {left_top = {x = -x_value, y = 0}, right_bottom = {x = x_value, y = y_value}}, ['locomotive'] = {left_top = {x = -x_value, y = 0}, right_bottom = {x = x_value, y = y_value}} } - ICT.set_wagon_area(data) ]] + ICT.set_wagon_area(data) this.locomotive_health = 10000 this.locomotive_max_health = 10000 From 383f172661205b87ffcf902453a932b7eae680d7 Mon Sep 17 00:00:00 2001 From: Gerkiz Date: Sun, 12 Jul 2020 18:59:30 +0200 Subject: [PATCH 2/6] remove unused function --- maps/mountain_fortress_v3/main.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/maps/mountain_fortress_v3/main.lua b/maps/mountain_fortress_v3/main.lua index 3170be18..58611543 100644 --- a/maps/mountain_fortress_v3/main.lua +++ b/maps/mountain_fortress_v3/main.lua @@ -210,7 +210,6 @@ function Public.reset_map() local Diff = Difficulty.get() local this = WPT.get() local wave_defense_table = WD.get_table() - local get_score = Score.get_table() for _, player in pairs(game.players) do if player.controller_type == defines.controllers.editor then From 22a40f19faf7968bb08f973e49811bb2758d8bee Mon Sep 17 00:00:00 2001 From: Gerkiz Date: Sun, 12 Jul 2020 20:54:44 +0200 Subject: [PATCH 3/6] fish_defender_v2 --- control.lua | 1 + locale/en/fish_defender_v2.cfg | 45 + maps/fish_defender_v2/boss_biters.lua | 99 ++ maps/fish_defender_v2/bouncy_shells.lua | 76 + maps/fish_defender_v2/commands.lua | 148 ++ maps/fish_defender_v2/crumbly_walls.lua | 27 + .../explosive_gun_bullets.lua | 46 + maps/fish_defender_v2/flame_boots.lua | 52 + maps/fish_defender_v2/laser_pointer.lua | 37 + maps/fish_defender_v2/main.lua | 1546 +++++++++++++++++ maps/fish_defender_v2/market.lua | 345 ++++ maps/fish_defender_v2/on_entity_damaged.lua | 65 + maps/fish_defender_v2/railgun_enhancer.lua | 157 ++ maps/fish_defender_v2/shotgun_buff.lua | 31 + maps/fish_defender_v2/table.lua | 103 ++ maps/fish_defender_v2/terrain.lua | 578 ++++++ maps/fish_defender_v2/trapped_capsules.lua | 61 + maps/fish_defender_v2/ultra_mines.lua | 52 + maps/fish_defender_v2/vehicle_nanobots.lua | 29 + 19 files changed, 3498 insertions(+) create mode 100644 locale/en/fish_defender_v2.cfg create mode 100644 maps/fish_defender_v2/boss_biters.lua create mode 100644 maps/fish_defender_v2/bouncy_shells.lua create mode 100644 maps/fish_defender_v2/commands.lua create mode 100644 maps/fish_defender_v2/crumbly_walls.lua create mode 100644 maps/fish_defender_v2/explosive_gun_bullets.lua create mode 100644 maps/fish_defender_v2/flame_boots.lua create mode 100644 maps/fish_defender_v2/laser_pointer.lua create mode 100644 maps/fish_defender_v2/main.lua create mode 100644 maps/fish_defender_v2/market.lua create mode 100644 maps/fish_defender_v2/on_entity_damaged.lua create mode 100644 maps/fish_defender_v2/railgun_enhancer.lua create mode 100644 maps/fish_defender_v2/shotgun_buff.lua create mode 100644 maps/fish_defender_v2/table.lua create mode 100644 maps/fish_defender_v2/terrain.lua create mode 100644 maps/fish_defender_v2/trapped_capsules.lua create mode 100644 maps/fish_defender_v2/ultra_mines.lua create mode 100644 maps/fish_defender_v2/vehicle_nanobots.lua diff --git a/control.lua b/control.lua index 907ab812..63665daa 100644 --- a/control.lua +++ b/control.lua @@ -70,6 +70,7 @@ require 'modules.autostash' ---- enable maps here ---- (maps higher up in the list may be more actually playable) --require 'maps.chronosphere.main' +--require 'maps.fish_defender_v2.main' --require 'maps.fish_defender.main' --require 'maps.biter_battles_v2.main' --require 'maps.mountain_fortress_v3.main' diff --git a/locale/en/fish_defender_v2.cfg b/locale/en/fish_defender_v2.cfg new file mode 100644 index 00000000..4618890b --- /dev/null +++ b/locale/en/fish_defender_v2.cfg @@ -0,0 +1,45 @@ +[fish_defender_v2] +map_info_main_caption=--Fish Defender v2-- +map_info_sub_caption= ~~blb blubby blub~~ +map_info_text=The biters have catched the scent of fish in the market.\nFend them off as long as possible!\nThis however will not be an easy task,\nsince their strength and resistance increases constantly over time.\n\nYour ultimate goal is to evacuate all the fish to cat planet!\nPut them in your rocket's cargo and launch them into space.\nDon't worry, you will still get space science.\n\nThe Market will gladly take any coin you might find.\nAdditional turret slots can be bought at the market.\nSeveral unique upgrades are available too.\nResearching tanks will unlock the artillery technology early.\nAny container bearing dangerous goods, like ammo, grenades or barrels,\ncauses heavy explosions when it breaks.\nMaybe this can be used to our advantage. +boss_message=Boss Wave __1__ - - __2__ +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 diff --git a/maps/fish_defender_v2/boss_biters.lua b/maps/fish_defender_v2/boss_biters.lua new file mode 100644 index 00000000..a2f4b6c9 --- /dev/null +++ b/maps/fish_defender_v2/boss_biters.lua @@ -0,0 +1,99 @@ +local FDT = require 'maps.fish_defender_v2.table' + +local boss_biter = {} +local math_random = math.random +local radius = 6 +local targets = {} +local acid_splashes = { + ['big-biter'] = 'acid-stream-worm-medium', + ['behemoth-biter'] = 'acid-stream-worm-big', + ['big-spitter'] = 'acid-stream-worm-medium', + ['behemoth-spitter'] = 'acid-stream-worm-big' +} +local acid_lines = { + ['big-spitter'] = 'acid-stream-spitter-medium', + ['behemoth-spitter'] = 'acid-stream-spitter-big' +} +for x = radius * -1, radius, 1 do + for y = radius * -1, radius, 1 do + if math.sqrt(x ^ 2 + y ^ 2) <= radius then + targets[#targets + 1] = {x = x, y = y} + end + end +end + +local function acid_nova(event) + for _ = 1, math.random(16, 32) do + local i = math.random(1, #targets) + event.entity.surface.create_entity( + { + name = acid_splashes[event.entity.name], + position = event.entity.position, + force = event.entity.force.name, + source = event.entity.position, + target = {x = event.entity.position.x + targets[i].x, y = event.entity.position.y + targets[i].y}, + max_range = radius, + speed = 0.001 + } + ) + end +end + +boss_biter.died = function(event) + local this = FDT.get() + if acid_splashes[event.entity.name] then + acid_nova(event) + end + if this.acid_lines_delay[event.entity.unit_number] then + this.acid_lines_delay[event.entity.unit_number] = nil + end + this.boss_biters[event.entity.unit_number] = nil +end + +local function acid_line(surface, name, source, target) + local distance = math.sqrt((source.x - target.x) ^ 2 + (source.y - target.y) ^ 2) + + if distance > 16 then + return false + end + + local modifier = {(target.x - source.x) / distance, (target.y - source.y) / distance} + + local position = {source.x, source.y} + + for i = 1, distance + 4, 1 do + if math_random(1, 3) == 1 then + surface.create_entity( + { + name = name, + position = source, + force = 'enemy', + source = source, + target = position, + max_range = 25, + speed = 1 + } + ) + end + position = {position[1] + modifier[1], position[2] + modifier[2]} + end + + return true +end + +boss_biter.damaged_entity = function(event) + if acid_lines[event.cause.name] then + local this = FDT.get() + if not this.acid_lines_delay[event.cause.unit_number] then + this.acid_lines_delay[event.cause.unit_number] = 0 + end + + if this.acid_lines_delay[event.cause.unit_number] < game.tick then + if acid_line(event.cause.surface, acid_lines[event.cause.name], event.cause.position, event.entity.position) then + this.acid_lines_delay[event.cause.unit_number] = game.tick + 180 + end + end + end +end + +return boss_biter diff --git a/maps/fish_defender_v2/bouncy_shells.lua b/maps/fish_defender_v2/bouncy_shells.lua new file mode 100644 index 00000000..76eb4d54 --- /dev/null +++ b/maps/fish_defender_v2/bouncy_shells.lua @@ -0,0 +1,76 @@ +local radius = 9 +local math_random = math.random + +local ammo_to_projectile_translation = { + ['shotgun-shell'] = 'shotgun-pellet', + ['piercing-shotgun-shell'] = 'piercing-shotgun-pellet' +} + +local function create_projectile(surface, position, target, name) + surface.create_entity( + { + name = name, + position = position, + force = 'player', + source = position, + target = target, + max_range = 16, + speed = 0.3 + } + ) +end + +local function bounce(surface, position, ammo) + if math_random(1, 3) ~= 1 then + return + end + local valid_entities = {} + for _, e in pairs( + surface.find_entities_filtered( + {area = {{position.x - radius, position.y - radius}, {position.x + radius, position.y + radius}}} + ) + ) do + if e.health then + if e.force.name ~= 'player' then + --local distance_from_center = math_sqrt((e.position.x - position.x) ^ 2 + (e.position.y - position.y) ^ 2) + --if distance_from_center <= radius then + valid_entities[#valid_entities + 1] = e + --end + end + end + end + + if not valid_entities[1] then + return + end + + for _ = 1, math_random(3, 6), 1 do + create_projectile(surface, position, valid_entities[math_random(1, #valid_entities)].position, ammo) + end +end + +local function bouncy_shells(event) + if event.damage_type.name ~= 'physical' then + return false + end + local player = event.cause + if player.shooting_state.state == defines.shooting.not_shooting then + return false + end + local selected_weapon = player.get_inventory(defines.inventory.character_guns)[player.selected_gun_index] + if selected_weapon.name ~= 'combat-shotgun' and selected_weapon.name ~= 'shotgun' then + return false + end + + local selected_ammo = player.get_inventory(defines.inventory.character_ammo)[player.selected_gun_index] + if not selected_ammo then + return + end + if not ammo_to_projectile_translation[selected_ammo.name] then + return + end + + bounce(player.surface, event.entity.position, ammo_to_projectile_translation[selected_ammo.name]) +end + +return bouncy_shells diff --git a/maps/fish_defender_v2/commands.lua b/maps/fish_defender_v2/commands.lua new file mode 100644 index 00000000..7d3a522b --- /dev/null +++ b/maps/fish_defender_v2/commands.lua @@ -0,0 +1,148 @@ +local Server = require 'utils.server' +local FDT = require 'maps.fish_defender_v2.table' +local Task = require 'utils.task' + +local mapkeeper = '[color=blue]Mapkeeper:[/color]' + +commands.add_command( + 'fishy_commands', + 'Usable only for admins - controls the scenario!', + function(cmd) + local p + local player = game.player + + if not player or not player.valid then + p = log + else + p = player.print + if not player.admin then + return + end + end + + local param = cmd.parameter + + if param == 'restart' or param == 'shutdown' or param == 'reset' or param == 'restartnow' then + goto continue + else + p('[ERROR] Arguments are:\nrestart\nshutdown\nreset\nrestartnow') + return + end + + ::continue:: + + local this = FDT.get() + local reset_map = require 'maps.fish_defender_v2.main'.reset_game + + if not this.reset_are_you_sure then + this.reset_are_you_sure = true + p( + '[WARNING] This command will disable the soft-reset feature, run this command again if you really want to do this!' + ) + return + end + + if param == 'restart' then + if this.restart then + this.reset_are_you_sure = nil + this.restart = false + this.soft_reset = true + p('[SUCCESS] Soft-reset is enabled.') + return + else + this.reset_are_you_sure = nil + this.restart = true + this.soft_reset = false + if this.shutdown then + this.shutdown = false + end + p('[WARNING] Soft-reset is disabled! Server will restart from scenario.') + return + end + elseif param == 'restartnow' then + this.reset_are_you_sure = nil + p(player.name .. ' has restarted the game.') + Server.start_scenario('Fish_Defender') + return + elseif param == 'shutdown' then + if this.shutdown then + this.reset_are_you_sure = nil + this.shutdown = false + this.soft_reset = true + p('[SUCCESS] Soft-reset is enabled.') + return + else + this.reset_are_you_sure = nil + this.shutdown = true + this.soft_reset = false + if this.restart then + this.restart = false + end + p('[WARNING] Soft-reset is disabled! Server will shutdown.') + return + end + elseif param == 'reset' then + this.reset_are_you_sure = nil + if player and player.valid then + game.print(mapkeeper .. ' ' .. player.name .. ', has reset the game!', {r = 0.98, g = 0.66, b = 0.22}) + else + game.print(mapkeeper .. ' server, has reset the game!', {r = 0.98, g = 0.66, b = 0.22}) + end + reset_map() + p('[WARNING] Game has been reset!') + return + end + end +) + +commands.add_command( + 'set_queue_speed', + 'Usable only for admins - sets the queue speed of this map!', + function(cmd) + local p + local player = game.player + local param = tonumber(cmd.parameter) + + if player then + if player ~= nil then + p = player.print + if not player.admin then + p("[ERROR] You're not admin!", Color.fail) + return + end + if not param then + return + end + p('Queue speed set to: ' .. param) + Task.set_queue_speed(param) + else + p = log + p('Queue speed set to: ' .. param) + Task.set_queue_speed(param) + end + end + end +) + +commands.add_command( + 'get_queue_speed', + 'Usable only for admins - gets the queue speed of this map!', + function() + local p + local player = game.player + + if player then + if player ~= nil then + p = player.print + if not player.admin then + p("[ERROR] You're not admin!", Color.fail) + return + end + p(Task.get_queue_speed()) + else + p = log + p(Task.get_queue_speed()) + end + end + end +) diff --git a/maps/fish_defender_v2/crumbly_walls.lua b/maps/fish_defender_v2/crumbly_walls.lua new file mode 100644 index 00000000..afa7cfd7 --- /dev/null +++ b/maps/fish_defender_v2/crumbly_walls.lua @@ -0,0 +1,27 @@ +local Event = require 'utils.event' +local FDT = require 'maps.fish_defender_v2.table' +local math_random = math.random + +local rock_raffle = {'sand-rock-big', 'rock-big', 'rock-big', 'rock-big', 'rock-huge'} + +local function on_entity_died(event) + local crumbly_walls_unlocked = FDT.get('crumbly_walls_unlocked') + if not crumbly_walls_unlocked then + return + end + local entity = event.entity + if not entity.valid then + return + end + if entity.name ~= 'stone-wall' then + return + end + if math_random(1, 4) == 1 then + return + end + entity.surface.create_entity( + {name = rock_raffle[math_random(1, #rock_raffle)], position = entity.position, force = 'player'} + ) +end + +Event.add(defines.events.on_entity_died, on_entity_died) diff --git a/maps/fish_defender_v2/explosive_gun_bullets.lua b/maps/fish_defender_v2/explosive_gun_bullets.lua new file mode 100644 index 00000000..034876f7 --- /dev/null +++ b/maps/fish_defender_v2/explosive_gun_bullets.lua @@ -0,0 +1,46 @@ +local radius = 3 + +local function splash_damage(surface, position, final_damage_amount) + local damage = math.random(math.floor(final_damage_amount * 3), math.floor(final_damage_amount * 4)) + for _, e in pairs( + surface.find_entities_filtered( + {area = {{position.x - radius, position.y - radius}, {position.x + radius, position.y + radius}}} + ) + ) do + if e.valid and e.health then + local distance_from_center = math.sqrt((e.position.x - position.x) ^ 2 + (e.position.y - position.y) ^ 2) + if distance_from_center <= radius then + local damage_distance_modifier = 1 - distance_from_center / radius + if damage > 0 then + if math.random(1, 3) == 1 then + surface.create_entity({name = 'explosion', position = e.position}) + end + e.damage(damage * damage_distance_modifier, 'player', 'explosion') + end + end + end + end +end + +local function explosive_bullets(event) + if math.random(1, 3) ~= 1 then + return false + end + if event.damage_type.name ~= 'physical' then + return false + end + local player = event.cause + if player.shooting_state.state == defines.shooting.not_shooting then + return false + end + local selected_weapon = player.get_inventory(defines.inventory.character_guns)[player.selected_gun_index] + if selected_weapon.name ~= 'submachine-gun' and selected_weapon.name ~= 'pistol' then + return false + end + + player.surface.create_entity({name = 'explosion', position = event.entity.position}) + + splash_damage(player.surface, event.entity.position, event.final_damage_amount) +end + +return explosive_bullets diff --git a/maps/fish_defender_v2/flame_boots.lua b/maps/fish_defender_v2/flame_boots.lua new file mode 100644 index 00000000..8fcb1e48 --- /dev/null +++ b/maps/fish_defender_v2/flame_boots.lua @@ -0,0 +1,52 @@ +local Event = require 'utils.event' +local FDT = require 'maps.fish_defender_v2.table' + +local function on_player_changed_position(event) + local flame_boots = FDT.get('flame_boots') + if not flame_boots then + return + end + local player = game.players[event.player_index] + if not player.character then + return + end + if player.character.driving then + return + end + + if not flame_boots[player.index] then + flame_boots[player.index] = {} + end + + if not flame_boots[player.index].fuel then + return + end + + if flame_boots[player.index].fuel < 0 then + player.print('Your flame boots have worn out.', {r = 0.22, g = 0.77, b = 0.44}) + flame_boots[player.index] = {} + return + end + + if flame_boots[player.index].fuel % 500 == 0 then + player.print('Fuel remaining: ' .. flame_boots[player.index].fuel, {r = 0.22, g = 0.77, b = 0.44}) + end + + if not flame_boots[player.index].step_history then + flame_boots[player.index].step_history = {} + end + + local elements = #flame_boots[player.index].step_history + + flame_boots[player.index].step_history[elements + 1] = {x = player.position.x, y = player.position.y} + + if elements < 50 then + return + end + + player.surface.create_entity({name = 'fire-flame', position = flame_boots[player.index].step_history[elements - 2]}) + + flame_boots[player.index].fuel = flame_boots[player.index].fuel - 1 +end + +Event.add(defines.events.on_player_changed_position, on_player_changed_position) diff --git a/maps/fish_defender_v2/laser_pointer.lua b/maps/fish_defender_v2/laser_pointer.lua new file mode 100644 index 00000000..ab3e02c7 --- /dev/null +++ b/maps/fish_defender_v2/laser_pointer.lua @@ -0,0 +1,37 @@ +local Event = require 'utils.event' +local FDT = require 'maps.fish_defender_v2.table' +local radius = 32 + +local function on_player_used_capsule(event) + local laser_pointer_unlocked = FDT.get('laser_pointer_unlocked') + if not laser_pointer_unlocked then + return + end + + local player = game.players[event.player_index] + local position = event.position + local used_item = event.item + if used_item.name ~= 'artillery-targeting-remote' then + return + end + + for _, unit in pairs(player.surface.find_enemy_units(position, radius, 'player')) do + if math.random(1, 2) == 1 then + unit.set_command( + { + type = defines.command.go_to_location, + destination = position, + radius = 2, + distraction = defines.distraction.none, + pathfind_flags = { + allow_destroy_friendly_entities = false, + prefer_straight_paths = false, + low_priority = false + } + } + ) + end + end +end + +Event.add(defines.events.on_player_used_capsule, on_player_used_capsule) diff --git a/maps/fish_defender_v2/main.lua b/maps/fish_defender_v2/main.lua new file mode 100644 index 00000000..0d346201 --- /dev/null +++ b/maps/fish_defender_v2/main.lua @@ -0,0 +1,1546 @@ +-- fish defender -- by mewmew -- + +--require "modules.rpg" + +require 'maps.fish_defender_v2.market' +require 'maps.fish_defender_v2.commands' +require 'maps.fish_defender_v2.shotgun_buff' +require 'maps.fish_defender_v2.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 Terrain = require 'maps.fish_defender_v2.terrain' +local Task = require 'utils.task' +local Unit_health_booster = require 'modules.biter_health_booster' +local Difficulty = require 'modules.difficulty_vote' +local Map = require 'modules.map_info' +local Event = require 'utils.event' +local Reset = require 'functions.soft_reset' +local Server = require 'utils.server' +local Poll = require 'comfy_panel.poll' +local boss_biter = require 'maps.fish_defender_v2.boss_biters' +local FDT = require 'maps.fish_defender_v2.table' +local Score = require 'comfy_panel.score' +local math_random = math.random +local insert = table.insert +local enable_start_grace_period = true + +local branch_version = '0.18.35' +local sub = string.sub + +local Public = {} + +local starting_items = { + ['pistol'] = 1, + ['firearm-magazine'] = 16, + ['raw-fish'] = 3, + ['iron-plate'] = 32, + ['stone'] = 12 +} + +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 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 function create_wave_gui(player) + if player.gui.top['fish_defense_waves'] then + player.gui.top['fish_defense_waves'].destroy() + end + local this = FDT.get() + 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 this.wave_count then + wave_count = this.wave_count + end + + if not this.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 % this.wave_interval / this.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(((this.wave_grace_period - (game.tick % this.wave_grace_period)) / 60) / 60) + if time_remaining <= 0 then + this.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 + this.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' + local this = FDT.get() + + 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(this.entity_limits) do + local name = v.str + local placed = v.placed + local limit = v.limit + local entry = {name, placed .. '/' .. limit} + for _, value_entry in pairs(entry) do + table.add { + type = 'label', + caption = value_entry + } + 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 + + 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() + 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 this = FDT.get() + local biter_pool + if this.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 this.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 this.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 this.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 biter_pool = get_biter_initial_pool() + local biter_raffle = {} + for _, biter_type in pairs(biter_pool) do + for _ = 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) + local this = FDT.get() + if this.attack_wave_threat < 1 then + return false + end + + local surface = game.surfaces[this.active_surface_index] + if not surface or not surface.valid then + return + end + + biter_pool = shuffle(biter_pool) + this.attack_wave_threat = this.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 + shuffle(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 + local this = FDT.get() + for _, entry in pairs(attack_group_count_thresholds) do + if this.wave_count >= entry[1] then + n = entry[2] + end + end + return n +end + +local function clear_corpses(surface) + local this = FDT.get() + + if not this.wave_count then + return + end + local chance = 4 + if this.wave_count > 250 then + chance = 3 + end + if this.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 function send_unit_group(unit_group) + local commands = {} + local this = FDT.get() + for x = unit_group.position.x, this.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 = this.market.position.x, y = unit_group.position.y}, + radius = 16, + distraction = defines.distraction.by_enemy + } + commands[#commands + 1] = { + type = defines.command.attack, + target = this.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) + local Diff = Difficulty.get() + local this = FDT.get() + if this.wave_count <= 2000 then + game.print( + {'fish_defender_v2.boss_message', this.wave_count, {'fish_defender_v2.' .. this.wave_count}}, + {r = 0.8, g = 0.1, b = 0.1} + ) + else + game.print({'fish_defender_v2.boss_message', this.wave_count}, {r = 0.8, g = 0.1, b = 0.1}) + end + + if not this.boss_waves[this.wave_count] then + local amount = this.wave_count + if amount > 1000 then + amount = 1000 + end + this.boss_waves[this.wave_count] = { + {name = 'behemoth-biter', count = math.floor(amount / 20)}, + {name = 'behemoth-spitter', count = math.floor(amount / 40)} + } + end + + local health_factor = this.difficulties_votes[Diff.difficulty_vote_index].boss_modifier + if this.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(this.boss_waves[this.wave_count]) do + for _ = 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 + this.boss_biters[biter.unit_number] = biter + Unit_health_booster.add_boss_unit(biter, this.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) + local this = FDT.get() + if not this.market or not this.market.valid 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 = this.market, + distraction = defines.distraction.none + }, + unit_count = 16, + force = 'enemy', + unit_search_distance = 24 + } + ) +end + +local function damage_entity_outside_and_inside_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 == 'land-mine' then + e.health = + e.health - math_random(math.floor(e.prototype.max_health * 0.2), math.floor(e.prototype.max_health * 0.4)) + if e.health <= 0 then + e.die('enemy') + end + return + end + + 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() + local Diff = Difficulty.get() + local this = FDT.get() + + if not this.market or not this.market.valid then + return + end + if this.wave_grace_period then + return + end + local surface = game.surfaces[this.active_surface_index] + if not surface or not surface.valid then + return + end + + 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 this.wave_count then + this.wave_count = 1 + else + this.wave_count = this.wave_count + 1 + end + + local m = 0.0015 + if Diff.difficulty_vote_index then + m = m * this.difficulties_votes[Diff.difficulty_vote_index].strength_modifier + end + game.forces.enemy.set_ammo_damage_modifier('melee', this.wave_count * m) + game.forces.enemy.set_ammo_damage_modifier('biological', this.wave_count * m) + this.biter_health_boost = 1 + (this.wave_count * (m * 2)) + + m = 4 + if Diff.difficulty_vote_index then + m = m * this.difficulties_votes[Diff.difficulty_vote_index].amount_modifier + end + + if this.wave_count % 50 == 0 then + this.attack_wave_threat = math.floor(this.wave_count * (m * 1.5)) + spawn_boss_units(surface) + if this.attack_wave_threat > 10000 then + this.attack_wave_threat = 10000 + end + else + this.attack_wave_threat = math.floor(this.wave_count * m) + if this.attack_wave_threat > 10000 then + this.attack_wave_threat = 10000 + end + end + + local evolution = this.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 this.endgame_modifier then + -- this.endgame_modifier = 1 + -- game.print("Endgame enemy evolution reached.", {r = 0.7, g = 0.1, b = 0.1}) + -- else + -- this.endgame_modifier = this.endgame_modifier + 1 + -- end + --end + + for _, e in pairs(surface.find_entities_filtered({area = {{110, -256}, {360, 256}}})) do + damage_entity_outside_and_inside_of_fence(e) + end + + local y_raffle = get_y_coord_raffle_table() + + local unit_groups = {} + if this.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}}}) + --shuffle(spawners) + + while this.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 _ = 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() + local get_score = Score.get_table().score_table + if not get_score['player'] then + return false + end + local score = get_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() + local this = FDT.get() + + if not this.game_has_ended 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 survival_time_label = t.add({type = 'label', caption = 'Survival Time >> '}) + survival_time_label.style.font = 'default-listbox' + survival_time_label.style.font_color = {r = 0.22, g = 0.77, b = 0.44} + + local market_age_label + + if this.market_age then + if this.market_age >= 216000 then + market_age_label = + t.add( + { + type = 'label', + caption = math.floor(((this.market_age / 60) / 60) / 60) .. + ' hours ' .. math.ceil((this.market_age % 216000 / 60) / 60) .. ' minutes' + } + ) + market_age_label.style.font = 'default-bold' + market_age_label.style.font_color = {r = 0.33, g = 0.66, b = 0.9} + else + market_age_label = + t.add({type = 'label', caption = math.ceil((this.market_age % 216000 / 60) / 60) .. ' minutes'}) + market_age_label.style.font = 'default-bold' + market_age_label.style.font_color = {r = 0.33, g = 0.66, b = 0.9} + end + end + + local mvp = get_mvps() + if mvp then + local mvp_defender_label = t.add({type = 'label', caption = 'MVP Defender >> '}) + mvp_defender_label.style.font = 'default-listbox' + mvp_defender_label.style.font_color = {r = 0.22, g = 0.77, b = 0.44} + + local mvp_killscore_label = + t.add({type = 'label', caption = mvp.killscore.name .. ' with a score of ' .. mvp.killscore.score}) + mvp_killscore_label.style.font = 'default-bold' + mvp_killscore_label.style.font_color = {r = 0.33, g = 0.66, b = 0.9} + + local mvp_builder_label = t.add({type = 'label', caption = 'MVP Builder >> '}) + mvp_builder_label.style.font = 'default-listbox' + mvp_builder_label.style.font_color = {r = 0.22, g = 0.77, b = 0.44} + + local mvp_built_ent_label = + t.add( + { + type = 'label', + caption = mvp.built_entities.name .. ' built ' .. mvp.built_entities.score .. ' things' + } + ) + mvp_built_ent_label.style.font = 'default-bold' + mvp_built_ent_label.style.font_color = {r = 0.33, g = 0.66, b = 0.9} + + local mvp_deaths_label = t.add({type = 'label', caption = 'MVP Deaths >> '}) + mvp_deaths_label.style.font = 'default-listbox' + mvp_deaths_label.style.font_color = {r = 0.22, g = 0.77, b = 0.44} + + local mvp_deaths_name_label = + t.add({type = 'label', caption = mvp.deaths.name .. ' died ' .. mvp.deaths.score .. ' times'}) + mvp_deaths_name_label.style.font = 'default-bold' + mvp_deaths_name_label.style.font_color = {r = 0.33, g = 0.66, b = 0.9} + + if not this.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) + this.results_sent = true + end + end + + player.play_sound {path = 'utility/game_lost', volume_modifier = 0.75} + 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 this = FDT.get() + local surface = game.surfaces[this.active_surface_index] + if not surface or not surface.valid then + return + end + + local is_branch_18 = sub(branch_version, 3, 4) + local get_active_version = sub(game.active_mods.base, 3, 4) + + if not surface or not surface.valid then + return + end + + if not this.market or not this.market.valid then + return + end + + local m = 32 + local m2 = m * 0.005 + if get_active_version >= is_branch_18 then + for i = 1, 1024, 1 do + surface.create_particle( + { + name = 'branch-particle', + position = this.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 + else + for i = 1, 1024, 1 do + surface.create_entity( + { + name = 'branch-particle', + position = this.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 + end + for x = -5, 5, 0.5 do + for y = -5, 5, 0.5 do + if math_random(1, 2) == 1 then + surface.create_trivial_smoke( + { + name = 'smoke-fast', + position = {this.market.position.x + (x * 0.35), this.market.position.y + (y * 0.35)} + } + ) + end + if math_random(1, 3) == 1 then + surface.create_trivial_smoke( + { + name = 'train-smoke', + position = {this.market.position.x + (x * 0.35), this.market.position.y + (y * 0.35)} + } + ) + end + end + end + surface.spill_item_stack(this.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 + + local this = FDT.get() + + if event.entity.force.name == 'enemy' then + local surface = event.entity.surface + + if this.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 this.entity_limits[event.entity.name] then + this.entity_limits[event.entity.name].placed = this.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] + local this = FDT.get() + local surface = game.surfaces[this.active_surface_index] + if not surface or not surface.valid then + return + end + + if player.online_time == 0 then + for item, amount in pairs(starting_items) do + player.insert({name = item, count = amount}) + end + + if global.show_floating_killscore then + global.show_floating_killscore[player.name] = false + end + end + + local spawn = player.force.get_spawn_position(surface) + local pos = surface.find_non_colliding_position('character', spawn, 3, 0.5) + + if not pos and player.online_time < 2 then + player.teleport(spawn, surface) + elseif player.online_time < 2 or player.surface.index ~= this.active_surface_index then + player.teleport(pos, surface) + end + + create_wave_gui(player) + add_fd_stats_button(player) + + if game.tick > 900 then + is_game_lost() + end + + --if this.charting_done then return end + --game.forces.player.chart(game.surfaces["fish_defender"], {{-256, -512},{768, 512}}) + --this.charting_done = true +end + +local function on_built_entity(event) + local get_score = Score.get_table().score_table + local this = FDT.get() + local entity = event.created_entity + if not entity.valid then + return + end + if this.entity_limits[entity.name] then + local surface = entity.surface + + if this.entity_limits[entity.name].placed < this.entity_limits[entity.name].limit then + this.entity_limits[entity.name].placed = this.entity_limits[entity.name].placed + 1 + surface.create_entity( + { + name = 'flying-text', + position = entity.position, + text = this.entity_limits[entity.name].placed .. + ' / ' .. + this.entity_limits[entity.name].limit .. ' ' .. this.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 = this.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 get_score then + if get_score[player.force.name] then + if get_score[player.force.name].players[player.name] then + get_score[player.force.name].players[player.name].built_entities = + get_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 + local this = FDT.get() + if this.entity_limits[entity.name] then + local surface = entity.surface + if this.entity_limits[entity.name].placed < this.entity_limits[entity.name].limit then + this.entity_limits[entity.name].placed = this.entity_limits[entity.name].placed + 1 + surface.create_entity( + { + name = 'flying-text', + position = entity.position, + text = this.entity_limits[entity.name].placed .. + ' / ' .. + this.entity_limits[entity.name].limit .. ' ' .. this.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 = this.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_player_changed_position(event) + local player = game.players[event.player_index] + local this = FDT.get() + local surface = game.surfaces[this.active_surface_index] + if not surface or not surface.valid then + return + end + 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}, surface) + if player.position.y > this.map_height or player.position.y < this.map_height * -1 then + player.teleport({player.position.x, 0}, surface) + 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) + local this = FDT.get() + if this.entity_limits[event.entity.name] then + this.entity_limits[event.entity.name].placed = this.entity_limits[event.entity.name].placed - 1 + update_fd_stats() + end +end + +local function on_robot_mined_entity(event) + local this = FDT.get() + if this.entity_limits[event.entity.name] then + this.entity_limits[event.entity.name].placed = this.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) + local this = FDT.get() + if not this.market_age then + return + end + local player = game.players[event.player_index] + player.character.destructible = false +end + +local function set_objective_health(final_damage_amount) + local this = FDT.get() + if final_damage_amount == 0 then + return + end + + if this.market_health <= 0 then + this.market.health = this.market.health + final_damage_amount + return + end + + this.market_health = math.floor(this.market_health - final_damage_amount) + if this.market_health > this.market_max_health then + this.market_health = this.market_max_health + end + + if this.market_health <= 0 then + market_kill_visuals() + this.market.die() + this.market = nil + this.market_age = game.tick - this.last_reset + this.game_has_ended = true + is_game_lost() + return + end + + local m = this.market_health / this.market_max_health + this.market.health = 150 * m + + rendering.set_text(this.health_text, 'HP: ' .. this.market_health .. ' / ' .. this.market_max_health) +end + +local function protect_entities(event) + local this = FDT.get() + local entity = event.entity + + if not entity or not entity.valid then + return + end + + if not this.market or not this.market.valid then + return + end + + if entity.force.index ~= 1 then + return + end --Player Force + + if event.cause then + if event.cause.force.index == 2 and entity == this.market then + set_objective_health(event.final_damage_amount) + elseif event.cause.force.index == 2 then + return + else + event.entity.health = event.entity.health + event.final_damage_amount + end + end + if entity and entity.valid then + event.entity.health = event.entity.health + event.final_damage_amount + end +end + +local function on_entity_damaged(event) + local entity = event.entity + + if not entity then + return + end + + if not entity.valid then + return + end + + protect_entities(event) +end + +local function on_player_repaired_entity(event) + local this = FDT.get() + if not event.entity then + return + end + if not event.entity.valid then + return + end + if not event.entity.health then + return + end + local entity = event.entity + if entity == this.market then + set_objective_health(-1) + end +end + +local function set_market_health() + local this = FDT.get() + if not this.market then + return + end + if not this.market.valid then + return + end + local m = this.market_health / this.market_max_health + this.market.health = 150 * m + rendering.set_text(this.health_text, 'HP: ' .. this.market_health .. ' / ' .. this.market_max_health) +end + +local function has_the_game_ended() + local this = FDT.get() + if this.market_age then + if not this.game_restart_timer then + this.game_restart_timer = 5400 + else + if this.game_restart_timer < 0 then + return + end + + this.game_restart_timer = this.game_restart_timer - 30 + end + local cause_msg + if this.restart then + cause_msg = 'restart' + elseif this.shutdown then + cause_msg = 'shutdown' + elseif this.soft_reset then + cause_msg = 'soft-reset' + end + + if this.game_restart_timer % 1800 == 0 then + if this.game_restart_timer > 0 then + this.game_reset = true + game.print( + 'Game will ' .. cause_msg .. ' in ' .. this.game_restart_timer / 60 .. ' seconds!', + {r = 0.22, g = 0.88, b = 0.22} + ) + end + if this.soft_reset and this.game_restart_timer == 0 then + this.game_reset_tick = nil + Public.reset_game() + return + end + if this.restart and this.game_restart_timer == 0 then + if not this.announced_message then + game.print('Soft-reset is disabled. Server will restart!', {r = 0.22, g = 0.88, b = 0.22}) + local message = 'Soft-reset is disabled. Server will restart!' + Server.to_discord_bold(table.concat {'*** ', message, ' ***'}) + Server.start_scenario('Fish_Defender') + this.announced_message = true + return + end + end + if this.shutdown and this.game_restart_timer == 0 then + if not this.announced_message then + game.print('Soft-reset is disabled. Server is shutting down!', {r = 0.22, g = 0.88, b = 0.22}) + local message = 'Soft-reset is disabled. Server is shutting down!' + Server.to_discord_bold(table.concat {'*** ', message, ' ***'}) + Server.stop_scenario() + this.announced_message = true + return + end + end + end + end +end + +function Public.reset_game() + FDT.reset_table() + Poll.reset() + local this = FDT.get() + local is_branch_18 = sub(branch_version, 3, 4) + local get_active_version = sub(game.active_mods.base, 3, 4) + + Difficulty.reset_difficulty_poll() + Difficulty.set_poll_closing_timeout = game.tick + 36000 + + local players = game.connected_players + for i = 1, #players do + local player = players[i] + Score.init_player_table(player) + if player.gui.left['fish_defense_game_lost'] then + player.gui.left['fish_defense_game_lost'].destroy() + end + end + + local map_gen_settings = {} + map_gen_settings.seed = math_random(10000, 99999) + 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'} + } + + if not this.active_surface_index then + this.active_surface_index = game.create_surface('fish_defender', map_gen_settings).index + else + this.active_surface_index = + Reset.soft_reset_map(game.surfaces[this.active_surface_index], map_gen_settings, starting_items).index + end + + local surface = game.surfaces[this.active_surface_index] + if not surface or not surface.valid then + return + end + + surface.peaceful_mode = false + + global.chunk_queue = {} + + Terrain.fish_eye(surface, {x = -2150, y = -300}) + + Task.get_task_queue(4) + Task.start_queue() + + 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 + + if not game.forces.decoratives then + game.create_force('decoratives') + end + + game.forces['decoratives'].set_cease_fire('enemy', true) + game.forces['enemy'].set_cease_fire('decoratives', true) + game.forces['player'].set_cease_fire('decoratives', true) + game.remove_offline_players() + + game.map_settings.enemy_expansion.enabled = false + game.forces['player'].technologies['artillery'].researched = false + + is_branch_18 = is_branch_18 .. sub(branch_version, 6, 7) + get_active_version = get_active_version .. sub(game.active_mods.base, 6, 7) + if get_active_version >= is_branch_18 then + game.reset_time_played() + end + + this.market_health = 500 + this.market_max_health = 500 +end + +function Public.on_init() + Public.reset_game() + + local T = Map.Pop_info() + T.localised_category = 'fish_defender_v2' + 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} + + local mgs = game.surfaces['nauvis'].map_gen_settings + mgs.width = 16 + mgs.height = 16 + game.surfaces['nauvis'].map_gen_settings = mgs + game.surfaces['nauvis'].clear() +end + +local function on_tick() + local Diff = Difficulty.get() + local this = FDT.get() + local surface = game.surfaces[this.active_surface_index] + if not surface or not surface.valid then + return + end + if game.tick % 30 == 0 then + has_the_game_ended() + if this.market then + set_market_health() + for _, player in pairs(game.connected_players) do + if surface.peaceful_mode == false then + create_wave_gui(player) + end + end + end + if game.tick % 180 == 0 then + if surface then + game.forces.player.chart(surface, {{-160, -128}, {192, 128}}) + if Diff.difficulty_vote_index then + this.wave_interval = this.difficulties_votes[Diff.difficulty_vote_index].wave_interval + end + end + end + end + + if game.tick % this.wave_interval == this.wave_interval - 1 then + if surface.peaceful_mode == true then + return + end + biter_attack_wave() + end +end + +local on_init = Public.on_init + +Event.add(defines.events.on_entity_damaged, on_entity_damaged) +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_player_repaired_entity, on_player_repaired_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) + +return Public diff --git a/maps/fish_defender_v2/market.lua b/maps/fish_defender_v2/market.lua new file mode 100644 index 00000000..743d3cc8 --- /dev/null +++ b/maps/fish_defender_v2/market.lua @@ -0,0 +1,345 @@ +require 'maps.fish_defender_v2.flame_boots' +require 'maps.fish_defender_v2.trapped_capsules' +require 'maps.fish_defender_v2.ultra_mines' +require 'maps.fish_defender_v2.crumbly_walls' +require 'maps.fish_defender_v2.vehicle_nanobots' +require 'maps.fish_defender_v2.laser_pointer' + +local Event = require 'utils.event' +local FDT = require 'maps.fish_defender_v2.table' +local Server = require 'utils.server' + +local slot_upgrade_offers = { + [1] = {'gun-turret', 'gun turret'}, + [2] = {'laser-turret', 'laser turret'}, + [3] = {'artillery-turret', 'artillery turret'}, + [4] = {'flamethrower-turret', 'flamethrower turret'}, + [5] = {'land-mine', 'land mine'} +} + +local special_descriptions = { + ['flame-boots'] = 'Flame Boots - Get yourself some hot boots.', + ['explosive-bullets'] = 'Unlock Explosive Bullets - Submachine-Gun and Pistol gains a chance to deal splash damage.', + ['bouncy-shells'] = 'Unlock Bouncy Shells - Shotgun projectiles may bounce to multiple targets.', + ['trapped-capsules'] = 'Unlock Trapped Capsules - Combat robots will send a last deadly projectile to a nearby enemy when killed.', + ['ultra-mines'] = 'Unlock Ultra Mines - Careful with these...', + ['railgun-enhancer'] = 'Unlock Railgun Enhancer - Turns the railgun into a powerful forking gun.', + ['crumbly-walls'] = 'Unlock Crumbly Walls - Fortifications which crumble, may turn into rocks.', + ['vehicle-nanobots'] = 'Unlock Vehicle Nanobots - Vehicles repair rapidly while driving.', + ['laser-pointer'] = 'Unlock Laser Pointer - The biters are on a quest to slay the red (artillery) dot.' +} + +local function refresh_market_offers() + local this = FDT.get() + if not this.market or not this.market.valid then + return + end + for i = 1, 100, 1 do + local a = this.market.remove_market_item(1) + if a == false then + break + end + end + + local str1 = + 'Gun Turret Slot for ' .. + tostring(this.entity_limits['gun-turret'].limit * this.entity_limits['gun-turret'].slot_price) + str1 = str1 .. ' Coins.' + + local str2 = + 'Laser Turret Slot for ' .. + tostring(this.entity_limits['laser-turret'].limit * this.entity_limits['laser-turret'].slot_price) + str2 = str2 .. ' Coins.' + + local str3 = + 'Artillery Slot for ' .. + tostring(this.entity_limits['artillery-turret'].limit * this.entity_limits['artillery-turret'].slot_price) + str3 = str3 .. ' Coins.' + + local current_limit = 1 + if this.entity_limits['flamethrower-turret'].limit ~= 0 then + current_limit = current_limit + this.entity_limits['flamethrower-turret'].limit + end + local str4 = + 'Flamethrower Turret Slot for ' .. + tostring(current_limit * this.entity_limits['flamethrower-turret'].slot_price) + str4 = str4 .. ' Coins.' + + local str5 = + 'Landmine Slot for ' .. + tostring(math.ceil((this.entity_limits['land-mine'].limit / 3) * this.entity_limits['land-mine'].slot_price)) + str5 = str5 .. ' Coins.' + + local market_items = { + {price = {}, offer = {type = 'nothing', effect_description = str1}}, + {price = {}, offer = {type = 'nothing', effect_description = str2}}, + {price = {}, offer = {type = 'nothing', effect_description = str3}}, + {price = {}, offer = {type = 'nothing', effect_description = str4}}, + {price = {}, offer = {type = 'nothing', effect_description = str5}}, + {price = {{'coin', 5}}, offer = {type = 'give-item', item = 'raw-fish', count = 1}}, + {price = {{'coin', 1}}, offer = {type = 'give-item', item = 'wood', count = 8}}, + {price = {{'coin', 8}}, offer = {type = 'give-item', item = 'grenade', count = 1}}, + {price = {{'coin', 32}}, offer = {type = 'give-item', item = 'cluster-grenade', count = 1}}, + {price = {{'coin', 1}}, offer = {type = 'give-item', item = 'land-mine', count = 1}}, + {price = {{'coin', 80}}, offer = {type = 'give-item', item = 'car', count = 1}}, + {price = {{'coin', 1200}}, offer = {type = 'give-item', item = 'tank', count = 1}}, + {price = {{'coin', 3}}, offer = {type = 'give-item', item = 'cannon-shell', count = 1}}, + {price = {{'coin', 7}}, offer = {type = 'give-item', item = 'explosive-cannon-shell', count = 1}}, + {price = {{'coin', 50}}, offer = {type = 'give-item', item = 'gun-turret', count = 1}}, + {price = {{'coin', 300}}, offer = {type = 'give-item', item = 'laser-turret', count = 1}}, + {price = {{'coin', 450}}, offer = {type = 'give-item', item = 'artillery-turret', count = 1}}, + {price = {{'coin', 10}}, offer = {type = 'give-item', item = 'artillery-shell', count = 1}}, + {price = {{'coin', 25}}, offer = {type = 'give-item', item = 'artillery-targeting-remote', count = 1}}, + {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}}, + {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}}, + {price = {{'coin', 30}}, offer = {type = 'give-item', item = 'submachine-gun', count = 1}}, + {price = {{'coin', 250}}, offer = {type = 'give-item', item = 'combat-shotgun', count = 1}}, + {price = {{'coin', 450}}, offer = {type = 'give-item', item = 'flamethrower', count = 1}}, + {price = {{'coin', 25}}, offer = {type = 'give-item', item = 'flamethrower-ammo', count = 1}}, + {price = {{'coin', 125}}, offer = {type = 'give-item', item = 'rocket-launcher', count = 1}}, + {price = {{'coin', 2}}, offer = {type = 'give-item', item = 'rocket', count = 1}}, + {price = {{'coin', 7}}, offer = {type = 'give-item', item = 'explosive-rocket', count = 1}}, + {price = {{'coin', 7500}}, offer = {type = 'give-item', item = 'atomic-bomb', count = 1}}, + {price = {{'coin', 325}}, offer = {type = 'give-item', item = 'railgun', count = 1}}, + {price = {{'coin', 8}}, offer = {type = 'give-item', item = 'railgun-dart', count = 1}}, + {price = {{'coin', 40}}, offer = {type = 'give-item', item = 'poison-capsule', count = 1}}, + {price = {{'coin', 4}}, offer = {type = 'give-item', item = 'defender-capsule', count = 1}}, + {price = {{'coin', 10}}, offer = {type = 'give-item', item = 'light-armor', count = 1}}, + {price = {{'coin', 125}}, 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}}, + {price = {{'coin', 12000}}, 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}}, + {price = {{'coin', 200}}, offer = {type = 'give-item', item = 'energy-shield-equipment', count = 1}}, + {price = {{'coin', 850}}, offer = {type = 'give-item', item = 'personal-laser-defense-equipment', count = 1}}, + {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}}, + {price = {{'coin', 200}}, offer = {type = 'give-item', item = 'belt-immunity-equipment', count = 1}}, + {price = {{'coin', 250}}, offer = {type = 'give-item', item = 'personal-roboport-equipment', count = 1}}, + {price = {{'coin', 35}}, offer = {type = 'give-item', item = 'construction-robot', count = 1}}, + {price = {{'coin', 25}}, offer = {type = 'give-item', item = 'cliff-explosives', count = 1}}, + {price = {{'coin', 80}}, offer = {type = 'nothing', effect_description = special_descriptions['flame-boots']}} + } + + for _, item in pairs(market_items) do + this.market.add_market_item(item) + end + + if not this.railgun_enhancer_unlocked then + this.market.add_market_item( + { + price = {{'coin', 1500}}, + offer = {type = 'nothing', effect_description = special_descriptions['railgun-enhancer']} + } + ) + end + if not this.trapped_capsules_unlocked then + this.market.add_market_item( + { + price = {{'coin', 3500}}, + offer = {type = 'nothing', effect_description = special_descriptions['trapped-capsules']} + } + ) + end + if not this.explosive_bullets_unlocked then + this.market.add_market_item( + { + price = {{'coin', 4500}}, + offer = {type = 'nothing', effect_description = special_descriptions['explosive-bullets']} + } + ) + end + if not this.bouncy_shells_unlocked then + this.market.add_market_item( + { + price = {{'coin', 10000}}, + offer = {type = 'nothing', effect_description = special_descriptions['bouncy-shells']} + } + ) + end + if not this.vehicle_nanobots_unlocked then + this.market.add_market_item( + { + price = {{'coin', 15000}}, + offer = {type = 'nothing', effect_description = special_descriptions['vehicle-nanobots']} + } + ) + end + --[[ + if not this.crumbly_walls_unlocked then + this.market.add_market_item({price = {{"coin", 35000}}, offer = {type = 'nothing', effect_description = special_descriptions["crumbly-walls"]}}) + end + if not this.ultra_mines_unlocked then + this.market.add_market_item({price = {{"coin", 45000}}, offer = {type = 'nothing', effect_description = special_descriptions["ultra-mines"]}}) + end + ]] + if not this.laser_pointer_unlocked then + this.market.add_market_item( + { + price = {{'coin', 65000}}, + offer = {type = 'nothing', effect_description = special_descriptions['laser-pointer']} + } + ) + end +end + +local function slot_upgrade(player, offer_index) + local this = FDT.get() + local price = + this.entity_limits[slot_upgrade_offers[offer_index][1]].limit * + this.entity_limits[slot_upgrade_offers[offer_index][1]].slot_price + + local gain = 1 + if offer_index == 5 then + price = + math.ceil( + (this.entity_limits[slot_upgrade_offers[offer_index][1]].limit / 3) * + this.entity_limits[slot_upgrade_offers[offer_index][1]].slot_price + ) + gain = 3 + end + + if slot_upgrade_offers[offer_index][1] == 'flamethrower-turret' then + price = + (this.entity_limits[slot_upgrade_offers[offer_index][1]].limit + 1) * + this.entity_limits[slot_upgrade_offers[offer_index][1]].slot_price + end + + 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 false + end + + this.entity_limits[slot_upgrade_offers[offer_index][1]].limit = + this.entity_limits[slot_upgrade_offers[offer_index][1]].limit + gain + game.print( + player.name .. ' has bought a ' .. slot_upgrade_offers[offer_index][2] .. ' slot for ' .. price .. ' coins!', + {r = 0.22, g = 0.77, b = 0.44} + ) + if math.random(1, 2) == 1 then + Server.to_discord_bold( + table.concat { + '*** ' .. + player.name .. + ' has bought a ' .. + slot_upgrade_offers[offer_index][2] .. ' slot for ' .. price .. ' coins! ***' + } + ) + end + refresh_market_offers() +end + +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 this = FDT.get() + + if slot_upgrade_offers[offer_index] then + if slot_upgrade(player, offer_index) then + return + end + end + + if offer_index < 50 then + return + end + + if bought_offer.effect_description == special_descriptions['flame-boots'] then + game.print(player.name .. ' has bought themselves some flame boots.', {r = 0.22, g = 0.77, b = 0.44}) + if not this.flame_boots[player.index].fuel then + this.flame_boots[player.index].fuel = math.random(1500, 3000) + else + this.flame_boots[player.index].fuel = this.flame_boots[player.index].fuel + math.random(1500, 3000) + end + + player.print('Fuel remaining: ' .. this.flame_boots[player.index].fuel, {r = 0.22, g = 0.77, b = 0.44}) + refresh_market_offers() + return + end + + if bought_offer.effect_description == special_descriptions['explosive-bullets'] then + game.print(player.name .. ' has unlocked explosive bullets.', {r = 0.22, g = 0.77, b = 0.44}) + this.explosive_bullets_unlocked = true + refresh_market_offers() + return + end + + if bought_offer.effect_description == special_descriptions['bouncy-shells'] then + game.print(player.name .. ' has unlocked bouncy shells.', {r = 0.22, g = 0.77, b = 0.44}) + this.bouncy_shells_unlocked = true + refresh_market_offers() + return + end + + if bought_offer.effect_description == special_descriptions['trapped-capsules'] then + game.print(player.name .. ' has unlocked trapped capsules!', {r = 0.22, g = 0.77, b = 0.44}) + this.trapped_capsules_unlocked = true + refresh_market_offers() + return + end + + if bought_offer.effect_description == special_descriptions['ultra-mines'] then + game.print(player.name .. ' has unlocked ultra mines!', {r = 0.22, g = 0.77, b = 0.44}) + this.ultra_mines_unlocked = true + refresh_market_offers() + return + end + + if bought_offer.effect_description == special_descriptions['laser-pointer'] then + game.print(player.name .. ' has unleashed the quest to slay the red dot!', {r = 0.22, g = 0.77, b = 0.44}) + this.laser_pointer_unlocked = true + refresh_market_offers() + return + end + + if bought_offer.effect_description == special_descriptions['railgun-enhancer'] then + game.print(player.name .. ' has unlocked the enhanced railgun!', {r = 0.22, g = 0.77, b = 0.44}) + this.railgun_enhancer_unlocked = true + refresh_market_offers() + return + end + + if bought_offer.effect_description == special_descriptions['crumbly-walls'] then + game.print(player.name .. ' has unlocked crumbly walls!', {r = 0.22, g = 0.77, b = 0.44}) + this.crumbly_walls_unlocked = true + refresh_market_offers() + return + end + + if bought_offer.effect_description == special_descriptions['vehicle-nanobots'] then + game.print(player.name .. ' has unlocked vehicle nanobots!', {r = 0.22, g = 0.77, b = 0.44}) + this.vehicle_nanobots_unlocked = true + refresh_market_offers() + return + end +end + +local function on_gui_opened(event) + if not event.entity then + return + end + if not event.entity.valid then + return + end + if event.entity.name == 'market' then + refresh_market_offers() + return + end +end + +Event.add(defines.events.on_market_item_purchased, on_market_item_purchased) +Event.add(defines.events.on_gui_opened, on_gui_opened) diff --git a/maps/fish_defender_v2/on_entity_damaged.lua b/maps/fish_defender_v2/on_entity_damaged.lua new file mode 100644 index 00000000..7f942107 --- /dev/null +++ b/maps/fish_defender_v2/on_entity_damaged.lua @@ -0,0 +1,65 @@ +require 'maps.fish_defender_v2.boss_biters' + +local Event = require 'utils.event' +local enhance_railgun = require 'maps.fish_defender_v2.railgun_enhancer' +local explosive_bullets = require 'maps.fish_defender_v2.explosive_gun_bullets' +local bouncy_shells = require 'maps.fish_defender_v2.bouncy_shells' +local FDT = require 'maps.fish_defender_v2.table' + +local function protect_market(event) + if event.entity.name ~= 'market' then + return + end + if event.cause then + if event.cause.force.name == 'enemy' then + return + end + end + event.entity.health = event.entity.health + event.final_damage_amount + return true +end + +local function on_entity_damaged(event) + if not event.entity then + return + end + if not event.entity.valid then + return + end + + if protect_market(event) then + return + end + + if not event.cause then + return + end + local explosive_bullets_unlocked = FDT.get('explosive_bullets_unlocked') + local bouncy_shells_unlocked = FDT.get('bouncy_shells_unlocked') + + --if event.cause.unit_number then + -- if this.boss_biters[event.cause.unit_number] then + -- boss_biter.damaged_entity(event) + -- end + --end + + if event.cause.name ~= 'character' then + return + end + + if enhance_railgun(event) then + return + end + if explosive_bullets_unlocked then + if explosive_bullets(event) then + return + end + end + if bouncy_shells_unlocked then + if bouncy_shells(event) then + return + end + end +end + +Event.add(defines.events.on_entity_damaged, on_entity_damaged) diff --git a/maps/fish_defender_v2/railgun_enhancer.lua b/maps/fish_defender_v2/railgun_enhancer.lua new file mode 100644 index 00000000..ae2dc8fb --- /dev/null +++ b/maps/fish_defender_v2/railgun_enhancer.lua @@ -0,0 +1,157 @@ +-- improves the damage of the railgun and adds visual effects -- by mewmew +-- laser turret research will increase it´s damage even further -- + +local FDT = require 'maps.fish_defender_v2.table' + +local damage_min = 400 +local damage_max = 800 +local math_random = math.random +local additional_visual_effects = true + +local biological_target_types = { + ['unit'] = true, + ['player'] = true, + ['turret'] = true, + ['unit-spawner'] = true +} + +local function create_visuals(source_entity, target_entity) + if not source_entity.valid then + return + end + if not target_entity.valid then + return + end + if not additional_visual_effects then + return + end + local surface = target_entity.surface + surface.create_entity({name = 'water-splash', position = target_entity.position}) + if biological_target_types[target_entity.type] then + surface.create_entity({name = 'blood-explosion-big', position = target_entity.position}) + for x = -8, 8, 1 do + for y = -8, 8, 1 do + if math_random(1, 16) == 1 then + surface.create_entity( + { + name = 'blood-fountain', + position = {target_entity.position.x + (x * 0.1), target_entity.position.y + (y * 0.1)} + } + ) + surface.create_entity( + { + name = 'blood-fountain-big', + position = {target_entity.position.x + (x * 0.1), target_entity.position.y + (y * 0.1)} + } + ) + end + end + end + else + if math_random(1, 3) ~= 1 then + surface.create_entity({name = 'fire-flame', position = target_entity.position}) + end + for x = -3, 3, 1 do + for y = -3, 3, 1 do + if math_random(1, 3) == 1 then + surface.create_trivial_smoke( + { + name = 'smoke-fast', + position = {target_entity.position.x + (x * 0.35), target_entity.position.y + (y * 0.35)} + } + ) + end + if math_random(1, 5) == 1 then + surface.create_trivial_smoke( + { + name = 'train-smoke', + position = {target_entity.position.x + (x * 0.35), target_entity.position.y + (y * 0.35)} + } + ) + end + end + end + end +end + +local function do_splash_damage_around_entity(source_entity, player) + if not source_entity.valid then + return + end + local research_damage_bonus = player.force.get_ammo_damage_modifier('laser-turret') + 1 + local research_splash_radius_bonus = player.force.get_ammo_damage_modifier('laser-turret') * 0.5 + local splash_area = { + { + source_entity.position.x - (2.5 + research_splash_radius_bonus), + source_entity.position.y - (2.5 + research_splash_radius_bonus) + }, + { + source_entity.position.x + (2.5 + research_splash_radius_bonus), + source_entity.position.y + (2.5 + research_splash_radius_bonus) + } + } + local entities = source_entity.surface.find_entities_filtered({area = splash_area}) + for _, entity in pairs(entities) do + if entity.valid then + if entity.health and entity ~= source_entity and entity ~= player then + if additional_visual_effects then + local surface = entity.surface + surface.create_entity( + { + name = 'railgun-beam', + position = source_entity.position, + source = source_entity.position, + target = entity.position + } + ) + surface.create_entity({name = 'water-splash', position = entity.position}) + if biological_target_types[entity.type] then + surface.create_entity({name = 'blood-fountain', position = entity.position}) + end + end + local damage = + math_random( + math.ceil((damage_min * research_damage_bonus) / 16), + math.ceil((damage_max * research_damage_bonus) / 16) + ) + entity.damage(damage, player.force, 'physical') + end + end + end +end + +local function enhance(event) + local railgun_enhancer_unlocked = FDT.get('railgun_enhancer_unlocked') + if not railgun_enhancer_unlocked then + return + end + if event.damage_type.name ~= 'physical' then + return + end + if event.original_damage_amount ~= 100 then + return + end + + local player = event.cause + if player.shooting_state.state == defines.shooting.not_shooting then + return + end + local selected_weapon = player.get_inventory(defines.inventory.character_guns)[player.selected_gun_index] + if selected_weapon.name ~= 'railgun' then + return + end + + create_visuals(event.cause, event.entity) + + do_splash_damage_around_entity(event.entity, player) + + event.entity.health = event.entity.health + event.final_damage_amount + + local research_damage_bonus = player.force.get_ammo_damage_modifier('laser-turret') + 1 + local damage = + math_random(math.ceil(damage_min * research_damage_bonus), math.ceil(damage_max * research_damage_bonus)) + event.entity.damage(damage, player.force, 'physical') + return true +end + +return enhance diff --git a/maps/fish_defender_v2/shotgun_buff.lua b/maps/fish_defender_v2/shotgun_buff.lua new file mode 100644 index 00000000..34f4378f --- /dev/null +++ b/maps/fish_defender_v2/shotgun_buff.lua @@ -0,0 +1,31 @@ +local Event = require 'utils.event' +local FDT = require 'maps.fish_defender_v2.table' +local gain_multiplier = 4 + +local function on_research_finished(event) + local research = event.research + local force_name = research.force.name + local this = FDT.get() + + if not this.shotgun_shell_damage_modifier_old[force_name] then + this.shotgun_shell_damage_modifier_old[force_name] = + game.forces[force_name].get_ammo_damage_modifier('shotgun-shell') - 0.1 + end + + if string.sub(research.name, 0, 26) == 'physical-projectile-damage' then + local current_damage = game.forces[force_name].get_ammo_damage_modifier('shotgun-shell') + local vanilla_gain = current_damage - this.shotgun_shell_damage_modifier_old[force_name] + local additional_gain = vanilla_gain * (gain_multiplier - 1) + game.forces[force_name].set_ammo_damage_modifier('shotgun-shell', current_damage + additional_gain) + end + + this.shotgun_shell_damage_modifier_old[force_name] = + game.forces[force_name].get_ammo_damage_modifier('shotgun-shell') +end + +local function on_init() + game.forces.player.set_ammo_damage_modifier('shotgun-shell', 1) +end + +Event.on_init(on_init) +Event.add(defines.events.on_research_finished, on_research_finished) diff --git a/maps/fish_defender_v2/table.lua b/maps/fish_defender_v2/table.lua new file mode 100644 index 00000000..7ae96d72 --- /dev/null +++ b/maps/fish_defender_v2/table.lua @@ -0,0 +1,103 @@ +-- one table to rule them all! +local Global = require 'utils.global' +local Event = require 'utils.event' + +local this = {} +local Public = {} + +Global.register( + this, + function(tbl) + this = tbl + end +) + +function Public.reset_table() + -- @start + -- these 3 are in case of stop/start/reloading the instance. + this.soft_reset = true + this.restart = false + this.shutdown = false + this.announced_message = false + this.force_chunk = false + -- @end + this.game_has_ended = false + this.game_reset = false + this.spawn_area_generated = false + this.results_sent = false + + this.explosive_bullets_unlocked = false + this.bouncy_shells_unlocked = false + this.trapped_capsules_unlocked = false + this.ultra_mines_unlocked = false + this.laser_pointer_unlocked = false + this.railgun_enhancer_unlocked = false + this.crumbly_walls_unlocked = false + this.vehicle_nanobots_unlocked = false + this.game_restart_timer = nil + this.wave_count = 0 + this.attack_wave_threat = nil + this.market = nil + this.market_age = nil + this.last_reset = game.tick + this.wave_interval = 3600 + this.wave_grace_period = game.tick + 3600 * 20 + -- this.wave_grace_period = game.tick + 3600 + this.boss_biters = {} + this.acid_lines_delay = {} + this.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 = 20} + } + this.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} + } + this.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}} + } + this.comfylatron_habitat = { + left_top = {x = -1500, y = -1500}, + right_bottom = {x = -80, y = 1500} + } + this.map_height = 96 + this.shotgun_shell_damage_modifier_old = {} + this.flame_boots = {} +end + +function Public.get(key) + if key then + return this[key] + else + return this + end +end + +local on_init = function() + Public.reset_table() +end + +Event.on_init(on_init) + +return Public diff --git a/maps/fish_defender_v2/terrain.lua b/maps/fish_defender_v2/terrain.lua new file mode 100644 index 00000000..f6ec8857 --- /dev/null +++ b/maps/fish_defender_v2/terrain.lua @@ -0,0 +1,578 @@ +local Event = require 'utils.event' +local map_functions = require 'tools.map_functions' +local simplex_noise = require 'utils.simplex_noise'.d2 +local FDT = require 'maps.fish_defender_v2.table' +local Task = require 'utils.task' +local Token = require 'utils.token' +local math_random = math.random +local math_abs = math.abs +local math_floor = math.floor +local math_sqrt = math.sqrt +local tiles_per_call = 16 +local total_calls = math.ceil(1024 / tiles_per_call) + +local Public = {} + +local rock_raffle = { + 'sand-rock-big', + 'sand-rock-big', + 'rock-big', + 'rock-big', + 'rock-big', + 'rock-big', + 'rock-big', + 'rock-big', + 'rock-huge' +} + +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 get_replacement_tile(surface, position) + for i = 1, 128, 1 do + local vectors = {{0, i}, {0, i * -1}, {i, 0}, {i * -1, 0}} + shuffle(vectors) + for k, v in pairs(vectors) do + local tile = surface.get_tile(position.x + v[1], position.y + v[2]) + if not tile.collides_with('resource-layer') then + return tile.name + end + end + end + return 'grass-1' +end + +local function is_enemy_territory(p) + if p.x - 64 < math_abs(p.y) then + return false + end + --if p.x - 64 < p.y then return false end + if p.x < 160 then + return false + end + if p.x > 1024 then + return false + end + if p.y > 512 then + return false + end + if p.y < -512 then + return false + end + local noise = math_abs(simplex_noise(0, p.y * 0.015, game.surfaces[1].map_gen_settings.seed) * 96) + local noise_2 = math_abs(simplex_noise(0, p.y * 0.1, game.surfaces[1].map_gen_settings.seed) * 16) + if p.x > 288 + noise + noise_2 + math_abs(p.y * 0.75) then + return false + end + return true +end + +local body_radius = 3072 +local body_square_radius = body_radius ^ 2 +local body_center_position = {x = -1500, y = 0} +local body_spacing = math_floor(body_radius * 0.82) +local body_circle_center_1 = {x = body_center_position.x, y = body_center_position.y - body_spacing} +local body_circle_center_2 = {x = body_center_position.x, y = body_center_position.y + body_spacing} + +local fin_radius = 800 +local square_fin_radius = fin_radius ^ 2 +local fin_circle_center_1 = {x = -480, y = 0} +local fin_circle_center_2 = {x = -480 - 360, y = 0} + +local function is_body(p) + local this = FDT.get() + if p.y <= this.map_height and p.y >= this.map_height * -1 and p.x <= 160 and p.x > body_center_position.x then + return true + end + + --Main Fish Body + local distance_to_center_1 = ((p.x - body_circle_center_1.x) ^ 2 + (p.y - body_circle_center_1.y) ^ 2) + local distance_to_center_2 = ((p.x - body_circle_center_2.x) ^ 2 + (p.y - body_circle_center_2.y) ^ 2) + --if distance_to_center_1 < body_square_radius and distance_to_center_2 < body_square_radius then return true end + if distance_to_center_1 < body_square_radius then + if distance_to_center_2 < body_square_radius then + return true + end + end + + --Fish Fins + distance_to_center_1 = ((p.x - fin_circle_center_1.x) ^ 2 + (p.y - fin_circle_center_1.y) ^ 2) + if + distance_to_center_1 + math_abs(simplex_noise(0, p.y * 0.075, game.surfaces[1].map_gen_settings.seed) * 32000) > + square_fin_radius + then + distance_to_center_2 = ((p.x - fin_circle_center_2.x) ^ 2 + (p.y - fin_circle_center_2.y) ^ 2) + if distance_to_center_2 < square_fin_radius then + return true + end + end + + return false +end + +local function is_out_of_map_tile(p) + if p.y > 850 then + return true + end + if p.y < -850 then + return true + end + if p.x < -3264 then + return true + end + if p.x > 800 then + return true + end + if is_enemy_territory(p) then + return false + end + if is_body(p) then + return false + end + return true +end + +local function place_fish_market(surface, position) + local market = surface.create_entity({name = 'market', position = position, force = 'player'}) + market.minable = false + return market +end + +local function enemy_territory(surface, left_top) + if left_top.x < 160 then + return + end + if left_top.x > 750 then + return + end + if left_top.y > 512 then + return + end + if left_top.y < -512 then + return + end + + local area = {{left_top.x, left_top.y}, {left_top.x + 32, left_top.y + 32}} + + if left_top.x > 256 then + for x = 0, 31, 1 do + for y = 0, 31, 1 do + local pos = {x = left_top.x + x, y = left_top.y + y} + if is_enemy_territory(pos) then + if math_random(1, 512) == 1 then + if surface.can_place_entity({name = 'biter-spawner', force = 'decoratives', position = pos}) then + local entity + if math_random(1, 4) == 1 then + entity = + surface.create_entity( + {name = 'spitter-spawner', force = 'decoratives', position = pos} + ) + else + entity = + surface.create_entity( + {name = 'biter-spawner', force = 'decoratives', position = pos} + ) + end + entity.active = false + entity.destructible = false + end + end + end + end + end + end + for _, entity in pairs(surface.find_entities_filtered({area = area, type = {'tree', 'cliff'}})) do + if is_enemy_territory(entity.position) then + entity.destroy() + end + end + for _, entity in pairs(surface.find_entities_filtered({area = area, type = 'resource'})) do + if is_enemy_territory(entity.position) then + surface.create_entity({name = 'uranium-ore', position = entity.position, amount = math_random(200, 8000)}) + entity.destroy() + end + end + for _, tile in pairs(surface.find_tiles_filtered({name = {'water', 'deepwater'}, area = area})) do + if is_enemy_territory(tile.position) then + surface.set_tiles( + {{name = get_replacement_tile(surface, tile.position), position = {tile.position.x, tile.position.y}}}, + true + ) + end + end +end + +local function fish_mouth(surface, left_top) + if left_top.x > -2300 then + return + end + if left_top.y > 64 then + return + end + if left_top.y < -64 then + return + end + if left_top.x < -3292 then + return + end + + for x = 0, 31, 1 do + for y = 0, 31, 1 do + local pos = {x = left_top.x + x, y = left_top.y + y} + local noise = simplex_noise(pos.x * 0.006, 0, game.surfaces[1].map_gen_settings.seed) * 20 + if pos.y <= 12 + noise and pos.y >= -12 + noise then + surface.set_tiles({{name = 'water', position = pos}}) + end + end + end +end + +local ores = {'coal', 'iron-ore', 'copper-ore', 'stone'} + +local function plankton_territory(surface, position, seed) + local noise = simplex_noise(position.x * 0.009, position.y * 0.009, seed) + local d = 196 + if + position.x + position.y > (d * -1) - (math_abs(noise) * d * 3) and + position.x > position.y - (d + (math_abs(noise) * d * 3)) + then + return 'out-of-map' + end + + local noise_2 = simplex_noise(position.x * 0.0075, position.y * 0.0075, seed + 10000) + --if noise_2 > 0.87 then surface.set_tiles({{name = "deepwater-green", position = position}}, true) return true end + if noise_2 > 0.87 then + return 'deepwater-green' + end + if noise_2 > 0.75 then + local i = math_floor(noise * 6) % 4 + 1 + --surface.set_tiles({{name = "grass-" .. i, position = position}}, true) + surface.create_entity({name = ores[i], position = position, amount = 1 + 2500 * math_abs(noise_2 * 3)}) + return ('grass-' .. i) + end + if noise_2 < -0.76 then + local i = math_floor(noise * 6) % 4 + 1 + --surface.set_tiles({{name = "grass-" .. i, position = position}}, true) + if noise_2 < -0.86 then + surface.create_entity( + {name = 'uranium-ore', position = position, amount = 1 + 1000 * math_abs(noise_2 * 2)} + ) + return ('grass-' .. i) + end + if math_random(1, 3) ~= 1 then + surface.create_entity({name = rock_raffle[math_random(1, #rock_raffle)], position = position}) + end + return ('grass-' .. i) + end + + if noise < 0.12 and noise > -0.12 then + local i = math_floor(noise * 32) % 4 + 1 + --surface.set_tiles({{name = "grass-" .. i, position = position}}, true) + if math_random(1, 5) == 1 then + surface.create_entity({name = rock_raffle[math_random(1, #rock_raffle)], position = position}) + end + return ('grass-' .. i) + end + + --surface.set_tiles({{name = "water", position = position}}, true) + if math_random(1, 128) == 1 then + surface.create_entity({name = 'fish', position = position}) + end + + return 'water' +end + +local function render_market_hp() + local this = FDT.get() + local surface = game.surfaces[this.active_surface_index] + if not surface or not surface.valid then + return + end + + this.health_text = + rendering.draw_text { + text = 'HP: ' .. this.market_health .. ' / ' .. this.market_max_health, + surface = surface, + target = this.market, + target_offset = {0, -3}, + color = {0, 255, 0}, + scale = 1.40, + font = 'default-game', + alignment = 'center', + scale_with_zoom = false + } + + this.caption = + rendering.draw_text { + text = 'Fish Market', + surface = surface, + target = this.market, + target_offset = {0, -4.4}, + color = {0, 255, 0}, + scale = 1.80, + font = 'default-game', + alignment = 'center', + scale_with_zoom = false + } +end + +local function generate_spawn_area(this, surface) + if this.spawn_area_generated then + return + end + + surface.request_to_generate_chunks({x = 0, y = 0}, 7) + surface.request_to_generate_chunks({x = 160, y = 0}, 4) + --surface.force_generate_chunk_requests() + + if not surface.is_chunk_generated({-7, 0}) then + return + end + if not surface.is_chunk_generated({5, 0}) then + return + end + + local spawn_position_x = -128 + + surface.create_entity({name = 'electric-beam', position = {160, -96}, source = {160, -96}, target = {160, 96}}) + + for _, tile in pairs( + surface.find_tiles_filtered({name = {'water', 'deepwater'}, area = {{-160, -160}, {160, 160}}}) + ) do + local noise = + math_abs( + simplex_noise(tile.position.x * 0.02, tile.position.y * 0.02, game.surfaces[1].map_gen_settings.seed) * 16 + ) + if tile.position.x > -160 + noise then + surface.set_tiles( + {{name = get_replacement_tile(surface, tile.position), position = {tile.position.x, tile.position.y}}}, + true + ) + end + end + + for _, entity in pairs( + surface.find_entities_filtered( + {type = {'resource', 'cliff'}, area = {{spawn_position_x - 32, -256}, {160, 256}}} + ) + ) do + if is_body(entity.position) then + if + entity.position.x > + spawn_position_x - 32 + + math_abs( + simplex_noise( + entity.position.x * 0.02, + entity.position.y * 0.02, + game.surfaces[1].map_gen_settings.seed + ) * 16 + ) + then + entity.destroy() + end + end + end + + 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 + + local y = 80 + local ore_positions = { + {x = spawn_position_x - 52, y = y}, + {x = spawn_position_x - 52, y = y * 0.5}, + {x = spawn_position_x - 52, y = 0}, + {x = spawn_position_x - 52, y = y * -0.5}, + {x = spawn_position_x - 52, y = y * -1} + } + shuffle(ore_positions) + map_functions.draw_smoothed_out_ore_circle(ore_positions[1], 'copper-ore', surface, 15, 2500) + map_functions.draw_smoothed_out_ore_circle(ore_positions[2], 'iron-ore', surface, 15, 2500) + map_functions.draw_smoothed_out_ore_circle(ore_positions[3], 'coal', surface, 15, 1500) + map_functions.draw_smoothed_out_ore_circle(ore_positions[4], 'stone', surface, 15, 1500) + map_functions.draw_noise_tile_circle({x = spawn_position_x - 20, y = 0}, 'water', surface, 16) + map_functions.draw_oil_circle(ore_positions[5], 'crude-oil', surface, 8, 200000) + + local pos = surface.find_non_colliding_position('market', {spawn_position_x, 0}, 50, 1) + this.market = place_fish_market(surface, pos) + + render_market_hp() + + local r = 16 + for _, entity in pairs( + surface.find_entities_filtered( + { + area = { + {this.market.position.x - r, this.market.position.y - r}, + {this.market.position.x + r, this.market.position.y + r} + }, + type = 'tree' + } + ) + ) do + local distance_to_center = + math_sqrt( + (entity.position.x - this.market.position.x) ^ 2 + (entity.position.y - this.market.position.y) ^ 2 + ) + if distance_to_center < r then + if math_random(1, r) > distance_to_center then + entity.destroy() + end + end + end + + local pos = surface.find_non_colliding_position('gun-turret', {spawn_position_x + 5, 1}, 50, 1) + local turret = surface.create_entity({name = 'gun-turret', position = pos, force = 'player'}) + turret.insert({name = 'firearm-magazine', count = 32}) + + for x = -20, 20, 1 do + for y = -20, 20, 1 do + local pos = {x = this.market.position.x + x, y = this.market.position.y + y} + --local distance_to_center = math_sqrt(x^2 + y^2) + --if distance_to_center > 8 and distance_to_center < 15 then + local distance_to_center = x ^ 2 + y ^ 2 + if distance_to_center > 64 and distance_to_center < 225 then + if + math_random(1, 3) == 1 and + surface.can_place_entity({name = 'wooden-chest', position = pos, force = 'player'}) + then + surface.create_entity({name = 'wooden-chest', position = pos, force = 'player'}) + end + end + end + end + + local area = {{x = -160, y = -96}, {x = 160, y = 96}} + for _, tile in pairs(surface.find_tiles_filtered({name = 'water', area = area})) do + if math_random(1, 32) == 1 then + surface.create_entity({name = 'fish', position = tile.position}) + end + end + + local pos = surface.find_non_colliding_position('character', {spawn_position_x + 1, 4}, 50, 1) + game.forces['player'].set_spawn_position(pos, surface) + for _, player in pairs(game.connected_players) do + local pos = surface.find_non_colliding_position('character', {spawn_position_x + 1, 4}, 50, 1) + player.teleport(pos, surface) + end + this.spawn_area_generated = true +end + +local function process_chunk(left_top) + local this = FDT.get() + local surface = game.surfaces[this.active_surface_index] + if not surface or not surface.valid then + return + end + + local seed = game.surfaces[1].map_gen_settings.seed + + generate_spawn_area(this, surface, left_top) + enemy_territory(surface, left_top) + fish_mouth(surface, left_top) + + local tiles = {} + + for x = 0, 31, 1 do + for y = 0, 31, 1 do + local pos = {x = left_top.x + x, y = left_top.y + y} + if is_out_of_map_tile(pos) then + --if not plankton_territory(surface, pos, seed) then surface.set_tiles({{name = "out-of-map", position = pos}}, true) end + local tile_to_set = plankton_territory(surface, pos, seed) + --local tile_to_set = "out-of-map" + tiles[#tiles + 1] = {name = tile_to_set, position = pos} + end + end + end + + surface.set_tiles(tiles, true) + + --if game.tick == 0 then return end + --if game.forces.player.is_chunk_charted(surface, {left_top.x / 32, left_top.y / 32}) then + game.forces.player.chart(surface, {{left_top.x, left_top.y}, {left_top.x + 31, left_top.y + 31}}) + --end + if this.market and this.market.valid then + this.game_reset = false + end +end + +local process_chunk_queue = + Token.register( + function(data) + local chunk_queue = data.chunk_queue + + for i = 1, #chunk_queue do + local pos = {x = chunk_queue[i].x, y = chunk_queue[i].y} + process_chunk(pos) + chunk_queue[i] = nil + end + end +) + +local function on_chunk_generated(event) + local map_name = 'fish_defender' + + if string.sub(event.surface.name, 0, #map_name) ~= map_name then + return + end + local left_top = event.area.left_top + local this = FDT.get() + if this.game_has_ended then + return + end + + if game.tick == 0 or this.game_reset or this.force_chunk then + process_chunk(left_top) + else + global.chunk_queue[#global.chunk_queue + 1] = {x = left_top.x, y = left_top.y} + + local data = { + chunk_queue = global.chunk_queue + } + Task.set_timeout_in_ticks(total_calls, process_chunk_queue, data) + end +end + +function Public.fish_eye(surface, position) + surface.request_to_generate_chunks(position, 2) + surface.force_generate_chunk_requests() + for x = -48, 48, 1 do + for y = -48, 48, 1 do + local p = {x = position.x + x, y = position.y + y} + --local distance = math_sqrt(((position.x - p.x) ^ 2) + ((position.y - p.y) ^ 2)) + --if distance < 44 then + -- surface.set_tiles({{name = "water-green", position = p}}, true) + --end + --if distance < 22 then + -- surface.set_tiles({{name = "out-of-map", position = p}}, true) + --end + + local distance = ((position.x - p.x) ^ 2) + ((position.y - p.y) ^ 2) + if distance < 1936 then + if distance < 484 then + surface.set_tiles({{name = 'out-of-map', position = p}}, true) + else + surface.set_tiles({{name = 'water-green', position = p}}, true) + end + end + end + end +end + +Event.add(defines.events.on_chunk_generated, on_chunk_generated) + +return Public diff --git a/maps/fish_defender_v2/trapped_capsules.lua b/maps/fish_defender_v2/trapped_capsules.lua new file mode 100644 index 00000000..a091e33d --- /dev/null +++ b/maps/fish_defender_v2/trapped_capsules.lua @@ -0,0 +1,61 @@ +local Event = require 'utils.event' +local FDT = require 'maps.fish_defender_v2.table' + +local radius = 20 + +local whitelist = { + ['defender'] = 'explosive-cannon-projectile', + ['distractor'] = 'explosive-uranium-cannon-projectile', + ['destroyer'] = 'explosive-uranium-cannon-projectile' +} + +local function on_entity_died(event) + local trapped_capsules_unlocked = FDT.get('trapped_capsules_unlocked') + if not trapped_capsules_unlocked then + return + end + + if not event.entity.valid then + return + end + if not whitelist[event.entity.name] then + return + end + + local valid_targets = {} + local position = event.entity.position + + for _, e in pairs( + event.entity.surface.find_entities_filtered( + { + area = {{position.x - radius, position.y - radius}, {position.x + radius, position.y + radius}}, + force = 'enemy' + } + ) + ) do + if e.health then + local distance_from_center = math.sqrt((e.position.x - position.x) ^ 2 + (e.position.y - position.y) ^ 2) + if distance_from_center <= radius then + valid_targets[#valid_targets + 1] = e + end + end + end + + if not valid_targets[1] then + return + end + + event.entity.surface.create_entity( + { + name = whitelist[event.entity.name], + position = position, + force = 'player', + source = position, + target = valid_targets[math.random(1, #valid_targets)].position, + max_range = 20, + speed = 0.1 + } + ) +end + +Event.add(defines.events.on_entity_died, on_entity_died) diff --git a/maps/fish_defender_v2/ultra_mines.lua b/maps/fish_defender_v2/ultra_mines.lua new file mode 100644 index 00000000..4da512e8 --- /dev/null +++ b/maps/fish_defender_v2/ultra_mines.lua @@ -0,0 +1,52 @@ +local Event = require 'utils.event' +local FDT = require 'maps.fish_defender_v2.table' +local radius = 8 + +local function damage_entities_around_target(entity, damage) + for _, e in pairs( + entity.surface.find_entities_filtered( + { + area = { + {entity.position.x - radius, entity.position.y - radius}, + {entity.position.x + radius, entity.position.y + radius} + } + } + ) + ) do + if e.health then + if e.force.name ~= 'player' then + local distance_from_center = + math.sqrt((e.position.x - entity.position.x) ^ 2 + (e.position.y - entity.position.y) ^ 2) + if distance_from_center <= radius then + e.damage(damage, 'player', 'explosion') + end + end + end + end +end + +local function on_entity_died(event) + local ultra_mines_unlocked = FDT.get('ultra_mines_unlocked') + if not ultra_mines_unlocked then + return + end + if not event.entity.valid then + return + end + if event.entity.name ~= 'land-mine' then + return + end + + event.entity.surface.create_entity( + { + name = 'big-artillery-explosion', + position = event.entity.position + } + ) + + local damage = (1 + event.entity.force.get_ammo_damage_modifier('grenade')) * 250 + + damage_entities_around_target(event.entity, damage) +end + +Event.add(defines.events.on_entity_died, on_entity_died) diff --git a/maps/fish_defender_v2/vehicle_nanobots.lua b/maps/fish_defender_v2/vehicle_nanobots.lua new file mode 100644 index 00000000..0d0ac852 --- /dev/null +++ b/maps/fish_defender_v2/vehicle_nanobots.lua @@ -0,0 +1,29 @@ +local Event = require 'utils.event' +local FDT = require 'maps.fish_defender_v2.table' + +local function on_player_changed_position(event) + local vehicle_nanobots_unlocked = FDT.get('vehicle_nanobots_unlocked') + + if not vehicle_nanobots_unlocked then + return + end + local player = game.players[event.player_index] + if not player.character then + return + end + if not player.character.driving then + return + end + if not player.vehicle then + return + end + if not player.vehicle.valid then + return + end + if player.vehicle.health == player.vehicle.prototype.max_health then + return + end + player.vehicle.health = player.vehicle.health + player.vehicle.prototype.max_health * 0.005 +end + +Event.add(defines.events.on_player_changed_position, on_player_changed_position) From a5061c02baf01d1c3c903b35a8ce2abfb4fed988 Mon Sep 17 00:00:00 2001 From: Gerkiz Date: Sun, 12 Jul 2020 20:57:41 +0200 Subject: [PATCH 4/6] revert fish_defender to old version --- maps/fish_defender/boss_biters.lua | 136 ++- maps/fish_defender/bouncy_shells.lua | 105 +-- maps/fish_defender/commands.lua | 148 --- maps/fish_defender/crumbly_walls.lua | 30 +- maps/fish_defender/explosive_gun_bullets.lua | 60 +- maps/fish_defender/flame_boots.lua | 84 +- maps/fish_defender/laser_pointer.lua | 56 +- maps/fish_defender/main.lua | 903 +++++++------------ maps/fish_defender/market.lua | 554 +++++------- maps/fish_defender/on_entity_damaged.lua | 85 +- maps/fish_defender/railgun_enhancer.lua | 215 ++--- maps/fish_defender/shotgun_buff.lua | 43 +- maps/fish_defender/table.lua | 103 --- maps/fish_defender/terrain.lua | 855 +++++++----------- maps/fish_defender/trapped_capsules.lua | 87 +- maps/fish_defender/ultra_mines.lua | 70 +- maps/fish_defender/vehicle_nanobots.lua | 5 +- 17 files changed, 1305 insertions(+), 2234 deletions(-) delete mode 100644 maps/fish_defender/commands.lua delete mode 100644 maps/fish_defender/table.lua diff --git a/maps/fish_defender/boss_biters.lua b/maps/fish_defender/boss_biters.lua index 7fc28437..7364d727 100644 --- a/maps/fish_defender/boss_biters.lua +++ b/maps/fish_defender/boss_biters.lua @@ -1,99 +1,83 @@ -local FDT = require 'maps.fish_defender.table' - local boss_biter = {} local math_random = math.random local radius = 6 local targets = {} local acid_splashes = { - ['big-biter'] = 'acid-stream-worm-medium', - ['behemoth-biter'] = 'acid-stream-worm-big', - ['big-spitter'] = 'acid-stream-worm-medium', - ['behemoth-spitter'] = 'acid-stream-worm-big' + ["big-biter"] = "acid-stream-worm-medium", + ["behemoth-biter"] = "acid-stream-worm-big", + ["big-spitter"] = "acid-stream-worm-medium", + ["behemoth-spitter"] = "acid-stream-worm-big" } local acid_lines = { - ['big-spitter'] = 'acid-stream-spitter-medium', - ['behemoth-spitter'] = 'acid-stream-spitter-big' + ["big-spitter"] = "acid-stream-spitter-medium", + ["behemoth-spitter"] = "acid-stream-spitter-big" } for x = radius * -1, radius, 1 do - for y = radius * -1, radius, 1 do - if math.sqrt(x ^ 2 + y ^ 2) <= radius then - targets[#targets + 1] = {x = x, y = y} - end - end + for y = radius * -1, radius, 1 do + if math.sqrt(x^2 + y^2) <= radius then + targets[#targets + 1] = {x = x, y = y} + end + end end local function acid_nova(event) - for _ = 1, math.random(16, 32) do - local i = math.random(1, #targets) - event.entity.surface.create_entity( - { - name = acid_splashes[event.entity.name], - position = event.entity.position, - force = event.entity.force.name, - source = event.entity.position, - target = {x = event.entity.position.x + targets[i].x, y = event.entity.position.y + targets[i].y}, - max_range = radius, - speed = 0.001 - } - ) - end + for _ = 1, math.random(16, 32) do + local i = math.random(1, #targets) + event.entity.surface.create_entity({ + name = acid_splashes[event.entity.name], + position = event.entity.position, + force = event.entity.force.name, + source = event.entity.position, + target = {x = event.entity.position.x + targets[i].x, y = event.entity.position.y + targets[i].y}, + max_range = radius, + speed = 0.001 + }) + end end boss_biter.died = function(event) - local this = FDT.get() - if acid_splashes[event.entity.name] then - acid_nova(event) - end - if this.acid_lines_delay[event.entity.unit_number] then - this.acid_lines_delay[event.entity.unit_number] = nil - end - this.boss_biters[event.entity.unit_number] = nil + if acid_splashes[event.entity.name] then acid_nova(event) end + if global.acid_lines_delay[event.entity.unit_number] then global.acid_lines_delay[event.entity.unit_number] = nil end + global.boss_biters[event.entity.unit_number] = nil end local function acid_line(surface, name, source, target) - local distance = math.sqrt((source.x - target.x) ^ 2 + (source.y - target.y) ^ 2) - - if distance > 16 then - return false - end - - local modifier = {(target.x - source.x) / distance, (target.y - source.y) / distance} - - local position = {source.x, source.y} - - for i = 1, distance + 4, 1 do - if math_random(1, 3) == 1 then - surface.create_entity( - { - name = name, - position = source, - force = 'enemy', - source = source, - target = position, - max_range = 25, - speed = 1 - } - ) - end - position = {position[1] + modifier[1], position[2] + modifier[2]} - end - - return true + local distance = math.sqrt((source.x - target.x) ^ 2 + (source.y - target.y) ^ 2) + + if distance > 16 then return false end + + local modifier = {(target.x - source.x) / distance, (target.y - source.y) / distance} + + local position = {source.x, source.y} + + for i = 1, distance + 4, 1 do + if math_random(1,3) == 1 then + surface.create_entity({ + name = name, + position = source, + force = "enemy", + source = source, + target = position, + max_range = 25, + speed = 1 + }) + end + position = {position[1] + modifier[1], position[2] + modifier[2]} + end + + return true end boss_biter.damaged_entity = function(event) - if acid_lines[event.cause.name] then - local this = FDT.get() - if not this.acid_lines_delay[event.cause.unit_number] then - this.acid_lines_delay[event.cause.unit_number] = 0 - end - - if this.acid_lines_delay[event.cause.unit_number] < game.tick then - if acid_line(event.cause.surface, acid_lines[event.cause.name], event.cause.position, event.entity.position) then - this.acid_lines_delay[event.cause.unit_number] = game.tick + 180 - end - end - end + if acid_lines[event.cause.name] then + if not global.acid_lines_delay[event.cause.unit_number] then global.acid_lines_delay[event.cause.unit_number] = 0 end + + if global.acid_lines_delay[event.cause.unit_number] < game.tick then + if acid_line(event.cause.surface, acid_lines[event.cause.name], event.cause.position, event.entity.position) then + global.acid_lines_delay[event.cause.unit_number] = game.tick + 180 + end + end + end end -return boss_biter +return boss_biter \ No newline at end of file diff --git a/maps/fish_defender/bouncy_shells.lua b/maps/fish_defender/bouncy_shells.lua index 76eb4d54..53ad988a 100644 --- a/maps/fish_defender/bouncy_shells.lua +++ b/maps/fish_defender/bouncy_shells.lua @@ -1,76 +1,63 @@ local radius = 9 local math_random = math.random +local math_sqrt = math.sqrt local ammo_to_projectile_translation = { - ['shotgun-shell'] = 'shotgun-pellet', - ['piercing-shotgun-shell'] = 'piercing-shotgun-pellet' + ["shotgun-shell"] = "shotgun-pellet", + ["piercing-shotgun-shell"] = "piercing-shotgun-pellet" } local function create_projectile(surface, position, target, name) - surface.create_entity( - { - name = name, - position = position, - force = 'player', - source = position, - target = target, - max_range = 16, - speed = 0.3 - } - ) + surface.create_entity({ + name = name, + position = position, + force = force, + source = position, + target = target, + max_range = 16, + speed = 0.3 + }) end local function bounce(surface, position, ammo) - if math_random(1, 3) ~= 1 then - return - end - local valid_entities = {} - for _, e in pairs( - surface.find_entities_filtered( - {area = {{position.x - radius, position.y - radius}, {position.x + radius, position.y + radius}}} - ) - ) do - if e.health then - if e.force.name ~= 'player' then - --local distance_from_center = math_sqrt((e.position.x - position.x) ^ 2 + (e.position.y - position.y) ^ 2) - --if distance_from_center <= radius then - valid_entities[#valid_entities + 1] = e - --end - end - end - end + if math_random(1,3) ~= 1 then return end + local valid_entities = {} + for _, e in pairs(surface.find_entities_filtered({area = {{position.x - radius, position.y - radius},{position.x + radius, position.y + radius}}})) do + if e.health then + if e.force.name ~= "player" then + --local distance_from_center = math_sqrt((e.position.x - position.x) ^ 2 + (e.position.y - position.y) ^ 2) + --if distance_from_center <= radius then + valid_entities[#valid_entities + 1] = e + --end + end + end + end + + if not valid_entities[1] then return end - if not valid_entities[1] then - return - end - - for _ = 1, math_random(3, 6), 1 do - create_projectile(surface, position, valid_entities[math_random(1, #valid_entities)].position, ammo) - end + for c = 1, math_random(3,6), 1 do + create_projectile(surface, position, valid_entities[math_random(1, #valid_entities)].position, ammo) + end end local function bouncy_shells(event) - if event.damage_type.name ~= 'physical' then - return false - end - local player = event.cause - if player.shooting_state.state == defines.shooting.not_shooting then - return false - end - local selected_weapon = player.get_inventory(defines.inventory.character_guns)[player.selected_gun_index] - if selected_weapon.name ~= 'combat-shotgun' and selected_weapon.name ~= 'shotgun' then - return false - end - - local selected_ammo = player.get_inventory(defines.inventory.character_ammo)[player.selected_gun_index] - if not selected_ammo then - return - end - if not ammo_to_projectile_translation[selected_ammo.name] then - return - end - - bounce(player.surface, event.entity.position, ammo_to_projectile_translation[selected_ammo.name]) + if event.damage_type.name ~= "physical" then return false end + local player = event.cause + if player.shooting_state.state == defines.shooting.not_shooting then return false end + local selected_weapon = player.get_inventory(defines.inventory.character_guns)[player.selected_gun_index] + if selected_weapon.name ~= "combat-shotgun" and selected_weapon.name ~= "shotgun" then return false end + + local selected_ammo = player.get_inventory(defines.inventory.character_ammo)[player.selected_gun_index] + if not selected_ammo then return end + if not ammo_to_projectile_translation[selected_ammo.name] then return end + + bounce( + player.surface, + event.entity.position, + ammo_to_projectile_translation[selected_ammo.name] + ) end return bouncy_shells + + diff --git a/maps/fish_defender/commands.lua b/maps/fish_defender/commands.lua deleted file mode 100644 index ad4dce2d..00000000 --- a/maps/fish_defender/commands.lua +++ /dev/null @@ -1,148 +0,0 @@ -local Server = require 'utils.server' -local FDT = require 'maps.fish_defender.table' -local Task = require 'utils.task' - -local mapkeeper = '[color=blue]Mapkeeper:[/color]' - -commands.add_command( - 'fishy_commands', - 'Usable only for admins - controls the scenario!', - function(cmd) - local p - local player = game.player - - if not player or not player.valid then - p = log - else - p = player.print - if not player.admin then - return - end - end - - local param = cmd.parameter - - if param == 'restart' or param == 'shutdown' or param == 'reset' or param == 'restartnow' then - goto continue - else - p('[ERROR] Arguments are:\nrestart\nshutdown\nreset\nrestartnow') - return - end - - ::continue:: - - local this = FDT.get() - local reset_map = require 'maps.fish_defender.main'.reset_game - - if not this.reset_are_you_sure then - this.reset_are_you_sure = true - p( - '[WARNING] This command will disable the soft-reset feature, run this command again if you really want to do this!' - ) - return - end - - if param == 'restart' then - if this.restart then - this.reset_are_you_sure = nil - this.restart = false - this.soft_reset = true - p('[SUCCESS] Soft-reset is enabled.') - return - else - this.reset_are_you_sure = nil - this.restart = true - this.soft_reset = false - if this.shutdown then - this.shutdown = false - end - p('[WARNING] Soft-reset is disabled! Server will restart from scenario.') - return - end - elseif param == 'restartnow' then - this.reset_are_you_sure = nil - p(player.name .. ' has restarted the game.') - Server.start_scenario('Fish_Defender') - return - elseif param == 'shutdown' then - if this.shutdown then - this.reset_are_you_sure = nil - this.shutdown = false - this.soft_reset = true - p('[SUCCESS] Soft-reset is enabled.') - return - else - this.reset_are_you_sure = nil - this.shutdown = true - this.soft_reset = false - if this.restart then - this.restart = false - end - p('[WARNING] Soft-reset is disabled! Server will shutdown.') - return - end - elseif param == 'reset' then - this.reset_are_you_sure = nil - if player and player.valid then - game.print(mapkeeper .. ' ' .. player.name .. ', has reset the game!', {r = 0.98, g = 0.66, b = 0.22}) - else - game.print(mapkeeper .. ' server, has reset the game!', {r = 0.98, g = 0.66, b = 0.22}) - end - reset_map() - p('[WARNING] Game has been reset!') - return - end - end -) - -commands.add_command( - 'set_queue_speed', - 'Usable only for admins - sets the queue speed of this map!', - function(cmd) - local p - local player = game.player - local param = tonumber(cmd.parameter) - - if player then - if player ~= nil then - p = player.print - if not player.admin then - p("[ERROR] You're not admin!", Color.fail) - return - end - if not param then - return - end - p('Queue speed set to: ' .. param) - Task.set_queue_speed(param) - else - p = log - p('Queue speed set to: ' .. param) - Task.set_queue_speed(param) - end - end - end -) - -commands.add_command( - 'get_queue_speed', - 'Usable only for admins - gets the queue speed of this map!', - function() - local p - local player = game.player - - if player then - if player ~= nil then - p = player.print - if not player.admin then - p("[ERROR] You're not admin!", Color.fail) - return - end - p(Task.get_queue_speed()) - else - p = log - p(Task.get_queue_speed()) - end - end - end -) diff --git a/maps/fish_defender/crumbly_walls.lua b/maps/fish_defender/crumbly_walls.lua index ea5ffddd..bc39db91 100644 --- a/maps/fish_defender/crumbly_walls.lua +++ b/maps/fish_defender/crumbly_walls.lua @@ -1,27 +1,15 @@ -local Event = require 'utils.event' -local FDT = require 'maps.fish_defender.table' +local event = require 'utils.event' local math_random = math.random -local rock_raffle = {'sand-rock-big', 'rock-big', 'rock-big', 'rock-big', 'rock-huge'} +local rock_raffle = {"sand-rock-big", "rock-big", "rock-big", "rock-big", "rock-huge"} local function on_entity_died(event) - local crumbly_walls_unlocked = FDT.get('crumbly_walls_unlocked') - if not crumbly_walls_unlocked then - return - end - local entity = event.entity - if not entity.valid then - return - end - if entity.name ~= 'stone-wall' then - return - end - if math_random(1, 4) == 1 then - return - end - entity.surface.create_entity( - {name = rock_raffle[math_random(1, #rock_raffle)], position = entity.position, force = 'player'} - ) + if not global.crumbly_walls_unlocked then return end + local entity = event.entity + if not entity.valid then return end + if entity.name ~= "stone-wall" then return end + if math_random(1,4) == 1 then return end + entity.surface.create_entity({name = rock_raffle[math_random(1, #rock_raffle)], position = entity.position, force = "player"}) end -Event.add(defines.events.on_entity_died, on_entity_died) +event.add(defines.events.on_entity_died, on_entity_died) diff --git a/maps/fish_defender/explosive_gun_bullets.lua b/maps/fish_defender/explosive_gun_bullets.lua index 034876f7..09932da2 100644 --- a/maps/fish_defender/explosive_gun_bullets.lua +++ b/maps/fish_defender/explosive_gun_bullets.lua @@ -1,46 +1,36 @@ local radius = 3 local function splash_damage(surface, position, final_damage_amount) - local damage = math.random(math.floor(final_damage_amount * 3), math.floor(final_damage_amount * 4)) - for _, e in pairs( - surface.find_entities_filtered( - {area = {{position.x - radius, position.y - radius}, {position.x + radius, position.y + radius}}} - ) - ) do - if e.valid and e.health then - local distance_from_center = math.sqrt((e.position.x - position.x) ^ 2 + (e.position.y - position.y) ^ 2) - if distance_from_center <= radius then - local damage_distance_modifier = 1 - distance_from_center / radius - if damage > 0 then - if math.random(1, 3) == 1 then - surface.create_entity({name = 'explosion', position = e.position}) - end - e.damage(damage * damage_distance_modifier, 'player', 'explosion') - end - end - end - end + local damage = math.random(math.floor(final_damage_amount * 3), math.floor(final_damage_amount * 4)) + for _, e in pairs(surface.find_entities_filtered({area = {{position.x - radius, position.y - radius},{position.x + radius, position.y + radius}}})) do + if e.valid and e.health then + local distance_from_center = math.sqrt((e.position.x - position.x) ^ 2 + (e.position.y - position.y) ^ 2) + if distance_from_center <= radius then + local damage_distance_modifier = 1 - distance_from_center / radius + if damage > 0 then + if math.random(1, 3) == 1 then surface.create_entity({name = "explosion", position = e.position}) end + e.damage(damage * damage_distance_modifier, "player", "explosion") + end + end + end + end end local function explosive_bullets(event) - if math.random(1, 3) ~= 1 then - return false - end - if event.damage_type.name ~= 'physical' then - return false - end - local player = event.cause - if player.shooting_state.state == defines.shooting.not_shooting then - return false - end - local selected_weapon = player.get_inventory(defines.inventory.character_guns)[player.selected_gun_index] - if selected_weapon.name ~= 'submachine-gun' and selected_weapon.name ~= 'pistol' then - return false - end + if math.random(1, 3) ~= 1 then return false end + if event.damage_type.name ~= "physical" then return false end + local player = event.cause + if player.shooting_state.state == defines.shooting.not_shooting then return false end + local selected_weapon = player.get_inventory(defines.inventory.character_guns)[player.selected_gun_index] + if selected_weapon.name ~= "submachine-gun" and selected_weapon.name ~= "pistol" then return false end - player.surface.create_entity({name = 'explosion', position = event.entity.position}) + player.surface.create_entity({name = "explosion", position = event.entity.position}) - splash_damage(player.surface, event.entity.position, event.final_damage_amount) + splash_damage( + player.surface, + event.entity.position, + event.final_damage_amount + ) end return explosive_bullets diff --git a/maps/fish_defender/flame_boots.lua b/maps/fish_defender/flame_boots.lua index 919ec064..22e3e2d5 100644 --- a/maps/fish_defender/flame_boots.lua +++ b/maps/fish_defender/flame_boots.lua @@ -1,52 +1,40 @@ -local Event = require 'utils.event' -local FDT = require 'maps.fish_defender.table' +local event = require 'utils.event' +local math_random = math.random local function on_player_changed_position(event) - local flame_boots = FDT.get('flame_boots') - if not flame_boots then - return - end - local player = game.players[event.player_index] - if not player.character then - return - end - if player.character.driving then - return - end - - if not flame_boots[player.index] then - flame_boots[player.index] = {} - end - - if not flame_boots[player.index].fuel then - return - end - - if flame_boots[player.index].fuel < 0 then - player.print('Your flame boots have worn out.', {r = 0.22, g = 0.77, b = 0.44}) - flame_boots[player.index] = {} - return - end - - if flame_boots[player.index].fuel % 500 == 0 then - player.print('Fuel remaining: ' .. flame_boots[player.index].fuel, {r = 0.22, g = 0.77, b = 0.44}) - end - - if not flame_boots[player.index].step_history then - flame_boots[player.index].step_history = {} - end - - local elements = #flame_boots[player.index].step_history - - flame_boots[player.index].step_history[elements + 1] = {x = player.position.x, y = player.position.y} - - if elements < 50 then - return - end - - player.surface.create_entity({name = 'fire-flame', position = flame_boots[player.index].step_history[elements - 2]}) - - flame_boots[player.index].fuel = flame_boots[player.index].fuel - 1 + if not global.flame_boots then return end + local player = game.players[event.player_index] + if not player.character then return end + if player.character.driving then return end + + if not global.flame_boots[player.index] then global.flame_boots[player.index] = {} end + + if not global.flame_boots[player.index].fuel then return end + + if global.flame_boots[player.index].fuel < 0 then + player.print("Your flame boots have worn out.", {r = 0.22, g = 0.77, b = 0.44}) + global.flame_boots[player.index] = {} + return + end + + if global.flame_boots[player.index].fuel % 500 == 0 then player.print("Fuel remaining: " .. global.flame_boots[player.index].fuel, {r = 0.22, g = 0.77, b = 0.44}) end + + if not global.flame_boots[player.index].step_history then global.flame_boots[player.index].step_history = {} end + + local elements = #global.flame_boots[player.index].step_history + + global.flame_boots[player.index].step_history[elements + 1] = {x = player.position.x, y = player.position.y} + + if elements < 50 then return end + + player.surface.create_entity({name = "fire-flame", position = global.flame_boots[player.index].step_history[elements - 2]}) + + global.flame_boots[player.index].fuel = global.flame_boots[player.index].fuel - 1 end -Event.add(defines.events.on_player_changed_position, on_player_changed_position) +local function on_init() + if not global.flame_boots then global.flame_boots = {} end +end + +event.on_init(on_init) +event.add(defines.events.on_player_changed_position, on_player_changed_position) diff --git a/maps/fish_defender/laser_pointer.lua b/maps/fish_defender/laser_pointer.lua index 33f111fd..272a1189 100644 --- a/maps/fish_defender/laser_pointer.lua +++ b/maps/fish_defender/laser_pointer.lua @@ -1,37 +1,31 @@ -local Event = require 'utils.event' -local FDT = require 'maps.fish_defender.table' +local event = require 'utils.event' local radius = 32 local function on_player_used_capsule(event) - local laser_pointer_unlocked = FDT.get('laser_pointer_unlocked') - if not laser_pointer_unlocked then - return - end + if not global.laser_pointer_unlocked then return end + + local player = game.players[event.player_index] + local position = event.position + local used_item = event.item + if used_item.name ~= "artillery-targeting-remote" then return end - local player = game.players[event.player_index] - local position = event.position - local used_item = event.item - if used_item.name ~= 'artillery-targeting-remote' then - return - end - - for _, unit in pairs(player.surface.find_enemy_units(position, radius, 'player')) do - if math.random(1, 2) == 1 then - unit.set_command( - { - type = defines.command.go_to_location, - destination = position, - radius = 2, - distraction = defines.distraction.none, - pathfind_flags = { - allow_destroy_friendly_entities = false, - prefer_straight_paths = false, - low_priority = false - } - } - ) - end - end + for _, unit in pairs(player.surface.find_enemy_units(position, radius, "player")) do + if math.random(1,2) == 1 then + unit.set_command({ + type = defines.command.go_to_location, + destination = position, + radius = 2, + distraction = defines.distraction.none, + pathfind_flags = { + allow_destroy_friendly_entities = false, + prefer_straight_paths = false, + low_priority = false + } + }) + end + end end -Event.add(defines.events.on_player_used_capsule, on_player_used_capsule) +event.add(defines.events.on_player_used_capsule, on_player_used_capsule) + + diff --git a/maps/fish_defender/main.lua b/maps/fish_defender/main.lua index 050d6820..09daa32c 100644 --- a/maps/fish_defender/main.lua +++ b/maps/fish_defender/main.lua @@ -2,43 +2,55 @@ --require "modules.rpg" +require 'maps.fish_defender.terrain' require 'maps.fish_defender.market' -require 'maps.fish_defender.commands' 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 Terrain = require 'maps.fish_defender.terrain' -local Task = require 'utils.task' local Unit_health_booster = require 'modules.biter_health_booster' local Difficulty = require 'modules.difficulty_vote' local Map = require 'modules.map_info' -local Event = require 'utils.event' -local Reset = require 'functions.soft_reset' +local event = require 'utils.event' local Server = require 'utils.server' -local Poll = require 'comfy_panel.poll' local boss_biter = require 'maps.fish_defender.boss_biters' -local FDT = require 'maps.fish_defender.table' local Score = require 'comfy_panel.score' local math_random = math.random local insert = table.insert local enable_start_grace_period = true +map_height = 96 -local branch_version = '0.18.35' -local sub = string.sub +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 Public = {} - -local starting_items = { - ['pistol'] = 1, - ['firearm-magazine'] = 16, - ['raw-fish'] = 3, - ['iron-plate'] = 32, - ['stone'] = 12 +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) @@ -50,22 +62,19 @@ local function shuffle(tbl) return tbl end -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 function create_wave_gui(player) if player.gui.top['fish_defense_waves'] then player.gui.top['fish_defense_waves'].destroy() end - local this = FDT.get() 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 this.wave_count then - wave_count = this.wave_count + if global.wave_count then + wave_count = global.wave_count end - if not this.wave_grace_period then + 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' @@ -74,16 +83,17 @@ local function create_wave_gui(player) label.style.minimal_width = 68 label.style.font_color = {r = 0.33, g = 0.66, b = 0.9} - local next_level_progress = game.tick % this.wave_interval / this.wave_interval + 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(((this.wave_grace_period - (game.tick % this.wave_grace_period)) / 60) / 60) + local time_remaining = + math.floor(((global.wave_grace_period - (game.tick % global.wave_grace_period)) / 60) / 60) if time_remaining <= 0 then - this.wave_grace_period = nil + global.wave_grace_period = nil return end @@ -95,7 +105,7 @@ local function create_wave_gui(player) label.style.font_color = {r = 0.33, g = 0.66, b = 0.9} if not enable_start_grace_period then - this.wave_grace_period = nil + global.wave_grace_period = nil return end end @@ -104,7 +114,6 @@ end local function show_fd_stats(player) local gui_id = 'fd-stats' local table_id = gui_id .. 'table' - local this = FDT.get() if player.gui.left[gui_id] then player.gui.left[gui_id].destroy() @@ -128,15 +137,15 @@ local function show_fd_stats(player) h.style.font = 'heading-2' end - for k, v in pairs(this.entity_limits) do + 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 _, value_entry in pairs(entry) do + for k, v in pairs(entry) do table.add { type = 'label', - caption = value_entry + caption = v } end end @@ -155,8 +164,8 @@ local function add_fd_stats_button(player) if player.gui.top[button_id] then player.gui.top[button_id].destroy() end - - player.gui.top.add { + local button = + player.gui.top.add { type = 'sprite-button', name = button_id, sprite = 'item/submachine-gun' @@ -179,7 +188,7 @@ local function on_gui_click(event) end end -local function on_market_item_purchased() +local function on_market_item_purchased(event) update_fd_stats() end @@ -195,16 +204,15 @@ local threat_values = { } local function get_biter_initial_pool() - local this = FDT.get() - local biter_pool - if this.wave_count > 1750 then + 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 this.wave_count > 1500 then + 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}, @@ -212,7 +220,7 @@ local function get_biter_initial_pool() } return biter_pool end - if this.wave_count > 1250 then + 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}, @@ -220,7 +228,7 @@ local function get_biter_initial_pool() } return biter_pool end - if this.wave_count > 1000 then + 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}, @@ -328,10 +336,11 @@ local function get_biter_initial_pool() 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 _ = 1, biter_type.weight, 1 do + for x = 1, biter_type.weight, 1 do insert(biter_raffle, {name = biter_type.name, threat = biter_type.threat}) end end @@ -339,18 +348,12 @@ local function get_biter_pool() end local function spawn_biter(pos, biter_pool) - local this = FDT.get() - if this.attack_wave_threat < 1 then + if global.attack_wave_threat < 1 then return false end - - local surface = game.surfaces[this.active_surface_index] - if not surface or not surface.valid then - return - end - + local surface = game.surfaces['fish_defender'] biter_pool = shuffle(biter_pool) - this.attack_wave_threat = this.attack_wave_threat - biter_pool[1].threat + 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 @@ -363,7 +366,7 @@ local function get_y_coord_raffle_table() for y = -96, 96, 8 do t[#t + 1] = y end - shuffle(t) + table.shuffle_table(t) return t end @@ -380,9 +383,8 @@ local attack_group_count_thresholds = { local function get_number_of_attack_groups() local n = 1 - local this = FDT.get() for _, entry in pairs(attack_group_count_thresholds) do - if this.wave_count >= entry[1] then + if global.wave_count >= entry[1] then n = entry[2] end end @@ -390,16 +392,14 @@ local function get_number_of_attack_groups() end local function clear_corpses(surface) - local this = FDT.get() - - if not this.wave_count then + if not global.wave_count then return end local chance = 4 - if this.wave_count > 250 then + if global.wave_count > 250 then chance = 3 end - if this.wave_count > 500 then + if global.wave_count > 500 then chance = 2 end for _, entity in pairs(surface.find_entities_filtered {type = 'corpse'}) do @@ -409,10 +409,52 @@ local function clear_corpses(surface) 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 = {} - local this = FDT.get() - for x = unit_group.position.x, this.market.position.x, -48 do + 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 @@ -426,13 +468,13 @@ local function send_unit_group(unit_group) end commands[#commands + 1] = { type = defines.command.attack_area, - destination = {x = this.market.position.x, y = unit_group.position.y}, + 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 = this.market, + target = global.market, distraction = defines.distraction.by_enemy } @@ -447,43 +489,42 @@ end local function spawn_boss_units(surface) local Diff = Difficulty.get() - local this = FDT.get() - if this.wave_count <= 2000 then + if global.wave_count <= 2000 then game.print( - {'fish_defender.boss_message', this.wave_count, {'fish_defender.' .. this.wave_count}}, + {'fish_defender.boss_message', global.wave_count, {'fish_defender.' .. global.wave_count}}, {r = 0.8, g = 0.1, b = 0.1} ) else - game.print({'fish_defender.boss_message', this.wave_count}, {r = 0.8, g = 0.1, b = 0.1}) + game.print({'fish_defender.boss_message', global.wave_count}, {r = 0.8, g = 0.1, b = 0.1}) end - if not this.boss_waves[this.wave_count] then - local amount = this.wave_count + if not boss_waves[global.wave_count] then + local amount = global.wave_count if amount > 1000 then amount = 1000 end - this.boss_waves[this.wave_count] = { + 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 = this.difficulties_votes[Diff.difficulty_vote_index].boss_modifier - if this.wave_count == 100 then + local health_factor = difficulties_votes[Diff.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(this.boss_waves[this.wave_count]) do - for _ = 1, entry.count, 1 do + 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 - this.boss_biters[biter.unit_number] = biter - Unit_health_booster.add_boss_unit(biter, this.biter_health_boost * health_factor, 0.55) + 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 @@ -493,8 +534,7 @@ local function spawn_boss_units(surface) end local function wake_up_the_biters(surface) - local this = FDT.get() - if not this.market or not this.market.valid then + if not global.market then return end @@ -539,7 +579,7 @@ local function wake_up_the_biters(surface) { command = { type = defines.command.attack, - target = this.market, + target = global.market, distraction = defines.distraction.none }, unit_count = 16, @@ -549,30 +589,19 @@ local function wake_up_the_biters(surface) ) end -local function damage_entity_outside_and_inside_of_fence(e) +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 == 'land-mine' then - e.health = - e.health - math_random(math.floor(e.prototype.max_health * 0.2), math.floor(e.prototype.max_health * 0.4)) - if e.health <= 0 then - e.die('enemy') - end - return - end - if e.type == 'entity-ghost' then e.destroy() return @@ -587,18 +616,14 @@ end local function biter_attack_wave() local Diff = Difficulty.get() - local this = FDT.get() - if not this.market or not this.market.valid then + if not global.market then return end - if this.wave_grace_period then - return - end - local surface = game.surfaces[this.active_surface_index] - if not surface or not surface.valid then + if global.wave_grace_period then return end + local surface = game.surfaces['fish_defender'] clear_corpses(surface) wake_up_the_biters(surface) @@ -608,61 +633,61 @@ local function biter_attack_wave() return end - if not this.wave_count then - this.wave_count = 1 + if not global.wave_count then + global.wave_count = 1 else - this.wave_count = this.wave_count + 1 + global.wave_count = global.wave_count + 1 end local m = 0.0015 if Diff.difficulty_vote_index then - m = m * this.difficulties_votes[Diff.difficulty_vote_index].strength_modifier + m = m * difficulties_votes[Diff.difficulty_vote_index].strength_modifier end - game.forces.enemy.set_ammo_damage_modifier('melee', this.wave_count * m) - game.forces.enemy.set_ammo_damage_modifier('biological', this.wave_count * m) - this.biter_health_boost = 1 + (this.wave_count * (m * 2)) + 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)) - m = 4 + local m = 4 if Diff.difficulty_vote_index then - m = m * this.difficulties_votes[Diff.difficulty_vote_index].amount_modifier + m = m * difficulties_votes[Diff.difficulty_vote_index].amount_modifier end - if this.wave_count % 50 == 0 then - this.attack_wave_threat = math.floor(this.wave_count * (m * 1.5)) + if global.wave_count % 50 == 0 then + global.attack_wave_threat = math.floor(global.wave_count * (m * 1.5)) spawn_boss_units(surface) - if this.attack_wave_threat > 10000 then - this.attack_wave_threat = 10000 + if global.attack_wave_threat > 10000 then + global.attack_wave_threat = 10000 end else - this.attack_wave_threat = math.floor(this.wave_count * m) - if this.attack_wave_threat > 10000 then - this.attack_wave_threat = 10000 + 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 = this.wave_count * 0.00125 + 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 this.endgame_modifier then - -- this.endgame_modifier = 1 + -- 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 - -- this.endgame_modifier = this.endgame_modifier + 1 + -- global.endgame_modifier = global.endgame_modifier + 1 -- end --end - for _, e in pairs(surface.find_entities_filtered({area = {{110, -256}, {360, 256}}})) do - damage_entity_outside_and_inside_of_fence(e) + 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 this.wave_count > 50 and math_random(1, 8) == 1 then + 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 @@ -674,9 +699,9 @@ local function biter_attack_wave() local biter_pool = get_biter_pool() --local spawners = surface.find_entities_filtered({type = "unit-spawner", area = {{160, -196},{512, 196}}}) - --shuffle(spawners) + --table.shuffle_table(spawners) - while this.attack_wave_threat > 0 do + while global.attack_wave_threat > 0 do for i = 1, #unit_groups, 1 do --local biter --if spawners[i] then @@ -700,7 +725,7 @@ local function biter_attack_wave() end local function get_sorted_list(column_name, score_list) - for _ = 1, #score_list, 1 do + for x = 1, #score_list, 1 do for y = 1, #score_list, 1 do if not score_list[y + 1] then break @@ -761,9 +786,7 @@ local function get_mvps() end local function is_game_lost() - local this = FDT.get() - - if not this.game_has_ended then + if global.market then return end @@ -783,68 +806,58 @@ local function is_game_lost() 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} - local survival_time_label = t.add({type = 'label', caption = 'Survival Time >> '}) - survival_time_label.style.font = 'default-listbox' - survival_time_label.style.font_color = {r = 0.22, g = 0.77, b = 0.44} - - local market_age_label - - if this.market_age then - if this.market_age >= 216000 then - market_age_label = - t.add( - { - type = 'label', - caption = math.floor(((this.market_age / 60) / 60) / 60) .. - ' hours ' .. math.ceil((this.market_age % 216000 / 60) / 60) .. ' minutes' - } - ) - market_age_label.style.font = 'default-bold' - market_age_label.style.font_color = {r = 0.33, g = 0.66, b = 0.9} - else - market_age_label = - t.add({type = 'label', caption = math.ceil((this.market_age % 216000 / 60) / 60) .. ' minutes'}) - market_age_label.style.font = 'default-bold' - market_age_label.style.font_color = {r = 0.33, g = 0.66, b = 0.9} - end + 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 mvp_defender_label = t.add({type = 'label', caption = 'MVP Defender >> '}) - mvp_defender_label.style.font = 'default-listbox' - mvp_defender_label.style.font_color = {r = 0.22, g = 0.77, b = 0.44} - - local mvp_killscore_label = + 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}) - mvp_killscore_label.style.font = 'default-bold' - mvp_killscore_label.style.font_color = {r = 0.33, g = 0.66, b = 0.9} + l.style.font = 'default-bold' + l.style.font_color = {r = 0.33, g = 0.66, b = 0.9} - local mvp_builder_label = t.add({type = 'label', caption = 'MVP Builder >> '}) - mvp_builder_label.style.font = 'default-listbox' - mvp_builder_label.style.font_color = {r = 0.22, g = 0.77, b = 0.44} - - local mvp_built_ent_label = + 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' } ) - mvp_built_ent_label.style.font = 'default-bold' - mvp_built_ent_label.style.font_color = {r = 0.33, g = 0.66, b = 0.9} + l.style.font = 'default-bold' + l.style.font_color = {r = 0.33, g = 0.66, b = 0.9} - local mvp_deaths_label = t.add({type = 'label', caption = 'MVP Deaths >> '}) - mvp_deaths_label.style.font = 'default-listbox' - mvp_deaths_label.style.font_color = {r = 0.22, g = 0.77, b = 0.44} + 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} - local mvp_deaths_name_label = - t.add({type = 'label', caption = mvp.deaths.name .. ' died ' .. mvp.deaths.score .. ' times'}) - mvp_deaths_name_label.style.font = 'default-bold' - mvp_deaths_name_label.style.font_color = {r = 0.33, g = 0.66, b = 0.9} - - if not this.results_sent then + 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') @@ -856,11 +869,13 @@ local function is_game_lost() insert(result, mvp.deaths.name .. ' died ' .. mvp.deaths.score .. ' times') local message = table.concat(result) Server.to_discord_embed(message) - this.results_sent = true + global.results_sent = true end end - player.play_sound {path = 'utility/game_lost', volume_modifier = 0.75} + 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 @@ -895,73 +910,41 @@ local function damage_entities_in_radius(surface, position, radius, damage) end local function market_kill_visuals() - local this = FDT.get() - local surface = game.surfaces[this.active_surface_index] - if not surface or not surface.valid then - return - end - - local is_branch_18 = sub(branch_version, 3, 4) - local get_active_version = sub(game.active_mods.base, 3, 4) - - if not surface or not surface.valid then - return - end - - if not this.market or not this.market.valid then - return - end - local m = 32 local m2 = m * 0.005 - if get_active_version >= is_branch_18 then - for i = 1, 1024, 1 do - surface.create_particle( - { - name = 'branch-particle', - position = this.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 - else - for i = 1, 1024, 1 do - surface.create_entity( - { - name = 'branch-particle', - position = this.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 i = 1, 1024, 1 do + global.market.surface.create_particle( + { + 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 - surface.create_trivial_smoke( + global.market.surface.create_trivial_smoke( { name = 'smoke-fast', - position = {this.market.position.x + (x * 0.35), this.market.position.y + (y * 0.35)} + position = {global.market.position.x + (x * 0.35), global.market.position.y + (y * 0.35)} } ) end if math_random(1, 3) == 1 then - surface.create_trivial_smoke( + global.market.surface.create_trivial_smoke( { name = 'train-smoke', - position = {this.market.position.x + (x * 0.35), this.market.position.y + (y * 0.35)} + position = {global.market.position.x + (x * 0.35), global.market.position.y + (y * 0.35)} } ) end end end - surface.spill_item_stack(this.market.position, {name = 'raw-fish', count = 1024}, true) + global.market.surface.spill_item_stack(global.market.position, {name = 'raw-fish', count = 1024}, true) end local biter_splash_damage = { @@ -993,12 +976,10 @@ local function on_entity_died(event) return end - local this = FDT.get() - if event.entity.force.name == 'enemy' then local surface = event.entity.surface - if this.boss_biters[event.entity.unit_number] then + if global.boss_biters[event.entity.unit_number] then boss_biter.died(event) end @@ -1035,37 +1016,43 @@ local function on_entity_died(event) return end - if this.entity_limits[event.entity.name] then - this.entity_limits[event.entity.name].placed = this.entity_limits[event.entity.name].placed - 1 + 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] - local this = FDT.get() - local surface = game.surfaces[this.active_surface_index] - if not surface or not surface.valid then - return - end if player.online_time == 0 then - for item, amount in pairs(starting_items) do - player.insert({name = item, count = amount}) - end - + 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 spawn = player.force.get_spawn_position(surface) - local pos = surface.find_non_colliding_position('character', spawn, 3, 0.5) - - if not pos and player.online_time < 2 then - player.teleport(spawn, surface) - elseif player.online_time < 2 or player.surface.index ~= this.active_surface_index then - player.teleport(pos, surface) + 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) @@ -1075,30 +1062,30 @@ local function on_player_joined_game(event) is_game_lost() end - --if this.charting_done then return end + --if global.charting_done then return end --game.forces.player.chart(game.surfaces["fish_defender"], {{-256, -512},{768, 512}}) - --this.charting_done = true + --global.charting_done = true end local function on_built_entity(event) local get_score = Score.get_table().score_table - local this = FDT.get() local entity = event.created_entity if not entity.valid then return end - if this.entity_limits[entity.name] then + if global.entity_limits[entity.name] then local surface = entity.surface - if this.entity_limits[entity.name].placed < this.entity_limits[entity.name].limit then - this.entity_limits[entity.name].placed = this.entity_limits[entity.name].placed + 1 + 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 = this.entity_limits[entity.name].placed .. + text = global.entity_limits[entity.name].placed .. ' / ' .. - this.entity_limits[entity.name].limit .. ' ' .. this.entity_limits[entity.name].str .. 's', + global.entity_limits[entity.name].limit .. + ' ' .. global.entity_limits[entity.name].str .. 's', color = {r = 0.98, g = 0.66, b = 0.22} } ) @@ -1108,7 +1095,7 @@ local function on_built_entity(event) { name = 'flying-text', position = entity.position, - text = this.entity_limits[entity.name].str .. ' limit reached.', + text = global.entity_limits[entity.name].str .. ' limit reached.', color = {r = 0.82, g = 0.11, b = 0.11} } ) @@ -1129,18 +1116,18 @@ end local function on_robot_built_entity(event) local entity = event.created_entity - local this = FDT.get() - if this.entity_limits[entity.name] then + if global.entity_limits[entity.name] then local surface = entity.surface - if this.entity_limits[entity.name].placed < this.entity_limits[entity.name].limit then - this.entity_limits[entity.name].placed = this.entity_limits[entity.name].placed + 1 + 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 = this.entity_limits[entity.name].placed .. + text = global.entity_limits[entity.name].placed .. ' / ' .. - this.entity_limits[entity.name].limit .. ' ' .. this.entity_limits[entity.name].str .. 's', + global.entity_limits[entity.name].limit .. + ' ' .. global.entity_limits[entity.name].str .. 's', color = {r = 0.98, g = 0.66, b = 0.22} } ) @@ -1150,7 +1137,7 @@ local function on_robot_built_entity(event) { name = 'flying-text', position = entity.position, - text = this.entity_limits[entity.name].str .. ' limit reached.', + text = global.entity_limits[entity.name].str .. ' limit reached.', color = {r = 0.82, g = 0.11, b = 0.11} } ) @@ -1161,13 +1148,63 @@ local function on_robot_built_entity(event) end end +local function on_tick() + local Diff = Difficulty.get() + 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 Diff.difficulty_vote_index then + global.wave_interval = difficulties_votes[Diff.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] - local this = FDT.get() - local surface = game.surfaces[this.active_surface_index] - if not surface or not surface.valid then - return - end if player.position.x + player.position.y < 0 then return end @@ -1175,9 +1212,9 @@ local function on_player_changed_position(event) return end if player.position.x >= 160 then - player.teleport({player.position.x - 1, player.position.y}, surface) - if player.position.y > this.map_height or player.position.y < this.map_height * -1 then - player.teleport({player.position.x, 0}, surface) + 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 @@ -1190,17 +1227,15 @@ local function on_player_changed_position(event) end local function on_player_mined_entity(event) - local this = FDT.get() - if this.entity_limits[event.entity.name] then - this.entity_limits[event.entity.name].placed = this.entity_limits[event.entity.name].placed - 1 + 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) - local this = FDT.get() - if this.entity_limits[event.entity.name] then - this.entity_limits[event.entity.name].placed = this.entity_limits[event.entity.name].placed - 1 + 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 @@ -1215,199 +1250,30 @@ local function on_research_finished(event) end local function on_player_respawned(event) - local this = FDT.get() - if not this.market_age then + if not global.market_age then return end local player = game.players[event.player_index] player.character.destructible = false end -local function set_objective_health(final_damage_amount) - local this = FDT.get() - if final_damage_amount == 0 then - return - end +local function on_init(event) + local Diff = Difficulty.get() + global.wave_interval = 3600 --interval between waves in ticks + global.wave_grace_period = 3600 * 20 + Diff.difficulty_poll_closing_timeout = global.wave_grace_period + global.boss_biters = {} + global.acid_lines_delay = {} - if this.market_health <= 0 then - this.market.health = this.market.health + final_damage_amount - return - end - - this.market_health = math.floor(this.market_health - final_damage_amount) - if this.market_health > this.market_max_health then - this.market_health = this.market_max_health - end - - if this.market_health <= 0 then - market_kill_visuals() - this.market.die() - this.market = nil - this.market_age = game.tick - this.last_reset - this.game_has_ended = true - is_game_lost() - return - end - - local m = this.market_health / this.market_max_health - this.market.health = 150 * m - - rendering.set_text(this.health_text, 'HP: ' .. this.market_health .. ' / ' .. this.market_max_health) -end - -local function protect_entities(event) - local this = FDT.get() - local entity = event.entity - - if not entity or not entity.valid then - return - end - - if not this.market or not this.market.valid then - return - end - - if entity.force.index ~= 1 then - return - end --Player Force - - if event.cause then - if event.cause.force.index == 2 and entity == this.market then - set_objective_health(event.final_damage_amount) - elseif event.cause.force.index == 2 then - return - else - event.entity.health = event.entity.health + event.final_damage_amount - end - end - if entity and entity.valid then - event.entity.health = event.entity.health + event.final_damage_amount - end -end - -local function on_entity_damaged(event) - local entity = event.entity - - if not entity then - return - end - - if not entity.valid then - return - end - - protect_entities(event) -end - -local function on_player_repaired_entity(event) - local this = FDT.get() - if not event.entity then - return - end - if not event.entity.valid then - return - end - if not event.entity.health then - return - end - local entity = event.entity - if entity == this.market then - set_objective_health(-1) - end -end - -local function set_market_health() - local this = FDT.get() - if not this.market then - return - end - if not this.market.valid then - return - end - local m = this.market_health / this.market_max_health - this.market.health = 150 * m - rendering.set_text(this.health_text, 'HP: ' .. this.market_health .. ' / ' .. this.market_max_health) -end - -local function has_the_game_ended() - local this = FDT.get() - if this.market_age then - if not this.game_restart_timer then - this.game_restart_timer = 5400 - else - if this.game_restart_timer < 0 then - return - end - - this.game_restart_timer = this.game_restart_timer - 30 - end - local cause_msg - if this.restart then - cause_msg = 'restart' - elseif this.shutdown then - cause_msg = 'shutdown' - elseif this.soft_reset then - cause_msg = 'soft-reset' - end - - if this.game_restart_timer % 1800 == 0 then - if this.game_restart_timer > 0 then - this.game_reset = true - game.print( - 'Game will ' .. cause_msg .. ' in ' .. this.game_restart_timer / 60 .. ' seconds!', - {r = 0.22, g = 0.88, b = 0.22} - ) - end - if this.soft_reset and this.game_restart_timer == 0 then - this.game_reset_tick = nil - Public.reset_game() - return - end - if this.restart and this.game_restart_timer == 0 then - if not this.announced_message then - game.print('Soft-reset is disabled. Server will restart!', {r = 0.22, g = 0.88, b = 0.22}) - local message = 'Soft-reset is disabled. Server will restart!' - Server.to_discord_bold(table.concat {'*** ', message, ' ***'}) - Server.start_scenario('Fish_Defender') - this.announced_message = true - return - end - end - if this.shutdown and this.game_restart_timer == 0 then - if not this.announced_message then - game.print('Soft-reset is disabled. Server is shutting down!', {r = 0.22, g = 0.88, b = 0.22}) - local message = 'Soft-reset is disabled. Server is shutting down!' - Server.to_discord_bold(table.concat {'*** ', message, ' ***'}) - Server.stop_scenario() - this.announced_message = true - return - end - end - end - end -end - -function Public.reset_game() - FDT.reset_table() - Poll.reset() - local this = FDT.get() - local is_branch_18 = sub(branch_version, 3, 4) - local get_active_version = sub(game.active_mods.base, 3, 4) - - Difficulty.reset_difficulty_poll() - Difficulty.set_poll_closing_timeout = game.tick + 36000 - - local players = game.connected_players - for i = 1, #players do - local player = players[i] - Score.init_player_table(player) - if player.gui.left['fish_defense_game_lost'] then - player.gui.left['fish_defense_game_lost'].destroy() - end - end + 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.seed = math_random(10000, 99999) map_gen_settings.height = 2048 map_gen_settings.water = 0.10 map_gen_settings.terrain_segmentation = 3 @@ -1422,27 +1288,8 @@ function Public.reset_game() ['trees'] = {frequency = 2, size = 1, richness = 1}, ['enemy-base'] = {frequency = 'none', size = 'none', richness = 'none'} } - - if not this.active_surface_index then - this.active_surface_index = game.create_surface('fish_defender', map_gen_settings).index - else - this.active_surface_index = - Reset.soft_reset_map(game.surfaces[this.active_surface_index], map_gen_settings, starting_items).index - end - - local surface = game.surfaces[this.active_surface_index] - if not surface or not surface.valid then - return - end - - surface.peaceful_mode = false - - global.chunk_queue = {} - - Terrain.fish_eye(surface, {x = -2150, y = -300}) - - Task.get_task_queue(4) - Task.start_queue() + 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 @@ -1453,94 +1300,38 @@ function Public.reset_game() game.forces['player'].technologies['atomic-bomb'].enabled = false --game.forces["player"].technologies["landfill"].enabled = false - if not game.forces.decoratives then - game.create_force('decoratives') - end - + 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) - game.remove_offline_players() - game.map_settings.enemy_expansion.enabled = false - game.forces['player'].technologies['artillery'].researched = false + global.comfylatron_habitat = { + left_top = {x = -1500, y = -1500}, + right_bottom = {x = -80, y = 1500} + } - is_branch_18 = is_branch_18 .. sub(branch_version, 6, 7) - get_active_version = get_active_version .. sub(game.active_mods.base, 6, 7) - if get_active_version >= is_branch_18 then - game.reset_time_played() - end + fish_eye(surface, {x = -2150, y = -300}) - this.market_health = 500 - this.market_max_health = 500 -end - -function Public.on_init() - Public.reset_game() + global.chunk_queue = {} local T = Map.Pop_info() T.localised_category = 'fish_defender' 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} - - local mgs = game.surfaces['nauvis'].map_gen_settings - mgs.width = 16 - mgs.height = 16 - game.surfaces['nauvis'].map_gen_settings = mgs - game.surfaces['nauvis'].clear() end -local function on_tick() - local Diff = Difficulty.get() - local this = FDT.get() - local surface = game.surfaces[this.active_surface_index] - if not surface or not surface.valid then - return - end - if game.tick % 30 == 0 then - has_the_game_ended() - if this.market then - set_market_health() - for _, player in pairs(game.connected_players) do - if surface.peaceful_mode == false then - create_wave_gui(player) - end - end - end - if game.tick % 180 == 0 then - if surface then - game.forces.player.chart(surface, {{-160, -128}, {192, 128}}) - if Diff.difficulty_vote_index then - this.wave_interval = this.difficulties_votes[Diff.difficulty_vote_index].wave_interval - end - end - end - 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) - if game.tick % this.wave_interval == this.wave_interval - 1 then - if surface.peaceful_mode == true then - return - end - biter_attack_wave() - end -end - -local on_init = Public.on_init - -Event.add(defines.events.on_entity_damaged, on_entity_damaged) -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_player_repaired_entity, on_player_repaired_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) - -return Public +require 'modules.difficulty_vote' diff --git a/maps/fish_defender/market.lua b/maps/fish_defender/market.lua index 9f9ed066..cb8877ff 100644 --- a/maps/fish_defender/market.lua +++ b/maps/fish_defender/market.lua @@ -5,341 +5,263 @@ require 'maps.fish_defender.crumbly_walls' require 'maps.fish_defender.vehicle_nanobots' require 'maps.fish_defender.laser_pointer' -local Event = require 'utils.event' -local FDT = require 'maps.fish_defender.table' +local event = require 'utils.event' local Server = require 'utils.server' local slot_upgrade_offers = { - [1] = {'gun-turret', 'gun turret'}, - [2] = {'laser-turret', 'laser turret'}, - [3] = {'artillery-turret', 'artillery turret'}, - [4] = {'flamethrower-turret', 'flamethrower turret'}, - [5] = {'land-mine', 'land mine'} -} + [1] = {"gun-turret", "gun turret"}, + [2] = {"laser-turret", "laser turret"}, + [3] = {"artillery-turret", "artillery turret"}, + [4] = {"flamethrower-turret", "flamethrower turret"}, + [5] = {"land-mine", "land mine"} + } local special_descriptions = { - ['flame-boots'] = 'Flame Boots - Get yourself some hot boots.', - ['explosive-bullets'] = 'Unlock Explosive Bullets - Submachine-Gun and Pistol gains a chance to deal splash damage.', - ['bouncy-shells'] = 'Unlock Bouncy Shells - Shotgun projectiles may bounce to multiple targets.', - ['trapped-capsules'] = 'Unlock Trapped Capsules - Combat robots will send a last deadly projectile to a nearby enemy when killed.', - ['ultra-mines'] = 'Unlock Ultra Mines - Careful with these...', - ['railgun-enhancer'] = 'Unlock Railgun Enhancer - Turns the railgun into a powerful forking gun.', - ['crumbly-walls'] = 'Unlock Crumbly Walls - Fortifications which crumble, may turn into rocks.', - ['vehicle-nanobots'] = 'Unlock Vehicle Nanobots - Vehicles repair rapidly while driving.', - ['laser-pointer'] = 'Unlock Laser Pointer - The biters are on a quest to slay the red (artillery) dot.' + ["flame-boots"] = "Flame Boots - Get yourself some hot boots.", + ["explosive-bullets"] = "Unlock Explosive Bullets - Submachine-Gun and Pistol gains a chance to deal splash damage.", + ["bouncy-shells"] = "Unlock Bouncy Shells - Shotgun projectiles may bounce to multiple targets.", + ["trapped-capsules"] = "Unlock Trapped Capsules - Combat robots will send a last deadly projectile to a nearby enemy when killed.", + ["ultra-mines"] = "Unlock Ultra Mines - Careful with these...", + ["railgun-enhancer"] = "Unlock Railgun Enhancer - Turns the railgun into a powerful forking gun.", + ["crumbly-walls"] = "Unlock Crumbly Walls - Fortifications which crumble, may turn into rocks.", + ["vehicle-nanobots"] = "Unlock Vehicle Nanobots - Vehicles repair rapidly while driving.", + ["laser-pointer"] = "Unlock Laser Pointer - The biters are on a quest to slay the red (artillery) dot." } +function place_fish_market(surface, position) + local market = surface.create_entity({name = "market", position = position, force = "player"}) + market.minable = false + return market +end + local function refresh_market_offers() - local this = FDT.get() - if not this.market or not this.market.valid then - return - end - for i = 1, 100, 1 do - local a = this.market.remove_market_item(1) - if a == false then - break - end - end - - local str1 = - 'Gun Turret Slot for ' .. - tostring(this.entity_limits['gun-turret'].limit * this.entity_limits['gun-turret'].slot_price) - str1 = str1 .. ' Coins.' - - local str2 = - 'Laser Turret Slot for ' .. - tostring(this.entity_limits['laser-turret'].limit * this.entity_limits['laser-turret'].slot_price) - str2 = str2 .. ' Coins.' - - local str3 = - 'Artillery Slot for ' .. - tostring(this.entity_limits['artillery-turret'].limit * this.entity_limits['artillery-turret'].slot_price) - str3 = str3 .. ' Coins.' - - local current_limit = 1 - if this.entity_limits['flamethrower-turret'].limit ~= 0 then - current_limit = current_limit + this.entity_limits['flamethrower-turret'].limit - end - local str4 = - 'Flamethrower Turret Slot for ' .. - tostring(current_limit * this.entity_limits['flamethrower-turret'].slot_price) - str4 = str4 .. ' Coins.' - - local str5 = - 'Landmine Slot for ' .. - tostring(math.ceil((this.entity_limits['land-mine'].limit / 3) * this.entity_limits['land-mine'].slot_price)) - str5 = str5 .. ' Coins.' - - local market_items = { - {price = {}, offer = {type = 'nothing', effect_description = str1}}, - {price = {}, offer = {type = 'nothing', effect_description = str2}}, - {price = {}, offer = {type = 'nothing', effect_description = str3}}, - {price = {}, offer = {type = 'nothing', effect_description = str4}}, - {price = {}, offer = {type = 'nothing', effect_description = str5}}, - {price = {{'coin', 5}}, offer = {type = 'give-item', item = 'raw-fish', count = 1}}, - {price = {{'coin', 1}}, offer = {type = 'give-item', item = 'wood', count = 8}}, - {price = {{'coin', 8}}, offer = {type = 'give-item', item = 'grenade', count = 1}}, - {price = {{'coin', 32}}, offer = {type = 'give-item', item = 'cluster-grenade', count = 1}}, - {price = {{'coin', 1}}, offer = {type = 'give-item', item = 'land-mine', count = 1}}, - {price = {{'coin', 80}}, offer = {type = 'give-item', item = 'car', count = 1}}, - {price = {{'coin', 1200}}, offer = {type = 'give-item', item = 'tank', count = 1}}, - {price = {{'coin', 3}}, offer = {type = 'give-item', item = 'cannon-shell', count = 1}}, - {price = {{'coin', 7}}, offer = {type = 'give-item', item = 'explosive-cannon-shell', count = 1}}, - {price = {{'coin', 50}}, offer = {type = 'give-item', item = 'gun-turret', count = 1}}, - {price = {{'coin', 300}}, offer = {type = 'give-item', item = 'laser-turret', count = 1}}, - {price = {{'coin', 450}}, offer = {type = 'give-item', item = 'artillery-turret', count = 1}}, - {price = {{'coin', 10}}, offer = {type = 'give-item', item = 'artillery-shell', count = 1}}, - {price = {{'coin', 25}}, offer = {type = 'give-item', item = 'artillery-targeting-remote', count = 1}}, - {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}}, - {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}}, - {price = {{'coin', 30}}, offer = {type = 'give-item', item = 'submachine-gun', count = 1}}, - {price = {{'coin', 250}}, offer = {type = 'give-item', item = 'combat-shotgun', count = 1}}, - {price = {{'coin', 450}}, offer = {type = 'give-item', item = 'flamethrower', count = 1}}, - {price = {{'coin', 25}}, offer = {type = 'give-item', item = 'flamethrower-ammo', count = 1}}, - {price = {{'coin', 125}}, offer = {type = 'give-item', item = 'rocket-launcher', count = 1}}, - {price = {{'coin', 2}}, offer = {type = 'give-item', item = 'rocket', count = 1}}, - {price = {{'coin', 7}}, offer = {type = 'give-item', item = 'explosive-rocket', count = 1}}, - {price = {{'coin', 7500}}, offer = {type = 'give-item', item = 'atomic-bomb', count = 1}}, - {price = {{'coin', 325}}, offer = {type = 'give-item', item = 'railgun', count = 1}}, - {price = {{'coin', 8}}, offer = {type = 'give-item', item = 'railgun-dart', count = 1}}, - {price = {{'coin', 40}}, offer = {type = 'give-item', item = 'poison-capsule', count = 1}}, - {price = {{'coin', 4}}, offer = {type = 'give-item', item = 'defender-capsule', count = 1}}, - {price = {{'coin', 10}}, offer = {type = 'give-item', item = 'light-armor', count = 1}}, - {price = {{'coin', 125}}, 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}}, - {price = {{'coin', 12000}}, 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}}, - {price = {{'coin', 200}}, offer = {type = 'give-item', item = 'energy-shield-equipment', count = 1}}, - {price = {{'coin', 850}}, offer = {type = 'give-item', item = 'personal-laser-defense-equipment', count = 1}}, - {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}}, - {price = {{'coin', 200}}, offer = {type = 'give-item', item = 'belt-immunity-equipment', count = 1}}, - {price = {{'coin', 250}}, offer = {type = 'give-item', item = 'personal-roboport-equipment', count = 1}}, - {price = {{'coin', 35}}, offer = {type = 'give-item', item = 'construction-robot', count = 1}}, - {price = {{'coin', 25}}, offer = {type = 'give-item', item = 'cliff-explosives', count = 1}}, - {price = {{'coin', 80}}, offer = {type = 'nothing', effect_description = special_descriptions['flame-boots']}} - } - - for _, item in pairs(market_items) do - this.market.add_market_item(item) - end - - if not this.railgun_enhancer_unlocked then - this.market.add_market_item( - { - price = {{'coin', 1500}}, - offer = {type = 'nothing', effect_description = special_descriptions['railgun-enhancer']} - } - ) - end - if not this.trapped_capsules_unlocked then - this.market.add_market_item( - { - price = {{'coin', 3500}}, - offer = {type = 'nothing', effect_description = special_descriptions['trapped-capsules']} - } - ) - end - if not this.explosive_bullets_unlocked then - this.market.add_market_item( - { - price = {{'coin', 4500}}, - offer = {type = 'nothing', effect_description = special_descriptions['explosive-bullets']} - } - ) - end - if not this.bouncy_shells_unlocked then - this.market.add_market_item( - { - price = {{'coin', 10000}}, - offer = {type = 'nothing', effect_description = special_descriptions['bouncy-shells']} - } - ) - end - if not this.vehicle_nanobots_unlocked then - this.market.add_market_item( - { - price = {{'coin', 15000}}, - offer = {type = 'nothing', effect_description = special_descriptions['vehicle-nanobots']} - } - ) - end - --[[ - if not this.crumbly_walls_unlocked then - this.market.add_market_item({price = {{"coin", 35000}}, offer = {type = 'nothing', effect_description = special_descriptions["crumbly-walls"]}}) + 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 - if not this.ultra_mines_unlocked then - this.market.add_market_item({price = {{"coin", 45000}}, offer = {type = 'nothing', effect_description = special_descriptions["ultra-mines"]}}) + + local str1 = "Gun Turret Slot for " .. tostring(global.entity_limits["gun-turret"].limit * global.entity_limits["gun-turret"].slot_price) + str1 = str1 .. " Coins." + + local str2 = "Laser Turret Slot for " .. tostring(global.entity_limits["laser-turret"].limit * global.entity_limits["laser-turret"].slot_price) + str2 = str2 .. " Coins." + + local str3 = "Artillery Slot for " .. tostring(global.entity_limits["artillery-turret"].limit * global.entity_limits["artillery-turret"].slot_price) + str3 = str3 .. " Coins." + + 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) + str4 = str4 .. " Coins." + + local str5 = "Landmine Slot for " .. tostring(math.ceil((global.entity_limits["land-mine"].limit / 3) * global.entity_limits["land-mine"].slot_price)) + str5 = str5 .. " Coins." + + local market_items = { + {price = {}, offer = {type = 'nothing', effect_description = str1}}, + {price = {}, offer = {type = 'nothing', effect_description = str2}}, + {price = {}, offer = {type = 'nothing', effect_description = str3}}, + {price = {}, offer = {type = 'nothing', effect_description = str4}}, + {price = {}, offer = {type = 'nothing', effect_description = str5}}, + {price = {{"coin", 5}}, offer = {type = 'give-item', item = "raw-fish", count = 1}}, + {price = {{"coin", 1}}, offer = {type = 'give-item', item = 'wood', count = 8}}, + {price = {{"coin", 8}}, offer = {type = 'give-item', item = 'grenade', count = 1}}, + {price = {{"coin", 32}}, offer = {type = 'give-item', item = 'cluster-grenade', count = 1}}, + {price = {{"coin", 1}}, offer = {type = 'give-item', item = 'land-mine', count = 1}}, + {price = {{"coin", 80}}, offer = {type = 'give-item', item = 'car', count = 1}}, + {price = {{"coin", 1200}}, offer = {type = 'give-item', item = 'tank', count = 1}}, + {price = {{"coin", 3}}, offer = {type = 'give-item', item = 'cannon-shell', count = 1}}, + {price = {{"coin", 7}}, offer = {type = 'give-item', item = 'explosive-cannon-shell', count = 1}}, + {price = {{"coin", 50}}, offer = {type = 'give-item', item = 'gun-turret', count = 1}}, + {price = {{"coin", 300}}, offer = {type = 'give-item', item = 'laser-turret', count = 1}}, + {price = {{"coin", 450}}, offer = {type = 'give-item', item = 'artillery-turret', count = 1}}, + {price = {{"coin", 10}}, offer = {type = 'give-item', item = 'artillery-shell', count = 1}}, + {price = {{"coin", 25}}, offer = {type = 'give-item', item = 'artillery-targeting-remote', count = 1}}, + {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}}, + {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}}, + {price = {{"coin", 30}}, offer = {type = 'give-item', item = "submachine-gun", count = 1}}, + {price = {{"coin", 250}}, offer = {type = 'give-item', item = 'combat-shotgun', count = 1}}, + {price = {{"coin", 450}}, offer = {type = 'give-item', item = 'flamethrower', count = 1}}, + {price = {{"coin", 25}}, offer = {type = 'give-item', item = 'flamethrower-ammo', count = 1}}, + {price = {{"coin", 125}}, offer = {type = 'give-item', item = 'rocket-launcher', count = 1}}, + {price = {{"coin", 2}}, offer = {type = 'give-item', item = 'rocket', count = 1}}, + {price = {{"coin", 7}}, offer = {type = 'give-item', item = 'explosive-rocket', count = 1}}, + {price = {{"coin", 7500}}, offer = {type = 'give-item', item = 'atomic-bomb', count = 1}}, + {price = {{"coin", 325}}, offer = {type = 'give-item', item = 'railgun', count = 1}}, + {price = {{"coin", 8}}, offer = {type = 'give-item', item = 'railgun-dart', count = 1}}, + {price = {{"coin", 40}}, offer = {type = 'give-item', item = 'poison-capsule', count = 1}}, + {price = {{"coin", 4}}, offer = {type = 'give-item', item = 'defender-capsule', count = 1}}, + {price = {{"coin", 10}}, offer = {type = 'give-item', item = 'light-armor', count = 1}}, + {price = {{"coin", 125}}, 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}}, + {price = {{"coin", 12000}}, 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}}, + {price = {{"coin", 200}}, offer = {type = 'give-item', item = 'energy-shield-equipment', count = 1}}, + {price = {{"coin", 850}}, offer = {type = 'give-item', item = 'personal-laser-defense-equipment', count = 1}}, + {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}}, + {price = {{"coin", 200}}, offer = {type = 'give-item', item = 'belt-immunity-equipment', count = 1}}, + {price = {{"coin", 250}}, offer = {type = 'give-item', item = 'personal-roboport-equipment', count = 1}}, + {price = {{"coin", 35}}, offer = {type = 'give-item', item = 'construction-robot', count = 1}}, + {price = {{"coin", 25}}, offer = {type = 'give-item', item = 'cliff-explosives', count = 1}}, + {price = {{"coin", 80}}, offer = {type = 'nothing', effect_description = special_descriptions["flame-boots"]}} + } + + for _, item in pairs(market_items) do + global.market.add_market_item(item) + end + + if not global.railgun_enhancer_unlocked then + global.market.add_market_item({price = {{"coin", 1500}}, offer = {type = 'nothing', effect_description = special_descriptions["railgun-enhancer"]}}) + end + if not global.trapped_capsules_unlocked then + global.market.add_market_item({price = {{"coin", 3500}}, offer = {type = 'nothing', effect_description = special_descriptions["trapped-capsules"]}}) + end + if not global.explosive_bullets_unlocked then + global.market.add_market_item({price = {{"coin", 4500}}, offer = {type = 'nothing', effect_description = special_descriptions["explosive-bullets"]}}) + end + if not global.bouncy_shells_unlocked then + global.market.add_market_item({price = {{"coin", 10000}}, offer = {type = 'nothing', effect_description = special_descriptions["bouncy-shells"]}}) + end + if not global.vehicle_nanobots_unlocked then + global.market.add_market_item({price = {{"coin", 15000}}, offer = {type = 'nothing', effect_description = special_descriptions["vehicle-nanobots"]}}) + end + --[[ + if not global.crumbly_walls_unlocked then + global.market.add_market_item({price = {{"coin", 35000}}, offer = {type = 'nothing', effect_description = special_descriptions["crumbly-walls"]}}) + end + if not global.ultra_mines_unlocked then + global.market.add_market_item({price = {{"coin", 45000}}, offer = {type = 'nothing', effect_description = special_descriptions["ultra-mines"]}}) end ]] - if not this.laser_pointer_unlocked then - this.market.add_market_item( - { - price = {{'coin', 65000}}, - offer = {type = 'nothing', effect_description = special_descriptions['laser-pointer']} - } - ) - end + if not global.laser_pointer_unlocked then + global.market.add_market_item({price = {{"coin", 65000}}, offer = {type = 'nothing', effect_description = special_descriptions["laser-pointer"]}}) + end end local function slot_upgrade(player, offer_index) - local this = FDT.get() - local price = - this.entity_limits[slot_upgrade_offers[offer_index][1]].limit * - this.entity_limits[slot_upgrade_offers[offer_index][1]].slot_price - - local gain = 1 - if offer_index == 5 then - price = - math.ceil( - (this.entity_limits[slot_upgrade_offers[offer_index][1]].limit / 3) * - this.entity_limits[slot_upgrade_offers[offer_index][1]].slot_price - ) - gain = 3 - end - - if slot_upgrade_offers[offer_index][1] == 'flamethrower-turret' then - price = - (this.entity_limits[slot_upgrade_offers[offer_index][1]].limit + 1) * - this.entity_limits[slot_upgrade_offers[offer_index][1]].slot_price - end - - 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 false - end - - this.entity_limits[slot_upgrade_offers[offer_index][1]].limit = - this.entity_limits[slot_upgrade_offers[offer_index][1]].limit + gain - game.print( - player.name .. ' has bought a ' .. slot_upgrade_offers[offer_index][2] .. ' slot for ' .. price .. ' coins!', - {r = 0.22, g = 0.77, b = 0.44} - ) - if math.random(1, 2) == 1 then - Server.to_discord_bold( - table.concat { - '*** ' .. - player.name .. - ' has bought a ' .. - slot_upgrade_offers[offer_index][2] .. ' slot for ' .. price .. ' coins! ***' - } - ) - end - refresh_market_offers() + local price = global.entity_limits[slot_upgrade_offers[offer_index][1]].limit * global.entity_limits[slot_upgrade_offers[offer_index][1]].slot_price + + local gain = 1 + if offer_index == 5 then + price = math.ceil((global.entity_limits[slot_upgrade_offers[offer_index][1]].limit / 3) * global.entity_limits[slot_upgrade_offers[offer_index][1]].slot_price) + gain = 3 + end + + if slot_upgrade_offers[offer_index][1] == "flamethrower-turret" then + price = (global.entity_limits[slot_upgrade_offers[offer_index][1]].limit + 1) * global.entity_limits[slot_upgrade_offers[offer_index][1]].slot_price + end + + 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 false + end + + global.entity_limits[slot_upgrade_offers[offer_index][1]].limit = global.entity_limits[slot_upgrade_offers[offer_index][1]].limit + gain + game.print(player.name .. " has bought a " .. slot_upgrade_offers[offer_index][2] .. " slot for " .. price .. " coins!", {r = 0.22, g = 0.77, b = 0.44}) + Server.to_discord_bold(table.concat{player.name .. " has bought a " .. slot_upgrade_offers[offer_index][2] .. " slot for " .. price .. " coins!"}) + refresh_market_offers() end 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 this = FDT.get() - - if slot_upgrade_offers[offer_index] then - if slot_upgrade(player, offer_index) then - return - end - end - - if offer_index < 50 then - return - end - - if bought_offer.effect_description == special_descriptions['flame-boots'] then - game.print(player.name .. ' has bought themselves some flame boots.', {r = 0.22, g = 0.77, b = 0.44}) - if not this.flame_boots[player.index].fuel then - this.flame_boots[player.index].fuel = math.random(1500, 3000) - else - this.flame_boots[player.index].fuel = this.flame_boots[player.index].fuel + math.random(1500, 3000) - end - - player.print('Fuel remaining: ' .. this.flame_boots[player.index].fuel, {r = 0.22, g = 0.77, b = 0.44}) - refresh_market_offers() - return - end - - if bought_offer.effect_description == special_descriptions['explosive-bullets'] then - game.print(player.name .. ' has unlocked explosive bullets.', {r = 0.22, g = 0.77, b = 0.44}) - this.explosive_bullets_unlocked = true - refresh_market_offers() - return - end - - if bought_offer.effect_description == special_descriptions['bouncy-shells'] then - game.print(player.name .. ' has unlocked bouncy shells.', {r = 0.22, g = 0.77, b = 0.44}) - this.bouncy_shells_unlocked = true - refresh_market_offers() - return - end - - if bought_offer.effect_description == special_descriptions['trapped-capsules'] then - game.print(player.name .. ' has unlocked trapped capsules!', {r = 0.22, g = 0.77, b = 0.44}) - this.trapped_capsules_unlocked = true - refresh_market_offers() - return - end - - if bought_offer.effect_description == special_descriptions['ultra-mines'] then - game.print(player.name .. ' has unlocked ultra mines!', {r = 0.22, g = 0.77, b = 0.44}) - this.ultra_mines_unlocked = true - refresh_market_offers() - return - end - - if bought_offer.effect_description == special_descriptions['laser-pointer'] then - game.print(player.name .. ' has unleashed the quest to slay the red dot!', {r = 0.22, g = 0.77, b = 0.44}) - this.laser_pointer_unlocked = true - refresh_market_offers() - return - end - - if bought_offer.effect_description == special_descriptions['railgun-enhancer'] then - game.print(player.name .. ' has unlocked the enhanced railgun!', {r = 0.22, g = 0.77, b = 0.44}) - this.railgun_enhancer_unlocked = true - refresh_market_offers() - return - end - - if bought_offer.effect_description == special_descriptions['crumbly-walls'] then - game.print(player.name .. ' has unlocked crumbly walls!', {r = 0.22, g = 0.77, b = 0.44}) - this.crumbly_walls_unlocked = true - refresh_market_offers() - return - end - - if bought_offer.effect_description == special_descriptions['vehicle-nanobots'] then - game.print(player.name .. ' has unlocked vehicle nanobots!', {r = 0.22, g = 0.77, b = 0.44}) - this.vehicle_nanobots_unlocked = true - refresh_market_offers() - return - end + 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 + + if slot_upgrade_offers[offer_index] then + if slot_upgrade(player, offer_index) then return end + end + + if offer_index < 50 then return end + + if bought_offer.effect_description == special_descriptions["flame-boots"] then + game.print(player.name .. " has bought themselves some flame boots.", {r = 0.22, g = 0.77, b = 0.44}) + if not global.flame_boots[player.index].fuel then + global.flame_boots[player.index].fuel = math.random(1500, 3000) + else + global.flame_boots[player.index].fuel = global.flame_boots[player.index].fuel + math.random(1500, 3000) + end + + player.print("Fuel remaining: " .. global.flame_boots[player.index].fuel, {r = 0.22, g = 0.77, b = 0.44}) + refresh_market_offers() + return + end + + if bought_offer.effect_description == special_descriptions["explosive-bullets"] then + game.print(player.name .. " has unlocked explosive bullets.", {r = 0.22, g = 0.77, b = 0.44}) + global.explosive_bullets_unlocked = true + refresh_market_offers() + return + end + + if bought_offer.effect_description == special_descriptions["bouncy-shells"] then + game.print(player.name .. " has unlocked bouncy shells.", {r = 0.22, g = 0.77, b = 0.44}) + global.bouncy_shells_unlocked = true + refresh_market_offers() + return + end + + if bought_offer.effect_description == special_descriptions["trapped-capsules"] then + game.print(player.name .. " has unlocked trapped capsules!", {r = 0.22, g = 0.77, b = 0.44}) + global.trapped_capsules_unlocked = true + refresh_market_offers() + return + end + + if bought_offer.effect_description == special_descriptions["ultra-mines"] then + game.print(player.name .. " has unlocked ultra mines!", {r = 0.22, g = 0.77, b = 0.44}) + global.ultra_mines_unlocked = true + refresh_market_offers() + return + end + + if bought_offer.effect_description == special_descriptions["laser-pointer"] then + game.print(player.name .. " has unleashed the quest to slay the red dot!", {r = 0.22, g = 0.77, b = 0.44}) + global.laser_pointer_unlocked = true + refresh_market_offers() + return + end + + if bought_offer.effect_description == special_descriptions["railgun-enhancer"] then + game.print(player.name .. " has unlocked the enhanced railgun!", {r = 0.22, g = 0.77, b = 0.44}) + global.railgun_enhancer_unlocked = true + refresh_market_offers() + return + end + + if bought_offer.effect_description == special_descriptions["crumbly-walls"] then + game.print(player.name .. " has unlocked crumbly walls!", {r = 0.22, g = 0.77, b = 0.44}) + global.crumbly_walls_unlocked = true + refresh_market_offers() + return + end + + if bought_offer.effect_description == special_descriptions["vehicle-nanobots"] then + game.print(player.name .. " has unlocked vehicle nanobots!", {r = 0.22, g = 0.77, b = 0.44}) + global.vehicle_nanobots_unlocked = true + refresh_market_offers() + return + end end local function on_gui_opened(event) - if not event.entity then - return - end - if not event.entity.valid then - return - end - if event.entity.name == 'market' then - refresh_market_offers() - return - end + if not event.entity then return end + if not event.entity.valid then return end + if event.entity.name == "market" then refresh_market_offers() return end end -Event.add(defines.events.on_market_item_purchased, on_market_item_purchased) -Event.add(defines.events.on_gui_opened, on_gui_opened) +event.add(defines.events.on_market_item_purchased, on_market_item_purchased) +event.add(defines.events.on_gui_opened, on_gui_opened) \ No newline at end of file diff --git a/maps/fish_defender/on_entity_damaged.lua b/maps/fish_defender/on_entity_damaged.lua index 8493bd8d..dbb66a36 100644 --- a/maps/fish_defender/on_entity_damaged.lua +++ b/maps/fish_defender/on_entity_damaged.lua @@ -1,65 +1,42 @@ -require 'maps.fish_defender.boss_biters' +local event = require 'utils.event' -local Event = require 'utils.event' local enhance_railgun = require 'maps.fish_defender.railgun_enhancer' local explosive_bullets = require 'maps.fish_defender.explosive_gun_bullets' local bouncy_shells = require 'maps.fish_defender.bouncy_shells' -local FDT = require 'maps.fish_defender.table' +local boss_biter = require "maps.fish_defender.boss_biters" local function protect_market(event) - if event.entity.name ~= 'market' then - return - end - if event.cause then - if event.cause.force.name == 'enemy' then - return - end - end - event.entity.health = event.entity.health + event.final_damage_amount - return true + if event.entity.name ~= "market" then return end + if event.cause then + if event.cause.force.name == "enemy" then return end + end + event.entity.health = event.entity.health + event.final_damage_amount + return true end local function on_entity_damaged(event) - if not event.entity then - return - end - if not event.entity.valid then - return - end - - if protect_market(event) then - return - end - - if not event.cause then - return - end - local explosive_bullets_unlocked = FDT.get('explosive_bullets_unlocked') - local bouncy_shells_unlocked = FDT.get('bouncy_shells_unlocked') - - --if event.cause.unit_number then - -- if this.boss_biters[event.cause.unit_number] then - -- boss_biter.damaged_entity(event) - -- end - --end - - if event.cause.name ~= 'character' then - return - end - - if enhance_railgun(event) then - return - end - if explosive_bullets_unlocked then - if explosive_bullets(event) then - return - end - end - if bouncy_shells_unlocked then - if bouncy_shells(event) then - return - end - end + if not event.entity then return end + if not event.entity.valid then return end + + if protect_market(event) then return end + + if not event.cause then return end + + --if event.cause.unit_number then + -- if global.boss_biters[event.cause.unit_number] then + -- boss_biter.damaged_entity(event) + -- end + --end + + if event.cause.name ~= "character" then return end + + if enhance_railgun(event) then return end + if global.explosive_bullets_unlocked then + if explosive_bullets(event) then return end + end + if global.bouncy_shells_unlocked then + if bouncy_shells(event) then return end + end end -Event.add(defines.events.on_entity_damaged, on_entity_damaged) +event.add(defines.events.on_entity_damaged, on_entity_damaged) \ No newline at end of file diff --git a/maps/fish_defender/railgun_enhancer.lua b/maps/fish_defender/railgun_enhancer.lua index bea65690..685df209 100644 --- a/maps/fish_defender/railgun_enhancer.lua +++ b/maps/fish_defender/railgun_enhancer.lua @@ -1,157 +1,98 @@ -- improves the damage of the railgun and adds visual effects -- by mewmew -- laser turret research will increase it´s damage even further -- -local FDT = require 'maps.fish_defender.table' - local damage_min = 400 local damage_max = 800 local math_random = math.random local additional_visual_effects = true local biological_target_types = { - ['unit'] = true, - ['player'] = true, - ['turret'] = true, - ['unit-spawner'] = true + ["unit"] = true, + ["player"] = true, + ["turret"] = true, + ["unit-spawner"] = true } local function create_visuals(source_entity, target_entity) - if not source_entity.valid then - return - end - if not target_entity.valid then - return - end - if not additional_visual_effects then - return - end - local surface = target_entity.surface - surface.create_entity({name = 'water-splash', position = target_entity.position}) - if biological_target_types[target_entity.type] then - surface.create_entity({name = 'blood-explosion-big', position = target_entity.position}) - for x = -8, 8, 1 do - for y = -8, 8, 1 do - if math_random(1, 16) == 1 then - surface.create_entity( - { - name = 'blood-fountain', - position = {target_entity.position.x + (x * 0.1), target_entity.position.y + (y * 0.1)} - } - ) - surface.create_entity( - { - name = 'blood-fountain-big', - position = {target_entity.position.x + (x * 0.1), target_entity.position.y + (y * 0.1)} - } - ) - end - end - end - else - if math_random(1, 3) ~= 1 then - surface.create_entity({name = 'fire-flame', position = target_entity.position}) - end - for x = -3, 3, 1 do - for y = -3, 3, 1 do - if math_random(1, 3) == 1 then - surface.create_trivial_smoke( - { - name = 'smoke-fast', - position = {target_entity.position.x + (x * 0.35), target_entity.position.y + (y * 0.35)} - } - ) - end - if math_random(1, 5) == 1 then - surface.create_trivial_smoke( - { - name = 'train-smoke', - position = {target_entity.position.x + (x * 0.35), target_entity.position.y + (y * 0.35)} - } - ) - end - end - end - end + if not source_entity.valid then return end + if not target_entity.valid then return end + if not additional_visual_effects then return end + local surface = target_entity.surface + surface.create_entity({name = "water-splash", position = target_entity.position}) + if biological_target_types[target_entity.type] then + surface.create_entity({name = "blood-explosion-big", position = target_entity.position}) + for x = -8, 8, 1 do + for y = -8, 8, 1 do + if math_random(1, 16) == 1 then + surface.create_entity({name = "blood-fountain", position = {target_entity.position.x + (x * 0.1), target_entity.position.y + (y * 0.1)}}) + surface.create_entity({name = "blood-fountain-big", position = {target_entity.position.x + (x * 0.1), target_entity.position.y + (y * 0.1)}}) + end + end + end + else + if math_random(1, 3) ~= 1 then + surface.create_entity({name = "fire-flame", position = target_entity.position}) + end + for x = -3, 3, 1 do + for y = -3, 3, 1 do + if math_random(1, 3) == 1 then + surface.create_trivial_smoke({name="smoke-fast", position={target_entity.position.x + (x * 0.35), target_entity.position.y + (y * 0.35)}}) + end + if math_random(1, 5) == 1 then + surface.create_trivial_smoke({name="train-smoke", position={target_entity.position.x + (x * 0.35), target_entity.position.y + (y * 0.35)}}) + end + end + end + end end local function do_splash_damage_around_entity(source_entity, player) - if not source_entity.valid then - return - end - local research_damage_bonus = player.force.get_ammo_damage_modifier('laser-turret') + 1 - local research_splash_radius_bonus = player.force.get_ammo_damage_modifier('laser-turret') * 0.5 - local splash_area = { - { - source_entity.position.x - (2.5 + research_splash_radius_bonus), - source_entity.position.y - (2.5 + research_splash_radius_bonus) - }, - { - source_entity.position.x + (2.5 + research_splash_radius_bonus), - source_entity.position.y + (2.5 + research_splash_radius_bonus) - } - } - local entities = source_entity.surface.find_entities_filtered({area = splash_area}) - for _, entity in pairs(entities) do - if entity.valid then - if entity.health and entity ~= source_entity and entity ~= player then - if additional_visual_effects then - local surface = entity.surface - surface.create_entity( - { - name = 'railgun-beam', - position = source_entity.position, - source = source_entity.position, - target = entity.position - } - ) - surface.create_entity({name = 'water-splash', position = entity.position}) - if biological_target_types[entity.type] then - surface.create_entity({name = 'blood-fountain', position = entity.position}) - end - end - local damage = - math_random( - math.ceil((damage_min * research_damage_bonus) / 16), - math.ceil((damage_max * research_damage_bonus) / 16) - ) - entity.damage(damage, player.force, 'physical') - end - end - end + if not source_entity.valid then return end + local research_damage_bonus = player.force.get_ammo_damage_modifier("laser-turret") + 1 + local research_splash_radius_bonus = player.force.get_ammo_damage_modifier("laser-turret") * 0.5 + local splash_area = { + {source_entity.position.x - (2.5 + research_splash_radius_bonus), source_entity.position.y - (2.5 + research_splash_radius_bonus)}, + {source_entity.position.x + (2.5 + research_splash_radius_bonus), source_entity.position.y + (2.5 + research_splash_radius_bonus)} + } + local entities = source_entity.surface.find_entities_filtered({area = splash_area}) + for _, entity in pairs(entities) do + if entity.valid then + if entity.health and entity ~= source_entity and entity ~= player then + if additional_visual_effects then + local surface = entity.surface + surface.create_entity({name = "railgun-beam", position = source_entity.position, source = source_entity.position, target = entity.position}) + surface.create_entity({name = "water-splash", position = entity.position}) + if biological_target_types[entity.type] then + surface.create_entity({name = "blood-fountain", position = entity.position}) + end + end + local damage = math_random(math.ceil((damage_min * research_damage_bonus) / 16), math.ceil((damage_max * research_damage_bonus) / 16)) + entity.damage(damage, player.force, "physical") + end + end + end end local function enhance(event) - local railgun_enhancer_unlocked = FDT.get('railgun_enhancer_unlocked') - if not railgun_enhancer_unlocked then - return - end - if event.damage_type.name ~= 'physical' then - return - end - if event.original_damage_amount ~= 100 then - return - end - - local player = event.cause - if player.shooting_state.state == defines.shooting.not_shooting then - return - end - local selected_weapon = player.get_inventory(defines.inventory.character_guns)[player.selected_gun_index] - if selected_weapon.name ~= 'railgun' then - return - end - - create_visuals(event.cause, event.entity) - - do_splash_damage_around_entity(event.entity, player) - - event.entity.health = event.entity.health + event.final_damage_amount - - local research_damage_bonus = player.force.get_ammo_damage_modifier('laser-turret') + 1 - local damage = - math_random(math.ceil(damage_min * research_damage_bonus), math.ceil(damage_max * research_damage_bonus)) - event.entity.damage(damage, player.force, 'physical') - return true + if not global.railgun_enhancer_unlocked then return end + if event.damage_type.name ~= "physical" then return end + if event.original_damage_amount ~= 100 then return end + + local player = event.cause + if player.shooting_state.state == defines.shooting.not_shooting then return end + local selected_weapon = player.get_inventory(defines.inventory.character_guns)[player.selected_gun_index] + if selected_weapon.name ~= "railgun" then return end + + create_visuals(event.cause, event.entity) + + do_splash_damage_around_entity(event.entity, player) + + event.entity.health = event.entity.health + event.final_damage_amount + + local research_damage_bonus = player.force.get_ammo_damage_modifier("laser-turret") + 1 + local damage = math_random(math.ceil(damage_min * research_damage_bonus), math.ceil(damage_max * research_damage_bonus)) + event.entity.damage(damage, player.force, "physical") + return true end -return enhance +return enhance \ No newline at end of file diff --git a/maps/fish_defender/shotgun_buff.lua b/maps/fish_defender/shotgun_buff.lua index 09fa9ab3..43e0a4b2 100644 --- a/maps/fish_defender/shotgun_buff.lua +++ b/maps/fish_defender/shotgun_buff.lua @@ -1,31 +1,28 @@ -local Event = require 'utils.event' -local FDT = require 'maps.fish_defender.table' +local event = require 'utils.event' local gain_multiplier = 4 local function on_research_finished(event) - local research = event.research - local force_name = research.force.name - local this = FDT.get() - - if not this.shotgun_shell_damage_modifier_old[force_name] then - this.shotgun_shell_damage_modifier_old[force_name] = - game.forces[force_name].get_ammo_damage_modifier('shotgun-shell') - 0.1 - end - - if string.sub(research.name, 0, 26) == 'physical-projectile-damage' then - local current_damage = game.forces[force_name].get_ammo_damage_modifier('shotgun-shell') - local vanilla_gain = current_damage - this.shotgun_shell_damage_modifier_old[force_name] - local additional_gain = vanilla_gain * (gain_multiplier - 1) - game.forces[force_name].set_ammo_damage_modifier('shotgun-shell', current_damage + additional_gain) - end - - this.shotgun_shell_damage_modifier_old[force_name] = - game.forces[force_name].get_ammo_damage_modifier('shotgun-shell') + local research = event.research + local force_name = research.force.name + + if not global.shotgun_shell_damage_modifier_old[force_name] then global.shotgun_shell_damage_modifier_old[force_name] = game.forces[force_name].get_ammo_damage_modifier("shotgun-shell") - 0.1 end + + if string.sub(research.name, 0, 26) == "physical-projectile-damage" then + local current_damage = game.forces[force_name].get_ammo_damage_modifier("shotgun-shell") + local vanilla_gain = current_damage - global.shotgun_shell_damage_modifier_old[force_name] + local additional_gain = vanilla_gain * (gain_multiplier - 1) + game.forces[force_name].set_ammo_damage_modifier("shotgun-shell", current_damage + additional_gain) + end + + global.shotgun_shell_damage_modifier_old[force_name] = game.forces[force_name].get_ammo_damage_modifier("shotgun-shell") end local function on_init() - game.forces.player.set_ammo_damage_modifier('shotgun-shell', 1) + game.forces.player.set_ammo_damage_modifier("shotgun-shell", 1) + global.shotgun_shell_damage_modifier_old = {} end -Event.on_init(on_init) -Event.add(defines.events.on_research_finished, on_research_finished) +event.on_init(on_init) +event.add(defines.events.on_research_finished, on_research_finished) + + diff --git a/maps/fish_defender/table.lua b/maps/fish_defender/table.lua deleted file mode 100644 index 7ae96d72..00000000 --- a/maps/fish_defender/table.lua +++ /dev/null @@ -1,103 +0,0 @@ --- one table to rule them all! -local Global = require 'utils.global' -local Event = require 'utils.event' - -local this = {} -local Public = {} - -Global.register( - this, - function(tbl) - this = tbl - end -) - -function Public.reset_table() - -- @start - -- these 3 are in case of stop/start/reloading the instance. - this.soft_reset = true - this.restart = false - this.shutdown = false - this.announced_message = false - this.force_chunk = false - -- @end - this.game_has_ended = false - this.game_reset = false - this.spawn_area_generated = false - this.results_sent = false - - this.explosive_bullets_unlocked = false - this.bouncy_shells_unlocked = false - this.trapped_capsules_unlocked = false - this.ultra_mines_unlocked = false - this.laser_pointer_unlocked = false - this.railgun_enhancer_unlocked = false - this.crumbly_walls_unlocked = false - this.vehicle_nanobots_unlocked = false - this.game_restart_timer = nil - this.wave_count = 0 - this.attack_wave_threat = nil - this.market = nil - this.market_age = nil - this.last_reset = game.tick - this.wave_interval = 3600 - this.wave_grace_period = game.tick + 3600 * 20 - -- this.wave_grace_period = game.tick + 3600 - this.boss_biters = {} - this.acid_lines_delay = {} - this.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 = 20} - } - this.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} - } - this.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}} - } - this.comfylatron_habitat = { - left_top = {x = -1500, y = -1500}, - right_bottom = {x = -80, y = 1500} - } - this.map_height = 96 - this.shotgun_shell_damage_modifier_old = {} - this.flame_boots = {} -end - -function Public.get(key) - if key then - return this[key] - else - return this - end -end - -local on_init = function() - Public.reset_table() -end - -Event.on_init(on_init) - -return Public diff --git a/maps/fish_defender/terrain.lua b/maps/fish_defender/terrain.lua index 48d81680..b0122994 100644 --- a/maps/fish_defender/terrain.lua +++ b/maps/fish_defender/terrain.lua @@ -1,76 +1,48 @@ -local Event = require 'utils.event' -local map_functions = require 'tools.map_functions' -local simplex_noise = require 'utils.simplex_noise'.d2 -local FDT = require 'maps.fish_defender.table' -local Task = require 'utils.task' -local Token = require 'utils.token' +local map_functions = require "tools.map_functions" +local simplex_noise = require "utils.simplex_noise".d2 local math_random = math.random local math_abs = math.abs local math_floor = math.floor local math_sqrt = math.sqrt -local tiles_per_call = 16 -local total_calls = math.ceil(1024 / tiles_per_call) -local Public = {} - -local rock_raffle = { - 'sand-rock-big', - 'sand-rock-big', - 'rock-big', - 'rock-big', - 'rock-big', - 'rock-big', - 'rock-big', - 'rock-big', - 'rock-huge' -} - -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 hourglass_center_piece_length = 64 +local worm_raffle_table = { + [1] = {"small-worm-turret", "small-worm-turret", "small-worm-turret", "small-worm-turret", "small-worm-turret", "small-worm-turret"}, + [2] = {"small-worm-turret", "small-worm-turret", "small-worm-turret", "small-worm-turret", "small-worm-turret", "medium-worm-turret"}, + [3] = {"small-worm-turret", "small-worm-turret", "small-worm-turret", "small-worm-turret", "medium-worm-turret", "medium-worm-turret"}, + [4] = {"small-worm-turret", "small-worm-turret", "small-worm-turret", "medium-worm-turret", "medium-worm-turret", "medium-worm-turret"}, + [5] = {"small-worm-turret", "small-worm-turret", "medium-worm-turret", "medium-worm-turret", "medium-worm-turret", "big-worm-turret"}, + [6] = {"small-worm-turret", "medium-worm-turret", "medium-worm-turret", "medium-worm-turret", "medium-worm-turret", "big-worm-turret"}, + [7] = {"medium-worm-turret", "medium-worm-turret", "medium-worm-turret", "medium-worm-turret", "big-worm-turret", "big-worm-turret"}, + [8] = {"medium-worm-turret", "medium-worm-turret", "medium-worm-turret", "medium-worm-turret", "big-worm-turret", "big-worm-turret"}, + [9] = {"medium-worm-turret", "medium-worm-turret", "medium-worm-turret", "big-worm-turret", "big-worm-turret", "big-worm-turret"}, + [10] = {"medium-worm-turret", "medium-worm-turret", "big-worm-turret", "big-worm-turret", "big-worm-turret", "big-worm-turret"} + } +local rock_raffle = {"sand-rock-big","sand-rock-big","rock-big","rock-big","rock-big","rock-big","rock-big","rock-big","rock-huge"} local function get_replacement_tile(surface, position) - for i = 1, 128, 1 do - local vectors = {{0, i}, {0, i * -1}, {i, 0}, {i * -1, 0}} - shuffle(vectors) - for k, v in pairs(vectors) do - local tile = surface.get_tile(position.x + v[1], position.y + v[2]) - if not tile.collides_with('resource-layer') then - return tile.name - end - end - end - return 'grass-1' + for i = 1, 128, 1 do + local vectors = {{0, i}, {0, i * -1}, {i, 0}, {i * -1, 0}} + table.shuffle_table(vectors) + for k, v in pairs(vectors) do + local tile = surface.get_tile(position.x + v[1], position.y + v[2]) + if not tile.collides_with("resource-layer") then return tile.name end + end + end + return "grass-1" end local function is_enemy_territory(p) - if p.x - 64 < math_abs(p.y) then - return false - end - --if p.x - 64 < p.y then return false end - if p.x < 160 then - return false - end - if p.x > 1024 then - return false - end - if p.y > 512 then - return false - end - if p.y < -512 then - return false - end - local noise = math_abs(simplex_noise(0, p.y * 0.015, game.surfaces[1].map_gen_settings.seed) * 96) - local noise_2 = math_abs(simplex_noise(0, p.y * 0.1, game.surfaces[1].map_gen_settings.seed) * 16) - if p.x > 288 + noise + noise_2 + math_abs(p.y * 0.75) then - return false - end - return true + if p.x - 64 < math_abs(p.y) then return false end + --if p.x - 64 < p.y then return false end + if p.x < 160 then return false end + if p.x > 1024 then return false end + if p.y > 512 then return false end + if p.y < -512 then return false end + local noise = math_abs(simplex_noise(0, p.y * 0.015, game.surfaces[1].map_gen_settings.seed) * 96) + local noise_2 = math_abs(simplex_noise(0, p.y * 0.1, game.surfaces[1].map_gen_settings.seed) * 16) + if p.x > 288 + noise + noise_2 + math_abs(p.y * 0.75) then return false end + return true end local body_radius = 3072 @@ -85,494 +57,323 @@ local square_fin_radius = fin_radius ^ 2 local fin_circle_center_1 = {x = -480, y = 0} local fin_circle_center_2 = {x = -480 - 360, y = 0} -local function is_body(p) - local this = FDT.get() - if p.y <= this.map_height and p.y >= this.map_height * -1 and p.x <= 160 and p.x > body_center_position.x then - return true - end - - --Main Fish Body - local distance_to_center_1 = ((p.x - body_circle_center_1.x) ^ 2 + (p.y - body_circle_center_1.y) ^ 2) - local distance_to_center_2 = ((p.x - body_circle_center_2.x) ^ 2 + (p.y - body_circle_center_2.y) ^ 2) - --if distance_to_center_1 < body_square_radius and distance_to_center_2 < body_square_radius then return true end - if distance_to_center_1 < body_square_radius then - if distance_to_center_2 < body_square_radius then - return true - end - end - - --Fish Fins - distance_to_center_1 = ((p.x - fin_circle_center_1.x) ^ 2 + (p.y - fin_circle_center_1.y) ^ 2) - if - distance_to_center_1 + math_abs(simplex_noise(0, p.y * 0.075, game.surfaces[1].map_gen_settings.seed) * 32000) > - square_fin_radius - then - distance_to_center_2 = ((p.x - fin_circle_center_2.x) ^ 2 + (p.y - fin_circle_center_2.y) ^ 2) - if distance_to_center_2 < square_fin_radius then - return true - end - end - - return false +local function is_body(p) + if p.y <= map_height and p.y >= map_height * -1 and p.x <= 160 and p.x > body_center_position.x then return true end + + --Main Fish Body + local distance_to_center_1 = ((p.x - body_circle_center_1.x)^2 + (p.y - body_circle_center_1.y)^2) + local distance_to_center_2 = ((p.x - body_circle_center_2.x)^2 + (p.y - body_circle_center_2.y)^2) + --if distance_to_center_1 < body_square_radius and distance_to_center_2 < body_square_radius then return true end + if distance_to_center_1 < body_square_radius then + if distance_to_center_2 < body_square_radius then return true end + end + + --Fish Fins + local distance_to_center_1 = ((p.x - fin_circle_center_1.x)^2 + (p.y - fin_circle_center_1.y)^2) + if distance_to_center_1 + math_abs(simplex_noise(0, p.y * 0.075, game.surfaces[1].map_gen_settings.seed) * 32000) > square_fin_radius then + local distance_to_center_2 = ((p.x - fin_circle_center_2.x)^2 + (p.y - fin_circle_center_2.y)^2) + if distance_to_center_2 < square_fin_radius then + return true + end + end + + return false end local function is_out_of_map_tile(p) - if p.y > 850 then - return true - end - if p.y < -850 then - return true - end - if p.x < -3264 then - return true - end - if p.x > 800 then - return true - end - if is_enemy_territory(p) then - return false - end - if is_body(p) then - return false - end - return true + if p.y > 850 then return true end + if p.y < -850 then return true end + if p.x < -3264 then return true end + if p.x > 800 then return true end + if is_enemy_territory(p) then return false end + if is_body(p) then return false end + return true end -local function place_fish_market(surface, position) - local market = surface.create_entity({name = 'market', position = position, force = 'player'}) - market.minable = false - return market +local function generate_spawn_area(surface) + surface.request_to_generate_chunks({x = 0, y = 0}, 7) + surface.request_to_generate_chunks({x = 160, y = 0}, 5) + --surface.force_generate_chunk_requests() + if global.spawn_area_generated then return end + if not surface.is_chunk_generated({-7, 0}) then return end + if not surface.is_chunk_generated({5, 0}) then return end + global.spawn_area_generated = true + + local spawn_position_x = -128 + + surface.create_entity({name = "electric-beam", position = {160, -96}, source = {160, -96}, target = {160,96}}) + + for _, tile in pairs(surface.find_tiles_filtered({name = {"water", "deepwater"}, area = {{-160, -160},{160, 160}}})) do + local noise = math_abs(simplex_noise(tile.position.x * 0.02, tile.position.y * 0.02, game.surfaces[1].map_gen_settings.seed) * 16) + if tile.position.x > -160 + noise then surface.set_tiles({{name = get_replacement_tile(surface, tile.position), position = {tile.position.x, tile.position.y}}}, true) end + end + + for _, entity in pairs(surface.find_entities_filtered({type = {"resource", "cliff"}, area = {{spawn_position_x - 32, -256},{160, 256}}})) do + if is_body(entity.position) then + if entity.position.x > spawn_position_x - 32 + math_abs(simplex_noise(entity.position.x * 0.02, entity.position.y * 0.02, game.surfaces[1].map_gen_settings.seed) * 16) then + entity.destroy() + end + end + end + + 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 + + local y = 80 + local ore_positions = {{x = spawn_position_x - 52, y = y},{x = spawn_position_x - 52, y = y * 0.5},{x = spawn_position_x - 52, y = 0},{x = spawn_position_x - 52, y = y * -0.5},{x = spawn_position_x - 52, y = y * -1}} + table.shuffle_table(ore_positions) + map_functions.draw_smoothed_out_ore_circle(ore_positions[1], "copper-ore", surface, 15, 2500) + map_functions.draw_smoothed_out_ore_circle(ore_positions[2], "iron-ore", surface, 15, 2500) + map_functions.draw_smoothed_out_ore_circle(ore_positions[3], "coal", surface, 15, 1500) + map_functions.draw_smoothed_out_ore_circle(ore_positions[4], "stone", surface, 15, 1500) + map_functions.draw_noise_tile_circle({x = spawn_position_x - 20, y = 0}, "water", surface, 16) + map_functions.draw_oil_circle(ore_positions[5], "crude-oil", surface, 8, 200000) + + local pos = surface.find_non_colliding_position("market",{spawn_position_x, 0}, 50, 1) + global.market = place_fish_market(surface, pos) + + local r = 16 + for _, entity in pairs(surface.find_entities_filtered({area = {{global.market.position.x - r, global.market.position.y - r}, {global.market.position.x + r, global.market.position.y + r}}, type = "tree"})) do + local distance_to_center = math_sqrt((entity.position.x - global.market.position.x)^2 + (entity.position.y - global.market.position.y)^2) + if distance_to_center < r then + if math_random(1, r) > distance_to_center then entity.destroy() end + end + end + + local pos = surface.find_non_colliding_position("gun-turret",{spawn_position_x + 5, 1}, 50, 1) + local turret = surface.create_entity({name = "gun-turret", position = pos, force = "player"}) + turret.insert({name = "firearm-magazine", count = 32}) + + for x = -20, 20, 1 do + for y = -20, 20, 1 do + local pos = {x = global.market.position.x + x, y = global.market.position.y + y} + --local distance_to_center = math_sqrt(x^2 + y^2) + --if distance_to_center > 8 and distance_to_center < 15 then + local distance_to_center = x^2 + y^2 + if distance_to_center > 64 and distance_to_center < 225 then + if math_random(1,3) == 1 and surface.can_place_entity({name = "wooden-chest", position = pos, force = "player"}) then + local chest = surface.create_entity({name = "wooden-chest", position = pos, force = "player"}) + end + end + end + end + + local area = {{x = -160, y = -96}, {x = 160, y = 96}} + for _, tile in pairs(surface.find_tiles_filtered({name = "water", area = area})) do + if math_random(1, 32) == 1 then + surface.create_entity({name = "fish", position = tile.position}) + end + end + + local pos = surface.find_non_colliding_position("character",{spawn_position_x + 1, 4}, 50, 1) + game.forces["player"].set_spawn_position(pos, surface) + for _, player in pairs(game.connected_players) do + local pos = surface.find_non_colliding_position("character",{spawn_position_x + 1, 4}, 50, 1) + player.teleport(pos, surface) + end end local function enemy_territory(surface, left_top) - if left_top.x < 160 then - return - end - if left_top.x > 750 then - return - end - if left_top.y > 512 then - return - end - if left_top.y < -512 then - return - end - - local area = {{left_top.x, left_top.y}, {left_top.x + 32, left_top.y + 32}} - - if left_top.x > 256 then - for x = 0, 31, 1 do - for y = 0, 31, 1 do - local pos = {x = left_top.x + x, y = left_top.y + y} - if is_enemy_territory(pos) then - if math_random(1, 512) == 1 then - if surface.can_place_entity({name = 'biter-spawner', force = 'decoratives', position = pos}) then - local entity - if math_random(1, 4) == 1 then - entity = - surface.create_entity( - {name = 'spitter-spawner', force = 'decoratives', position = pos} - ) - else - entity = - surface.create_entity( - {name = 'biter-spawner', force = 'decoratives', position = pos} - ) - end - entity.active = false - entity.destructible = false - end - end - end - end - end - end - for _, entity in pairs(surface.find_entities_filtered({area = area, type = {'tree', 'cliff'}})) do - if is_enemy_territory(entity.position) then - entity.destroy() - end - end - for _, entity in pairs(surface.find_entities_filtered({area = area, type = 'resource'})) do - if is_enemy_territory(entity.position) then - surface.create_entity({name = 'uranium-ore', position = entity.position, amount = math_random(200, 8000)}) - entity.destroy() - end - end - for _, tile in pairs(surface.find_tiles_filtered({name = {'water', 'deepwater'}, area = area})) do - if is_enemy_territory(tile.position) then - surface.set_tiles( - {{name = get_replacement_tile(surface, tile.position), position = {tile.position.x, tile.position.y}}}, - true - ) - end - end + --surface.request_to_generate_chunks({x = 256, y = 0}, 16) + --surface.force_generate_chunk_requests() + + if left_top.x < 160 then return end + if left_top.x > 750 then return end + if left_top.y > 512 then return end + if left_top.y < -512 then return end + + local area = {{left_top.x, left_top.y},{left_top.x + 32, left_top.y + 32}} + + --local area = {{160, -512},{750, 512}} + --for _, tile in pairs(surface.find_tiles_filtered({area = area})) do + -- if is_enemy_territory(tile.position) then + -- surface.set_tiles({{name = "water-mud", position = {tile.position.x, tile.position.y}}}, true) + -- end + --end + if left_top.x > 256 then + for x = 0, 31, 1 do + for y = 0, 31, 1 do + local pos = {x = left_top.x + x, y = left_top.y + y} + if is_enemy_territory(pos) then + if math_random(1, 512) == 1 then + if surface.can_place_entity({name = "biter-spawner", force = "decoratives", position = pos}) then + local entity + if math_random(1,4) == 1 then + entity = surface.create_entity({name = "spitter-spawner", force = "decoratives", position = pos}) + else + entity = surface.create_entity({name = "biter-spawner", force = "decoratives", position = pos}) + end + entity.active = false + entity.destructible = false + end + end + --if pos.x % 32 == 0 and pos.y % 32 == 0 then + -- 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 + -- surface.regenerate_decorative(decorative_names, {{x=math_floor(pos.x/32),y=math_floor(pos.y/32)}}) + --end + end + end + end + end + for _, entity in pairs(surface.find_entities_filtered({area = area, type = {"tree", "cliff"}})) do + if is_enemy_territory(entity.position) then entity.destroy() end + end + for _, entity in pairs(surface.find_entities_filtered({area = area, type = "resource"})) do + if is_enemy_territory(entity.position) then + surface.create_entity({name = "uranium-ore", position = entity.position, amount = math_random(200, 8000)}) + entity.destroy() + end + end + for _, tile in pairs(surface.find_tiles_filtered({name = {"water", "deepwater"}, area = area})) do + if is_enemy_territory(tile.position) then + surface.set_tiles({{name = get_replacement_tile(surface, tile.position), position = {tile.position.x, tile.position.y}}}, true) + end + end end local function fish_mouth(surface, left_top) - if left_top.x > -2300 then - return - end - if left_top.y > 64 then - return - end - if left_top.y < -64 then - return - end - if left_top.x < -3292 then - return - end + if left_top.x > -2300 then return end + if left_top.y > 64 then return end + if left_top.y < -64 then return end + if left_top.x < -3292 then return end - for x = 0, 31, 1 do - for y = 0, 31, 1 do - local pos = {x = left_top.x + x, y = left_top.y + y} - local noise = simplex_noise(pos.x * 0.006, 0, game.surfaces[1].map_gen_settings.seed) * 20 - if pos.y <= 12 + noise and pos.y >= -12 + noise then - surface.set_tiles({{name = 'water', position = pos}}) - end - end - end + for x = 0, 31, 1 do + for y = 0, 31, 1 do + local pos = {x = left_top.x + x, y = left_top.y + y} + local noise = simplex_noise(pos.x * 0.006, 0, game.surfaces[1].map_gen_settings.seed) * 20 + if pos.y <= 12 + noise and pos.y >= -12 + noise then surface.set_tiles({{name = "water", position = pos}}) end + end + end end -local ores = {'coal', 'iron-ore', 'copper-ore', 'stone'} +function fish_eye(surface, position) + surface.request_to_generate_chunks(position, 2) + surface.force_generate_chunk_requests() + for x = -48, 48, 1 do + for y = -48, 48, 1 do + local p = {x = position.x + x, y = position.y + y} + --local distance = math_sqrt(((position.x - p.x) ^ 2) + ((position.y - p.y) ^ 2)) + --if distance < 44 then + -- surface.set_tiles({{name = "water-green", position = p}}, true) + --end + --if distance < 22 then + -- surface.set_tiles({{name = "out-of-map", position = p}}, true) + --end -local function plankton_territory(surface, position, seed) - local noise = simplex_noise(position.x * 0.009, position.y * 0.009, seed) - local d = 196 - if - position.x + position.y > (d * -1) - (math_abs(noise) * d * 3) and - position.x > position.y - (d + (math_abs(noise) * d * 3)) - then - return 'out-of-map' - end - - local noise_2 = simplex_noise(position.x * 0.0075, position.y * 0.0075, seed + 10000) - --if noise_2 > 0.87 then surface.set_tiles({{name = "deepwater-green", position = position}}, true) return true end - if noise_2 > 0.87 then - return 'deepwater-green' - end - if noise_2 > 0.75 then - local i = math_floor(noise * 6) % 4 + 1 - --surface.set_tiles({{name = "grass-" .. i, position = position}}, true) - surface.create_entity({name = ores[i], position = position, amount = 1 + 2500 * math_abs(noise_2 * 3)}) - return ('grass-' .. i) - end - if noise_2 < -0.76 then - local i = math_floor(noise * 6) % 4 + 1 - --surface.set_tiles({{name = "grass-" .. i, position = position}}, true) - if noise_2 < -0.86 then - surface.create_entity( - {name = 'uranium-ore', position = position, amount = 1 + 1000 * math_abs(noise_2 * 2)} - ) - return ('grass-' .. i) - end - if math_random(1, 3) ~= 1 then - surface.create_entity({name = rock_raffle[math_random(1, #rock_raffle)], position = position}) - end - return ('grass-' .. i) - end - - if noise < 0.12 and noise > -0.12 then - local i = math_floor(noise * 32) % 4 + 1 - --surface.set_tiles({{name = "grass-" .. i, position = position}}, true) - if math_random(1, 5) == 1 then - surface.create_entity({name = rock_raffle[math_random(1, #rock_raffle)], position = position}) - end - return ('grass-' .. i) - end - - --surface.set_tiles({{name = "water", position = position}}, true) - if math_random(1, 128) == 1 then - surface.create_entity({name = 'fish', position = position}) - end - - return 'water' + local distance = ((position.x - p.x) ^ 2) + ((position.y - p.y) ^ 2) + if distance < 1936 then + if distance < 484 then + surface.set_tiles({{name = "out-of-map", position = p}}, true) + else + surface.set_tiles({{name = "water-green", position = p}}, true) + end + end + + end + end end -local function render_market_hp() - local this = FDT.get() - local surface = game.surfaces[this.active_surface_index] - if not surface or not surface.valid then - return - end +local ores = {"coal", "iron-ore", "copper-ore", "stone"} - this.health_text = - rendering.draw_text { - text = 'HP: ' .. this.market_health .. ' / ' .. this.market_max_health, - surface = surface, - target = this.market, - target_offset = {0, -3}, - color = {0, 255, 0}, - scale = 1.40, - font = 'default-game', - alignment = 'center', - scale_with_zoom = false - } - - this.caption = - rendering.draw_text { - text = 'Fish Market', - surface = surface, - target = this.market, - target_offset = {0, -4.4}, - color = {0, 255, 0}, - scale = 1.80, - font = 'default-game', - alignment = 'center', - scale_with_zoom = false - } -end - -local function generate_spawn_area(this, surface) - if this.spawn_area_generated then - return - end - - surface.request_to_generate_chunks({x = 0, y = 0}, 7) - surface.request_to_generate_chunks({x = 160, y = 0}, 4) - --surface.force_generate_chunk_requests() - - if not surface.is_chunk_generated({-7, 0}) then - return - end - if not surface.is_chunk_generated({5, 0}) then - return - end - - local spawn_position_x = -128 - - surface.create_entity({name = 'electric-beam', position = {160, -96}, source = {160, -96}, target = {160, 96}}) - - for _, tile in pairs( - surface.find_tiles_filtered({name = {'water', 'deepwater'}, area = {{-160, -160}, {160, 160}}}) - ) do - local noise = - math_abs( - simplex_noise(tile.position.x * 0.02, tile.position.y * 0.02, game.surfaces[1].map_gen_settings.seed) * 16 - ) - if tile.position.x > -160 + noise then - surface.set_tiles( - {{name = get_replacement_tile(surface, tile.position), position = {tile.position.x, tile.position.y}}}, - true - ) - end - end - - for _, entity in pairs( - surface.find_entities_filtered( - {type = {'resource', 'cliff'}, area = {{spawn_position_x - 32, -256}, {160, 256}}} - ) - ) do - if is_body(entity.position) then - if - entity.position.x > - spawn_position_x - 32 + - math_abs( - simplex_noise( - entity.position.x * 0.02, - entity.position.y * 0.02, - game.surfaces[1].map_gen_settings.seed - ) * 16 - ) - then - entity.destroy() - end - end - end - - 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 - - local y = 80 - local ore_positions = { - {x = spawn_position_x - 52, y = y}, - {x = spawn_position_x - 52, y = y * 0.5}, - {x = spawn_position_x - 52, y = 0}, - {x = spawn_position_x - 52, y = y * -0.5}, - {x = spawn_position_x - 52, y = y * -1} - } - shuffle(ore_positions) - map_functions.draw_smoothed_out_ore_circle(ore_positions[1], 'copper-ore', surface, 15, 2500) - map_functions.draw_smoothed_out_ore_circle(ore_positions[2], 'iron-ore', surface, 15, 2500) - map_functions.draw_smoothed_out_ore_circle(ore_positions[3], 'coal', surface, 15, 1500) - map_functions.draw_smoothed_out_ore_circle(ore_positions[4], 'stone', surface, 15, 1500) - map_functions.draw_noise_tile_circle({x = spawn_position_x - 20, y = 0}, 'water', surface, 16) - map_functions.draw_oil_circle(ore_positions[5], 'crude-oil', surface, 8, 200000) - - local pos = surface.find_non_colliding_position('market', {spawn_position_x, 0}, 50, 1) - this.market = place_fish_market(surface, pos) - - render_market_hp() - - local r = 16 - for _, entity in pairs( - surface.find_entities_filtered( - { - area = { - {this.market.position.x - r, this.market.position.y - r}, - {this.market.position.x + r, this.market.position.y + r} - }, - type = 'tree' - } - ) - ) do - local distance_to_center = - math_sqrt( - (entity.position.x - this.market.position.x) ^ 2 + (entity.position.y - this.market.position.y) ^ 2 - ) - if distance_to_center < r then - if math_random(1, r) > distance_to_center then - entity.destroy() - end - end - end - - local pos = surface.find_non_colliding_position('gun-turret', {spawn_position_x + 5, 1}, 50, 1) - local turret = surface.create_entity({name = 'gun-turret', position = pos, force = 'player'}) - turret.insert({name = 'firearm-magazine', count = 32}) - - for x = -20, 20, 1 do - for y = -20, 20, 1 do - local pos = {x = this.market.position.x + x, y = this.market.position.y + y} - --local distance_to_center = math_sqrt(x^2 + y^2) - --if distance_to_center > 8 and distance_to_center < 15 then - local distance_to_center = x ^ 2 + y ^ 2 - if distance_to_center > 64 and distance_to_center < 225 then - if - math_random(1, 3) == 1 and - surface.can_place_entity({name = 'wooden-chest', position = pos, force = 'player'}) - then - surface.create_entity({name = 'wooden-chest', position = pos, force = 'player'}) - end - end - end - end - - local area = {{x = -160, y = -96}, {x = 160, y = 96}} - for _, tile in pairs(surface.find_tiles_filtered({name = 'water', area = area})) do - if math_random(1, 32) == 1 then - surface.create_entity({name = 'fish', position = tile.position}) - end - end - - local pos = surface.find_non_colliding_position('character', {spawn_position_x + 1, 4}, 50, 1) - game.forces['player'].set_spawn_position(pos, surface) - for _, player in pairs(game.connected_players) do - local pos = surface.find_non_colliding_position('character', {spawn_position_x + 1, 4}, 50, 1) - player.teleport(pos, surface) - end - this.spawn_area_generated = true +local function plankton_territory(surface, position, seed) + local noise = simplex_noise(position.x * 0.009, position.y * 0.009, seed) + local d = 196 + local tile_to_set = "out-of-map" + if position.x + position.y > (d * -1) - (math_abs(noise) * d * 3) and position.x > position.y - (d + (math_abs(noise) * d * 3)) then return "out-of-map" end + + local noise_2 = simplex_noise(position.x * 0.0075, position.y * 0.0075, seed + 10000) + --if noise_2 > 0.87 then surface.set_tiles({{name = "deepwater-green", position = position}}, true) return true end + if noise_2 > 0.87 then return "deepwater-green" end + if noise_2 > 0.75 then + local i = math_floor(noise * 6) % 4 + 1 + --surface.set_tiles({{name = "grass-" .. i, position = position}}, true) + surface.create_entity({name = ores[i], position = position, amount = 1 + 2500 * math_abs(noise_2 * 3)}) + return ("grass-" .. i) + end + if noise_2 < -0.76 then + local i = math_floor(noise * 6) % 4 + 1 + --surface.set_tiles({{name = "grass-" .. i, position = position}}, true) + if noise_2 < -0.86 then surface.create_entity({name = "uranium-ore", position = position, amount = 1 + 1000 * math_abs(noise_2 * 2)}) return ("grass-" .. i) end + if math_random(1, 3) ~= 1 then surface.create_entity({name = rock_raffle[math_random(1, #rock_raffle)], position = position}) end + return ("grass-" .. i) + end + + if noise < 0.12 and noise > -0.12 then + local i = math_floor(noise * 32) % 4 + 1 + --surface.set_tiles({{name = "grass-" .. i, position = position}}, true) + if math_random(1, 5) == 1 then surface.create_entity({name = rock_raffle[math_random(1, #rock_raffle)], position = position}) end + return ("grass-" .. i) + end + + --surface.set_tiles({{name = "water", position = position}}, true) + if math_random(1, 128) == 1 then surface.create_entity({name = "fish", position = position}) end + + return "water" end local function process_chunk(left_top) - local this = FDT.get() - local surface = game.surfaces[this.active_surface_index] - if not surface or not surface.valid then - return - end - - local seed = game.surfaces[1].map_gen_settings.seed - - generate_spawn_area(this, surface, left_top) - enemy_territory(surface, left_top) - fish_mouth(surface, left_top) - - local tiles = {} - - for x = 0, 31, 1 do - for y = 0, 31, 1 do - local pos = {x = left_top.x + x, y = left_top.y + y} - if is_out_of_map_tile(pos) then - --if not plankton_territory(surface, pos, seed) then surface.set_tiles({{name = "out-of-map", position = pos}}, true) end - local tile_to_set = plankton_territory(surface, pos, seed) - --local tile_to_set = "out-of-map" - tiles[#tiles + 1] = {name = tile_to_set, position = pos} - end - end - end - - surface.set_tiles(tiles, true) - - --if game.tick == 0 then return end - --if game.forces.player.is_chunk_charted(surface, {left_top.x / 32, left_top.y / 32}) then - game.forces.player.chart(surface, {{left_top.x, left_top.y}, {left_top.x + 31, left_top.y + 31}}) - --end - if this.market and this.market.valid then - this.game_reset = false - end + local surface = game.surfaces["fish_defender"] + local seed = game.surfaces[1].map_gen_settings.seed + + generate_spawn_area(surface) + enemy_territory(surface, left_top) + fish_mouth(surface, left_top) + + local tiles = {} + + for x = 0, 31, 1 do + for y = 0, 31, 1 do + local pos = {x = left_top.x + x, y = left_top.y + y} + if is_out_of_map_tile(pos) then + --if not plankton_territory(surface, pos, seed) then surface.set_tiles({{name = "out-of-map", position = pos}}, true) end + local tile_to_set = plankton_territory(surface, pos, seed) + --local tile_to_set = "out-of-map" + table.insert(tiles, {name = tile_to_set, position = pos}) + end + end + end + + surface.set_tiles(tiles,true) + + --if game.tick == 0 then return end + --if game.forces.player.is_chunk_charted(surface, {left_top.x / 32, left_top.y / 32}) then + game.forces.player.chart(surface, {{left_top.x, left_top.y},{left_top.x + 31, left_top.y + 31}}) + --end end -local process_chunk_queue = - Token.register( - function(data) - local chunk_queue = data.chunk_queue - - for i = 1, #chunk_queue do - local pos = {x = chunk_queue[i].x, y = chunk_queue[i].y} - process_chunk(pos) - chunk_queue[i] = nil - end - end -) +local function process_chunk_queue() + for k, left_top in pairs(global.chunk_queue) do + process_chunk(left_top) + table.remove(global.chunk_queue, k) + return + end +end local function on_chunk_generated(event) - local map_name = 'fish_defender' - - if string.sub(event.surface.name, 0, #map_name) ~= map_name then - return - end - local left_top = event.area.left_top - local this = FDT.get() - if this.game_has_ended then - return - end - - if game.tick == 0 or this.game_reset or this.force_chunk then - process_chunk(left_top) - else - global.chunk_queue[#global.chunk_queue + 1] = {x = left_top.x, y = left_top.y} - - local data = { - chunk_queue = global.chunk_queue - } - Task.set_timeout_in_ticks(total_calls, process_chunk_queue, data) - end + if game.surfaces["fish_defender"].index ~= event.surface.index then return end + local left_top = event.area.left_top + + if game.tick == 0 then + process_chunk(left_top) + else + table.insert(global.chunk_queue, {x = left_top.x, y = left_top.y}) + end end -function Public.fish_eye(surface, position) - surface.request_to_generate_chunks(position, 2) - surface.force_generate_chunk_requests() - for x = -48, 48, 1 do - for y = -48, 48, 1 do - local p = {x = position.x + x, y = position.y + y} - --local distance = math_sqrt(((position.x - p.x) ^ 2) + ((position.y - p.y) ^ 2)) - --if distance < 44 then - -- surface.set_tiles({{name = "water-green", position = p}}, true) - --end - --if distance < 22 then - -- surface.set_tiles({{name = "out-of-map", position = p}}, true) - --end - - local distance = ((position.x - p.x) ^ 2) + ((position.y - p.y) ^ 2) - if distance < 1936 then - if distance < 484 then - surface.set_tiles({{name = 'out-of-map', position = p}}, true) - else - surface.set_tiles({{name = 'water-green', position = p}}, true) - end - end - end - end -end - -Event.add(defines.events.on_chunk_generated, on_chunk_generated) - -return Public +local event = require 'utils.event' +event.on_nth_tick(25, process_chunk_queue) +event.add(defines.events.on_chunk_generated, on_chunk_generated) \ No newline at end of file diff --git a/maps/fish_defender/trapped_capsules.lua b/maps/fish_defender/trapped_capsules.lua index fdd9f89d..c287b768 100644 --- a/maps/fish_defender/trapped_capsules.lua +++ b/maps/fish_defender/trapped_capsules.lua @@ -1,61 +1,44 @@ -local Event = require 'utils.event' -local FDT = require 'maps.fish_defender.table' +local event = require 'utils.event' local radius = 20 local whitelist = { - ['defender'] = 'explosive-cannon-projectile', - ['distractor'] = 'explosive-uranium-cannon-projectile', - ['destroyer'] = 'explosive-uranium-cannon-projectile' + ["defender"] = "explosive-cannon-projectile", + ["distractor"] = "explosive-uranium-cannon-projectile", + ["destroyer"] = "explosive-uranium-cannon-projectile" } local function on_entity_died(event) - local trapped_capsules_unlocked = FDT.get('trapped_capsules_unlocked') - if not trapped_capsules_unlocked then - return - end - - if not event.entity.valid then - return - end - if not whitelist[event.entity.name] then - return - end - - local valid_targets = {} - local position = event.entity.position - - for _, e in pairs( - event.entity.surface.find_entities_filtered( - { - area = {{position.x - radius, position.y - radius}, {position.x + radius, position.y + radius}}, - force = 'enemy' - } - ) - ) do - if e.health then - local distance_from_center = math.sqrt((e.position.x - position.x) ^ 2 + (e.position.y - position.y) ^ 2) - if distance_from_center <= radius then - valid_targets[#valid_targets + 1] = e - end - end - end - - if not valid_targets[1] then - return - end - - event.entity.surface.create_entity( - { - name = whitelist[event.entity.name], - position = position, - force = 'player', - source = position, - target = valid_targets[math.random(1, #valid_targets)].position, - max_range = 20, - speed = 0.1 - } - ) + if not global.trapped_capsules_unlocked then return end + + if not event.entity.valid then return end + if not whitelist[event.entity.name] then return end + + local valid_targets = {} + local position = event.entity.position + + for _, e in pairs(event.entity.surface.find_entities_filtered({area = {{position.x - radius, position.y - radius},{position.x + radius, position.y + radius}}, force = "enemy"})) do + if e.health then + local distance_from_center = math.sqrt((e.position.x - position.x) ^ 2 + (e.position.y - position.y) ^ 2) + if distance_from_center <= radius then + valid_targets[#valid_targets + 1] = e + end + end + end + + if not valid_targets[1] then return end + + event.entity.surface.create_entity({ + name = whitelist[event.entity.name], + position = position, + force = "player", + source = position, + target = valid_targets[math.random(1, #valid_targets)].position, + max_range = 20, + speed = 0.1 + }) end -Event.add(defines.events.on_entity_died, on_entity_died) +event.add(defines.events.on_entity_died, on_entity_died) + + diff --git a/maps/fish_defender/ultra_mines.lua b/maps/fish_defender/ultra_mines.lua index 0773b0eb..63e2d402 100644 --- a/maps/fish_defender/ultra_mines.lua +++ b/maps/fish_defender/ultra_mines.lua @@ -1,52 +1,34 @@ -local Event = require 'utils.event' -local FDT = require 'maps.fish_defender.table' +local event = require 'utils.event' local radius = 8 local function damage_entities_around_target(entity, damage) - for _, e in pairs( - entity.surface.find_entities_filtered( - { - area = { - {entity.position.x - radius, entity.position.y - radius}, - {entity.position.x + radius, entity.position.y + radius} - } - } - ) - ) do - if e.health then - if e.force.name ~= 'player' then - local distance_from_center = - math.sqrt((e.position.x - entity.position.x) ^ 2 + (e.position.y - entity.position.y) ^ 2) - if distance_from_center <= radius then - e.damage(damage, 'player', 'explosion') - end - end - end - end + for _, e in pairs(entity.surface.find_entities_filtered({area = {{entity.position.x - radius, entity.position.y - radius},{entity.position.x + radius, entity.position.y + radius}}})) do + if e.health then + if e.force.name ~= "player" then + local distance_from_center = math.sqrt((e.position.x - entity.position.x) ^ 2 + (e.position.y - entity.position.y) ^ 2) + if distance_from_center <= radius then + e.damage(damage, "player", "explosion") + end + end + end + end end local function on_entity_died(event) - local ultra_mines_unlocked = FDT.get('ultra_mines_unlocked') - if not ultra_mines_unlocked then - return - end - if not event.entity.valid then - return - end - if event.entity.name ~= 'land-mine' then - return - end - - event.entity.surface.create_entity( - { - name = 'big-artillery-explosion', - position = event.entity.position - } - ) - - local damage = (1 + event.entity.force.get_ammo_damage_modifier('grenade')) * 250 - - damage_entities_around_target(event.entity, damage) + if not global.ultra_mines_unlocked then return end + if not event.entity.valid then return end + if event.entity.name ~= "land-mine" then return end + + event.entity.surface.create_entity({ + name = "big-artillery-explosion", + position = event.entity.position + }) + + local damage = (1 + event.entity.force.get_ammo_damage_modifier("grenade")) * 250 + + damage_entities_around_target(event.entity, damage) end -Event.add(defines.events.on_entity_died, on_entity_died) +event.add(defines.events.on_entity_died, on_entity_died) + + diff --git a/maps/fish_defender/vehicle_nanobots.lua b/maps/fish_defender/vehicle_nanobots.lua index 5bc654e5..dbb82a26 100644 --- a/maps/fish_defender/vehicle_nanobots.lua +++ b/maps/fish_defender/vehicle_nanobots.lua @@ -1,10 +1,7 @@ local Event = require 'utils.event' -local FDT = require 'maps.fish_defender.table' local function on_player_changed_position(event) - local vehicle_nanobots_unlocked = FDT.get('vehicle_nanobots_unlocked') - - if not vehicle_nanobots_unlocked then + if not global.vehicle_nanobots_unlocked then return end local player = game.players[event.player_index] From 92ced6c64a1259d324e1f400305b56cd5272cd29 Mon Sep 17 00:00:00 2001 From: Gerkiz Date: Sun, 12 Jul 2020 21:01:11 +0200 Subject: [PATCH 5/6] minor fix --- maps/fish_defender_v2/main.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/maps/fish_defender_v2/main.lua b/maps/fish_defender_v2/main.lua index 0d346201..07d6b860 100644 --- a/maps/fish_defender_v2/main.lua +++ b/maps/fish_defender_v2/main.lua @@ -1368,7 +1368,7 @@ local function has_the_game_ended() game.print('Soft-reset is disabled. Server will restart!', {r = 0.22, g = 0.88, b = 0.22}) local message = 'Soft-reset is disabled. Server will restart!' Server.to_discord_bold(table.concat {'*** ', message, ' ***'}) - Server.start_scenario('Fish_Defender') + Server.start_scenario('Fish_Defender_v2') this.announced_message = true return end From c2829984feb064265c537577f423224614ab9291 Mon Sep 17 00:00:00 2001 From: Gerkiz Date: Sun, 12 Jul 2020 21:11:43 +0200 Subject: [PATCH 6/6] minor fix --- maps/fish_defender_v2/commands.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/maps/fish_defender_v2/commands.lua b/maps/fish_defender_v2/commands.lua index 7d3a522b..f88900a6 100644 --- a/maps/fish_defender_v2/commands.lua +++ b/maps/fish_defender_v2/commands.lua @@ -62,7 +62,7 @@ commands.add_command( elseif param == 'restartnow' then this.reset_are_you_sure = nil p(player.name .. ' has restarted the game.') - Server.start_scenario('Fish_Defender') + Server.start_scenario('Fish_Defender_v2') return elseif param == 'shutdown' then if this.shutdown then