require("config") require("balance") local mod_gui = require("mod-gui") require("production-score") require("util") function create_spawn_positions() local config = global.map_config local width = config.map_width local height = config.map_height local displacement = config.average_team_displacement local height_scale = height/width local radius = starting_area_constant[config.starting_area_size.selected]/32 local count = #global.teams local max_distance = starting_area_constant[config.starting_area_size.selected] + displacement local min_distance = starting_area_constant[config.starting_area_size.selected]/2 + (32*(count-1)) local edge_addition = (radius +2)*32 local elevator_set = false if height_scale == 1 then if max_distance > width then displacement = width - edge_addition end end if height_scale < 1 then if #global.teams == 2 then if max_distance > width then displacement = width - edge_addition end max_distance = 0 end if max_distance > height then displacement = height - edge_addition end end if height_scale > 1 then if #global.teams == 2 then if max_distance > height then displacement = height - edge_addition end elevator_set = true max_distance = 0 end if max_distance > width then displacement = width - edge_addition end end local distance = 0.5*displacement if distance < min_distance then game.print({"map-size-below-minimum"}) end local positions = {} if count == 1 then positions[1] = {x = 0, y = 0} else for k = 1, count do local rotation = (k*2*math.pi)/count local X = 32*(math.floor((math.cos(rotation)*distance+0.5)/32)) local Y = 32*(math.floor((math.sin(rotation)*distance+0.5)/32)) if elevator_set then --[[Swap X and Y for elevators]] Y = 32*(math.floor((math.cos(rotation)*distance+0.5)/32)) X = 32*(math.floor((math.sin(rotation)*distance+0.5)/32)) end positions[k] = {x = X, y = Y} end end if #positions == 2 and height_scale == 1 then --If there are 2 teams in a square map, we adjust positions so they are in the corners of the map for k, position in pairs (positions) do if position.x == 0 then position.x = position.y end if position.y == 0 then position.y = -position.x end end end if #positions == 4 then --If there are 4 teams we adjust positions so they are in the corners of the map height_scale = math.min(height_scale, 2) height_scale = math.max(height_scale, 0.5) for k, position in pairs (positions) do if position.x == 0 then position.x = position.y end if position.y == 0 then position.y = -position.x end if height_scale > 1 then position.y = position.y * height_scale else position.x = position.x * (1/height_scale) end end if height_scale < 1 then --If the map is wider than tall, swap 1 and 3 so two allied teams will be together positions[1], positions[3] = positions[3], positions[1] end end global.spawn_positions = positions return positions end function create_next_surface() if game.surfaces["Battle_surface"] ~= nil then return end global.round_number = global.round_number + 1 local settings = global.copy_surface.map_gen_settings settings.starting_area = global.map_config.starting_area_size.selected if global.map_config.biters_disabled then settings.autoplace_controls["enemy-base"].size = "none" end if global.map_config.seed ~= 0 then settings.seed = math.random(4000000000) else settings.seed = global.map_config.seed end settings.height = global.map_config.map_height settings.width = global.map_config.map_width settings.starting_points = create_spawn_positions() global.surface = game.create_surface("Battle_surface", settings) global.surface.daytime = 0 global.surface.always_day = global.map_config.always_day end function destroy_player_gui(player) local button_flow = mod_gui.get_button_flow(player) for k, name in pairs ( { "objective_button", "diplomacy_button", "admin_button", "silo_gui_sprite_button", "production_score_button", "oil_harvest_button" }) do if button_flow[name] then button_flow[name].destroy() end end local frame_flow = mod_gui.get_frame_flow(player) for k, name in pairs ( { "objective_frame", "admin_button", "admin_frame", "silo_gui_frame", "production_score_frame", "oil_harvest_frame" }) do if frame_flow[name] then frame_flow[name].destroy() end end local center_gui = player.gui.center for k, name in pairs ({"diplomacy_frame"}) do if center_gui[name] then center_gui[name].destroy() end end end function destroy_joining_guis(gui) if gui.random_join_frame then gui.random_join_frame.destroy() end if gui.pick_join_frame then gui.pick_join_frame.destroy() end if gui.auto_assign_frame then gui.auto_assign_frame.destroy() end end function make_color_dropdown(k, gui) local team = global.teams[k] local menu = gui.add{type = "drop-down", name = k.."_color"} local count = 1 for k, color in pairs (global.colors) do menu.add_item({color.name}) if color.name == team.color then menu.selected_index = count end count = count + 1 end end function make_team_gui_config(gui) if not gui.valid then return end local config_table = gui.add{name = "team_gui_config_table", column_count = 2, type = "table"} config_table.style.column_alignments[2] = "right" make_config_table(config_table, global.team_config) set_mode_input(config_table) end function add_team_to_team_table(gui, k) local team = global.teams[k] local textfield = gui.add{type = "textfield", name = k.."_name", text = team.name} textfield.style.maximal_width = 100 make_color_dropdown(k, gui) local caption if tonumber(team.team) then caption = team.team elseif team.team:find("?") then caption = "?" else caption = team.team end local team_button = gui.add{type = "button", name = k.."_next_team_button", caption = caption, tooltip = {"team-button-tooltip"}} team_button.style.font = "default" team_button.style.top_padding = 0 team_button.style.bottom_padding = 0 team_button.style.minimal_width = 30 local bin = gui.add{name = k.."_trash_button", type = "sprite-button", sprite = "utility/trash_bin", tooltip = {"remove-team-tooltip"}} bin.style.top_padding = 0 bin.style.bottom_padding = 0 bin.style.right_padding = 0 bin.style.left_padding = 0 bin.style.minimal_height = 26 bin.style.minimal_width = 26 end function make_team_gui(gui) local frame = gui.add{type = "frame", name = "team_gui", caption = {"team-gui"}, direction = "vertical"} local holding_table = frame.add{type = "table", name = "team_gui_holding_table", column_count = 1} local inner_frame = holding_table.add{type = "frame", style = "image_frame", name = "team_gui_inner_frame", direction = "vertical"} inner_frame.style.left_padding = 8 inner_frame.style.right_padding = 8 inner_frame.style.top_padding = 8 inner_frame.style.bottom_padding = 8 local scroll = inner_frame.add{type = "scroll-pane", name = "team_gui_scroll"} scroll.style.maximal_height = 200 local team_table = scroll.add{type = "table", column_count = 4, name = "team_table"} for k, name in pairs ({"team-name", "color", "team", "remove"}) do team_table.add{type = "label", caption = {name}} end for k, team in pairs (global.teams) do add_team_to_team_table(team_table, k) end local button = inner_frame.add{name = "add_team_button", type = "button", caption = {"add-team"}, tooltip = {"add-team-tooltip"}} button.style.font = "default" button.style.top_padding = 2 button.style.bottom_padding = 2 make_team_gui_config(holding_table) end function create_config_gui(player) local gui = mod_gui.get_frame_flow(player) if gui.config_gui then gui.config_gui.destroy() end if gui.team_gui then gui.team_gui.destroy() end local frame = gui.add{type = "frame", name = "config_gui", caption = {"config-gui"}, direction = "vertical"} local button = frame.add{type = "button", name = "balance_options", caption = {"balance-options"}} button.style.font = "default" button.style.top_padding = 0 button.style.bottom_padding = 0 local button = frame.add{type = "button", name = "disable_items", caption = {"disable-items"}} button.style.font = "default" button.style.top_padding = 0 button.style.bottom_padding = 0 local config_table = frame.add{type = "table", name = "config_table", column_count = 2} config_table.style.column_alignments[2] = "right" make_config_table(config_table, global.map_config) button.style.font = "default" button.style.top_padding = 0 button.style.bottom_padding = 0 local button = frame.add{type = "button", name = "config_confirm", caption = {"config-confirm"}} button.style.font = "default" button.style.top_padding = 0 button.style.bottom_padding = 0 make_team_gui(gui) end function end_round(admin) for k, player in pairs (game.players) do destroy_player_gui(player) player.force = game.forces.player destroy_joining_guis(player.gui.center) if player.connected then local character = player.character player.character = nil if character then character.destroy() end player.set_controller{type = defines.controllers.ghost} player.teleport({0,1000}, game.surfaces.Lobby) if player.admin then create_config_gui(player) end end end if game.surfaces["Battle_surface"] ~= nil then game.delete_surface(game.surfaces["Battle_surface"]) end if admin then game.print({"admin-ended-round", admin.name}) end game.print{"next-round-start", global.time_between_rounds} global.next_round_start_tick = game.tick + global.time_between_rounds * 60 global.setup_finished = false end function prepare_map() create_next_surface() global.next_round_start_tick = nil setup_teams() chart_starting_area_for_force_spawns() set_evolution_factor() end function prepare_next_round() global.next_round_start_tick = nil global.setup_finished = false global.team_won = false prepare_map() end function set_mode_input(gui) local selected = global.team_config.game_mode.selected local visibility_map = { ["required_production_score"] = "production_score", ["required_oil_barrels"] = "oil_harvest", ["oil_only_in_center"] = "oil_harvest" } local children = gui.children for k, child in pairs (children) do local name = child.name or "" local mapped = visibility_map[name] if mapped then local bool = (mapped == selected) children[k].style.visible = bool children[k+1].style.visible = bool end end end game_mode_buttons = { ["production_score"] = {type = "button", caption = {"production_score"}, name = "production_score_button", style = mod_gui.button_style}, ["oil_harvest"] = {type = "button", caption = {"oil_harvest"}, name = "oil_harvest_button", style = mod_gui.button_style} } function init_player_gui(player) local button_flow = mod_gui.get_button_flow(player) button_flow.add{type = "button", caption = {"objective"}, name = "objective_button", style = mod_gui.button_style} local button = button_flow.add{type = "button", caption = {"diplomacy"}, name = "diplomacy_button", style = mod_gui.button_style} button.style.visible = #global.teams > 1 local game_mode_button = game_mode_buttons[global.team_config.game_mode.selected] if game_mode_button then button_flow.add(game_mode_button) end if player.admin then button_flow.add{type = "button", caption = {"admin"}, name = "admin_button", style = mod_gui.button_style} end end function fpn(n) return (math.floor(n*32)/32) end function get_color(team, lighten) local c = global.colors[global.color_map[team.color]].color if lighten then return {r = 1 - (1 - c[1]) * 0.5, g = 1 - (1 - c[2]) * 0.5, b = 1 - (1 - c[3]) * 0.5, a = 1} end return {r = fpn(c[1]), g = fpn(c[2]), b = fpn(c[3]), a = fpn(c[4])} end function add_player_list_gui(team, gui) local force = game.forces[team.name] if not force then --Force doesn't exist, probably shouldn't have been called, but just in case, fill with an empty gui gui.add{type = "flow"} return end if #force.players == 0 then gui.add{type = "label", caption = {"none"}} return end local scroll = gui.add{type = "scroll-pane"} scroll.style.maximal_height = 120 local name_table = scroll.add{type = "table", column_count = 1} name_table.style.vertical_spacing = 0 local added = {} local first = true if #force.connected_players > 0 then local online_names = "" for k, player in pairs (force.connected_players) do if not first then online_names = online_names..", " end first = false online_names = online_names..player.name added[player.name] = true end local online_label = name_table.add{type = "label", caption = {"online", online_names}} online_label.style.single_line = false online_label.style.maximal_width = 180 end first = true if #force.players > #force.connected_players then local offline_names = "" for k, player in pairs (force.players) do if not added[player.name] then if not first then offline_names = offline_names..", " end first = false offline_names = offline_names..player.name added[player.name] = true end end local offline_label = name_table.add{type = "label", caption = {"offline", offline_names}} offline_label.style.single_line = false offline_label.style.font_color = {r = 0.7, g = 0.7, b = 0.7} offline_label.style.maximal_width = 180 end end function update_diplomacy_frame(player) local flow = player.gui.center.diplomacy_frame if not flow then return end gui = flow.diplomacy_inner_frame if not gui then return end local diplomacy_table = gui.diplomacy_table if not diplomacy_table then diplomacy_table = gui.add{type = "table", name = "diplomacy_table", column_count = 6} diplomacy_table.style.horizontal_spacing = 16 diplomacy_table.style.vertical_spacing = 8 diplomacy_table.draw_horizontal_lines = true diplomacy_table.draw_vertical_lines = true else diplomacy_table.clear() end for k, name in pairs ({"team-name", "players", "stance", "enemy", "neutral", "ally"}) do local label = diplomacy_table.add{type = "label", name = name, caption = {name}} label.style.font = "default-bold" end for k, team in pairs (global.teams) do local force = game.forces[team.name] if force then local label = diplomacy_table.add{type = "label", name = team.name.."_name", caption = team.name} label.style.single_line = false label.style.maximal_width = 150 label.style.font = "default-semibold" label.style.font_color = get_color(team, true) add_player_list_gui(team, diplomacy_table) if force.name == player.force.name then diplomacy_table.add{type = "label"} diplomacy_table.add{type = "label"} diplomacy_table.add{type = "label"} diplomacy_table.add{type = "label"} else local stance = get_stance(player.force, force) local their_stance = get_stance(force, player.force) local stance_label = diplomacy_table.add{type = "label", name = team.name.."_stance", caption = {their_stance}} if their_stance == "ally" then stance_label.style.font_color = {r = 0.5, g = 1, b = 0.5} elseif their_stance == "enemy" then stance_label.style.font_color = {r = 1, g = 0.5, b = 0.5} end diplomacy_table.add{type = "checkbox", name = team.name.."_enemy", state = (stance == "enemy")}.enabled = not global.team_config.locked_teams diplomacy_table.add{type = "checkbox", name = team.name.."_neutral", state = (stance == "neutral")}.enabled = not global.team_config.locked_teams diplomacy_table.add{type = "checkbox", name = team.name.."_ally", state = (stance == "ally")}.enabled = not global.team_config.locked_teams end end end if not flow.diplomacy_confirm then local button = flow.add{type = "button", name = "diplomacy_confirm", caption = {"confirm"}} --button.style.font = "default" --button.style.top_padding = 0 --button.style.bottom_padding = 0 button.style.align = "right" button.enabled = not global.team_config.locked_teams end end function set_player(player, force, color) local surface = global.surface if not surface.valid then return end local position local distance = 32 repeat position = surface.find_non_colliding_position("player", force.get_spawn_position(surface),distance,1) distance = distance + 32 until (position ~= nil) or (distance >= 320) if position then player.teleport(position, surface) else player.print({"cant-find-position"}) return end player.force = force player.color = color player.set_controller { type = defines.controllers.character, character = surface.create_entity{name = "player", position = position, force = force} } init_player_gui(player) for k, other_player in pairs (game.players) do update_diplomacy_frame(other_player) end give_inventory(player) give_equipment(player) game.print({"joined", player.name, player.force.name}) end function choose_joining_gui(player) if #global.teams == 1 then local team = global.teams[1] local force = game.forces[team.name] set_player(player, force, get_color(team)) return end local setting = global.team_config.team_joining.selected if setting == "random" then create_random_join_gui(player.gui.center) return end if setting == "player_pick" then create_pick_join_gui(player.gui.center) return end if setting == "auto_assign" then create_auto_assign_gui(player.gui.center) return end end function create_random_join_gui(gui) if gui.random_join_frame then gui.random_join_frame.destroy() end local frame = gui.add{type = "frame", name = "random_join_frame", caption = {"random-join"}} local button = frame.add{type = "button", name = "random_join_button", caption = {"random-join-button"}} button.style.font = "default" button.style.top_padding = 0 button.style.bottom_padding = 0 end function create_auto_assign_gui(gui) local name = "auto_assign" if gui[name.."_frame"] then gui[name.."_frame"].destroy() end local frame = gui.add{type = "frame", name = name.."_frame", caption = {name.."_frame"}} local button = frame.add{type = "button", name = name.."_button", caption = {name.."_button"}} button.style.font = "default" button.style.top_padding = 0 button.style.bottom_padding = 0 end function create_pick_join_gui(gui) if gui.pick_join_frame then gui.pick_join_frame.destroy() end local frame = gui.add{type = "frame", name = "pick_join_frame", caption = {"pick-join"}, direction = "vertical"} frame.style.title_bottom_padding = 8 local inner_frame = frame.add{type = "frame", style = "image_frame", name = "pick_join_inner_frame", direction = "vertical"} inner_frame.style.left_padding = 8 inner_frame.style.top_padding = 8 inner_frame.style.right_padding = 8 inner_frame.style.bottom_padding = 8 local pick_join_table = inner_frame.add{type = "table", name = "pick_join_table", column_count = 4} pick_join_table.style.horizontal_spacing = 16 pick_join_table.style.vertical_spacing = 8 pick_join_table.draw_horizontal_lines = true pick_join_table.draw_vertical_lines = true pick_join_table.style.column_alignments[3] = "right" pick_join_table.add{type = "label", name = "pick_join_table_force_name", caption = {"team-name"}}.style.font = "default-semibold" pick_join_table.add{type = "label", name = "pick_join_table_player_count", caption = {"players"}}.style.font = "default-semibold" pick_join_table.add{type = "label", name = "pick_join_table_team", caption = {"team-number"}}.style.font = "default-semibold" pick_join_table.add{type = "label", name = "pick_join_table_pad", caption = {"join"}}.style.font = "default-semibold" for k, team in pairs (global.teams) do local force = game.forces[team.name] if force ~= nil then local name = pick_join_table.add{type = "label", name = force.name.."_label", caption = force.name} name.style.font = "default-semibold" name.style.font_color = get_color(team, true) add_player_list_gui(team, pick_join_table) local caption if tonumber(team.team) then caption = team.team elseif team.team:find("?") then caption = team.team:gsub("?", "") else caption = team.team end pick_join_table.add{type = "label", name = force.name.."_team", caption = caption} pick_join_table.add{type = "checkbox", name = force.name,state = false} end end local button = frame.add{type = "button", name = "player_pick_confirm", caption = {"confirm"}} button.style.font = "default" button.style.top_padding = 0 button.style.bottom_padding = 0 end function add_team_button_press(event) local gui = event.element local index = #global.teams + 1 for k = 1, index do if not global.teams[k] then index = k break end end local color = global.colors[(1+index%(#global.colors))] local name = color.name.." "..index local team = {name = name, color = color.name, team = "-"} global.teams[index] = team for k, player in pairs (game.players) do local gui = mod_gui.get_frame_flow(player).team_gui if gui then add_team_to_team_table(gui.team_gui_holding_table.team_gui_inner_frame.team_gui_scroll.team_table, index) end end end function trash_team_button_press(event) local gui = event.element if not gui.valid then return end if not gui.name:find("_trash_button") then return end local team_index = gui.name:gsub("_trash_button", "") team_index = tonumber(team_index) local count = 0 for k, team in pairs (global.teams) do count = count + 1 end if count > 1 then global.teams[team_index] = nil remove_team_from_team_table(gui) else game.players[event.player_index].print({"cant-remove-only-team"}) end end function remove_team_from_team_table(gui) local index = nil for k, child in pairs (gui.parent.children) do if child == gui then index = k break end end local delete_list = {} for k, player in pairs (game.players) do local gui = mod_gui.get_frame_flow(player).team_gui if gui then for k, child in pairs (gui.team_gui_holding_table.team_gui_inner_frame.team_gui_scroll.team_table.children) do if k == index - 3 or k == index - 2 or k == index - 1 or k == index then table.insert(delete_list, child) end end end end for k, element in pairs (delete_list) do element.destroy() end end function set_teams_from_gui(player) local gui = mod_gui.get_frame_flow(player).team_gui if not gui then return end local count = 1 local teams = {} local team = {} local disallow = { ["player"] = true, ["enemy"] = true, ["neutral"] = true, ["spectator"] = true } for k, child in pairs (gui.team_gui_holding_table.team_gui_inner_frame.team_gui_scroll.team_table.children) do local name = child.name if name:find("_name") then if disallow[child.text] then player.print({"disallowed-team-name", child.text}) return end team.name = child.text end if name:find("_color") then team.color = global.colors[child.selected_index].name end if name:find("_next_team_button") then team.team = tonumber(child.caption) or child.caption end if name:find("_trash_button") then table.insert(teams, team) team = {} end for k, other_team in pairs (teams) do if other_team.name == team.name then player.print({"duplicate-team-name", team.name}) return false end end end global.teams = teams return true end function on_team_button_press(event) local gui = event.element if not gui.valid then return end if not gui.name:find("_next_team_button") then return end local left_click = (event.button == defines.mouse_button_type.left) local index = gui.caption if index == "-" then if left_click then index = 1 else index = "?" end elseif index == "?" then if left_click then index = "-" else index = #global.teams end elseif index == tostring(#global.teams) then if left_click then index = "?" else index = index -1 end else if left_click then index = tonumber(index) + 1 elseif index == tostring(1) then index = "-" else index = index -1 end end gui.caption = index end function create_balance_option(gui) if gui.balance_options_frame then gui.balance_options_frame.destroy() return end local frame = gui.add{name = "balance_options_frame", type = "frame", direction = "vertical", caption = {"balance-options"}} local scrollpane = frame.add{name = "balance_options_scrollpane", type = "scroll-pane"} scrollpane.style.maximal_height = 500 scrollpane.style.bottom_padding = 9 for modifier_name, array in pairs (global.modifier_list) do local label = scrollpane.add{name = modifier_name.."label", type = "label", caption = {modifier_name}} label.style.font = "default-bold" local table = scrollpane.add{name = modifier_name.."table", type = "table", column_count = 2} table.style.column_alignments[2] = "right" for name, modifier in pairs (array) do local label if modifier_name == "ammo_damage_modifier" then local string = "ammo-category-name."..name label = table.add{name = name.."label", type = "label", caption = {"", {string}, {"colon"}}} elseif modifier_name == "gun_speed_modifier" then local string = "ammo-category-name."..name label = table.add{name = name.."label", type = "label", caption = {"", {string}, {"colon"}}} elseif modifier_name == "turret_attack_modifier" then local string = "entity-name."..name label = table.add{name = name.."label", type = "label", caption = {"", {string}, {"colon"}}} else label = table.add{name = name.."label", type = "label", caption = {"", {name}, {"colon"}}} end label.style.minimal_width = 200 local input = table.add{name = name.."text", type = "textfield"} input.text = modifier input.style.maximal_width = 50 end end local button = frame.add{type = "button", name = "balance_options_confirm", caption = {"balance-confirm"}} button.style.font = "default" button.style.top_padding = 0 button.style.bottom_padding = 0 local button = frame.add{type = "button", name = "balance_options_cancel", caption = {"cancel"}} button.style.font = "default" button.style.top_padding = 0 button.style.bottom_padding = 0 end function create_disable_frame(gui) if gui.disable_items_frame then gui.disable_items_frame.destroy() return end disable_frame = gui.add{name = "disable_items_frame", type = "frame", direction = "vertical", caption = {"disable-items"}} local disable_table = disable_frame.add{type = "table", name = "disable_items_table", column_count = 6} disable_table.style.horizontal_spacing = 2 disable_table.style.vertical_spacing = 2 local items = game.item_prototypes if global.disabled_items then for k, item in pairs (global.disabled_items) do if items[item] then local choose = disable_table.add{type = "choose-elem-button", elem_type = "item"} choose.elem_value = item end end end disable_table.add{type = "choose-elem-button", elem_type = "item"} local another_flow = disable_frame.add{type = "flow"} local button = another_flow.add{type = "button", name = "disable_items_confirm", caption = {"balance-confirm"}} button.style.font = "default" button.style.top_padding = 0 button.style.bottom_padding = 0 local button = another_flow.add{type = "button", name = "disable_items_cancel", caption = {"cancel"}} button.style.font = "default" button.style.top_padding = 0 button.style.bottom_padding = 0 end function parse_disabled_items(gui) if not gui.disable_items_frame then return end local disable_table = gui.disable_items_frame.disable_items_table if not disable_table then return end global.disabled_items = {} for k, child in pairs (disable_table.children) do if child.elem_value then global.disabled_items[k] = child.elem_value end end if #global.disabled_items == 0 then global.disabled_items = nil end end function set_balance_settings(gui) for modifier_name, array in pairs (global.modifier_list) do local modifier_table = gui[modifier_name.."table"] if modifier_table then for name, modifier in pairs (array) do local text = modifier_table[name.."text"].text if text then local n = tonumber(text) if n == nil then game.players[gui.player_index].print({"must-be-number", name}) return end global.modifier_list[modifier_name][name] = n end end end end end function config_confirm(gui) local parent = gui.parent local config = parent.config_table local player = game.players[gui.player_index] if not set_teams_from_gui(player) then return end if not parse_config_from_gui(config, global.map_config) then return end if not parse_config_from_gui(mod_gui.get_frame_flow(player).team_gui.team_gui_holding_table.team_gui_config_table, global.team_config) then return end destroy_config_for_all() prepare_next_round() global.next_round_start_tick = nil end function player_pick_button_press(event) local gui = event.element local player = game.players[event.player_index] for k, team in pairs (global.teams) do local force = game.forces[team.name] if force then local check = gui.parent.pick_join_inner_frame.pick_join_table[force.name] if check.state then gui.parent.destroy() set_player(player,force,get_color(team)) for k, player in pairs (game.forces.player.players) do create_pick_join_gui(player.gui.center) end break end end end end function auto_assign(player) local force local team repeat local index = math.random(#global.teams) team = global.teams[index] force = game.forces[team.name] until force ~= nil local count = #force.connected_players for k, this_team in pairs (global.teams) do local other_force = game.forces[this_team.name] if other_force ~= nil then if #other_force.connected_players < count then count = #other_force.connected_players force = other_force team = this_team end end end set_player(player,force,get_color(team)) end function destroy_config_for_all() local names = {"config_gui", "balance_options_frame", "team_gui", "disable_items_frame"} for i, name in pairs (names) do for k, player in pairs (game.players) do if mod_gui.get_frame_flow(player)[name] then mod_gui.get_frame_flow(player)[name].destroy() end end end end function set_evolution_factor() local n = global.map_config.evolution_factor if n >= 1 then n = 1 end if n <= 0 then n = 0 end game.forces.enemy.evolution_factor = n global.map_config.evolution_factor = n end function random_join(player) local force local team repeat local index = math.random(#global.teams) team = global.teams[index] force = game.forces[team.name] until force ~= nil set_player(player, force, get_color(team)) end function objective_button_press(event) local gui = event.element local player = game.players[event.player_index] local flow = mod_gui.get_frame_flow(player) local frame = flow.objective_frame if frame then frame.style.visible = not frame.style.visible return end frame = flow.add{type = "frame", name = "objective_frame", caption = {"objective"}, direction = "vertical"} frame.style.visible = true local big_label = frame.add{type = "label", caption = {global.team_config.game_mode.selected.."_description"}} big_label.style.single_line = false big_label.style.font = "default-bold" big_label.style.top_padding = 0 big_label.style.maximal_width = 300 local label_table = frame.add{type = "table", column_count = 2} for k, name in pairs ({"friendly_fire", "locked_teams", "team_joining", "spawn_position"}) do label_table.add{type = "label", caption = {"", {name}, {"colon"}}, tooltip = {name.."_tooltip"}} local setting = global.team_config[name] if setting ~= nil then if type(setting) == "table" then label_table.add{type = "label", caption = {setting.selected}} elseif type(setting) == "boolean" then label_table.add{type = "label", caption = {setting}} else label_table.add{type = "label", caption = setting} end end end if global.disabled_items then label_table.add{type = "label", caption = {"", {"disabled-items", {"colon"}}}} local flow = label_table.add{type = "table", column_count = 4} flow.style.horizontal_spacing = 2 flow.style.vertical_spacing = 2 local items = game.item_prototypes for k, item in pairs (global.disabled_items) do if items[item] then flow.add{type = "sprite", sprite = "item/"..item, tooltip = items[item].localised_name} end end end end function admin_button_press(event) local gui = event.element local player = game.players[event.player_index] local flow = mod_gui.get_frame_flow(player) if flow.admin_frame then flow.admin_frame.style.visible = not flow.admin_frame.style.visible return end local frame = flow.add{type = "frame", caption = {"admin"}, name = "admin_frame"} frame.style.visible = true local button = frame.add{type = "button", caption = {"end-round"}, name = "admin_end_round", tooltip = {"end-round-tooltip"}} button.style.font = "default" button.style.top_padding = 2 button.style.bottom_padding = 2 end function admin_frame_button_press(event) local gui = event.element if not gui.valid then return end if not gui.parent then return end if not gui.parent.valid then return end if gui.parent.name ~= "admin_frame" then return end local player = game.players[event.player_index] if not player.admin then player.print({"only-admins"}) destroy_player_gui(player) init_player_gui(player) return end if gui.name == "admin_end_round" then end_round(player) end end function diplomacy_button_press(event) local gui = event.element local player = game.players[event.player_index] local flow = player.gui.center local frame = flow.diplomacy_frame if frame then frame.destroy() return end frame = player.gui.center.add{type = "frame", name = "diplomacy_frame", caption = {"diplomacy"}, direction = "vertical"} frame.style.visible = true frame.style.title_bottom_padding = 8 player.opened = frame local inner_frame = frame.add{type = "frame", style = "image_frame", name = "diplomacy_inner_frame", direction = "vertical"} inner_frame.style.left_padding = 8 inner_frame.style.top_padding = 8 inner_frame.style.right_padding = 8 inner_frame.style.bottom_padding = 8 update_diplomacy_frame(player) end function production_score_button_press(event) local gui = event.element local player = game.players[event.player_index] local flow = mod_gui.get_frame_flow(player) local frame = flow.production_score_frame if frame then frame.destroy() return end frame = flow.add{type = "frame", name = "production_score_frame", caption = {"production_score"}, direction = "vertical"} frame.style.title_bottom_padding = 8 frame.add{type = "label", caption = {"", {"required_production_score"}, {"colon"}, " ", util.format_number(global.team_config.required_production_score)}} local inner_frame = frame.add{type = "frame", style = "image_frame", name = "production_score_inner_frame", direction = "vertical"} inner_frame.style.left_padding = 8 inner_frame.style.top_padding = 8 inner_frame.style.right_padding = 8 inner_frame.style.bottom_padding = 8 update_production_score_frame(player) end function update_production_score_frame(player) local gui = mod_gui.get_frame_flow(player) local frame = gui.production_score_frame if not frame then return end inner_frame = frame.production_score_inner_frame if not inner_frame then return end inner_frame.clear() local information_table = inner_frame.add{type = "table", column_count = 3} information_table.draw_horizontal_line_after_headers = true information_table.draw_vertical_lines = true information_table.style.horizontal_spacing = 16 information_table.style.vertical_spacing = 8 information_table.style.column_alignments[3] = "right" for k, caption in pairs ({"", "team-name", "production_score"}) do local label = information_table.add{type = "label", caption = {caption}} label.style.font = "default-bold" end local rank = 1 local team_map = {} for k, team in pairs (global.teams) do team_map[team.name] = team end for name, score in spairs (global.production_scores, function(t, a, b) return t[b] < t[a] end) do if team_map[name] then information_table.add{type = "label", caption = "#"..rank} local label = information_table.add{type = "label", caption = name} label.style.font = "default-semibold" label.style.font_color = get_color(team_map[name], true) information_table.add{type = "label", caption = util.format_number(score)} rank = rank + 1 end end end function oil_harvest_button_press(event) local gui = event.element if not gui.valid then return end if gui.name ~= "oil_harvest_button" then return end local player = game.players[event.player_index] local flow = mod_gui.get_frame_flow(player) local frame = flow.oil_harvest_frame if frame then frame.destroy() return end frame = flow.add{type = "frame", name = "oil_harvest_frame", caption = {"oil_harvest"}, direction = "vertical"} frame.style.title_bottom_padding = 8 frame.add{type = "label", caption = {"", {"required_oil_barrels"}, {"colon"}, " ", util.format_number(global.team_config.required_oil_barrels)}} local inner_frame = frame.add{type = "frame", style = "image_frame", name = "oil_harvest_inner_frame", direction = "vertical"} inner_frame.style.left_padding = 8 inner_frame.style.top_padding = 8 inner_frame.style.right_padding = 8 inner_frame.style.bottom_padding = 8 update_oil_harvest_frame(player) end function update_oil_harvest_frame(player) local gui = mod_gui.get_frame_flow(player) local frame = gui.oil_harvest_frame if not frame then return end inner_frame = frame.oil_harvest_inner_frame if not inner_frame then return end inner_frame.clear() local information_table = inner_frame.add{type = "table", column_count = 3} information_table.draw_horizontal_line_after_headers = true information_table.draw_vertical_lines = true information_table.style.horizontal_spacing = 16 information_table.style.vertical_spacing = 8 information_table.style.column_alignments[3] = "right" for k, caption in pairs ({"", "team-name", "oil_harvest"}) do local label = information_table.add{type = "label", caption = {caption}} label.style.font = "default-bold" end local rank = 1 local team_map = {} for k, team in pairs (global.teams) do team_map[team.name] = team end if not global.oil_harvest_scores then global.oil_harvest_scores = {} end for name, score in spairs (global.oil_harvest_scores, function(t, a, b) return t[b] < t[a] end) do if team_map[name] then information_table.add{type = "label", caption = "#"..rank} local label = information_table.add{type = "label", caption = name} label.style.font = "default-semibold" label.style.font_color = get_color(team_map[name], true) information_table.add{type = "label", caption = util.format_number(score)} rank = rank + 1 end end end function diplomacy_confirm(event) local gui = event.element local player = game.players[event.player_index] if global.team_config.locked_teams then player.print({"locked-teams"}) return end if global.team_config.who_decides_diplomacy.selected == "team_leader" then local team_leader = player.force.connected_players[1] if player.name ~= team_leader.name then player.print({"not-team-leader", team_leader.name}) return end end local diplomacy_table = gui.parent.diplomacy_inner_frame.diplomacy_table local some_change = false local changed_forces = {} for k, child in pairs (diplomacy_table.children) do if child.type == "checkbox" then if child.state then if child.name:find("_ally") then if child.state then local name = child.name:gsub("_ally", "") local force = game.forces[name] if get_stance(player.force, force) ~= "ally" then team_changed_diplomacy(player.force, force, "ally") table.insert(changed_forces, force) some_change = true end end elseif child.name:find("_neutral") then if child.state then local name = child.name:gsub("_neutral", "") local force = game.forces[name] if get_stance(player.force, force) ~= "neutral" then team_changed_diplomacy(player.force, force, "neutral") table.insert(changed_forces, force) some_change = true end end elseif child.name:find("_enemy") then if child.state then local name = child.name:gsub("_enemy", "") local force = game.forces[name] if get_stance(player.force, force) ~= "enemy" then team_changed_diplomacy(player.force, force, "enemy") table.insert(changed_forces, force) some_change = true end end end end end end if some_change then player.force.print({"player-changed-diplomacy", player.name}) for k, force in pairs (changed_forces) do for k, player in pairs (force.players) do update_diplomacy_frame(player) end end for k, player in pairs (player.force.players) do update_diplomacy_frame(player) end end player.opened.destroy() end function team_changed_diplomacy(force, other_force, stance) if stance == "ally" then force.set_friend(other_force, true) force.set_cease_fire(other_force, true) elseif stance == "neutral" then force.set_friend(other_force, false) force.set_cease_fire(other_force, true) elseif stance == "enemy" then force.set_friend(other_force, false) force.set_cease_fire(other_force, false) end game.print({"team-changed-diplomacy", force.name, other_force.name, {stance}}) end function diplomacy_check_press(event) local gui = event.element if not gui.valid then return end if not (gui.name:find("_enemy") or gui.name:find("_neutral") or gui.name:find("_ally")) then return end if global.team_config.locked_teams then gui.state = not gui.state return end if not gui.state then gui.state = true return end local index = 1 for k, child in pairs (gui.parent.children) do if child.name == gui.name then index = k break end end if gui.name:find("_neutral") then gui.parent.children[index+1].state = false gui.parent.children[index-1].state = false elseif gui.name:find("_ally") then gui.parent.children[index-2].state = false gui.parent.children[index-1].state = false else gui.parent.children[index+1].state = false gui.parent.children[index+2].state = false end end function get_stance(force, other_force) if force.get_friend(other_force) == true then return "ally" elseif force.get_cease_fire(other_force) == true then return "neutral" else return "enemy" end end function give_inventory(player) if not global.inventory_list then return end if not global.inventory_list[global.team_config.starting_inventory.selected] then return end local list = global.inventory_list[global.team_config.starting_inventory.selected] for name, count in pairs (list) do if game.item_prototypes[name] then player.insert{name = name, count = count} else game.print(name.." is not a valid item") end end end function setup_teams() local ignore = { ["player"] = true, ["enemy"] = true, ["neutral"] = true, ["spectator"] = true } for name, force in pairs (game.forces) do if not ignore[name] then game.merge_forces(name, "player") end end for k, team in pairs (global.teams) do local new_team if game.forces[team.name] then new_team = game.forces[team.name] log("In function 'setup_teams' something went wrong where a team which should have been merged into player was still valid") else new_team = game.create_force(team.name) end new_team.reset() set_spawn_position(k, new_team, global.surface) set_random_team(team) end for k, team in pairs (global.teams) do local force = game.forces[team.name] set_diplomacy(team) setup_research(force) disable_combat_technologies(force) force.reset_technology_effects() apply_balance(force) end disable_items_for_all() end function disable_items_for_all() if not global.disabled_items then return end local items = game.item_prototypes local recipes = game.recipe_prototypes local recipes_to_disable = {} for k, item in pairs (global.disabled_items) do if recipes[item] then recipes_to_disable[k] = item else local found = false for recipe_name, recipe in pairs (recipes) do for j, product in pairs (recipe.products) do if product.name == item then recipes_to_disable[k] = recipe.name found = true break end end if found then break end end end end for k, force in pairs (game.forces) do for j, name in pairs (recipes_to_disable) do force.recipes[name].enabled = false end end end function set_random_team(team) if tonumber(team.team) then return end if team.team == "-" then return end team.team = "?"..math.random(#global.teams) end function set_diplomacy(team) local force = game.forces[team.name] if not force or not force.valid then return end local team_number if tonumber(team.team) then team_number = team.team elseif team.team:find("?") then team_number = team.team:gsub("?", "") team_number = tonumber(team_number) else team_number = "Don't match me" end for k, other_team in pairs (global.teams) do if game.forces[other_team.name] then local other_number if tonumber(other_team.team) then other_number = other_team.team elseif other_team.team:find("?") then other_number = other_team.team:gsub("?", "") other_number = tonumber(other_number) else other_number = "Okay i won't match" end if other_number == team_number then force.set_cease_fire(other_team.name, true) force.set_friend(other_team.name, true) else force.set_cease_fire(other_team.name, false) force.set_friend(other_team.name, false) end end end end function set_spawn_position(k, force, surface) local setting = global.team_config.spawn_position.selected if setting == "fixed" then local position = global.spawn_positions[k] force.set_spawn_position(position, surface) return end if setting == "random" then local rand = math.random local position local index repeat index = math.random(1, #global.spawn_positions) position = global.spawn_positions[index] until position ~= nil force.set_spawn_position(position, surface) table.remove(global.spawn_positions, index) return end if setting == "team_together" then if k == #global.spawn_positions then set_team_together_spawns(surface) end end end function set_team_together_spawns(surface) local grouping = {} for k, team in pairs (global.teams) do local team_number if tonumber(team.team) then team_number = team.team elseif team.team:find("?") then team_number = team.team:gsub("?", "") team_number = tonumber(team_number) else team_number = "-" end if tonumber(team_number) then if not grouping[team_number] then grouping[team_number] = {} end table.insert(grouping[team_number], team.name) else if not grouping.no_group then grouping.no_group = {} end table.insert(grouping.no_group, team.name) end end local count = 1 for k, group in pairs (grouping) do for j, team_name in pairs (group) do local force = game.forces[team_name] if force then local position = global.spawn_positions[count] if position then force.set_spawn_position(position, surface) count = count + 1 end end end end end function chart_starting_area_for_force_spawns() local surface = global.surface local size = global.map_config.starting_area_size.selected local radius = math.ceil(starting_area_constant[size]/64) for k, team in pairs (global.teams) do local name = team.name local force = game.forces[name] if force ~= nil then local origin = force.get_spawn_position(surface) local area = {{origin.x-200, origin.y-200},{origin.x+200,origin.y+200}} surface.request_to_generate_chunks(origin, radius) force.chart(surface, area) end end global.check_starting_area_generation = true end function check_starting_area_chunks_are_generated() if not global.check_starting_area_generation then return end if game.tick % (#global.teams) ~= 0 then return end local surface = global.surface local size = global.map_config.starting_area_size.selected local check_radius = math.ceil(starting_area_constant[size]/64) - 1 local total = 0 local generated = 0 local width = surface.map_gen_settings.width/2 local height = surface.map_gen_settings.height/2 local abs = math.abs for k, team in pairs (global.teams) do local name = team.name local force = game.forces[name] if force ~= nil then local origin = force.get_spawn_position(surface) local origin_X = math.ceil(origin.x/32) local origin_Y = math.ceil(origin.y/32) for X = -check_radius, check_radius -1 do for Y = -check_radius, check_radius -1 do total = total + 1 local chunk_position = {x = X + origin_X,y = Y + origin_Y} if (surface.is_chunk_generated(chunk_position)) then generated = generated + 1 elseif (abs(chunk_position.x * 32) > width) or (abs(chunk_position.y * 32) > height) then --The chunk is outside the map generated = generated + 1 end end end end end global.progress = generated/total if total == generated then game.speed = 1 global.check_starting_area_generation = false global.finish_setup = game.tick +(#global.teams) update_progress_bar(true) return end update_progress_bar() end function check_player_color() if game.tick % 300 ~= 0 then return end for k, player in pairs (game.connected_players) do for i, team in pairs (global.teams) do if team.name == player.force.name then local c = get_color(team) if (fpn(player.color.r) ~= fpn(c.r)) or (fpn(player.color.g) ~= fpn(c.g)) or (fpn(player.color.b) ~= fpn(c.b)) then player.color = c game.print({"player-changed-color", player.name, team.name}) end break end end end end function check_round_start() if not global.next_round_start_tick then return end if game.tick ~= global.next_round_start_tick then return end destroy_config_for_all() prepare_next_round() end function check_no_rush_end() if not global.end_no_rush then return end if game.tick % 60 ~= 0 then return end if game.tick < global.end_no_rush then return end if global.team_config.no_rush_time > 0 then game.print({"no-rush-ends"}) end global.end_no_rush = nil global.surface.peaceful_mode = global.map_config.peaceful_mode game.forces.enemy.kill_all_units() end function check_no_rush_players() if not global.end_no_rush then return end if game.tick % 60 ~= 0 then return end local size = global.map_config.starting_area_size.selected local radius = starting_area_constant[size]/2 local surface = global.surface for k, player in pairs (game.connected_players) do local force = player.force if force.name ~= "player" then local origin = force.get_spawn_position(surface) local Xo = origin.x local Yo = origin.y local position = player.position local Xp = position.x local Yp = position.y if Xp > (Xo + radius) then Xp = Xo + radius end if Xp < (Xo - radius) then Xp = Xo - radius end if Yp > (Yo + radius) then Yp = Yo + radius end if Yp < (Yo - radius) then Yp = Yo - radius end if position.x ~= Xp or position.y ~= Yp then player.teleport({Xp, Yp}) local time_left = math.ceil((global.end_no_rush-game.tick)/3600) player.print({"no-rush-teleport", time_left}) end end end end function check_update_production_score() if global.team_config.game_mode.selected ~= "production_score" then return end if game.tick % 60 ~= 0 then return end global.production_scores = production_score.get_production_scores(global.price_list) for k, player in pairs (game.players) do update_production_score_frame(player) end local required = global.team_config.required_production_score if not global.team_won then for team_name, score in pairs (global.production_scores) do if score >= required then global.team_won = true game.print({"team-won", team_name}) end end end end function check_update_oil_harvest_score() if global.team_config.game_mode.selected ~= "oil_harvest" then return end if game.tick % 60 ~= 0 then return end local item_to_check = "crude-oil-barrel" if not game.item_prototypes[item_to_check] then error("Playing oil harvest game mode when crude oil barrels don't exist") return end local scores = {} for force_name, force in pairs (game.forces) do local statistics = force.item_production_statistics local input = statistics.get_input_count(item_to_check) local output = statistics.get_output_count(item_to_check) scores[force_name] = input - output end global.oil_harvest_scores = scores for k, player in pairs (game.players) do update_oil_harvest_frame(player) end local required = global.team_config.required_oil_barrels if not global.team_won then for team_name, score in pairs (global.oil_harvest_scores) do if score >= required then global.team_won = true game.print({"team-won", team_name}) end end end end function finish_setup() if not global.finish_setup then return end local index = global.finish_setup - game.tick local surface = global.surface if index == 0 then final_setup_step() return end local name = global.teams[index].name if not name then return end local force = game.forces[name] if not force then return end create_silo_for_force(force) if global.team_config.reveal_team_positions then for k, other_force in pairs (game.forces) do chart_area_for_force(surface, force.get_spawn_position(surface), 64, other_force) end end create_wall_for_force(force) force.friendly_fire = global.team_config.friendly_fire force.share_chart = global.team_config.share_chart local hide_crude_recipe_in_stats = global.team_config.game_mode.selected ~= "oil_harvest" local fill_recipe = force.recipes["fill-crude-oil-barrel"] if fill_recipe then fill_recipe.hidden_from_flow_stats = hide_crude_recipe_in_stats end local empty_recipe = force.recipes["empty-crude-oil-barrel"] if empty_recipe then empty_recipe.hidden_from_flow_stats = hide_crude_recipe_in_stats end end function final_setup_step() local surface = global.surface global.finish_setup = nil game.print({"map-ready"}) global.setup_finished = true for k, player in pairs (game.connected_players) do destroy_player_gui(player) player.teleport({0,1000}, "Lobby") choose_joining_gui(player) end global.end_no_rush = game.tick + (global.team_config.no_rush_time*60*60) if global.team_config.no_rush_time > 0 then global.surface.peaceful_mode = true game.forces.enemy.kill_all_units() game.print({"no-rush-begins", global.team_config.no_rush_time}) end if global.team_config.reveal_map_center then for k, force in pairs (game.forces) do local radius = global.map_config.average_team_displacement/2 force.chart(surface, {{-radius, -radius}, {radius, radius}}) end end end function chart_area_for_force(surface, origin, radius, force) if not force.valid then return end if (not origin.x) or (not origin.y) then game.print ("No valid value in position array") return end local area = {{origin.x-radius, origin.y-radius},{origin.x+radius, origin.y+radius}} force.chart(surface, area) end function update_progress_bar() if not global.progress then return end local percent = global.progress local finished = (percent >=1) function update_bar_gui(gui) if gui.progress_bar then if finished then gui.progress_bar.destroy() else gui.progress_bar.bar.value = percent end return end if finished then return end local frame = gui.add{type = "frame", name = "progress_bar", caption = {"progress-bar"}} local bar = frame.add{type = "progressbar", size = 100, value = percent, name = "bar"} end for k, player in pairs (game.players) do update_bar_gui(player.gui.center) end if finished then global.progress = nil global.setup_duration = nil global.finish_tick = nil end end function create_silo_for_force(force) local condition = global.team_config.game_mode.selected local need_silo = {conquest = true, space_race = true, last_silo_standing = true} if not need_silo[condition] then return end if global.team_config.game_mode.selected == "freeplay" then return end if not force then return end if not force.valid then return end local surface = global.surface local origin = force.get_spawn_position(surface) local offset_x = 0 local offset_y = -25 local silo_position = {origin.x+offset_x, origin.y+offset_y} local area = {{silo_position[1]-5,silo_position[2]-6},{silo_position[1]+6, silo_position[2]+6}} for i, entity in pairs(surface.find_entities_filtered({area = area, force = "neutral"})) do entity.destroy() end local silo = surface.create_entity{name = "rocket-silo", position = silo_position, force = force} silo.minable = false silo.backer_name = tostring(force.name) local tiles_1 = {} local tiles_2 = {} for X = -5, 5 do for Y = -6, 5 do table.insert(tiles_2, {name = "hazard-concrete-left", position = {silo_position[1]+X, silo_position[2]+Y}}) end end surface.set_tiles(tiles_2) if global.team_config.game_mode.selected ~= "space_race" then if not global.silos then global.silos = {} end global.silos[force.name] = silo end end function setup_research(force) if not force then return end if not force.valid then return end local tier = global.team_config.research_level.selected local index local set = (tier ~= "none") for k, name in pairs (global.team_config.research_level.options) do if global.research_ingredient_list[name] ~= nil then global.research_ingredient_list[name] = set end if name == tier then set = false end end --[[Unlocks all research, and then unenables them based on a blacklist]] force.research_all_technologies() for k, technology in pairs (force.technologies) do for j, ingredient in pairs (technology.research_unit_ingredients) do if not global.research_ingredient_list[ingredient.name] then technology.researched = false break end end end end function create_wall_for_force(force) if not global.team_config.team_walls then return end if not force.valid then return end local surface = global.surface local height = global.map_config.map_height/2 local width = global.map_config.map_width/2 local origin = force.get_spawn_position(surface) local size = global.map_config.starting_area_size.selected local radius = math.ceil(starting_area_constant[size]/2) -20 --[[radius in tiles]] local limit = math.min(width - math.abs(origin.x), height - math.abs(origin.y)) - 1 if width > 0 and height > 0 then radius = math.min(radius, limit) end local perimeter_top = {} local perimeter_bottom = {} local perimeter_left = {} local perimeter_right = {} local tiles = {} local insert = table.insert for X = -radius, radius-1 do for Y = -radius, radius-1 do if X == -radius then insert(perimeter_left, {origin.x + X, origin.y + Y}) elseif X == radius -1 then insert(perimeter_right, {origin.x + X, origin.y + Y}) end if Y == -radius then insert(perimeter_top, {origin.x + X, origin.y + Y}) elseif Y == radius -1 then insert(perimeter_bottom, {origin.x + X, origin.y + Y}) end end end local tile_name = "concrete" local areas = { {{perimeter_top[1][1], perimeter_top[1][2]-1}, {perimeter_top[#perimeter_top][1], perimeter_top[1][2]+2}}, {{perimeter_bottom[1][1], perimeter_bottom[1][2]-2}, {perimeter_bottom[#perimeter_bottom][1], perimeter_bottom[1][2]+1}}, {{perimeter_left[1][1]-1, perimeter_left[1][2]}, {perimeter_left[1][1]+2, perimeter_left[#perimeter_left][2]}}, {{perimeter_right[1][1]-2, perimeter_right[1][2]}, {perimeter_right[1][1]+1, perimeter_right[#perimeter_right][2]}}, } for k, area in pairs (areas) do for i, entity in pairs(surface.find_entities_filtered({area = area})) do entity.destroy() end end for k, position in pairs (perimeter_left) do insert(tiles, {name = tile_name, position = {position[1],position[2]}}) insert(tiles, {name = tile_name, position = {position[1]+1,position[2]}}) if (position[2] % 32 == 14) or (position[2] % 32 == 15) or (position[2] % 32 == 16) or (position[2] % 32 == 17) then surface.create_entity{name = "gate", position = {position[1],position[2]}, direction = 0, force = force} else surface.create_entity{name = "stone-wall", position = {position[1],position[2]}, force = force} end end for k, position in pairs (perimeter_right) do insert(tiles, {name = tile_name, position = {position[1]-1,position[2]}}) insert(tiles, {name = tile_name, position = {position[1],position[2]}}) if (position[2] % 32 == 14) or (position[2] % 32 == 15) or (position[2] % 32 == 16) or (position[2] % 32 == 17) then surface.create_entity{name = "gate", position = {position[1],position[2]}, direction = 0, force = force} else surface.create_entity{name = "stone-wall", position = {position[1],position[2]}, force = force} end end for k, position in pairs (perimeter_top) do insert(tiles, {name = tile_name, position = {position[1],position[2]}}) insert(tiles, {name = tile_name, position = {position[1],position[2]+1}}) if (position[1] % 32 == 14) or (position[1] % 32 == 15) or (position[1] % 32 == 16) or (position[1] % 32 == 17) then surface.create_entity{name = "gate", position = {position[1],position[2]}, direction = 2, force = force} else surface.create_entity{name = "stone-wall", position = {position[1],position[2]}, force = force} end end for k, position in pairs (perimeter_bottom) do insert(tiles, {name = tile_name, position = {position[1],position[2]-1}}) insert(tiles, {name = tile_name, position = {position[1],position[2]}}) if (position[1] % 32 == 14) or (position[1] % 32 == 15) or (position[1] % 32 == 16) or (position[1] % 32 == 17) then surface.create_entity{name = "gate", position = {position[1],position[2]}, direction = 2, force = force} else surface.create_entity{name = "stone-wall", position = {position[1],position[2]}, force = force} end end surface.set_tiles(tiles) end function spairs(t, order) local keys = {} for k in pairs(t) do keys[#keys+1] = k end if order then table.sort(keys, function(a, b) return order(t, a, b) end) else table.sort(keys) end local i = 0 return function() i = i + 1 if keys[i] then return keys[i], t[keys[i]] end end end function verify_oil_harvest() if game.item_prototypes["crude-oil-barrel"] and game.entity_prototypes["crude-oil"] and game.recipe_prototypes["fill-crude-oil-barrel"] and game.recipe_prototypes["empty-crude-oil-barrel"] then return end for k, mode in pairs (global.team_config.game_mode.options) do if mode == "oil_harvest" then table.remove(global.team_config.game_mode.options, k) log("Oil harvest mode removed from scenario, as oil barrels and crude oil were not present in this configuration.") break end end end function oil_harvest_prune_oil(event) if global.team_config.game_mode.selected ~= "oil_harvest" then return end if not global.team_config.oil_only_in_center then return end local area = event.area local center = {x = (area.left_top.x + area.right_bottom.x)/2, y = (area.left_top.y + area.right_bottom.y)/2} local distance_from_center = (center.x*center.x + center.y*center.y)^0.5 if distance_from_center > global.map_config.average_team_displacement/3 then for k, entity in pairs (event.surface.find_entities_filtered{area = area, name = "crude-oil"}) do entity.destroy() end end end button_press_functions = { ["add_team_button"] = add_team_button_press, ["admin_button"] = admin_button_press, ["auto_assign_button"] = function(event) event.element.parent.destroy() auto_assign(game.players[event.player_index]) end, ["balance_options_cancel"] = function(event) event.element.parent.destroy() end, ["balance_options_confirm"] = function(event) set_balance_settings(event.element.parent.balance_options_scrollpane) event.element.parent.destroy() end, ["balance_options"] = function(event) create_balance_option(mod_gui.get_frame_flow(game.players[event.player_index])) end, ["config_confirm"] = function(event) config_confirm(event.element) end, ["diplomacy_button"] = diplomacy_button_press, ["diplomacy_cancel"] = function(event) game.players[event.player_index].opened.destroy() end, ["diplomacy_confirm"] = diplomacy_confirm, ["disable_items_cancel"] = function(event) event.element.parent.parent.destroy() end, ["disable_items_confirm"] = function (event) parse_disabled_items(event.element.parent.parent.parent) event.element.parent.parent.destroy() end, ["disable_items"] = function(event) create_disable_frame(mod_gui.get_frame_flow(game.players[event.player_index])) end, ["objective_button"] = objective_button_press, ["oil_harvest_button"] = oil_harvest_button_press, ["player_pick_confirm"] = player_pick_button_press, ["production_score_button"] = production_score_button_press, ["random_join_button"] = function(event) event.element.parent.destroy() random_join(game.players[event.player_index]) end, } pvp = {} pvp.on_init = function(event) load_config() verify_oil_harvest() global.copy_surface = game.surfaces[1] local settings = game.surfaces[1].map_gen_settings global.map_config.starting_area_size.selected = settings.starting_area global.map_config.map_height = settings.height global.map_config.map_width = settings.width global.map_config.starting_area_size.selected = settings.starting_area global.round_number = 0 global.next_round_start_tick = 60*60 local surface = game.create_surface("Lobby",{width = 1, height = 1}) surface.set_tiles({{name = "out-of-map",position = {1,1}}}) for k, force in pairs (game.forces) do force.disable_all_prototypes() force.disable_research() end global.price_list = production_score.generate_price_list() end pvp.on_rocket_launched = function(event) if global.team_config.game_mode.selected == "last_silo_standing" then return end local force = event.rocket.force if event.rocket.get_item_count("satellite") == 0 then force.print({"rocket-launched-without-satellite"}) return end if not global.team_won then global.team_won = true game.print({"team-won",force.name}) end end pvp.on_entity_died = function(event) local silo = event.entity if not (silo and silo.valid and silo.name == "rocket-silo") then return end local killing_force = event.force local force = silo.force if not global.silos then return end global.silos[force.name] = nil if not killing_force then killing_force = {} killing_force.name = "neutral" end game.print({"silo-destroyed",force.name, killing_force.name}) local index = 0 local winner_name = "none" for k, listed_silo in pairs (global.silos) do if listed_silo ~= nil then index = index + 1 winner_name = k end end for k, player in pairs (force.players) do player.force = game.forces.player if player.connected then local character = player.character player.character = nil if character then character.destroy() end player.set_controller{type = defines.controllers.ghost} player.teleport({0,1000}, game.surfaces.Lobby) player.print{"join-new-team"} destroy_player_gui(player) choose_joining_gui(player) end end if force.name == killing_force.name then game.merge_forces(force.name, "neutral") else game.merge_forces(force.name, killing_force.name) end if index > 1 then return end if not global.team_won then global.team_won = true game.print({"team-won", winner_name}) end end pvp.on_player_created = function(event) if event.player_index ~= 1 then return end if global.map_config.map_height < 64 or global.map_config.map_width < 64 then game.print({"minimum-map-size"}) end local player = game.players[event.player_index] local character = player.character player.character = nil if character then character.destroy() end player.teleport({0,1000}, game.surfaces.Lobby) player.set_controller{type = defines.controllers.ghost} create_config_gui(player) for k, v in pairs (game.surfaces[1].find_entities()) do v.destroy() end end pvp.on_player_joined_game = function(event) if game.tick < 10 then global.next_round_start_tick = nil return end local player = game.players[event.player_index] if not (player and player.valid and player.force.name == "player") then return end local character = player.character player.character = nil if character then character.destroy() end player.set_controller{type = defines.controllers.ghost} if global.setup_finished then player.teleport({0,1000}, game.surfaces.Lobby) choose_joining_gui(player) else player.teleport({0,1000}, game.surfaces.Lobby) if player.admin then create_config_gui(player) end player.print({"setup-in-process"}) end player.set_controller{type = defines.controllers.ghost} end pvp.on_gui_selection_state_changed = function(event) local gui = event.element if not (gui and gui.valid and gui.name and gui.name == "game_mode_dropdown") then return end global.team_config.game_mode.selected = global.team_config.game_mode.options[gui.selected_index] set_mode_input(gui.parent) end pvp.on_gui_checked_state_changed = function(event) local player = game.players[event.player_index] local gui = event.element if not (player and player.valid and gui and gui.valid) then return end if gui.parent.name == "pick_join_table" then for k, team in pairs (global.teams) do local force = game.forces[team.name] if force then local check = gui.parent[team.name] if check and (check.name ~= gui.name) then check.state = false end else if gui.parent[team.name] then create_pick_join_gui(player.gui.center) return end end end return end diplomacy_check_press(event) end pvp.on_player_left_game = function(event) for k, player in pairs (game.players) do local gui = player.gui.center if gui.diplomacy_frame then update_diplomacy_frame(player) end if gui.pick_join_frame then create_pick_join_gui(gui) end end end pvp.on_gui_elem_changed = function(event) local gui = event.element local player = game.players[event.player_index] if not (player and player.valid and gui and gui.valid) then return end local parent = gui.parent if parent.name == "disable_items_table" then if gui.elem_value then for k, child in pairs (gui.parent.children) do if child ~= gui and child.elem_value == gui.elem_value then gui.destroy() player.print({"duplicate-disable"}) break end end parent.add{type = "choose-elem-button", elem_type = "item"} else gui.destroy() end end end pvp.on_gui_click = function(event) local gui = event.element local player = game.players[event.player_index] if not (player and player.valid and gui and gui.valid) then return end if gui.name then local button_function = button_press_functions[gui.name] if button_function then button_function(event) return end end trash_team_button_press(event) on_team_button_press(event) admin_frame_button_press(event) end pvp.on_gui_closed = function(event) local gui = event.element if not (gui and gui.valid) then return end if gui.name == "diplomacy_frame" then gui.destroy() return end end pvp.on_tick = function(event) check_no_rush_end() check_no_rush_players() check_player_color() check_update_production_score() check_update_oil_harvest_score() if global.setup_finished == false then check_round_start() check_starting_area_chunks_are_generated() finish_setup() end end pvp.on_chunk_generated = function(event) oil_harvest_prune_oil(event) end return pvp