From 06687500d05a6090635352aac9fa3af492c3218e Mon Sep 17 00:00:00 2001 From: MewMew <=> Date: Sat, 16 Mar 2019 07:31:34 +0100 Subject: [PATCH] biter_battles_v2 update --- maps/biter_battles_v2/ai.lua | 110 +++++++++++++++ maps/biter_battles_v2/biter_battles_v2.lua | 4 +- maps/biter_battles_v2/feeding.lua | 59 ++------ maps/biter_battles_v2/game_won.lua | 137 ++++++++++++++----- maps/biter_battles_v2/gui.lua | 9 +- maps/biter_battles_v2/on_tick.lua | 15 +- maps/biter_battles_v2/pregenerate_chunks.lua | 2 +- 7 files changed, 247 insertions(+), 89 deletions(-) diff --git a/maps/biter_battles_v2/ai.lua b/maps/biter_battles_v2/ai.lua index eadbbd6c..3f86ced6 100644 --- a/maps/biter_battles_v2/ai.lua +++ b/maps/biter_battles_v2/ai.lua @@ -1,6 +1,27 @@ local event = require 'utils.event' +local math_random = math.random local ai = {} +local threat_values = { + ["small-spitter"] = 2, + ["small-biter"] = 2, + ["medium-spitter"] = 4, + ["medium-biter"] = 4, + ["big-spitter"] = 8, + ["big-biter"] = 8, + ["behemoth-spitter"] = 16, + ["behemoth-biter"] = 16 +} + +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 + ai.send_near_biter_to_silo = function() if not global.rocket_silo then return end game.surfaces["surface"].set_multi_command({ @@ -26,4 +47,93 @@ ai.send_near_biter_to_silo = function() }) end +local function get_random_close_spawner(surface, biter_force_name) + local spawners = surface.find_entities_filtered({type = "unit-spawner", force = biter_force_name}) + if not spawners[1] then return false end + spawners = shuffle(spawners) + local spawner = spawners[1] + for i = 2, 4, 1 do + if not spawners[i] then return spawner end + if spawners[i].position.x ^ 2 + spawners[i].position.y ^ 2 < spawner.position.x ^ 2 + spawner.position.y ^ 2 then spawner = spawners[i] end + end + return spawner +end + +local function select_units_around_spawner(spawner, force_name, biter_force_name) + local biters = spawner.surface.find_enemy_units(spawner.position, 128, force_name) + if not biters[1] then return false end + local valid_biters = {} + local threat = global.bb_threat[biter_force_name] * 0.5 + for _, biter in pairs(biters) do + valid_biters[#valid_biters + 1] = biter + threat = threat - threat_values[biter.name] + if threat < 0 then return valid_biters end + end +end + +local function send_group(unit_group, force_name, nearest_player_unit) + unit_group.set_command({ + type = defines.command.compound, + structure_type = defines.compound_command.return_last, + commands = { + { + type = defines.command.attack_area, + destination = nearest_player_unit.position, + radius = 32, + distraction=defines.distraction.by_enemy + }, + { + type = defines.command.attack, + target = global.rocket_silo[force_name], + distraction = defines.distraction.by_enemy + } + } + }) + return true +end + +local function create_attack_group(surface, force_name, biter_force_name) + if global.bb_threat[biter_force_name] <= 0 then return false end + local spawner = get_random_close_spawner(surface, biter_force_name) + if not spawner then return false end --game.print("no unit-spawner for " .. biter_force_name) + local nearest_player_unit = surface.find_nearest_enemy({position = spawner.position, max_distance = 2048, force = biter_force_name}) + if not nearest_player_unit then nearest_player_unit = global.rocket_silo[force_name] end + local unit_group_position = {x = (spawner.position.x + nearest_player_unit.position.x) * 0.5, y = (spawner.position.y + nearest_player_unit.position.y) * 0.5} + local pos = surface.find_non_colliding_position("rocket-silo", unit_group_position, 96, 1) + if pos then unit_group_position = pos end + local units = select_units_around_spawner(spawner, force_name, biter_force_name) + if not units then return false end + local unit_group = surface.create_unit_group({position = unit_group_position, force = biter_force_name}) + for _, unit in pairs(units) do unit_group.add_member(unit) end + send_group(unit_group, force_name, nearest_player_unit) +end + +ai.main_attack = function() + local surface = game.surfaces["biter_battles"] + + for _, force_name in pairs({"north", "south"}) do + create_attack_group(surface, force_name, force_name .. "_biters") + end +end + +--Biter Evasion +local function on_entity_damaged(event) + if not event.entity.valid then return end + if event.entity.type ~= "unit" then return end + if global.bb_evasion[event.entity.force.name] < math_random(1,1000) then return end + event.entity.health = event.entity.health + event.final_damage_amount +end + +--Biter Threat Value Substraction +local function on_entity_died(event) + if not event.entity.valid then return end + if threat_values[event.entity.name] then + global.bb_threat[event.entity.force.name] = global.bb_threat[event.entity.force.name] - threat_values[event.entity.name] + return + end +end + +event.add(defines.events.on_entity_damaged, on_entity_damaged) +event.add(defines.events.on_entity_died, on_entity_died) + return ai \ No newline at end of file diff --git a/maps/biter_battles_v2/biter_battles_v2.lua b/maps/biter_battles_v2/biter_battles_v2.lua index 6f326ee0..52b4d9c7 100644 --- a/maps/biter_battles_v2/biter_battles_v2.lua +++ b/maps/biter_battles_v2/biter_battles_v2.lua @@ -7,8 +7,8 @@ local math_random = math.random local function init_surface() if game.surfaces["biter_battles"] then return end local map_gen_settings = {} - map_gen_settings.water = "0.5" - map_gen_settings.starting_area = "5" + map_gen_settings.water = "0.6" + map_gen_settings.starting_area = "5" map_gen_settings.cliff_settings = {cliff_elevation_interval = 12, cliff_elevation_0 = 32} map_gen_settings.autoplace_controls = { ["coal"] = {frequency = "3", size = "1", richness = "1"}, diff --git a/maps/biter_battles_v2/feeding.lua b/maps/biter_battles_v2/feeding.lua index 967d36b4..ca928ba9 100644 --- a/maps/biter_battles_v2/feeding.lua +++ b/maps/biter_battles_v2/feeding.lua @@ -1,5 +1,3 @@ -local event = require 'utils.event' - local food_values = { ["automation-science-pack"] = {value = 0.001, name = "automation science"}, ["logistic-science-pack"] = {value = 0.00292, name = "logistic science"}, @@ -10,17 +8,6 @@ local food_values = { ["space-science-pack"] = {value = 0.420, name = "space science"}, } -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 force_translation = { ["south_biters"] = "south", ["north_biters"] = "north" @@ -43,9 +30,8 @@ local function set_biter_endgame_damage(force_name, biter_force) end local function feed_biters(player, food) - --local enemy_force_name = enemy_team_of[player.force.name] --------------- - - enemy_force_name = player.force.name + local enemy_force_name = enemy_team_of[player.force.name] --------------- + --enemy_force_name = player.force.name local biter_force_name = enemy_force_name .. "_biters" @@ -56,7 +42,7 @@ local function feed_biters(player, food) return end - --i.remove({name = food, count = flask_amount}) + i.remove({name = food, count = flask_amount}) if flask_amount >= 20 then game.print(player.name .. " fed " .. flask_amount .. " flasks of " .. food_values[food].name .. " juice to team " .. enemy_force_name .. "'s biters!", {r = 0.98, g = 0.66, b = 0.22}) @@ -69,53 +55,32 @@ local function feed_biters(player, food) end --ADD TOTAL FOOD FEED - --global.bb_total_food[enemy_force_name] = global.bb_total_food[enemy_force_name] + (food_values[food].value * flask_amount) + --global.bb_total_food[biter_force_name] = global.bb_total_food[biter_force_name] + (food_values[food].value * flask_amount) for a = 1, flask_amount, 1 do --SET THREAT INCOME - local e = (global.bb_evolution[enemy_force_name] * 100) + 1 + local e = (global.bb_evolution[biter_force_name] * 100) + 1 local diminishing_modifier = 1 / (10 ^ (e * 0.03)) - global.bb_threat_income[enemy_force_name] = global.bb_threat_income[enemy_force_name] + (food_values[food].value * diminishing_modifier * 10) + global.bb_threat_income[biter_force_name] = global.bb_threat_income[biter_force_name] + (food_values[food].value * diminishing_modifier * 10) ---SET EVOLUTION local e = (game.forces[biter_force_name].evolution_factor * 100) + 1 local diminishing_modifier = 1 / (10 ^ (e * 0.03)) - global.bb_evolution[enemy_force_name] = global.bb_evolution[enemy_force_name] + (food_values[food].value * diminishing_modifier) - if global.bb_evolution[enemy_force_name] < 1 then - game.forces[biter_force_name].evolution_factor = global.bb_evolution[enemy_force_name] + global.bb_evolution[biter_force_name] = global.bb_evolution[biter_force_name] + (food_values[food].value * diminishing_modifier) + if global.bb_evolution[biter_force_name] < 1 then + game.forces[biter_force_name].evolution_factor = global.bb_evolution[biter_force_name] else game.forces[biter_force_name].evolution_factor = 1 end end --ADD INSTANT THREAT - global.bb_threat[enemy_force_name] = global.bb_threat[enemy_force_name] + (food_values[food].value * 100 * flask_amount) + global.bb_threat[biter_force_name] = global.bb_threat[biter_force_name] + (food_values[food].value * 100 * flask_amount) - set_biter_endgame_damage(enemy_force_name, game.forces[biter_force_name]) + set_biter_endgame_damage(biter_force_name, game.forces[biter_force_name]) - global.bb_evasion[biter_force_name] = (global.bb_evolution[enemy_force_name] - 1) * 333 + global.bb_evasion[biter_force_name] = (global.bb_evolution[biter_force_name] - 1) * 333 if global.bb_evasion[biter_force_name] > 900 then global.bb_evasion[biter_force_name] = 900 end end ---Biter Evasion -local math_random = math.random -local function on_entity_damaged(event) - if not event.entity.valid then return end - if event.entity.type ~= "unit" then return end - if global.bb_evasion[event.entity.force.name] < math_random(1,1000) then return end - event.entity.health = event.entity.health + event.final_damage_amount -end - ---Biter Threat Value Reduction -local function on_entity_died(event) - if not event.entity.valid then return end - if threat_values[event.entity.name] then - global.bb_threat[event.entity.force.name] = global.bb_threat[event.entity.force.name] - threat_values[event.entity.name] - return - end -end - -event.add(defines.events.on_entity_damaged, on_entity_damaged) -event.add(defines.events.on_entity_died, on_entity_died) - return feed_biters \ No newline at end of file diff --git a/maps/biter_battles_v2/game_won.lua b/maps/biter_battles_v2/game_won.lua index 4d3b723a..52e96bfe 100644 --- a/maps/biter_battles_v2/game_won.lua +++ b/maps/biter_battles_v2/game_won.lua @@ -1,13 +1,74 @@ local event = require 'utils.event' local math_random = math.random -local particles = {"coal-particle", "copper-ore-particle", "iron-ore-particle", "stone-particle"} +local gui_values = { + ["north"] = {c1 = "Team North", color1 = {r = 0.55, g = 0.55, b = 0.99}}, + ["south"] = {c1 = "Team South", color1 = {r = 0.99, g = 0.33, b = 0.33}} + } + +local function shuffle(tbl) + local size = #tbl + for i = size, 1, -1 do + local rand = math_random(size) + tbl[i], tbl[rand] = tbl[rand], tbl[i] + end + return tbl +end + +local function create_victory_gui(player) + local values = gui_values[global.bb_game_won_by_team] + local frame = player.gui.left.add {type = "frame", name = "bb_victory_gui", direction = "vertical", caption = values.c1 .. " team has won!" } + frame.style.font = "heading-1" + frame.style.font_color = values.color1 +end + +local function destroy_entity(e) + if not e.valid then return end + local names = {"big-artillery-explosion", "big-explosion", "big-explosion", "big-explosion", "fire-flame", "massive-explosion"} + e.surface.create_entity({name = names[math.random(1,#names)], position = e.position}) + e.die() +end + +local function annihilate_base(center_pos, surface, force_name) + local entities = {} + for _, e in pairs(surface.find_entities_filtered({force = force_name})) do + if e.name ~= "player" then + entities[#entities + 1] = e + end + end + if not entities[2] then return end + entities = shuffle(entities) + + for i1 = #entities, 1, -1 do + for i2 = #entities, 1, -1 do + local distance_to_center_1 = (entities[i1].position.x - center_pos.x)^2 + (entities[i1].position.y - center_pos.y)^2 + local distance_to_center_2 = (entities[i2].position.x - center_pos.x)^2 + (entities[i2].position.y - center_pos.y)^2 + if distance_to_center_1 > distance_to_center_2 then + local k = entities[i1] + entities[i1] = entities[i2] + entities[i2] = k + end + end + end + + for i = 1, #entities, 1 do + local t = i * 8 + if not global.on_tick_schedule[game.tick + t] then global.on_tick_schedule[game.tick + t] = {} end + local pos = global.rocket_silo[global.bb_game_won_by_team].position + global.on_tick_schedule[game.tick + t][#global.on_tick_schedule[game.tick + t] + 1] = { + func = destroy_entity, + args = {entities[i]} + } + end +end + local function create_fireworks_rocket(surface, position) + local particles = {"coal-particle", "copper-ore-particle", "iron-ore-particle", "stone-particle"} local particle = particles[math_random(1, #particles)] local m = math_random(16, 36) local m2 = m * 0.005 - for i = 1, 80, 1 do + for i = 1, 60, 1 do surface.create_entity({ name = particle, position = position, @@ -18,21 +79,24 @@ local function create_fireworks_rocket(surface, position) }) end - if math_random(1,16) ~= 1 then return end + if math_random(1,12) ~= 1 then return end surface.create_entity({name = "explosion", position = position}) end local function fireworks(surface) - local radius = 96 - for t = 1, 18000, 1 do - if not global.on_tick_schedule[game.tick + t] then global.on_tick_schedule[game.tick + t] = {} end - for x = 1, 3, 1 do + local radius = 52 + for t = 1, 10800, 1 do + if t % 3 == 0 then + if not global.on_tick_schedule[game.tick + t] then global.on_tick_schedule[game.tick + t] = {} end + local pos = global.rocket_silo[global.bb_game_won_by_team].position global.on_tick_schedule[game.tick + t][#global.on_tick_schedule[game.tick + t] + 1] = { func = create_fireworks_rocket, - args = {surface, {x = radius - math_random(0, radius * 2),y = radius - math_random(0, radius * 2)}} - } + args = { + surface, + {x = (pos.x - radius) + math_random(0, radius * 2),y = (pos.y - radius) + math_random(0, radius * 2)} + } + } end - t = t + 1 end end @@ -112,15 +176,15 @@ local function show_mvps(player) if not global.results_sent_north then local result = {} - insert(result, 'NORTH: \\n') - 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" ) + table.insert(result, 'NORTH: \\n') + table.insert(result, 'MVP Defender: \\n') + table.insert(result, mvp.killscore.name .. " with a score of " .. mvp.killscore.score .. "\\n" ) + table.insert(result, '\\n') + table.insert(result, 'MVP Builder: \\n') + table.insert(result, mvp.built_entities.name .. " built " .. mvp.built_entities.score .. " things\\n" ) + table.insert(result, '\\n') + table.insert(result, 'MVP Deaths: \\n') + table.insert(result, mvp.deaths.name .. " died " .. mvp.deaths.score .. " times" ) local message = table.concat(result) server_commands.to_discord_embed(message) global.results_sent_north = true @@ -157,15 +221,15 @@ local function show_mvps(player) if not global.results_sent_south then local result = {} - insert(result, 'SOUTH: \\n') - 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" ) + table.insert(result, 'SOUTH: \\n') + table.insert(result, 'MVP Defender: \\n') + table.insert(result, mvp.killscore.name .. " with a score of " .. mvp.killscore.score .. "\\n" ) + table.insert(result, '\\n') + table.insert(result, 'MVP Builder: \\n') + table.insert(result, mvp.built_entities.name .. " built " .. mvp.built_entities.score .. " things\\n" ) + table.insert(result, '\\n') + table.insert(result, 'MVP Deaths: \\n') + table.insert(result, mvp.deaths.name .. " died " .. mvp.deaths.score .. " times" ) local message = table.concat(result) server_commands.to_discord_embed(message) global.results_sent_south = true @@ -173,17 +237,26 @@ local function show_mvps(player) end end +local enemy_team_of = { + ["north"] = "south", + ["south"] = "north" +} + local function on_entity_died(event) if not event.entity.valid then return end if event.entity.name ~= "rocket-silo" then return end - if event.entity == global.rocket_silo.south or event.entity == global.rocket_silo.north then + if event.entity == global.rocket_silo.south or event.entity == global.rocket_silo.north then + global.bb_game_won_by_team = enemy_team_of[event.entity.force.name] for _, player in pairs(game.connected_players) do player.play_sound{path="utility/game_won", volume_modifier=1} if player.gui.left["bb_main_gui"] then player.gui.left["bb_main_gui"].destroy() end - show_mvps(player) - end + create_victory_gui(player) + show_mvps(player) + if player.character then player.character.destructible = false end + end fireworks(event.entity.surface) - end + annihilate_base(event.entity.position, event.entity.surface, event.entity.force.name) + end end event.add(defines.events.on_entity_died, on_entity_died) diff --git a/maps/biter_battles_v2/gui.lua b/maps/biter_battles_v2/gui.lua index 0c1a1296..22fb6e1f 100644 --- a/maps/biter_battles_v2/gui.lua +++ b/maps/biter_battles_v2/gui.lua @@ -14,10 +14,10 @@ local food_names = { } local gui_values = { - [1] = {force = "north", c1 = "Team North", c2 = "JOIN NORTH", n1 = "join_north_button", + ["north"] = {force = "north", biter_force = "north_biters", c1 = "Team North", c2 = "JOIN NORTH", n1 = "join_north_button", t1 = "Evolution of the North side biters. Can go beyond 100% for endgame modifiers.", t2 = "Threat causes biters to attack. Reduces when biters are slain.", color1 = {r = 0.55, g = 0.55, b = 0.99}, color2 = {r = 0.66, g = 0.66, b = 0.99}}, - [2] = {force = "south", c1 = "Team South", c2 = "JOIN SOUTH", n1 = "join_south_button", + ["south"] = {force = "south", biter_force = "south_biters", c1 = "Team South", c2 = "JOIN SOUTH", n1 = "join_south_button", t1 = "Evolution of the South side biters. Can go beyond 100% for endgame modifiers.", t2 = "Threat causes biters to attack. Reduces when biters are slain.", color1 = {r = 0.99, g = 0.33, b = 0.33}, color2 = {r = 0.99, g = 0.44, b = 0.44}} } @@ -79,6 +79,7 @@ end local function create_main_gui(player) if player.gui.left["bb_main_gui"] then player.gui.left["bb_main_gui"].destroy() end + if global.bb_game_won_by_team then return end if player.force.name == "player" then create_first_join_gui(player) return end local frame = player.gui.left.add { type = "frame", name = "bb_main_gui", direction = "vertical" } @@ -124,7 +125,7 @@ local function create_main_gui(player) local l = t.add { type = "label", caption = "Evo:"} --l.style.minimal_width = 25 l.tooltip = gui_value.t1 - local l = t.add {type = "label", caption = tostring(math.ceil(100 * global.bb_evolution[gui_value.force])) .. "%"} + local l = t.add {type = "label", caption = tostring(math.ceil(100 * global.bb_evolution[gui_value.biter_force])) .. "%"} l.style.minimal_width = 38 l.style.font_color = gui_value.color2 l.style.font = "default-bold" @@ -133,7 +134,7 @@ local function create_main_gui(player) local l = t.add { type = "label", caption = "Threat: "} l.style.minimal_width = 25 l.tooltip = gui_value.t2 - local l = t.add { type = "label", caption = math.ceil(global.bb_threat[gui_value.force])} + local l = t.add { type = "label", caption = math.ceil(global.bb_threat[gui_value.biter_force])} l.style.font_color = gui_value.color2 l.style.font = "default-bold" l.style.minimal_width = 25 diff --git a/maps/biter_battles_v2/on_tick.lua b/maps/biter_battles_v2/on_tick.lua index f3b4d87b..15ee4c74 100644 --- a/maps/biter_battles_v2/on_tick.lua +++ b/maps/biter_battles_v2/on_tick.lua @@ -20,8 +20,8 @@ end local function on_tick(event) if game.tick % 60 ~= 0 then return end - global.bb_threat["north"] = global.bb_threat["north"] + global.bb_threat_income["north"] - global.bb_threat["south"] = global.bb_threat["south"] + global.bb_threat_income["south"] + global.bb_threat["north_biters"] = global.bb_threat["north_biters"] + global.bb_threat_income["north_biters"] + global.bb_threat["south_biters"] = global.bb_threat["south_biters"] + global.bb_threat_income["south_biters"] gui() if game.tick % 300 ~= 0 then return end if global.spy_fish_timeout["south"] - game.tick > 0 then @@ -33,7 +33,16 @@ local function on_tick(event) reveal_team("south") else global.spy_fish_timeout["north"] = 0 - end + end + + if game.tick % 3600 ~= 0 then return end + if global.bb_game_won_by_team then + for _, p in pairs(game.connected_players) do + if p.character then p.character.destructible = false end + end + return + end + ai.main_attack() end event.add(defines.events.on_tick, on_tick) diff --git a/maps/biter_battles_v2/pregenerate_chunks.lua b/maps/biter_battles_v2/pregenerate_chunks.lua index 0140d7b1..34590cff 100644 --- a/maps/biter_battles_v2/pregenerate_chunks.lua +++ b/maps/biter_battles_v2/pregenerate_chunks.lua @@ -77,7 +77,7 @@ local function create_schedule(radius) end local function on_player_joined_game(event) - if not global.chunk_gen_coords then create_schedule(6) end + if not global.chunk_gen_coords then create_schedule(20) end end event.add(defines.events.on_player_joined_game, on_player_joined_game) \ No newline at end of file