1
0
mirror of https://github.com/Oarcinae/FactorioScenarioMultiplayerSpawn.git synced 2024-12-04 09:43:00 +02:00

Improving GUI internal logic and user experience (shared spawns now auto refresh)

This commit is contained in:
Oarcinae 2024-08-28 01:36:02 -04:00
parent 42ad29a6f0
commit 60fba766a1
5 changed files with 462 additions and 233 deletions

View File

@ -262,6 +262,20 @@ script.on_event(defines.events.on_gui_closed, function(event)
end)
--- For sliders and other value changing elements.
script.on_event(defines.events.on_gui_value_changed, function(event)
if not event.element.valid then return end -- Should we ever react to invalid GUI elements?
SeparateSpawnsGuiValueChanged(event)
end)
--- For dropdowns and listboxes.
script.on_event(defines.events.on_gui_selection_state_changed, function(event)
if not event.element.valid then return end -- Should we ever react to invalid GUI elements?
SeparateSpawnsGuiSelectionStateChanged(event)
end)
--on_gui_checked_state_changed Called when LuaGuiElement checked state is changed (related to checkboxes and radio buttons).
--on_gui_click Called when LuaGuiElement is clicked.
--on_gui_closed Called when the player closes the GUI they have open. [...]

View File

@ -1,6 +1,9 @@
ACTIVE ITEM:
11. Change Near/Far buttons to radio selection w/ text explanation and have a single Spawn button.
ACTIVE ITEMS:
22. Remove separate buddy spawn menu?
23. Refresh the spawn controls GUI when player accepts/rejects
24. Remove the shared spawn separate GUI window?
10. Tooltips for GUI elements in spawn menu options!
13. Add regrowth settings GUI tab? Not sure how the other settings fit in with a dedicated regrowth tab? Need to be able to enable/disable other surfaces during runtime?
@ -11,6 +14,7 @@ ACTIVE ITEM:
19. Support run time toggling of main_force_name
20. Force enable_world_eater to require enable_regrowth
Other Ideas, Not Committed:
- Add option to spawn on existing chunks (look for chunks with any entities in them, or use regrowth logic)
- Add option for spawn pen to be on a specified surface
@ -37,3 +41,6 @@ Other Ideas, Not Committed:
8. Check and update all functions using surfaces to clearly use either the LuaSurface obj OR a string name.
9. Create server settings admin GUI tab
15. Figure out how to define custom lua table/data structs to make syntax/linting work?
23. Setup multiplayer testing using multiple instances and some batch files.
11. Change Near/Far buttons to radio selection w/ text explanation and have a single Spawn button.
21. Refactor the spawn menu GUI (don't destroy the menu unless we need to, refresh only the elements we need to, save data to a global using tags?)

View File

@ -111,6 +111,11 @@ function SpawnCtrlGuiOptionsSelect(event)
end
end
FakeTabChangeEventOarcGui(player)
-- Refresh the shared spawn spawn gui for all players
for _,p in pairs(game.connected_players) do
RefreshSharedSpawnFrameIfExist(p)
end
end
end

View File

@ -98,6 +98,11 @@ function InitSpawnGlobalsAndForces()
global.ocore.delayedSpawns --[[@as OarcDelayedSpawnsTable]] = {}
end
-- This temporarily stores the spawn choices that a player makes from the GUI interactions.
if (global.ocore.spawnChoices == nil) then
global.ocore.spawnChoices --[[@as OarcSpawnChoicesTable]] = {}
end
-- This is what I use to communicate a buddy spawn request between the buddies.
-- This contains information of who is asking, and what options were selected.
if (global.ocore.buddySpawnOpts == nil) then
@ -715,7 +720,7 @@ end
---Cleans up a player's unique spawn point.
---TODO: Move relevant stuff to regrowth?
---@param playerName string
---@param cleanup boolean
---@param cleanup boolean Marks the chunks for cleanup by the regrowth mod.
---@param immediate boolean Trrigger cleanup immediately.
---@return nil
function UniqueSpawnCleanupRemove(playerName, cleanup, immediate)
@ -727,11 +732,12 @@ function UniqueSpawnCleanupRemove(playerName, cleanup, immediate)
local spawnPos = spawn.position
local spawn_radius_tiles = global.ocfg.surfaces_config[spawn.surface].spawn_config.general.spawn_radius_tiles
-- Check if it was near someone else's base. (Really just buddy base is possible I think.)
-- Check if it was near someone else's base. (Really just buddy base is possible I think?)
nearOtherSpawn = false
for spawnPlayerName, otherSpawnPos in pairs(global.ocore.uniqueSpawns) do
if ((spawnPlayerName ~= playerName) and
(util.distance(spawnPos, otherSpawnPos.pos) < (spawn_radius_tiles * 3))) then
for spawnPlayerName, otherSpawnPos in pairs(global.ocore.uniqueSpawns --[[@as OarcUniqueSpawnsTable]]) do
if ((spawn.surface == otherSpawnPos.surface) and
(spawnPlayerName ~= playerName) and
(util.distance(spawnPos, otherSpawnPos.position) < (spawn_radius_tiles * 3))) then
log("Won't remove base as it's close to another spawn: " .. spawnPlayerName)
nearOtherSpawn = true
end
@ -1147,6 +1153,19 @@ function PlayerHasDelayedSpawn(player_name)
return false
end
---Get the list of surfaces that are allowed for spawning.
---@return string[]
function GetAllowedSurfaces()
---@type string[]
local surfaceList = {}
for surfaceName,allowed in pairs(global.ocore.surfaces --[[@as table<string, boolean>]]) do
if allowed then
table.insert(surfaceList, surfaceName)
end
end
return surfaceList
end
--[[
___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___
| __|/ _ \ | _ \ / __|| __| / __|| _ \| __|/ __||_ _|| __||_ _|/ __|
@ -1349,8 +1368,8 @@ end
You can ignore this unless you're making changes to the mod, in which case it might be helpful.
]]
---@enum BuddySpawnChoice
BUDDY_SPAWN_CHOICE = {
---@enum SpawnTeamChoice
SPAWN_TEAM_CHOICE = {
join_main_team = 1,
join_own_team = 2,
join_buddy_team = 3,
@ -1382,9 +1401,14 @@ BUDDY_SPAWN_CHOICE = {
---@alias OarcDelayedSpawnsTable table<string, OarcDelayedSpawn>
---This contains information of who is being asked to buddy spawn, and what options were selected.
---@alias OarcBuddySpawnOpts { surface: string, teamRadioSelection: BuddySpawnChoice, moatChoice: boolean, buddyChoice: string, distChoice: string }
---@alias OarcBuddySpawnOpts { surface: string, teamRadioSelection: SpawnTeamChoice, moatChoice: boolean, buddyChoice: string, distChoice: string }
---Table of [OarcBuddySpawnOpts](lua://OarcBuddySpawnOpts) indexed by player name.
---@alias OarcBuddySpawnOptsTable table<string, OarcBuddySpawnOpts>
---This contains the spawn choices for a player in the spawn menu.
---@alias OarcSpawnChoices { surface: string, team: SpawnTeamChoice, moat: boolean, buddy: string?, distance: integer }
---Table of [OarcSpawnChoices](lua://OarcSpawnChoices) indexed by player name.
---@alias OarcSpawnChoicesTable table<string, OarcSpawnChoices>
---Table of players in the "waiting room" for a buddy spawn.
---@alias OarcWaitingBuddiesTable table<integer, string>

View File

@ -74,6 +74,212 @@ function WelcomeTextGuiClick(event)
end
end
---Creates the spawn options gui frame to hold all the spawn options.
---@param player LuaPlayer
---@return LuaGuiElement
function CreateSpawnOptionsGuiFrame(player)
local spawn_opts_gui = player.gui.screen.add {
name = "spawn_opts",
type = "frame",
direction = "vertical",
caption = { "oarc-spawn-options" }
}
spawn_opts_gui.style.maximal_width = SPAWN_GUI_MAX_WIDTH
spawn_opts_gui.style.maximal_height = SPAWN_GUI_MAX_HEIGHT
spawn_opts_gui.auto_center = true
return spawn_opts_gui
end
---Show the surface select dropdown
---@param parent_flow LuaGuiElement
---@return nil
function ShowSurfaceSelectDropdown(parent_flow)
local surfacesHorizontalFlow = parent_flow.add {
name = "surfaces_horizontal_flow",
type = "flow",
direction = "horizontal"
}
local surface_list = GetAllowedSurfaces()
AddLabel(surfacesHorizontalFlow, "surfacesHorizontalFlowLabel", "Select Surface: ", my_label_style)
surfacesHorizontalFlow.add {
name = "surface_select_dropdown",
tags = { action = "oarc_spawn_options", setting = "surface_select" },
type = "drop-down",
items = surface_list,
selected_index = 1
}
end
---Display the team select radio buttons
---@param parent_flow LuaGuiElement
---@param enable_separate_teams boolean
---@param enable_buddy_spawn boolean
---@return nil
function DisplayTeamSelectRadioButtons(parent_flow, enable_separate_teams, enable_buddy_spawn)
local main_team_radio = parent_flow.add {
name = "isolated_spawn_main_team_radio",
tags = { action = "oarc_spawn_options", setting = "team_select", value = SPAWN_TEAM_CHOICE.join_main_team },
type = "radiobutton",
caption = { "oarc-join-main-team-radio" },
state = true
}
if (enable_separate_teams) then
parent_flow.add {
name = "isolated_spawn_new_team_radio",
tags = { action = "oarc_spawn_options", setting = "team_select", value = SPAWN_TEAM_CHOICE.join_own_team },
type = "radiobutton",
caption = { "oarc-create-own-team-radio" },
state = false
}
if (enable_buddy_spawn) then
parent_flow.add {
name = "isolated_spawn_buddy_team_radio",
tags = { action = "oarc_spawn_options", setting = "team_select", value = SPAWN_TEAM_CHOICE.join_buddy_team },
type = "radiobutton",
caption = { "oarc-create-buddy-team" },
state = false
}
end
else
-- If separate teams are not enabled, default to joining the main team, and disable the radio buttons.
main_team_radio.ignored_by_interaction = true
end
end
---Create a distance select slider
---@param parent_flow LuaGuiElement
---@param minimum_distance number
---@param maximum_distance number
---@return nil
function CreateDistanceSelectSlider(parent_flow, minimum_distance, maximum_distance)
local sliderFlow = parent_flow.add { name = "spawn_distance_slider_flow",
type = "flow",
direction = "horizontal",
style = "player_input_horizontal_flow"
}
sliderFlow.style.horizontal_align = "center"
sliderFlow.add { name = "spawn_distance_slider_label",
type = "label",
caption = "test" }
sliderFlow.add { name = "spawn_distance_slider",
type = "slider",
tags = { action = "oarc_spawn_options", setting = "distance_select" },
minimum_value = minimum_distance,
maximum_value = maximum_distance,
value = minimum_distance,
discrete_slider = true,
value_step = 1,
}
sliderFlow.add { name = "spawn_distance_slider_value",
type = "textfield",
ignored_by_interaction = true,
caption = minimum_distance,
style = "slider_value_textfield",
text = tostring(minimum_distance)
}
end
---Create a confim button for player to request spawn creation
---@param parent_flow LuaGuiElement
---@return nil
function CreateSpawnRequestButton(parent_flow)
local spawnRequestFlow = parent_flow.add {
name = "spawn_request_flow",
type = "flow",
direction = "horizontal"
}
spawnRequestFlow.style.horizontal_align = "right"
spawnRequestFlow.style.horizontally_stretchable = true
spawnRequestFlow.add {
name = "spawn_request",
tags = { action = "oarc_spawn_options", setting = "spawn_request" },
type = "button",
caption = { "oarc-solo-spawn-near" },
style = "confirm_button"
}
end
---Creates the shared spawn frame for joining another player's base
---@param parent_flow LuaGuiElement
---@param enable_shared_spawns boolean
---@return nil
function CreateSharedSpawnFrame(parent_flow, enable_shared_spawns)
local sharedSpawnFrame = parent_flow.spawn_shared_flow
if sharedSpawnFrame == nil then
sharedSpawnFrame = parent_flow.add {
name = "spawn_shared_flow",
type = "frame",
direction = "vertical",
style = "bordered_frame"
}
--- Let's us refresh the frame if it already exists
else
for _,child in pairs(sharedSpawnFrame.children) do
child.destroy()
end
end
if enable_shared_spawns then
local numAvailSpawns = GetNumberOfAvailableSharedSpawns()
if (numAvailSpawns > 0) then
sharedSpawnFrame.add {
name = "join_other_spawn",
tags = { action = "oarc_spawn_options", setting = "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
end
---Refresh the shared spawn frame if it exists
---@param player LuaPlayer
---@return nil
function RefreshSharedSpawnFrameIfExist(player)
local spawn_opts = player.gui.screen.spawn_opts
if spawn_opts == nil then return end
CreateSharedSpawnFrame(spawn_opts, global.ocfg.gameplay.enable_shared_spawns)
end
---Creates the buddy spawn frame for spawning with a buddy
---@param parent_flow LuaGuiElement
---@return nil
function CreateBuddySpawnFrame(parent_flow, enable_buddy_spawn)
if enable_buddy_spawn then -- TODO: Confirm if this must also require enable_shared_spawns!!
local buddySpawnFrame = parent_flow.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
---Display the spawn options and explanation
---@param player LuaPlayer
---@return nil
@ -88,88 +294,50 @@ function DisplaySpawnOptions(player)
return
end
-- Get gameplay settings from config
local gameplay = global.ocfg.gameplay
player.gui.screen.add { name = "spawn_opts",
-- Create the primary frame and a warning label
local sGui = CreateSpawnOptionsGuiFrame(player)
AddLabel(sGui, "warning_lbl1", { "oarc-click-info-btn-help" }, my_warning_style)
-- Create the default settings entry for the OarcSpawnChoices table
---@type OarcSpawnChoices
local spawn_choices_entry = {
surface = global.ocfg.gameplay.default_surface,
team = SPAWN_TEAM_CHOICE.join_main_team,
moat = false,
buddy = nil,
distance = global.ocfg.gameplay.near_spawn_distance
}
global.ocore.spawnChoices[player.name] = spawn_choices_entry
-- Holds the main spawn options
local soloSpawnFlow = sGui.add {
name = "spawn_solo_flow",
type = "frame",
direction = "vertical",
caption = { "oarc-spawn-options" } }
local sGui = player.gui.screen.spawn_opts
sGui.style.maximal_width = SPAWN_GUI_MAX_WIDTH
sGui.style.maximal_height = SPAWN_GUI_MAX_HEIGHT
sGui.auto_center = true
-- Warnings and explanations...
local warn_msg = { "oarc-click-info-btn-help" }
AddLabel(sGui, "warning_lbl1", warn_msg, my_warning_style)
-- TODO: Not sure what this is for...? SPAWN_MSG1 is not defined anywhere.
-- 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" }
style = "bordered_frame"
}
-- Pick surface
if (gameplay.enable_spawning_on_other_surfaces) then
local surfacesHorizontalFlow = soloSpawnFlow.add { name = "surfaces_horizontal_flow",
type = "flow",
direction = "horizontal" }
---@type string[]
local surfaceList = {}
for surfaceName,allowed in pairs(global.ocore.surfaces) do
if allowed then
table.insert(surfaceList, surfaceName)
end
end
AddLabel(surfacesHorizontalFlow, "surfacesHorizontalFlowLabel", "Select Surface: ", my_label_style)
surfacesHorizontalFlow.add { name = "surface_select_dropdown",
type = "drop-down",
items = surfaceList,
selected_index = 1}
ShowSurfaceSelectDropdown(soloSpawnFlow)
end
-- Radio buttons to pick your team.
if (gameplay.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)
DisplayTeamSelectRadioButtons(soloSpawnFlow, gameplay.enable_separate_teams, gameplay.enable_buddy_spawn)
-- Allow players to spawn with a moat around their area.
--TODO: Vanilla spawn points are not implemented yet.
-- and not global.ocfg.enable_vanilla_spawns
if (gameplay.allow_moats_around_spawns) then
soloSpawnFlow.add { name = "isolated_spawn_moat_option_checkbox",
soloSpawnFlow.add {
name = "isolated_spawn_moat_option_checkbox",
type = "checkbox",
caption = { "oarc-moat-option" },
state = false }
state = false
}
end
-- if (global.ocfg.enable_vanilla_spawns and (TableLength(global.vanillaSpawns) > 0)) then
-- soloSpawnFlow.add{name = "isolated_spawn_vanilla_option_checkbox",
@ -178,44 +346,11 @@ function DisplaySpawnOptions(player)
-- state=false}
-- end
local sliderFlow = soloSpawnFlow.add { name = "spawn_distance_slider_flow",
type = "flow",
direction = "horizontal",
style = "player_input_horizontal_flow"
}
sliderFlow.style.horizontal_align = "center"
sliderFlow.add { name = "spawn_distance_slider_label",
type = "label",
caption = "test" }
sliderFlow.add { name = "spawn_distance_slider",
type = "slider",
minimum_value = global.ocfg.gameplay.near_spawn_distance,
maximum_value = global.ocfg.gameplay.far_spawn_distance,
value = global.ocfg.gameplay.near_spawn_distance,
discrete_slider = true,
value_step = 1
}
sliderFlow.add { name = "spawn_distance_slider_value",
type = "textfield",
ignored_by_interaction = true,
caption = global.ocfg.gameplay.near_spawn_distance,
style = "slider_value_textfield"
}
CreateDistanceSelectSlider(soloSpawnFlow, gameplay.near_spawn_distance, gameplay.far_spawn_distance)
-- The confirm button to request a spawn
CreateSpawnRequestButton(soloSpawnFlow)
-- 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",
@ -223,50 +358,16 @@ function DisplaySpawnOptions(player)
-- AddLabel(soloSpawnFlow, "vanilla_spawn_lbl2",
-- {"oarc-vanilla-spawns-available", TableLength(global.vanillaSpawns)}, my_label_style)
-- else
AddLabel(soloSpawnFlow, "isolated_spawn_lbl1",
{ "oarc-starting-area-normal" }, my_label_style)
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 gameplay.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
CreateSharedSpawnFrame(sGui, gameplay.enable_shared_spawns)
-- Awesome buddy spawning system
---TODO: Vanilla spawn points are not implemented yet.
-- if (not global.ocfg.enable_vanilla_spawns) then
if gameplay.enable_shared_spawns and gameplay.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
CreateBuddySpawnFrame(sGui, gameplay.enable_buddy_spawn)
-- end
-- Some final notes
@ -280,28 +381,147 @@ function DisplaySpawnOptions(player)
AddLabel(sGui, "note_lbl1", spawn_distance_notes, my_note_style)
end
---This just updates the radio buttons/checkboxes when players click them.
---@param event EventData.on_gui_checked_state_changed
---@return nil
function SpawnOptsRadioSelect(event)
if not event.element.valid then return end
local elemName = event.element.name
local player = game.players[event.player_index]
local tags = event.element.tags
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
if (tags.action ~= "oarc_spawn_options") then
return
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
if (tags.setting == "team_select") then
global.ocore.spawnChoices[player.name].team = tags.value
-- Need to handle the radio button logic manually
if (elemName == "isolated_spawn_main_team_radio") then
if (event.element.parent.isolated_spawn_new_team_radio ~= nil) then
event.element.parent.isolated_spawn_new_team_radio.state = false
end
if (event.element.parent.isolated_spawn_buddy_team_radio ~= nil) then
event.element.parent.isolated_spawn_buddy_team_radio.state = false
end
elseif (elemName == "isolated_spawn_new_team_radio") then
event.element.parent.isolated_spawn_main_team_radio.state = false
if (event.element.parent.isolated_spawn_buddy_team_radio ~= nil) then
event.element.parent.isolated_spawn_buddy_team_radio.state = false
end
elseif (elemName == "isolated_spawn_buddy_team_radio") then
event.element.parent.isolated_spawn_main_team_radio.state = false
event.element.parent.isolated_spawn_new_team_radio.state = false
end
end
end
---Handle the gui click of the spawn options
---@param event EventData.on_gui_click
---@return nil
function SpawnChoicesGuiClickNew(event)
if not event.element.valid then return end
local player = game.players[event.player_index]
local tags = event.element.tags
if (tags.action ~= "oarc_spawn_options") then
return
end
local setting_name = tags.setting
if (tags.setting == "spawn_request") then
SpawnRequest(player)
end
end
---Handle slider value changes
---@param event EventData.on_gui_value_changed
---@return nil
function SpawnOptsValueChanged(event)
if not event.element.valid then return end
local player = game.players[event.player_index]
local tags = event.element.tags
if (tags.action ~= "oarc_spawn_options") then
return
end
if (tags.setting == "distance_select") then
local distance = event.element.slider_value
global.ocore.spawnChoices[player.name].distance = distance
event.element.parent.spawn_distance_slider_value.text = tostring(distance)
-- log("GUI DEBUG Selected distance: " .. distance)
end
end
---Handle dropdown selection changes
---@param event EventData.on_gui_selection_state_changed
---@return nil
function SpawnOptsSelectionChanged(event)
if not event.element.valid then return end
local player = game.players[event.player_index]
local tags = event.element.tags
if (tags.action ~= "oarc_spawn_options") then
return
end
if (tags.setting == "surface_select") then
local index = event.element.selected_index
local surfaceName = event.element.get_item(index) --[[@as string]]
global.ocore.spawnChoices[player.name].surface = surfaceName
log("GUI DEBUG Selected surface: " .. surfaceName)
end
end
---Requests the generation of a spawn point for the player
---@param player LuaPlayer
---@return nil
function SpawnRequest(player)
-- Get the player's spawn choices
---@type OarcSpawnChoices
local spawnChoices = global.ocore.spawnChoices[player.name]
if (spawnChoices == nil) then error("ERROR! No spawn choices found for player!") return end
-- Cache some useful variables
local gameplay = global.ocfg.gameplay
local surface = game.surfaces[spawnChoices.surface]
-- Create a new force for player if they choose that radio button
if spawnChoices.team ~= SPAWN_TEAM_CHOICE.join_main_team then
CreatePlayerCustomForce(player)
end
-- Find coordinates of a good place to spawn
local newSpawn = { x = 0, y = 0 }
newSpawn = FindUngeneratedCoordinates(gameplay.near_spawn_distance, gameplay.far_spawn_distance, surface)
-- If that fails, find a random map edge in a rand direction.
if ((newSpawn.x == 0) and (newSpawn.y == 0)) then
newSpawn = FindMapEdge(GetRandomVector(), 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, spawnChoices.surface, newSpawn)
-- Send the player there
-- global.ocfg.enable_vanilla_spawns --TODO: Vanilla spawn points are not implemented yet.
QueuePlayerForDelayedSpawn(player.name, spawnChoices.surface, newSpawn, spawnChoices.moat, false)
SendBroadcastMsg({ "oarc-player-is-joining-far", player.name, spawnChoices.surface })
-- Unlock spawn control gui tab
SetOarcGuiTabEnabled(player, OARC_SPAWN_CTRL_TAB_NAME, true)
player.print({ "oarc-please-wait" })
player.print({ "", { "oarc-please-wait" }, "!" })
player.print({ "", { "oarc-please-wait" }, "!!" })
-- Destroy the spawn options gui
if (player.gui.screen.spawn_opts ~= nil) then
player.gui.screen.spawn_opts.destroy()
end
end
@ -327,7 +547,7 @@ function SpawnOptsGuiClick(event)
local joinOwnTeamRadio, moatChoice = false, false
local surfaceName = global.ocfg.gameplay.default_surface -- Default to default surface
local surface = game.surfaces[surfaceName]
-- Check if a valid button on the gui was pressed
-- and delete the GUI
if ((elemName == "default_spawn_btn") or
@ -382,67 +602,9 @@ function SpawnOptsGuiClick(event)
defaultSurface)
-- Unlock spawn control gui tab
SetOarcGuiTabEnabled(player, OARC_SPAWN_CTRL_TAB_NAME, true)
elseif ((elemName == "isolated_spawn_near") or (elemName == "isolated_spawn_far")) then
local newSpawn = { x = 0, y = 0 }
local gameplay = global.ocfg.gameplay
-- Create a new force for player if they choose that radio button
if gameplay.enable_separate_teams and joinOwnTeamRadio then
local newForce = CreatePlayerCustomForce(player)
end
---TODO: Vanilla spawn points are not implemented yet.
-- -- 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(gameplay.near_spawn_distance, gameplay.far_spawn_distance, surface)
elseif (elemName == "isolated_spawn_near") then
newSpawn = FindUngeneratedCoordinates(gameplay.near_spawn_distance, gameplay.far_spawn_distance, 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(), 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, surfaceName, newSpawn)
-- Send the player there
QueuePlayerForDelayedSpawn(player.name,
surfaceName,
newSpawn,
moatChoice,
false) -- global.ocfg.enable_vanilla_spawns --TODO: Vanilla spawn points are not implemented yet.
if (elemName == "isolated_spawn_near") then
SendBroadcastMsg({ "oarc-player-is-joining-near", player.name, surfaceName })
elseif (elemName == "isolated_spawn_far") then
SendBroadcastMsg({ "oarc-player-is-joining-far", player.name, surfaceName })
end
-- Unlock spawn control gui tab
SetOarcGuiTabEnabled(player, OARC_SPAWN_CTRL_TAB_NAME, true)
player.print({ "oarc-please-wait" })
player.print({ "", { "oarc-please-wait" }, "!" })
player.print({ "", { "oarc-please-wait" }, "!!" })
--- MOVED
elseif (elemName == "join_other_spawn") then
DisplaySharedSpawnOptions(player)
@ -810,18 +972,18 @@ function BuddySpawnOptsGuiClick(event)
surfaceName = buddySpawnGui.surfaces_horizontal_flow.surface_select_dropdown.get_item(surfaceDropdownIndex) --[[@as string]]
end
---@type BuddySpawnChoice
---@type SpawnTeamChoice
local buddyTeamRadioSelection = nil
if (global.ocfg.gameplay.enable_separate_teams) then
if buddySpawnGui.buddy_spawn_main_team_radio.state then
buddyTeamRadioSelection = BUDDY_SPAWN_CHOICE.join_main_team
buddyTeamRadioSelection = SPAWN_TEAM_CHOICE.join_main_team
elseif buddySpawnGui.buddy_spawn_new_team_radio.state then
buddyTeamRadioSelection = BUDDY_SPAWN_CHOICE.join_own_team
buddyTeamRadioSelection = SPAWN_TEAM_CHOICE.join_own_team
elseif buddySpawnGui.buddy_spawn_buddy_team_radio.state then
buddyTeamRadioSelection = BUDDY_SPAWN_CHOICE.join_buddy_team
buddyTeamRadioSelection = SPAWN_TEAM_CHOICE.join_buddy_team
end
else
buddyTeamRadioSelection = BUDDY_SPAWN_CHOICE.join_main_team
buddyTeamRadioSelection = SPAWN_TEAM_CHOICE.join_main_team
end
if (global.ocfg.gameplay.allow_moats_around_spawns) then
@ -950,11 +1112,11 @@ function DisplayBuddySpawnRequestMenu(player, requestingBuddyName)
---@type LocalisedString
local teamText = "error!"
if (buddySpawnOpts.teamRadioSelection == BUDDY_SPAWN_CHOICE.join_main_team) then
if (buddySpawnOpts.teamRadioSelection == SPAWN_TEAM_CHOICE.join_main_team) then
teamText = { "oarc-buddy-txt-main-team" }
elseif (buddySpawnOpts.teamRadioSelection == BUDDY_SPAWN_CHOICE.join_own_team) then
elseif (buddySpawnOpts.teamRadioSelection == SPAWN_TEAM_CHOICE.join_own_team) then
teamText = { "oarc-buddy-txt-new-teams" }
elseif (buddySpawnOpts.teamRadioSelection == BUDDY_SPAWN_CHOICE.join_buddy_team) then
elseif (buddySpawnOpts.teamRadioSelection == SPAWN_TEAM_CHOICE.join_buddy_team) then
teamText = { "oarc-buddy-txt-buddy-team" }
end
@ -1045,12 +1207,12 @@ function BuddySpawnRequestMenuClick(event)
local newSpawn = { x = 0, y = 0 }
-- Create a new force for each player if they chose that option
if requesterOptions.teamRadioSelection == BUDDY_SPAWN_CHOICE.join_own_team then
if requesterOptions.teamRadioSelection == SPAWN_TEAM_CHOICE.join_own_team then
CreatePlayerCustomForce(player)
CreatePlayerCustomForce(game.players[requesterName])
-- Create a new force for the combined players if they chose that option
elseif requesterOptions.teamRadioSelection == BUDDY_SPAWN_CHOICE.join_buddy_team then
elseif requesterOptions.teamRadioSelection == SPAWN_TEAM_CHOICE.join_buddy_team then
local buddyForce = CreatePlayerCustomForce(game.players[requesterName])
player.force = buddyForce
end
@ -1166,6 +1328,9 @@ end
---@return nil
function SeparateSpawnsGuiClick(event)
WelcomeTextGuiClick(event)
SpawnChoicesGuiClickNew(event)
SpawnOptsGuiClick(event)
SharedSpwnOptsGuiClick(event)
BuddySpawnOptsGuiClick(event)
@ -1179,4 +1344,18 @@ end
---@return nil
function SeparateSpawnsGuiCheckedStateChanged(event)
SpawnOptsRadioSelect(event)
end
---Gui value changed event handlers
---@param event EventData.on_gui_value_changed
---@return nil
function SeparateSpawnsGuiValueChanged(event)
SpawnOptsValueChanged(event)
end
---Gui selection state changed event handlers
---@param event EventData.on_gui_selection_state_changed
---@return nil
function SeparateSpawnsGuiSelectionStateChanged(event)
SpawnOptsSelectionChanged(event)
end