1
0
mirror of https://github.com/Oarcinae/FactorioScenarioMultiplayerSpawn.git synced 2024-12-12 10:13:58 +02:00
FactorioScenarioMultiplayer.../lib/separate_spawns_guis.lua

1230 lines
49 KiB
Lua

-- separate_spawns_guis.lua
-- Nov 2016
-- I made a separate file for all the GUI related functions
require("lib/separate_spawns")
local SPAWN_GUI_MAX_WIDTH = 500
local SPAWN_GUI_MAX_HEIGHT = 1000
-- Use this for testing shared spawns...
-- local sharedSpawnExample1 = {openAccess=true,
-- position={x=50,y=50},
-- players={"ABC", "DEF"}}
-- local sharedSpawnExample2 = {openAccess=false,
-- position={x=200,y=200},
-- players={"ABC", "DEF"}}
-- local sharedSpawnExample3 = {openAccess=true,
-- position={x=400,y=400},
-- players={"A", "B", "C", "D"}}
-- global.sharedSpawns = {testName1=sharedSpawnExample1,
-- testName2=sharedSpawnExample2,
-- Oarc=sharedSpawnExample3}
-- A display gui message
-- Meant to be display the first time a player joins.
function DisplayWelcomeTextGui(player)
if (TableLength(player.gui.center.children) > 0) then
log("DisplayWelcomeTextGui called while some other dialog is already displayed!")
return
end
player.gui.center.add{name = "welcome_msg",
type = "frame",
direction = "vertical",
caption=global.ocfg.welcome_title}
local wGui = player.gui.center.welcome_msg
wGui.style.maximal_width = SPAWN_GUI_MAX_WIDTH
wGui.style.maximal_height = SPAWN_GUI_MAX_HEIGHT
-- Start with server message.
AddLabel(wGui, "server_msg_lbl1", global.ocfg.server_rules, my_label_style)
AddLabel(wGui, "contact_info_msg_lbl1", global.ocfg.server_contact, my_label_style)
AddSpacer(wGui, "server_msg_spacer1")
-- Informational message about the scenario
AddLabel(wGui, "scenario_info_msg_lbl1", SCENARIO_INFO_MSG, my_label_style)
AddSpacer(wGui, "scenario_info_msg_spacer1")
-- Warning about spawn creation time
AddLabel(wGui, "spawn_time_msg_lbl1", {"oarc-spawn-time-warning-msg"}, my_warning_style)
local button_flow = wGui.add{type = "flow"}
button_flow.style.horizontal_align = "right"
button_flow.style.horizontally_stretchable = true
button_flow.add{name = "welcome_okay_btn",
type = "button",
caption={"oarc-i-understand"},
style = "confirm_button"}
end
-- Handle the gui click of the welcome msg
function WelcomeTextGuiClick(event)
if not (event and event.element and event.element.valid) then return end
local player = game.players[event.player_index]
local buttonClicked = event.element.name
if not player then
log("Another gui click happened with no valid player...")
return
end
if (buttonClicked == "welcome_okay_btn") then
if (player.gui.center.welcome_msg ~= nil) then
player.gui.center.welcome_msg.destroy()
end
DisplaySpawnOptions(player)
end
end
-- Display the spawn options and explanation
function DisplaySpawnOptions(player)
if (player == nil) then
log("DisplaySpawnOptions with no valid player...")
return
end
if (player.gui.center.spawn_opts ~= nil) then
log("Tried to display spawn options when it was already displayed!")
return
end
player.gui.center.add{name = "spawn_opts",
type = "frame",
direction = "vertical",
caption={"oarc-spawn-options"}}
local sGui = player.gui.center.spawn_opts
sGui.style.maximal_width = SPAWN_GUI_MAX_WIDTH
sGui.style.maximal_height = SPAWN_GUI_MAX_HEIGHT
-- Warnings and explanations...
local warn_msg = {"oarc-click-info-btn-help"}
AddLabel(sGui, "warning_lbl1", warn_msg, my_warning_style)
AddLabel(sGui, "spawn_msg_lbl1", SPAWN_MSG1, my_label_style)
-- Button and message about the regular vanilla spawn
-- if ENABLE_DEFAULT_SPAWN then
-- sGui.add{name = "default_spawn_btn",
-- type = "button",
-- caption={"oarc-vanilla-spawn"}}
-- local normal_spawn_text = {"oarc-default-spawn-behavior"}
-- AddLabel(sGui, "normal_spawn_lbl1", normal_spawn_text, my_label_style)
-- -- AddSpacerLine(sGui, "normal_spawn_spacer")
-- end
-- The main spawning options. Solo near and solo far.
-- If enable, you can also choose to be on your own team.
local soloSpawnFlow = sGui.add{name = "spawn_solo_flow",
type = "frame",
direction="vertical",
style = "bordered_frame"}
-- Radio buttons to pick your team.
if (global.ocfg.enable_separate_teams) then
soloSpawnFlow.add{name = "isolated_spawn_main_team_radio",
type = "radiobutton",
caption={"oarc-join-main-team-radio"},
state=true}
soloSpawnFlow.add{name = "isolated_spawn_new_team_radio",
type = "radiobutton",
caption={"oarc-create-own-team-radio"},
state=false}
end
-- OPTIONS frame
-- AddLabel(soloSpawnFlow, "options_spawn_lbl1",
-- "Additional spawn options can be selected here. Not all are compatible with each other.", my_label_style)
-- Allow players to spawn with a moat around their area.
if (global.ocfg.spawn_config.gen_settings.moat_choice_enabled and not global.ocfg.enable_vanilla_spawns) then
soloSpawnFlow.add{name = "isolated_spawn_moat_option_checkbox",
type = "checkbox",
caption={"oarc-moat-option"},
state=false}
end
-- if (global.ocfg.enable_vanilla_spawns and (#global.vanillaSpawns > 0)) then
-- soloSpawnFlow.add{name = "isolated_spawn_vanilla_option_checkbox",
-- type = "checkbox",
-- caption="Use a pre-set vanilla spawn point. " .. #global.vanillaSpawns .. " available.",
-- state=false}
-- end
-- Isolated spawn options. The core gameplay of this scenario.
local soloSpawnbuttons = soloSpawnFlow.add{name = "spawn_solo_flow",
type = "flow",
direction="horizontal"}
soloSpawnbuttons.style.horizontal_align = "center"
soloSpawnbuttons.style.horizontally_stretchable = true
soloSpawnbuttons.add{name = "isolated_spawn_near",
type = "button",
caption={"oarc-solo-spawn-near"},
style = "confirm_button"}
soloSpawnbuttons.add{name = "isolated_spawn_far",
type = "button",
caption={"oarc-solo-spawn-far"},
style = "confirm_button"}
if (global.ocfg.enable_vanilla_spawns) then
AddLabel(soloSpawnFlow, "isolated_spawn_lbl1",
{"oarc-starting-area-vanilla"}, my_label_style)
AddLabel(soloSpawnFlow, "vanilla_spawn_lbl2",
{"oarc-vanilla-spawns-available", #global.vanillaSpawns}, my_label_style)
else
AddLabel(soloSpawnFlow, "isolated_spawn_lbl1",
{"oarc-starting-area-normal"}, my_label_style)
end
-- Spawn options to join another player's base.
local sharedSpawnFrame = sGui.add{name = "spawn_shared_flow",
type = "frame",
direction="vertical",
style = "bordered_frame"}
if global.ocfg.enable_shared_spawns then
local numAvailSpawns = GetNumberOfAvailableSharedSpawns()
if (numAvailSpawns > 0) then
sharedSpawnFrame.add{name = "join_other_spawn",
type = "button",
caption={"oarc-join-someone-avail", numAvailSpawns}}
local join_spawn_text = {"oarc-join-someone-info"}
AddLabel(sharedSpawnFrame, "join_other_spawn_lbl1", join_spawn_text, my_label_style)
else
AddLabel(sharedSpawnFrame, "join_other_spawn_lbl1", {"oarc-no-shared-avail"}, my_label_style)
sharedSpawnFrame.add{name = "join_other_spawn_check",
type = "button",
caption={"oarc-join-check-again"}}
end
else
AddLabel(sharedSpawnFrame, "join_other_spawn_lbl1",
{"oarc-shared-spawn-disabled"}, my_warning_style)
end
-- Awesome buddy spawning system
if (not global.ocfg.enable_vanilla_spawns) then
if global.ocfg.enable_shared_spawns and global.ocfg.enable_buddy_spawn then
local buddySpawnFrame = sGui.add{name = "spawn_buddy_flow",
type = "frame",
direction="vertical",
style = "bordered_frame"}
-- AddSpacerLine(buddySpawnFrame, "buddy_spawn_msg_spacer")
buddySpawnFrame.add{name = "buddy_spawn",
type = "button",
caption={"oarc-buddy-spawn"}}
AddLabel(buddySpawnFrame, "buddy_spawn_lbl1",
{"oarc-buddy-spawn-info"} , my_label_style)
end
end
-- Some final notes
if (global.ocfg.max_players_shared_spawn > 0) then
AddLabel(sGui, "max_players_lbl2",
{"oarc-max-players-shared-spawn", global.ocfg.max_players_shared_spawn-1},
my_note_style)
end
local spawn_distance_notes={"oarc-spawn-dist-notes", global.ocfg.near_dist_start, global.ocfg.near_dist_end, global.ocfg.far_dist_start, global.ocfg.far_dist_end}
AddLabel(sGui, "note_lbl1", spawn_distance_notes, my_note_style)
end
-- This just updates the radio buttons/checkboxes when players click them.
function SpawnOptsRadioSelect(event)
if not (event and event.element and event.element.valid) then return end
local elemName = event.element.name
if (elemName == "isolated_spawn_main_team_radio") then
event.element.parent.isolated_spawn_new_team_radio.state=false
elseif (elemName == "isolated_spawn_new_team_radio") then
event.element.parent.isolated_spawn_main_team_radio.state=false
end
if (elemName == "buddy_spawn_main_team_radio") then
event.element.parent.buddy_spawn_new_team_radio.state=false
event.element.parent.buddy_spawn_buddy_team_radio.state=false
elseif (elemName == "buddy_spawn_new_team_radio") then
event.element.parent.buddy_spawn_main_team_radio.state=false
event.element.parent.buddy_spawn_buddy_team_radio.state=false
elseif (elemName == "buddy_spawn_buddy_team_radio") then
event.element.parent.buddy_spawn_main_team_radio.state=false
event.element.parent.buddy_spawn_new_team_radio.state=false
end
end
-- Handle the gui click of the spawn options
function SpawnOptsGuiClick(event)
if not (event and event.element and event.element.valid) then return end
local player = game.players[event.player_index]
local elemName = event.element.name
if not player then
log("Another gui click happened with no valid player...")
return
end
if (player.gui.center.spawn_opts == nil) then
return -- Gui event unrelated to this gui.
end
local pgcs = player.gui.center.spawn_opts
local joinMainTeamRadio, joinOwnTeamRadio, moatChoice, vanillaChoice = false
-- Check if a valid button on the gui was pressed
-- and delete the GUI
if ((elemName == "default_spawn_btn") or
(elemName == "isolated_spawn_near") or
(elemName == "isolated_spawn_far") or
(elemName == "join_other_spawn") or
(elemName == "buddy_spawn") or
(elemName == "join_other_spawn_check")) then
if (global.ocfg.enable_separate_teams) then
joinMainTeamRadio =
pgcs.spawn_solo_flow.isolated_spawn_main_team_radio.state
joinOwnTeamRadio =
pgcs.spawn_solo_flow.isolated_spawn_new_team_radio.state
else
joinMainTeamRadio = true
joinOwnTeamRadio = false
end
if (global.ocfg.spawn_config.gen_settings.moat_choice_enabled and not global.ocfg.enable_vanilla_spawns and
(pgcs.spawn_solo_flow.isolated_spawn_moat_option_checkbox ~= nil)) then
moatChoice = pgcs.spawn_solo_flow.isolated_spawn_moat_option_checkbox.state
end
-- if (global.ocfg.enable_vanilla_spawns and
-- (pgcs.spawn_solo_flow.isolated_spawn_vanilla_option_checkbox ~= nil)) then
-- vanillaChoice = pgcs.spawn_solo_flow.isolated_spawn_vanilla_option_checkbox.state
-- end
pgcs.destroy()
else
return -- Do nothing, no valid element item was clicked.
end
if (elemName == "default_spawn_btn") then
GivePlayerStarterItems(player)
ChangePlayerSpawn(player, player.force.get_spawn_position(GAME_SURFACE_NAME))
SendBroadcastMsg({"oarc-player-is-joining-main-force", player.name})
ChartArea(player.force, player.position, math.ceil(global.ocfg.spawn_config.gen_settings.land_area_tiles/CHUNK_SIZE), player.surface)
-- Create the button at the top left for setting respawn point and sharing base.
CreateSpawnCtrlGui(player)
elseif ((elemName == "isolated_spawn_near") or (elemName == "isolated_spawn_far")) then
-- Create a new spawn point
local newSpawn = {x=0,y=0}
-- Create a new force for player if they choose that radio button
if global.ocfg.enable_separate_teams and joinOwnTeamRadio then
local newForce = CreatePlayerCustomForce(player)
end
-- Find an unused vanilla spawn
-- if (vanillaChoice) then
if (global.ocfg.enable_vanilla_spawns) then
if (elemName == "isolated_spawn_far") then
newSpawn = FindUnusedVanillaSpawn(game.surfaces[GAME_SURFACE_NAME],
global.ocfg.far_dist_end*CHUNK_SIZE)
elseif (elemName == "isolated_spawn_near") then
newSpawn = FindUnusedVanillaSpawn(game.surfaces[GAME_SURFACE_NAME],
global.ocfg.near_dist_start*CHUNK_SIZE)
end
-- Default OARC-type pre-set layout spawn.
else
-- Find coordinates of a good place to spawn
if (elemName == "isolated_spawn_far") then
newSpawn = FindUngeneratedCoordinates(global.ocfg.far_dist_start,global.ocfg.far_dist_end, player.surface)
elseif (elemName == "isolated_spawn_near") then
newSpawn = FindUngeneratedCoordinates(global.ocfg.near_dist_start,global.ocfg.near_dist_end, player.surface)
end
end
-- If that fails, find a random map edge in a rand direction.
if ((newSpawn.x == 0) and (newSpawn.y == 0)) then
newSpawn = FindMapEdge(GetRandomVector(), player.surface)
log("Resorting to find map edge! x=" .. newSpawn.x .. ",y=" .. newSpawn.y)
end
-- Create that player's spawn in the global vars
ChangePlayerSpawn(player, newSpawn)
-- Send the player there
-- QueuePlayerForDelayedSpawn(player.name, newSpawn, moatChoice, vanillaChoice)
QueuePlayerForDelayedSpawn(player.name, newSpawn, moatChoice, global.ocfg.enable_vanilla_spawns)
if (elemName == "isolated_spawn_near") then
SendBroadcastMsg({"oarc-player-is-joining-near", player.name})
elseif (elemName == "isolated_spawn_far") then
SendBroadcastMsg({"oarc-player-is-joining-far", player.name})
end
-- Create the button at the top left for setting respawn point and sharing base.
CreateSpawnCtrlGui(player)
player.print({"oarc-please-wait"})
player.print({"", {"oarc-please-wait"}, "!"})
player.print({"", {"oarc-please-wait"}, "!!"})
elseif (elemName == "join_other_spawn") then
DisplaySharedSpawnOptions(player)
-- Provide a way to refresh the gui to check if people have shared their
-- bases.
elseif (elemName == "join_other_spawn_check") then
DisplaySpawnOptions(player)
-- Hacky buddy spawn system
elseif (elemName == "buddy_spawn") then
table.insert(global.waitingBuddies, player.name)
SendBroadcastMsg({"oarc-looking-for-buddy", player.name})
DisplayBuddySpawnOptions(player)
end
end
-- Display the spawn options and explanation
function DisplaySharedSpawnOptions(player)
player.gui.center.add{name = "shared_spawn_opts",
type = "frame",
direction = "vertical",
caption={"oarc-avail-bases-join"}}
local shGuiFrame = player.gui.center.shared_spawn_opts
local shGui = shGuiFrame.add{type="scroll-pane", name="spawns_scroll_pane", caption=""}
ApplyStyle(shGui, my_fixed_width_style)
shGui.style.maximal_width = SPAWN_GUI_MAX_WIDTH
shGui.style.maximal_height = SPAWN_GUI_MAX_HEIGHT
shGui.horizontal_scroll_policy = "never"
for spawnName,sharedSpawn in pairs(global.sharedSpawns) do
if (sharedSpawn.openAccess and
(game.players[spawnName] ~= nil) and
game.players[spawnName].connected) then
local spotsRemaining = global.ocfg.max_players_shared_spawn - GetOnlinePlayersAtSharedSpawn(spawnName)
if (global.ocfg.max_players_shared_spawn == 0) then
shGui.add{type="button", caption=spawnName, name=spawnName}
elseif (spotsRemaining > 0) then
shGui.add{type="button", caption={oarc-spawn-spots-remaining, spawnName, spotsRemaining}, name=spawnName}
end
if (shGui.spawnName ~= nil) then
-- AddSpacer(buddyGui, spawnName .. "spacer_lbl")
ApplyStyle(shGui[spawnName], my_small_button_style)
end
end
end
shGui.add{name = "shared_spawn_cancel",
type = "button",
caption={"oarc-cancel-return-to-previous"},
style = "back_button"}
end
-- Handle the gui click of the shared spawn options
function SharedSpwnOptsGuiClick(event)
if not (event and event.element and event.element.valid) then return end
local player = game.players[event.player_index]
local buttonClicked = event.element.name
if not player then
log("Another gui click happened with no valid player...")
return
end
if (event.element.parent) then
if (event.element.parent.name ~= "spawns_scroll_pane") then
return
end
end
-- Check for cancel button, return to spawn options
if (buttonClicked == "shared_spawn_cancel") then
DisplaySpawnOptions(player)
if (player.gui.center.shared_spawn_opts ~= nil) then
player.gui.center.shared_spawn_opts.destroy()
end
-- Else check for which spawn was selected
-- If a spawn is removed during this time, the button will not do anything
else
for spawnName,sharedSpawn in pairs(global.sharedSpawns) do
if ((buttonClicked == spawnName) and
(game.players[spawnName] ~= nil) and
(game.players[spawnName].connected)) then
-- Add the player to that shared spawns join queue.
if (global.sharedSpawns[spawnName].joinQueue == nil) then
global.sharedSpawns[spawnName].joinQueue = {}
end
table.insert(global.sharedSpawns[spawnName].joinQueue, player.name)
-- Clear the shared spawn options gui.
if (player.gui.center.shared_spawn_opts ~= nil) then
player.gui.center.shared_spawn_opts.destroy()
end
-- Display wait menu with cancel button.
DisplaySharedSpawnJoinWaitMenu(player)
-- Tell other player they are requesting a response.
game.players[spawnName].print({"oarc-player-requesting-join-you", player.name})
break
end
end
end
end
function DisplaySharedSpawnJoinWaitMenu(player)
player.gui.center.add{name = "join_shared_spawn_wait_menu",
type = "frame",
direction = "vertical",
caption={"oarc-waiting-for-spawn-owner"}}
local sGui = player.gui.center.join_shared_spawn_wait_menu
sGui.style.maximal_width = SPAWN_GUI_MAX_WIDTH
sGui.style.maximal_height = SPAWN_GUI_MAX_HEIGHT
-- Warnings and explanations...
AddLabel(sGui, "warning_lbl1", {"oarc-you-will-spawn-once-host"}, my_warning_style)
sGui.add{name = "cancel_shared_spawn_wait_menu",
type = "button",
caption={"oarc-cancel-return-to-previous"},
style = "back_button"}
end
-- Handle the gui click of the buddy wait menu
function SharedSpawnJoinWaitMenuClick(event)
if not (event and event.element and event.element.valid) then return end
local player = game.players[event.player_index]
local elemName = event.element.name
if not player then
log("Another gui click happened with no valid player...")
return
end
if (player.gui.center.join_shared_spawn_wait_menu == nil) then
return -- Gui event unrelated to this gui.
end
-- Check if player is cancelling the request.
if (elemName == "cancel_shared_spawn_wait_menu") then
player.gui.center.join_shared_spawn_wait_menu.destroy()
DisplaySpawnOptions(player)
-- Find and remove the player from the joinQueue they were in.
for spawnName,sharedSpawn in pairs(global.sharedSpawns) do
if (sharedSpawn.joinQueue ~= nil) then
for index,requestingPlayer in pairs(sharedSpawn.joinQueue) do
if (requestingPlayer == player.name) then
table.remove(global.sharedSpawns[spawnName].joinQueue, index)
game.players[spawnName].print({"oarc-player-cancel-join-request", player.name})
return
end
end
end
end
log("ERROR! Failed to remove player from joinQueue!")
end
end
function CreateSpawnCtrlGui(player)
if player and (player.gui.top.spwn_ctrls == nil) then
player.gui.top.add{name="spwn_ctrls", type="button", caption={"oarc-spawn-ctrl"}}
end
end
local function IsSharedSpawnActive(player)
if ((global.sharedSpawns[player.name] == nil) or
(global.sharedSpawns[player.name].openAccess == false)) then
return false
else
return true
end
end
-- Get a random warp point to go to
function GetRandomSpawnPoint()
local numSpawnPoints = TableLength(global.sharedSpawns)
if (numSpawnPoints > 0) then
local randSpawnNum = math.random(1,numSpawnPoints)
local counter = 1
for _,sharedSpawn in pairs(global.sharedSpawns) do
if (randSpawnNum == counter) then
return sharedSpawn.position
end
counter = counter + 1
end
end
return {x=0,y=0}
end
-- This is a toggle function, it either shows or hides the spawn controls
function ExpandSpawnCtrlGui(player, tick)
local spwnCtrlPanel = player.gui.left["spwn_ctrl_panel"]
if (spwnCtrlPanel) then
spwnCtrlPanel.destroy()
else
local spwnCtrlPanel = player.gui.left.add{type="frame",
name="spwn_ctrl_panel", caption={"oarc-spawn-controls"}}
local spwnCtrls = spwnCtrlPanel.add{type="scroll-pane",
name="spwn_ctrl_panel", caption=""}
ApplyStyle(spwnCtrls, my_fixed_width_style)
spwnCtrls.style.maximal_height = SPAWN_GUI_MAX_HEIGHT
spwnCtrls.horizontal_scroll_policy = "never"
if global.ocfg.enable_shared_spawns then
if (global.uniqueSpawns[player.name] ~= nil) then
-- This checkbox allows people to join your base when they first
-- start the game.
spwnCtrls.add{type="checkbox", name="accessToggle",
caption={"oarc-spawn-allow-joiners"},
state=IsSharedSpawnActive(player)}
ApplyStyle(spwnCtrls["accessToggle"], my_fixed_width_style)
end
end
-- Sets the player's custom spawn point to their current location
if ((tick - global.playerCooldowns[player.name].setRespawn) > RESPAWN_COOLDOWN_TICKS) then
spwnCtrls.add{type="button", name="setRespawnLocation", caption={"oarc-set-respawn-loc"}}
spwnCtrls["setRespawnLocation"].style.font = "default-small-semibold"
else
AddLabel(spwnCtrls, "respawn_cooldown_note1", {"oarc-set-respawn-loc-cooldown", formattime(RESPAWN_COOLDOWN_TICKS-(tick - global.playerCooldowns[player.name].setRespawn))}, my_note_style)
end
AddLabel(spwnCtrls, "respawn_cooldown_note2", {"oarc-set-respawn-note"}, my_note_style)
-- Display a list of people in the join queue for your base.
if (global.ocfg.enable_shared_spawns and IsSharedSpawnActive(player)) then
if ((global.sharedSpawns[player.name].joinQueue ~= nil) and
(#global.sharedSpawns[player.name].joinQueue > 0)) then
AddLabel(spwnCtrls, "drop_down_msg_lbl1", {"oarc-select-player-join-queue"}, my_label_style)
spwnCtrls.add{name = "join_queue_dropdown",
type = "drop-down",
items = global.sharedSpawns[player.name].joinQueue}
spwnCtrls.add{name = "accept_player_request",
type = "button",
caption={"oarc-accept"}}
spwnCtrls.add{name = "reject_player_request",
type = "button",
caption={"oarc-reject"}}
else
AddLabel(spwnCtrls, "empty_join_queue_note1", {"oarc-no-player-join-reqs"}, my_note_style)
end
spwnCtrls.add{name = "join_queue_spacer", type = "label",
caption=" "}
end
end
end
function SpawnCtrlGuiOptionsSelect(event)
if not (event and event.element and event.element.valid) then return end
local player = game.players[event.element.player_index]
local name = event.element.name
if not player then
log("Another gui click happened with no valid player...")
return
end
-- Handle changes to spawn sharing.
if (name == "accessToggle") then
if event.element.state then
if DoesPlayerHaveCustomSpawn(player) then
if (global.sharedSpawns[player.name] == nil) then
CreateNewSharedSpawn(player)
else
global.sharedSpawns[player.name].openAccess = true
end
SendBroadcastMsg({"oarc-start-shared-base", player.name})
end
else
if (global.sharedSpawns[player.name] ~= nil) then
global.sharedSpawns[player.name].openAccess = false
SendBroadcastMsg({"oarc-stop-shared-base", player.name})
end
end
end
end
function SpawnCtrlGuiClick(event)
if not (event and event.element and event.element.valid) then return end
local player = game.players[event.element.player_index]
local elemName = event.element.name
if not player then
log("Another gui click happened with no valid player...")
return
end
if (elemName == "spwn_ctrls") then
ExpandSpawnCtrlGui(player, event.tick)
end
if (event.element.parent) then
if (event.element.parent.name ~= "spwn_ctrl_panel") then
return
end
end
-- Sets a new respawn point and resets the cooldown.
if (elemName == "setRespawnLocation") then
if DoesPlayerHaveCustomSpawn(player) then
ChangePlayerSpawn(player, player.position)
ExpandSpawnCtrlGui(player, event.tick)
player.print({"oarc-spawn-point-updated"})
end
end
-- Accept or reject pending player join requests to a shared base
if ((elemName == "accept_player_request") or (elemName == "reject_player_request")) then
if ((event.element.parent.join_queue_dropdown == nil) or
(event.element.parent.join_queue_dropdown.selected_index == 0)) then
player.print({"oarc-selected-player-not-wait"})
ExpandSpawnCtrlGui(player, event.tick)
return
end
local joinQueueIndex = event.element.parent.join_queue_dropdown.selected_index
local joinQueuePlayerChoice = event.element.parent.join_queue_dropdown.get_item(joinQueueIndex)
if ((game.players[joinQueuePlayerChoice] == nil) or
(not game.players[joinQueuePlayerChoice].connected)) then
player.print({"oarc-selected-player-not-wait"})
ExpandSpawnCtrlGui(player, event.tick)
return
end
if (elemName == "reject_player_request") then
player.print({"oarc-reject-joiner", joinQueuePlayerChoice})
SendMsg(joinQueuePlayerChoice, {"oarc-your-request-rejected"})
ExpandSpawnCtrlGui(player, event.tick)
-- Close the waiting players menu
if (game.players[joinQueuePlayerChoice].gui.center.join_shared_spawn_wait_menu) then
game.players[joinQueuePlayerChoice].gui.center.join_shared_spawn_wait_menu.destroy()
DisplaySpawnOptions(game.players[joinQueuePlayerChoice])
end
-- Find and remove the player from the joinQueue they were in.
for index,requestingPlayer in pairs(global.sharedSpawns[player.name].joinQueue) do
if (requestingPlayer == joinQueuePlayerChoice) then
table.remove(global.sharedSpawns[player.name].joinQueue, index)
return
end
end
elseif (elemName == "accept_player_request") then
-- Find and remove the player from the joinQueue they were in.
for index,requestingPlayer in pairs(global.sharedSpawns[player.name].joinQueue) do
if (requestingPlayer == joinQueuePlayerChoice) then
table.remove(global.sharedSpawns[player.name].joinQueue, index)
end
end
-- If player exists, then do stuff.
if (game.players[joinQueuePlayerChoice]) then
-- Send an announcement
SendBroadcastMsg({"oarc-player-joining-base", joinQueuePlayerChoice, player.name})
-- Close the waiting players menu
if (game.players[joinQueuePlayerChoice].gui.center.join_shared_spawn_wait_menu) then
game.players[joinQueuePlayerChoice].gui.center.join_shared_spawn_wait_menu.destroy()
end
-- Spawn the player
local joiningPlayer = game.players[joinQueuePlayerChoice]
ChangePlayerSpawn(joiningPlayer, global.sharedSpawns[player.name].position)
SendPlayerToSpawn(joiningPlayer)
GivePlayerStarterItems(joiningPlayer)
table.insert(global.sharedSpawns[player.name].players, joiningPlayer.name)
joiningPlayer.force = game.players[player.name].force
-- Create the button at the top left for setting respawn point and sharing base.
CreateSpawnCtrlGui(joiningPlayer)
ExpandSpawnCtrlGui(player, event.tick)
else
SendBroadcastMsg({"oarc-player-left-while-joining", joinQueuePlayerChoice})
end
end
end
end
-- Display the buddy spawn menu
function DisplayBuddySpawnOptions(player)
player.gui.center.add{name = "buddy_spawn_opts",
type = "frame",
direction = "vertical",
caption={"oarc-buddy-spawn-options"}}
local buddyGui = player.gui.center.buddy_spawn_opts
buddyGui.style.maximal_width = SPAWN_GUI_MAX_WIDTH
buddyGui.style.maximal_height = SPAWN_GUI_MAX_HEIGHT
-- Warnings and explanations...
AddLabel(buddyGui, "buddy_info_msg", {"oarc-buddy-spawn-instructions"}, my_label_style)
-- AddSpacerLine(buddyGui, "buddy_info_spacer")
buddyList = {}
for _,buddyName in pairs(global.waitingBuddies) do
if (buddyName ~= player.name) then
table.insert(buddyList, buddyName)
end
end
AddLabel(buddyGui, "drop_down_msg_lbl1", {"oarc-buddy-select-info"}, my_label_style)
buddyGui.add{name = "waiting_buddies_dropdown",
type = "drop-down",
items = buddyList}
buddyGui.add{name = "refresh_buddy_list",
type = "button",
caption={"oarc-buddy-refresh"}}
-- AddSpacerLine(buddyGui, "waiting_buddies_spacer")
-- The buddy spawning options.
local buddySpawnFlow = buddyGui.add{name = "spawn_buddy_flow",
type = "flow",
direction="vertical"}
-- Allow picking of teams
if (global.ocfg.enable_separate_teams) then
buddySpawnFlow.add{name = "buddy_spawn_main_team_radio",
type = "radiobutton",
caption={"oarc-join-main-team-radio"},
state=true}
buddySpawnFlow.add{name = "buddy_spawn_new_team_radio",
type = "radiobutton",
caption={"oarc-create-own-team-radio"},
state=false}
buddySpawnFlow.add{name = "buddy_spawn_buddy_team_radio",
type = "radiobutton",
caption={"oarc-create-buddy-team"},
state=false}
end
if (global.ocfg.spawn_config.gen_settings.moat_choice_enabled) then
buddySpawnFlow.add{name = "buddy_spawn_moat_option_checkbox",
type = "checkbox",
caption={"oarc-moat-option"},
state=false}
end
AddSpacer(buddyGui, "buddy_options_spacer")
buddySpawnFlow.add{name = "buddy_spawn_request_near",
type = "button",
caption={"oarc-buddy-spawn-near"},
style = "confirm_button"}
buddySpawnFlow.add{name = "buddy_spawn_request_far",
type = "button",
caption={"oarc-buddy-spawn-far"},
style = "confirm_button"}
AddSpacerLine(buddyGui, "buddy_spawn_spacer")
buddyGui.add{name = "buddy_spawn_cancel",
type = "button",
caption={"oarc-cancel-return-to-previous"},
style = "back_button"}
-- Some final notes
AddSpacerLine(buddyGui, "note_spacer1")
if (global.ocfg.max_players_shared_spawn > 0) then
AddLabel(buddyGui, "buddy_max_players_lbl1",
{"oarc-max-players-shared-spawn", global.ocfg.max_players_shared_spawn-1},
my_note_style)
end
local spawn_distance_notes={"oarc-spawn-dist-notes", global.ocfg.near_dist_start, global.ocfg.near_dist_end, global.ocfg.far_dist_start, global.ocfg.far_dist_end}
AddLabel(buddyGui, "note_lbl1", spawn_distance_notes, my_note_style)
end
-- Handle the gui click of the spawn options
function BuddySpawnOptsGuiClick(event)
if not (event and event.element and event.element.valid) then return end
local player = game.players[event.player_index]
local elemName = event.element.name
if not player then
log("Another gui click happened with no valid player...")
return
end
if (player.gui.center.buddy_spawn_opts == nil) then
return -- Gui event unrelated to this gui.
end
-- Just refresh the buddy list dropdown values only.
if (elemName == "refresh_buddy_list") then
player.gui.center.buddy_spawn_opts.waiting_buddies_dropdown.clear_items()
for _,buddyName in pairs(global.waitingBuddies) do
if (player.name ~= buddyName) then
player.gui.center.buddy_spawn_opts.waiting_buddies_dropdown.add_item(buddyName)
end
end
return
end
-- Handle the cancel button to exit this menu
if (elemName == "buddy_spawn_cancel") then
player.gui.center.buddy_spawn_opts.destroy()
DisplaySpawnOptions(player)
-- Remove them from the buddy list when they cancel
for i=#global.waitingBuddies,1,-1 do
local name = global.waitingBuddies[i]
if (name == player.name) then
table.remove(global.waitingBuddies, i)
end
end
end
local joinMainTeamRadio, joinOwnTeamRadio, joinBuddyTeamRadio, moatChoice = false
local buddyChoice = nil
-- Handle the spawn request button clicks
if ((elemName == "buddy_spawn_request_near") or
(elemName == "buddy_spawn_request_far")) then
local buddySpawnGui = player.gui.center.buddy_spawn_opts
local dropDownIndex = buddySpawnGui.waiting_buddies_dropdown.selected_index
if (dropDownIndex > 0) then
buddyChoice = buddySpawnGui.waiting_buddies_dropdown.get_item(dropDownIndex)
else
player.print({"oarc-invalid-buddy"})
return
end
local buddyIsStillWaiting = false
for _,buddyName in pairs(global.waitingBuddies) do
if (buddyChoice == buddyName) then
if (game.players[buddyChoice]) then
buddyIsStillWaiting = true
end
break
end
end
if (not buddyIsStillWaiting) then
player.print({"oarc-buddy-not-avail"})
player.gui.center.buddy_spawn_opts.destroy()
DisplayBuddySpawnOptions(player)
return
end
if (global.ocfg.enable_separate_teams) then
joinMainTeamRadio = buddySpawnGui.spawn_buddy_flow.buddy_spawn_main_team_radio.state
joinOwnTeamRadio = buddySpawnGui.spawn_buddy_flow.buddy_spawn_new_team_radio.state
joinBuddyTeamRadio = buddySpawnGui.spawn_buddy_flow.buddy_spawn_buddy_team_radio.state
else
joinMainTeamRadio = true
joinOwnTeamRadio = false
joinBuddyTeamRadio = false
end
if (global.ocfg.spawn_config.gen_settings.moat_choice_enabled) then
moatChoice = buddySpawnGui.spawn_buddy_flow.buddy_spawn_moat_option_checkbox.state
end
-- Save the chosen spawn options somewhere for later use.
global.buddySpawnOptions[player.name] = {joinMainTeamRadio=joinMainTeamRadio,
joinOwnTeamRadio=joinOwnTeamRadio,
joinBuddyTeamRadio=joinBuddyTeamRadio,
moatChoice=moatChoice,
buddyChoice=buddyChoice,
distChoice=elemName}
player.gui.center.buddy_spawn_opts.destroy()
-- Display prompts to the players
DisplayBuddySpawnWaitMenu(player)
DisplayBuddySpawnRequestMenu(game.players[buddyChoice], player.name)
if (game.players[buddyChoice].gui.center.buddy_spawn_opts ~= nil) then
game.players[buddyChoice].gui.center.buddy_spawn_opts.destroy()
end
-- Remove them from the buddy list while they make up their minds.
for i=#global.waitingBuddies,1,-1 do
name = global.waitingBuddies[i]
if ((name == player.name) or (name == buddyChoice)) then
table.remove(global.waitingBuddies, i)
end
end
else
return -- Do nothing, no valid element item was clicked.
end
end
function DisplayBuddySpawnWaitMenu(player)
player.gui.center.add{name = "buddy_wait_menu",
type = "frame",
direction = "vertical",
caption={"oarc-waiting-for-buddy"}}
local sGui = player.gui.center.buddy_wait_menu
sGui.style.maximal_width = SPAWN_GUI_MAX_WIDTH
sGui.style.maximal_height = SPAWN_GUI_MAX_HEIGHT
-- Warnings and explanations...
AddLabel(sGui, "warning_lbl1", {"oarc-wait-buddy-select-yes"}, my_warning_style)
AddSpacer(sGui, "warning_spacer")
sGui.add{name = "cancel_buddy_wait_menu",
type = "button",
caption={"oarc-cancel-return-to-previous"}}
end
-- Handle the gui click of the buddy wait menu
function BuddySpawnWaitMenuClick(event)
if not (event and event.element and event.element.valid) then return end
local player = game.players[event.player_index]
local elemName = event.element.name
if not player then
log("Another gui click happened with no valid player...")
return
end
if (player.gui.center.buddy_wait_menu == nil) then
return -- Gui event unrelated to this gui.
end
-- Check if player is cancelling the request.
if (elemName == "cancel_buddy_wait_menu") then
player.gui.center.buddy_wait_menu.destroy()
DisplaySpawnOptions(player)
local buddy = game.players[global.buddySpawnOptions[player.name].buddyChoice]
if (buddy.gui.center.buddy_request_menu ~= nil) then
buddy.gui.center.buddy_request_menu.destroy()
end
if (buddy.gui.center.buddy_spawn ~= nil) then
buddy.gui.center.buddy_spawn_opts.destroy()
end
DisplaySpawnOptions(buddy)
buddy.print({"oarc-buddy-cancel-request", player.name})
end
end
function DisplayBuddySpawnRequestMenu(player, requestingBuddyName)
if not player then
log("Another gui click happened with no valid player...")
return
end
player.gui.center.add{name = "buddy_request_menu",
type = "frame",
direction = "vertical",
caption="Buddy Request!"}
local sGui = player.gui.center.buddy_request_menu
sGui.style.maximal_width = SPAWN_GUI_MAX_WIDTH
sGui.style.maximal_height = SPAWN_GUI_MAX_HEIGHT
-- Warnings and explanations...
AddLabel(sGui, "warning_lbl1", {"oarc-buddy-requesting-from-you", requestingBuddyName}, my_warning_style)
local teamText = "error!"
if (global.buddySpawnOptions[requestingBuddyName].joinMainTeamRadio) then
teamText = {"oarc-buddy-txt-main-team"}
elseif (global.buddySpawnOptions[requestingBuddyName].joinOwnTeamRadio) then
teamText = {"oarc-buddy-txt-new-teams"}
elseif (global.buddySpawnOptions[requestingBuddyName].joinBuddyTeamRadio) then
teamText = {"oarc-buddy-txt-buddy-team"}
end
local moatText = " "
if (global.buddySpawnOptions[requestingBuddyName].moatChoice) then
moatText = {"oarc-buddy-txt-moat"}
end
local distText = "error!"
if (global.buddySpawnOptions[requestingBuddyName].distChoice == "buddy_spawn_request_near") then
distText = {"oarc-buddy-txt-near"}
elseif (global.buddySpawnOptions[requestingBuddyName].distChoice == "buddy_spawn_request_far") then
distText = {"oarc-buddy-txt-far"}
end
local requestText = {"", requestingBuddyName, {"oarc-buddy-txt-would-like"}, teamText, {"oarc-buddy-txt-next-to-you"}, moatText, distText}
AddLabel(sGui, "note_lbl1", requestText, my_warning_style)
AddSpacer(sGui, "note_spacer1")
sGui.add{name = "accept_buddy_request",
type = "button",
caption={"oarc-accept"}}
sGui.add{name = "decline_buddy_request",
type = "button",
caption={"oarc-reject"}}
end
-- Handle the gui click of the buddy request menu
function BuddySpawnRequestMenuClick(event)
if not (event and event.element and event.element.valid) then return end
local player = game.players[event.player_index]
local elemName = event.element.name
local requesterName = nil
local requesterOptions = {}
if not player then
log("Another gui click happened with no valid player...")
return
end
if (player.gui.center.buddy_request_menu == nil) then
return -- Gui event unrelated to this gui.
end
-- Check if it's a button press and lookup the matching buddy info
if ((elemName == "accept_buddy_request") or (elemName == "decline_buddy_request")) then
for name,opts in pairs(global.buddySpawnOptions) do
if (opts.buddyChoice == player.name) then
requesterName = name
requesterOptions = opts
end
end
if (requesterName == nil) then
player.print("Error! Invalid buddy info...")
log("Error! Invalid buddy info...")
player.gui.center.buddy_request_menu.destroy()
DisplaySpawnOptions(player)
end
else
return -- Not a button click
end
-- Handle player accepted
if (elemName == "accept_buddy_request") then
if (game.players[requesterName].gui.center.buddy_wait_menu ~= nil) then
game.players[requesterName].gui.center.buddy_wait_menu.destroy()
end
if (player.gui.center.buddy_request_menu ~= nil) then
player.gui.center.buddy_request_menu.destroy()
end
-- Create a new spawn point
local newSpawn = {x=0,y=0}
-- Create a new force for each player if they chose that option
if requesterOptions.joinOwnTeamRadio then
local newForce = CreatePlayerCustomForce(player)
local buddyForce = CreatePlayerCustomForce(game.players[requesterName])
-- Create a new force for the combined players if they chose that option
elseif requesterOptions.joinBuddyTeamRadio then
local buddyForce = CreatePlayerCustomForce(game.players[requesterName])
player.force = buddyForce
end
-- Find coordinates of a good place to spawn
if (requesterOptions.distChoice == "buddy_spawn_request_far") then
newSpawn = FindUngeneratedCoordinates(global.ocfg.far_dist_start,global.ocfg.far_dist_end, player.surface)
elseif (requesterOptions.distChoice == "buddy_spawn_request_near") then
newSpawn = FindUngeneratedCoordinates(global.ocfg.near_dist_start,global.ocfg.near_dist_end, player.surface)
end
-- If that fails, find a random map edge in a rand direction.
if ((newSpawn.x == 0) and (newSpawn.x == 0)) then
newSpawn = FindMapEdge(GetRandomVector(), player.surface)
log("Resorting to find map edge! x=" .. newSpawn.x .. ",y=" .. newSpawn.y)
end
-- Create that spawn in the global vars
local buddySpawn = {x=0,y=0}
if (requesterOptions.moatChoice) then
buddySpawn = {x=newSpawn.x+(global.ocfg.spawn_config.gen_settings.land_area_tiles*2)+10, y=newSpawn.y}
else
buddySpawn = {x=newSpawn.x+(global.ocfg.spawn_config.gen_settings.land_area_tiles*2), y=newSpawn.y}
end
ChangePlayerSpawn(player, newSpawn)
ChangePlayerSpawn(game.players[requesterName], buddySpawn)
-- Send the player there
QueuePlayerForDelayedSpawn(player.name, newSpawn, requesterOptions.moatChoice, false)
QueuePlayerForDelayedSpawn(requesterName, buddySpawn, requesterOptions.moatChoice, false)
SendBroadcastMsg(requesterName .. " and " .. player.name .. " are joining the game together!")
-- Create the button at the top left for setting respawn point and sharing base.
CreateSpawnCtrlGui(player)
CreateSpawnCtrlGui(game.players[requesterName])
player.print({"oarc-please-wait"})
player.print({"", {"oarc-please-wait"}, "!"})
player.print({"", {"oarc-please-wait"}, "!!"})
game.players[requesterName].print({"oarc-please-wait"})
game.players[requesterName].print({"", {"oarc-please-wait"}, "!"})
game.players[requesterName].print({"", {"oarc-please-wait"}, "!!"})
end
-- Check if player is cancelling the request.
if (elemName == "decline_buddy_request") then
player.gui.center.buddy_request_menu.destroy()
DisplaySpawnOptions(player)
local requesterBuddy = game.players[requesterName]
if (requesterBuddy.gui.center.buddy_wait_menu ~= nil) then
requesterBuddy.gui.center.buddy_wait_menu.destroy()
end
if (requesterBuddy.gui.center.buddy_spawn ~= nil) then
requesterBuddy.gui.center.buddy_spawn_opts.destroy()
end
DisplaySpawnOptions(requesterBuddy)
requesterBuddy.print({"oarc-buddy-declined", player.name})
end
end
function DisplayPleaseWaitForSpawnDialog(player, delay_seconds)
player.gui.center.add{name = "wait_for_spawn_dialog",
type = "frame",
direction = "vertical",
caption={"oarc-spawn-wait"}}
local pleaseWaitGui = player.gui.center.wait_for_spawn_dialog
pleaseWaitGui.style.maximal_width = SPAWN_GUI_MAX_WIDTH
pleaseWaitGui.style.maximal_height = SPAWN_GUI_MAX_HEIGHT
-- Warnings and explanations...
local wait_warning_text = {"oarc-wait-text", delay_seconds}
AddLabel(pleaseWaitGui, "warning_lbl1", wait_warning_text, my_warning_style)
end