From d1246adb5894b4eb4329d829c5794e1f2a46e95e Mon Sep 17 00:00:00 2001 From: Oarcinae Date: Fri, 27 Sep 2024 10:07:21 -0400 Subject: [PATCH 01/16] Fix not removing chunks from regrowth map when forcefully removing. Downgrade error to log-warn as well just in case. --- lib/regrowth_map.lua | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/regrowth_map.lua b/lib/regrowth_map.lua index e82d078..d7a91c9 100644 --- a/lib/regrowth_map.lua +++ b/lib/regrowth_map.lua @@ -493,6 +493,7 @@ function OarcRegrowthRemoveAllChunks() -- If it is FORCE removal, then remove it regardless of pollution. if (c_remove.force) then game.surfaces[surface_name].delete_chunk(c_pos) + global.rg[surface_name].map[c_pos.x][c_pos.y] = nil elseif (global.rg[surface_name].map[c_pos.x][c_pos.y] == REGROWTH_FLAG_REMOVAL) then @@ -506,9 +507,12 @@ function OarcRegrowthRemoveAllChunks() global.rg[surface_name].map[c_pos.x][c_pos.y] = nil end end + + -- If we hit here, the chunk was probably refreshed or something and so we don't want to delete it. + -- We won't check it again since we clear the removal list after this. This should be correct. else -- This should never happen, TODO: check if it does? - error("ERROR - OarcRegrowthRemoveAllChunks: Chunk not in map: " .. c_pos.x .. "," .. c_pos.y .. " on surface: " .. surface_name) + log("WARN - OarcRegrowthRemoveAllChunks: Chunk not in map: " .. c_pos.x .. "," .. c_pos.y .. " on surface: " .. surface_name) end -- Remove entry From 2afa1dd8f57a3161fd7e322c75ca488245516cc9 Mon Sep 17 00:00:00 2001 From: Oarcinae Date: Fri, 27 Sep 2024 10:14:49 -0400 Subject: [PATCH 02/16] Fix offline protection log spam. --- lib/offline_protection.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/offline_protection.lua b/lib/offline_protection.lua index a303c41..ebc64fb 100644 --- a/lib/offline_protection.lua +++ b/lib/offline_protection.lua @@ -19,7 +19,7 @@ function OarcModifyEnemyGroup(event) -- Check validity if ((group == nil) or (group.command == nil) or not TableContains(ENEMY_FORCES_NAMES, group.force.name)) then - log("OarcModifyEnemyGroup ignoring INVALID group/command") + log("WARN - OarcModifyEnemyGroup ignoring INVALID group/command " .. serpent.block(group)) return end @@ -72,7 +72,7 @@ function OarcModifyEnemyGroup(event) -- This is unexpected, not sure under which conditions this would happen. if (group.command.type == defines.command.attack_area) then -- SendBroadcastMsg("OarcModifyEnemyGroup find_nearest_enemy attack_area FAILED!?!? " .. GetGPStext(group.surface.name, group.position) .. " Target: " .. GetGPStext(group.surface.name, group.command.destination)) - log("ERROR - OarcModifyEnemyGroup find_nearest_enemy attack_area FAILED!?!?") + log("ERROR - OarcModifyEnemyGroup find_nearest_enemy attack_area FAILED!?!?" .. serpent.block(group)) -- for _,member in pairs(group.members) do -- member.destroy() -- end @@ -95,7 +95,7 @@ function OarcModifyEnemyGroup(event) -- I don't think this should happen ever... if ((target_player == nil) or (not target_player.valid)) then -- SendBroadcastMsg("ERROR?? target_player nil/invalid " .. GetGPStext(group.surface.name, group.position) .. " Target: " .. GetGPStext(group.surface.name, target_entity.position)) - log("ERROR - OarcModifyEnemyGroup target_player nil/invalid?") + log("ERROR - OarcModifyEnemyGroup target_player nil/invalid?" .. serpent.block(group)) -- for _,member in pairs(group.members) do -- member.destroy() -- end @@ -125,6 +125,6 @@ function OarcModifyEnemyGroup(event) member.destroy() end -- SendBroadcastMsg("Enemy group deleted: " .. GetGPStext(group.surface.name, group.position) .. " Target: " .. GetGPStext(group.surface.name, target_entity.position) .. " " .. target_player.name) - log("OarcModifyEnemyGroup REMOVED enemy group since nobody was online? " .. target_player.name) + -- log("OarcModifyEnemyGroup REMOVED enemy group since nobody was online? " .. target_player.name) end \ No newline at end of file From 3ad5d85c87b509697f846746aee0e1c400a9023c Mon Sep 17 00:00:00 2001 From: Oarcinae Date: Fri, 4 Oct 2024 13:27:42 -0400 Subject: [PATCH 03/16] Saving work on player list. Mostly working? --- control.lua | 17 +++-- lib/gui_tabs/player_list.lua | 120 ++++++++++++++++++++++++++++++++ lib/gui_tabs/spawn_controls.lua | 2 +- lib/oarc_gui_tabs.lua | 40 ++++++++++- lib/oarc_gui_utils.lua | 6 +- lib/oarc_tests.lua | 12 ---- lib/oarc_utils.lua | 7 +- lib/separate_spawns.lua | 15 +++- locale/en/locale.cfg | 13 ++++ 9 files changed, 204 insertions(+), 28 deletions(-) create mode 100644 lib/gui_tabs/player_list.lua diff --git a/control.lua b/control.lua index dc1f4be..14179e3 100644 --- a/control.lua +++ b/control.lua @@ -68,9 +68,14 @@ end) -------------------------------------------------------------------------------- -- oarc_new_spawn_created = script.generate_event_name() --- script.on_configuration_changed(function(data) --- -- Regenerate event ID: --- end) +script.on_configuration_changed(function(data) + -- Regenerate event ID: + + -- Reset the players GUI + for _,player in pairs(game.players) do + RecreateOarcGui(player) + end +end) script.on_event(defines.events.on_runtime_mod_setting_changed, function(event) if (not StringStartsWith(event.setting, "oarc-mod")) then return end @@ -96,6 +101,7 @@ script.on_event(defines.events.on_player_changed_surface, function(event) SeparateSpawnsPlayerChangedSurface(event) end) + ---------------------------------------- -- Shared chat, so you don't have to type /s -- But you do lose your player colors across forces. @@ -253,10 +259,7 @@ script.on_event(defines.events.on_gui_click, function(event) SeparateSpawnsGuiClick(event) ClickOarcGuiButton(event) - ServerInfoGuiClick(event) - SpawnCtrlGuiClick(event) - SettingsControlsTabGuiClick(event) - SettingsSurfaceControlsTabGuiClick(event) + OarcGuiTabsClick(event) end) --- Called when LuaGuiElement checked state is changed (related to checkboxes and radio buttons). diff --git a/lib/gui_tabs/player_list.lua b/lib/gui_tabs/player_list.lua new file mode 100644 index 0000000..27532df --- /dev/null +++ b/lib/gui_tabs/player_list.lua @@ -0,0 +1,120 @@ +-- Contains the GUI for the player list tab. + +---Used by AddOarcGuiTab +---@param tab_container LuaGuiElement +---@param player LuaPlayer +---@return nil +function CreatePlayerListTab(tab_container, player) + + local scroll_pane = tab_container.add { + type = "scroll-pane", + direction = "vertical", + vertical_scroll_policy = "always", + } + + + -- Make a table: player name, force name, home surface, time played, gps button + local player_table = scroll_pane.add { + type = "table", + column_count = 6, + style = "bordered_table", + } + + --- Add the header rows + AddLabel(player_table, nil, {"oarc-player-list-tab-column-header-player"}, "caption_label") + AddLabel(player_table, nil, {"oarc-player-list-tab-column-header-force"}, "caption_label") + AddLabel(player_table, nil, {"oarc-player-list-tab-column-header-surface"}, "caption_label") + AddLabel(player_table, nil, {"oarc-player-list-tab-column-header-time-player"}, "caption_label") + AddLabel(player_table, nil, {"oarc-player-list-tab-column-header-location"}, "caption_label") + AddLabel(player_table, nil, {"oarc-player-list-tab-column-header-status"}, "caption_label") + + -- List online players first + for _,online_player in pairs(game.connected_players) do + AddPlayerRow(player_table, online_player.name, true) + end + + -- List offline players later + for _,player in pairs(game.players) do + if (not player.connected) then + AddPlayerRow(player_table, player.name, false) + end + end + +end + + +---Add a row to the table for a player +---@param table LuaGuiElement +---@param player_name string +---@param online boolean +---@return nil +function AddPlayerRow(table, player_name, online) + local player = game.players[player_name] + if (player) then + AddLabel(table, nil, player.name, my_label_style) + AddLabel(table, nil, player.force.name, my_label_style) + + -- Get the player's home surface + local spawn = FindPlayerHomeSpawn(player.name) + if (spawn) then + AddLabel(table, nil, spawn.surface_name, my_label_style) + else + AddLabel(table, nil, "Unknown", my_label_style) + end + + AddLabel(table, nil, FormatTimeHoursSecs(player.online_time), my_label_style) + CreatePlayerGPSButton(table, player.name) + + if online then + if (player.admin) then + AddLabel(table, nil, {"oarc-player-online"}, my_player_list_admin_style) + else + AddLabel(table, nil, {"oarc-player-online"}, my_player_list_style) + end + else + AddLabel(table, nil, {"oarc-player-offline"}, my_player_list_offline_style) + end + end +end + + +---Display a GPS button for a specific location. (For the player list) +---@param container LuaGuiElement +---@param player_name string +---@return nil +function CreatePlayerGPSButton(container, player_name) + local gps_button = container.add { + type = "sprite-button", + sprite = "utility/gps_map_icon", + tags = { + action = "oarc_player_list_tab", + setting = "show_location", + player_name = player_name, + }, + style = "slot_button", + tooltip = { "oarc-player-list-tab-location-button-tooltip" }, + } + gps_button.style.width = 28 + gps_button.style.height = 28 +end + +---Handle the gui click of the player list tab in the Oarc GUI. +---@param event EventData.on_gui_click +---@return nil +function PlayerListGuiClick(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_player_list_tab") then + return + end + + -- Shows the player's current location on the map + if (tags.setting == "show_location") then + local player_name = tags.player_name --[[@as string]] + local target_player = game.players[player_name] + + player.open_map(target_player.position, 0.05) -- TODO: Update this for spage age! + end +end \ No newline at end of file diff --git a/lib/gui_tabs/spawn_controls.lua b/lib/gui_tabs/spawn_controls.lua index 2d034c1..a2243c8 100644 --- a/lib/gui_tabs/spawn_controls.lua +++ b/lib/gui_tabs/spawn_controls.lua @@ -301,7 +301,7 @@ function SpawnCtrlGuiClick(event) elseif (tags.setting == "show_location") then local surface_name = tags.surface --[[@as string]] local position = tags.position --[[@as MapPosition]] - player.open_map(position, 0.05) + player.open_map(position, 0.05) -- TODO: Update this for spage age! player.print({"", { "oarc-spawn-gps-location" }, GetGPStext(surface_name, position)}) -- Accept or reject pending player join requests to a shared base diff --git a/lib/oarc_gui_tabs.lua b/lib/oarc_gui_tabs.lua index 4703383..a743280 100644 --- a/lib/oarc_gui_tabs.lua +++ b/lib/oarc_gui_tabs.lua @@ -5,6 +5,7 @@ require("lib/gui_tabs/server_info") require("lib/gui_tabs/spawn_controls") require("lib/gui_tabs/settings_controls") require("lib/gui_tabs/mod_info_faq") +require("lib/gui_tabs/player_list") -------------------------------------------------------------------------------- -- GUI Tab Handler @@ -18,17 +19,20 @@ OARC_SERVER_INFO_TAB_NAME = "server_info" OARC_SPAWN_CTRL_TAB_NAME = "spawn_controls" OARC_CONFIG_CTRL_TAB_NAME = "settings" OARC_MOD_INFO_CTRL_TAB_NAME = "mod_info" +OARC_MOD_PLAYER_LIST_TAB_NAME = "player_list" OARC_SERVER_INFO_TAB_LOCALIZED = {"oarc-server-info-tab-title"} OARC_SPAWN_CTRL_TAB_LOCALIZED = {"oarc-spawn-ctrls-tab-title"} OARC_CONFIG_CTRL_TAB_LOCALIZED = {"oarc-settings-tab-title"} OARC_MOD_INFO_CTRL_TAB_LOCALIZED = {"oarc-mod-info-tab-title"} +OARC_PLAYER_LIST_TAB_LOCALIZED = {"oarc-player-list-tab-title"} local OARC_GUI_TAB_CONTENT_FUNCTIONS = { [OARC_SERVER_INFO_TAB_NAME] = CreateServerInfoTab, [OARC_SPAWN_CTRL_TAB_NAME] = CreateSpawnControlsTab, [OARC_MOD_INFO_CTRL_TAB_NAME] = CreateModInfoTab, [OARC_CONFIG_CTRL_TAB_NAME] = CreateSettingsControlsTab, + [OARC_MOD_PLAYER_LIST_TAB_NAME] = CreatePlayerListTab } ---@param player LuaPlayer @@ -57,6 +61,10 @@ function InitOarcGuiTabs(player) AddOarcGuiTab(player, OARC_CONFIG_CTRL_TAB_NAME, OARC_CONFIG_CTRL_TAB_LOCALIZED) SetOarcGuiTabEnabled(player, OARC_CONFIG_CTRL_TAB_NAME, true) + -- Player list tab + AddOarcGuiTab(player, OARC_MOD_PLAYER_LIST_TAB_NAME, OARC_PLAYER_LIST_TAB_LOCALIZED) + SetOarcGuiTabEnabled(player, OARC_MOD_PLAYER_LIST_TAB_NAME, true) + HideOarcGui(player) end @@ -298,9 +306,39 @@ function SwitchOarcGuiTab(player, tab_name) end end ---@param event EventData.on_gui_closed +---Handles the closing of the OARC GUI. +---@param event EventData.on_gui_closed +---@return nil function OarcGuiClosed(event) if (event.element and (event.element.name == "oarc_gui")) then HideOarcGui(game.players[event.player_index]) end end + +---Completely destroys and recreates the OARC GUI for a player. +---@param player LuaPlayer +---@return nil +function RecreateOarcGui(player) + if (mod_gui.get_button_flow(player).oarc_button ~= nil) then + mod_gui.get_button_flow(player).oarc_button.destroy() + end + + if (mod_gui.get_frame_flow(player)[OARC_GUI] ~= nil) then + mod_gui.get_frame_flow(player)[OARC_GUI].destroy() + end + + InitOarcGuiTabs(player) +end + + +---Server info gui click event handler +---@param event EventData.on_gui_click +---@return nil +function OarcGuiTabsClick(event) + if not event.element.valid then return end + ServerInfoGuiClick(event) + SpawnCtrlGuiClick(event) + SettingsControlsTabGuiClick(event) + SettingsSurfaceControlsTabGuiClick(event) + PlayerListGuiClick(event) +end \ No newline at end of file diff --git a/lib/oarc_gui_utils.lua b/lib/oarc_gui_utils.lua index 4bef959..ca57b53 100644 --- a/lib/oarc_gui_utils.lua +++ b/lib/oarc_gui_utils.lua @@ -100,7 +100,7 @@ my_shared_item_list_fixed_width_style = { my_player_list_admin_style = { font = "default-semibold", font_color = {r=1,g=0.5,b=0.5}, - minimal_width = 200, + -- minimal_width = 200, top_padding = 0, bottom_padding = 0, single_line = false, @@ -109,7 +109,7 @@ my_player_list_admin_style = { ---@diagnostic disable-next-line: missing-fields my_player_list_style = { font = "default-semibold", - minimal_width = 200, + -- minimal_width = 200, top_padding = 0, bottom_padding = 0, single_line = false, @@ -119,7 +119,7 @@ my_player_list_style = { my_player_list_offline_style = { -- font = "default-semibold", font_color = {r=0.5,g=0.5,b=0.5}, - minimal_width = 200, + -- minimal_width = 200, top_padding = 0, bottom_padding = 0, single_line = false, diff --git a/lib/oarc_tests.lua b/lib/oarc_tests.lua index a81351c..a3092a9 100644 --- a/lib/oarc_tests.lua +++ b/lib/oarc_tests.lua @@ -162,18 +162,6 @@ function ClearTestButtons(player) end end -function RecreateOarcGui(player) - if (mod_gui.get_button_flow(player).oarc_button ~= nil) then - mod_gui.get_button_flow(player).oarc_button.destroy() - end - - if (mod_gui.get_frame_flow(player)[OARC_GUI] ~= nil) then - mod_gui.get_frame_flow(player)[OARC_GUI].destroy() - end - - InitOarcGuiTabs(player) -end - function SetNauvisChunksGenerated() local nauvis = game.surfaces["nauvis"] diff --git a/lib/oarc_utils.lua b/lib/oarc_utils.lua index 0087f13..cb5e467 100644 --- a/lib/oarc_utils.lua +++ b/lib/oarc_utils.lua @@ -208,12 +208,13 @@ end ---@return string function FormatTimeHoursSecs(ticks) local seconds = ticks / 60 - local minutes = math.floor((seconds)/60) - local hours = math.floor((minutes)/60) - local minutes = math.floor(minutes - 60*hours) + local total_minutes = math.floor((seconds)/60) + local hours = math.floor((total_minutes)/60) + local minutes = math.floor(total_minutes - 60*hours) return string.format("%dh:%02dm", hours, minutes) end + -- -- Simple math clamp -- function clamp(val, min, max) -- if (val > max) then diff --git a/lib/separate_spawns.lua b/lib/separate_spawns.lua index b7d7447..29a4d9a 100644 --- a/lib/separate_spawns.lua +++ b/lib/separate_spawns.lua @@ -737,7 +737,7 @@ function RemoveOrResetPlayer(player, remove_player) end end ----Searches all unique spawns for the primary one for a player. +---Searches all unique spawns for the primary one for a player. This will return null if they joined someeone else's spawn. ---@param player_name string ---@return OarcUniqueSpawn? function FindPrimaryUniqueSpawn(player_name) @@ -748,6 +748,19 @@ function FindPrimaryUniqueSpawn(player_name) end end +---Find the primary home spawn of a player, if one exists. It could be they joined a shared spawn. +---@param player_name string +---@return OarcUniqueSpawn? +function FindPlayerHomeSpawn(player_name) + for _,spawns in pairs(global.unique_spawns) do + for _,spawn in pairs(spawns) do + if (spawn.primary) and ((spawn.host_name == player_name) or TableContains(spawn.joiners, player_name)) then + return spawn + end + end + end +end + ---Searches all unique spawns for a list of secondary ones for a player. ---@param player_name string ---@return table -- Indexed by surface name! diff --git a/locale/en/locale.cfg b/locale/en/locale.cfg index 0335831..b00d39d 100644 --- a/locale/en/locale.cfg +++ b/locale/en/locale.cfg @@ -181,6 +181,7 @@ oarc-server-info-tab-title=Server Info oarc-spawn-ctrls-tab-title=Spawn Controls oarc-settings-tab-title=Settings oarc-mod-info-tab-title=Mod Info +oarc-player-list-tab-title=Player List oarc-server-info-tab-welcome-msg-title=Welcome Message oarc-server-info-tab-discord-invite=Discord Invite: @@ -197,6 +198,18 @@ oarc-player-not-found=Player __1__ is not found? oarc-player-about-to-spawn=Player __1__ is about to spawn, try again later. oarc-player-none-selected=No player selected! +oarc-player-list-tab-column-header-player=Player +oarc-player-list-tab-column-header-force=Team (Force) +oarc-player-list-tab-column-header-surface=Home Surface +oarc-player-list-tab-column-header-time-player=Time Played +oarc-player-list-tab-column-header-location=Location +oarc-player-list-tab-column-header-status=Status + +oarc-player-online=Online +oarc-player-offline=Offline + +oarc-player-list-tab-location-button-tooltip=Click to show player location. + oarc-settings-tab-title-mod-settings=Mod Settings oarc-settings-tab-admin-warning=You are an admin. Changing these settings late in the game may cause issues!\nChanging settings will not modify existing spawns. BE CAREFUL! From b61dde3cba0b46be7a0ccb0276285a1ef35470ed Mon Sep 17 00:00:00 2001 From: Oarcinae Date: Fri, 4 Oct 2024 14:10:11 -0400 Subject: [PATCH 04/16] Clean up player list. Should be good enough now. --- lib/gui_tabs/player_list.lua | 31 +++++++++++++++++++------------ lib/oarc_gui_utils.lua | 2 +- locale/en/locale.cfg | 3 ++- 3 files changed, 22 insertions(+), 14 deletions(-) diff --git a/lib/gui_tabs/player_list.lua b/lib/gui_tabs/player_list.lua index 27532df..9337c3b 100644 --- a/lib/gui_tabs/player_list.lua +++ b/lib/gui_tabs/player_list.lua @@ -51,26 +51,33 @@ end function AddPlayerRow(table, player_name, online) local player = game.players[player_name] if (player) then - AddLabel(table, nil, player.name, my_label_style) + if player.admin then + local label = AddLabel(table, nil, player.name, my_player_list_admin_style) + label.tooltip = "Admin" + else + AddLabel(table, nil, player.name, my_label_style) + end AddLabel(table, nil, player.force.name, my_label_style) - -- Get the player's home surface - local spawn = FindPlayerHomeSpawn(player.name) - if (spawn) then - AddLabel(table, nil, spawn.surface_name, my_label_style) + -- List home surface name or holding pen + if (player.surface.name == HOLDING_PEN_SURFACE_NAME) then + AddLabel(table, nil, {"oarc-player-waiting-to-spawn"}, my_label_style) else - AddLabel(table, nil, "Unknown", my_label_style) + local spawn = FindPlayerHomeSpawn(player.name) + if (spawn) then + AddLabel(table, nil, spawn.surface_name, my_label_style) + else + AddLabel(table, nil, "Unknown?", my_label_style) -- Shouldn't happen + end end AddLabel(table, nil, FormatTimeHoursSecs(player.online_time), my_label_style) + CreatePlayerGPSButton(table, player.name) if online then - if (player.admin) then - AddLabel(table, nil, {"oarc-player-online"}, my_player_list_admin_style) - else - AddLabel(table, nil, {"oarc-player-online"}, my_player_list_style) - end + local label = AddLabel(table, nil, {"oarc-player-online"}, my_player_list_style) + label.style.font_color = {r=0.1, g=1, b=0.1} else AddLabel(table, nil, {"oarc-player-offline"}, my_player_list_offline_style) end @@ -92,7 +99,7 @@ function CreatePlayerGPSButton(container, player_name) player_name = player_name, }, style = "slot_button", - tooltip = { "oarc-player-list-tab-location-button-tooltip" }, + tooltip = {"", {"oarc-player-list-tab-location-button-tooltip"}, " (", game.players[player_name].surface.name, ")"}, } gps_button.style.width = 28 gps_button.style.height = 28 diff --git a/lib/oarc_gui_utils.lua b/lib/oarc_gui_utils.lua index ca57b53..b5ea3cd 100644 --- a/lib/oarc_gui_utils.lua +++ b/lib/oarc_gui_utils.lua @@ -99,7 +99,7 @@ my_shared_item_list_fixed_width_style = { ---@diagnostic disable-next-line: missing-fields my_player_list_admin_style = { font = "default-semibold", - font_color = {r=1,g=0.5,b=0.5}, + font_color = { r=0.9, g=0.7, b=0.3 }, -- minimal_width = 200, top_padding = 0, bottom_padding = 0, diff --git a/locale/en/locale.cfg b/locale/en/locale.cfg index b00d39d..2fe68e5 100644 --- a/locale/en/locale.cfg +++ b/locale/en/locale.cfg @@ -207,8 +207,9 @@ oarc-player-list-tab-column-header-status=Status oarc-player-online=Online oarc-player-offline=Offline +oarc-player-waiting-to-spawn=Not Spawned Yet -oarc-player-list-tab-location-button-tooltip=Click to show player location. +oarc-player-list-tab-location-button-tooltip=Click to view map location. oarc-settings-tab-title-mod-settings=Mod Settings From 9604c196382204c73d3142a3bb069600af075640 Mon Sep 17 00:00:00 2001 From: Oarcinae Date: Fri, 4 Oct 2024 19:01:30 -0400 Subject: [PATCH 05/16] More fish. --- lib/oarc_utils.lua | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/lib/oarc_utils.lua b/lib/oarc_utils.lua index 0087f13..c495512 100644 --- a/lib/oarc_utils.lua +++ b/lib/oarc_utils.lua @@ -1357,6 +1357,11 @@ function CreateCropCircle(surface, centerPos, chunkArea, tileRadius, fillTile, m -- land connections if the spawn is on or near land. elseif ((distSqr < moat_radius_sqr) and (distSqr > tile_radius_sqr)) then table.insert(dirtTiles, { name = "water", position = { i, j } }) + + --5% chance of fish in water + if (math.random(1,20) == 1) then + surface.create_entity({name="fish", position={i + 0.5, j + 0.5}}) + end end end end @@ -1410,6 +1415,11 @@ function CreateCropOctagon(surface, centerPos, chunkArea, tileRadius, fillTile, -- land connections if the spawn is on or near land. elseif ((distVar > tileRadius) and (distVar <= moat_width_outer)) then table.insert(dirtTiles, { name = "water", position = { i, j } }) + + --5% chance of fish in water + if (math.random(1,20) == 1) then + surface.create_entity({name="fish", position={i + 0.5, j + 0.5}}) + end end end end @@ -1461,6 +1471,11 @@ function CreateCropSquare(surface, centerPos, chunkArea, tileRadius, fillTile, m -- land connections if the spawn is on or near land. elseif ((max_distance > tileRadius) and (max_distance <= moat_width_outer)) then table.insert(dirtTiles, { name = "water", position = { i, j } }) + + --5% chance of fish in water + if (math.random(1,20) == 1) then + surface.create_entity({name="fish", position={i + 0.5, j + 0.5}}) + end end end end From c5871b8ed904f2f9a7b27ee51b833635517be9d1 Mon Sep 17 00:00:00 2001 From: Oarcinae Date: Sat, 5 Oct 2024 09:44:56 -0400 Subject: [PATCH 06/16] Making some dev notes regarding upcoming 2.0 and space age changes I'll need to investigate. --- devplan.txt | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/devplan.txt b/devplan.txt index f1e2abe..fe896a1 100644 --- a/devplan.txt +++ b/devplan.txt @@ -35,6 +35,46 @@ Major: - Radar quality affects regrowth safe range? - Update electric pole connections for shared power if things change in V2.0 +- Source: https://forums.factorio.com/115737 +- Specifics that I might need to investigate: +Added LuaPlayer::land_on_planet() method. +Added LuaPlayer::enter_space_platform() and leave_space_platform() method. +Added cargo-landing-pad prototype. +Added space-platform-starter-pack, space-location, planet and space-connection prototypes. +Added surface-property and surface prototypes. +Added new controller type (remote), which is to build space platforms, so it allows ghost building but not any physical manipulation. +Added LuaPlayer::physical_surface, physical_surface_index, physical_vehicle and physical_position read. +Electric pole created through LuaSurface::create_entity can be requested to not auto connect. +Added LuaSurface::global_effect read/write. +Added LuaSurface::localised_name read/write. +LuaGameScript::print, LuaPlayer::print, LuaSurface::print and LuaForce::print no longer accept Color as a second parameter. +Added LuaSurface::set_property() and get_property() methods. +Added LuaSurface::execute_lightning() method. +Added LuaSurface::create_global_electric_network() and destroy_global_electric_network() methods. +Added LuaSurface::has_global_electric_network read. +Added LuaSurface::platform read. +Added LuaSurface::pollutant_type read. +Added airborne-pollutant prototype and changed various pollution related properties to support multiple pollution types. +Added LuaSurface::deletable read. +Added LuaForce::set_surface_hidden() and get_surface_hidden() methods. +Added cause argument to LuaSurface::create_entity. +Added LuaSurfacePrototype::surface_properties read. +Added on_player_controller_changed event. +Removed LuaPlayer::open_map, zoom_to_world, and close_map. LuaPlayer::set_controller with type 'remote' replaces these. +oved LuaGameScript::styles to LuaPrototypes::style. +Removed LuaGameScript::active_mods. Use LuaBootstrap::active_mods instead. +Renamed `global` into `storage`. +Added LuaGameScript::technology_notifications_enabled (read/write). +Added LuaGameScript::planets read. +Added LuaGameScript::get_vehicles. +Added LuaForce::platforms read. +Added LuaGameScript::set_win_ending_info() and set_lose_ending_info() methods. +Added LuaForce::unlock_space_location(), lock_space_location() and is_space_location_unlocked() methods. +Added LuaForce::create_space_platform() method. +Added LuaForce::unlock_space_platforms(), lock_space_platforms() and is_space_platforms_unlocked() methods. +Changed LuaForce::evolution_factor, evolution_factor_by_pollution, evolution_factor_by_time and evolution_factor_by_killing_spawners to get_* and set_* methods. +Added LuaForce::copy_from() and copy_chart() methods. + ------------------------------------------------------------------------------------------------------------------------ Other Ideas, Not Committed: From ffc9b450a5c75576e5324e5cb6c12d04678686f2 Mon Sep 17 00:00:00 2001 From: Oarcinae Date: Sun, 6 Oct 2024 15:28:16 -0400 Subject: [PATCH 07/16] Saving my work for surface starting items and resources config GUI. Have the starting items working. Need to setup GUI for resources next. --- control.lua | 35 ++- lib/config.lua | 35 ++- lib/config_parser.lua | 13 +- lib/gui_tabs/player_list.lua | 2 +- lib/gui_tabs/server_info.lua | 2 +- lib/gui_tabs/spawn_controls.lua | 4 +- lib/gui_tabs/surface_config.lua | 530 ++++++++++++++++++++++++++++++++ lib/oarc_gui_tabs.lua | 115 +++++-- lib/oarc_gui_utils.lua | 1 + lib/separate_spawns.lua | 6 +- locale/en/locale.cfg | 1 + 11 files changed, 683 insertions(+), 61 deletions(-) create mode 100644 lib/gui_tabs/surface_config.lua diff --git a/control.lua b/control.lua index 14179e3..26b794e 100644 --- a/control.lua +++ b/control.lua @@ -254,27 +254,24 @@ end) -- Gui Events ---------------------------------------- script.on_event(defines.events.on_gui_click, function(event) - if not event.element.valid then return end -- Should we ever react to invalid GUI elements? + if not event.element.valid then return end SeparateSpawnsGuiClick(event) - - ClickOarcGuiButton(event) OarcGuiTabsClick(event) end) --- Called when LuaGuiElement checked state is changed (related to checkboxes and radio buttons). script.on_event(defines.events.on_gui_checked_state_changed, function (event) - if not event.element.valid then return end -- Should we ever react to invalid GUI elements? + if not event.element.valid then return end SeparateSpawnsGuiCheckedStateChanged(event) - - SpawnCtrlGuiOptionsSelect(event) + OarcGuiTabsCheckedStateChanged(event) end) script.on_event(defines.events.on_gui_selected_tab_changed, function (event) - if not event.element.valid then return end -- Should we ever react to invalid GUI elements? + if not event.element.valid then return end - OarcGuiSelectedTabChanged(event) + OarcGuiTabsSelectedTabChanged(event) end) -- For capturing player escaping custom GUI so we can close it using ESC key. @@ -285,30 +282,36 @@ 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? + if not event.element.valid then return end SeparateSpawnsGuiValueChanged(event) - SettingsControlsTabGuiValueChanged(event) + OarcGuiTabsValueChanged(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? + if not event.element.valid then return end SeparateSpawnsGuiSelectionStateChanged(event) - SettingsControlsTabGuiSelectionStateChanged(event) + OarcGuiTabsSelectionStateChanged(event) end) script.on_event(defines.events.on_gui_text_changed, function(event) - if not event.element.valid then return end -- Should we ever react to invalid GUI elements? + if not event.element.valid then return end - SettingsControlsTabGuiTextChanged(event) + OarcGuiTabsTextChanged(event) end) script.on_event(defines.events.on_gui_confirmed, function(event) - if not event.element.valid then return end -- Should we ever react to invalid GUI elements? + if not event.element.valid then return end + + OarcGuiTabsConfirmed(event) +end) + +script.on_event(defines.events.on_gui_elem_changed, function(event) + if not event.element.valid then return end - SettingsControlsTabGuiTextconfirmed(event) + OarcGuiTabsElemChanged(event) end) ---------------------------------------- diff --git a/lib/config.lua b/lib/config.lua index f1237b9..7f18513 100644 --- a/lib/config.lua +++ b/lib/config.lua @@ -26,6 +26,9 @@ SPAWN_SHAPE_CHOICE_SQUARE = "square" RESOURCES_SHAPE_CHOICE_CIRCLE = "circle" RESOURCES_SHAPE_CHOICE_SQUARE = "square" +MAX_CRASHED_SHIP_RESOURCES_ITEMS = 5 +MAX_CRASHED_SHIP_WRECKAGE_ITEMS = 1 + ---@type OarcConfigStartingItems NAUVIS_STARTER_ITEMS = { @@ -364,22 +367,22 @@ OCFG = { starting_items = NAUVIS_STARTER_ITEMS, spawn_config = NAUVIS_SPAWN_CONFIG }, - ["vulcanus"] = { - starting_items = NAUVIS_STARTER_ITEMS, - spawn_config = NAUVIS_SPAWN_CONFIG - }, - ["fulgora"] = { - starting_items = NAUVIS_STARTER_ITEMS, - spawn_config = NAUVIS_SPAWN_CONFIG - }, - ["gleba"] = { - starting_items = NAUVIS_STARTER_ITEMS, - spawn_config = NAUVIS_SPAWN_CONFIG - }, - ["aquilo"] = { - starting_items = NAUVIS_STARTER_ITEMS, - spawn_config = NAUVIS_SPAWN_CONFIG - } + -- ["vulcanus"] = { + -- starting_items = NAUVIS_STARTER_ITEMS, + -- spawn_config = NAUVIS_SPAWN_CONFIG + -- }, + -- ["fulgora"] = { + -- starting_items = NAUVIS_STARTER_ITEMS, + -- spawn_config = NAUVIS_SPAWN_CONFIG + -- }, + -- ["gleba"] = { + -- starting_items = NAUVIS_STARTER_ITEMS, + -- spawn_config = NAUVIS_SPAWN_CONFIG + -- }, + -- ["aquilo"] = { + -- starting_items = NAUVIS_STARTER_ITEMS, + -- spawn_config = NAUVIS_SPAWN_CONFIG + -- } }, -- Surfaces blacklist (Ignore these surfaces completely for spawning and regrowth!) diff --git a/lib/config_parser.lua b/lib/config_parser.lua index 01ec7f5..93e85bf 100644 --- a/lib/config_parser.lua +++ b/lib/config_parser.lua @@ -158,7 +158,7 @@ function ValidateAndLoadConfig() -- Load the template config into the global table. ---@class OarcConfig - global.ocfg = OCFG + global.ocfg = table.deepcopy(OCFG) -- Check that each entry in OCFG matches the default value of the mod setting. This is just for my own sanity. -- Helps make sure mod default settings and my internal config are in sync. @@ -221,6 +221,17 @@ function ValidateSettings() if (global.ocfg.surfaces_config["nauvis"] == nil) then error("nauvis surface config does not exist! Please check your mod settings or config!") end + + -- Very for each surface config that the item counts are valid. + for surface_name,surface_config in pairs(global.ocfg.surfaces_config) do + if (table_size(surface_config.starting_items.crashed_ship_resources) > MAX_CRASHED_SHIP_RESOURCES_ITEMS) then + error("Too many items in crashed_ship_resources for surface: " .. surface_name) + end + + if (table_size(surface_config.starting_items.crashed_ship_wreakage) > MAX_CRASHED_SHIP_WRECKAGE_ITEMS) then + error("Too many items in player_start_items for surface: " .. surface_name) + end + end end -- Read in the mod settings and copy them to the OARC_CFG table, overwriting the defaults in config.lua. diff --git a/lib/gui_tabs/player_list.lua b/lib/gui_tabs/player_list.lua index 9337c3b..b3b79a0 100644 --- a/lib/gui_tabs/player_list.lua +++ b/lib/gui_tabs/player_list.lua @@ -108,7 +108,7 @@ end ---Handle the gui click of the player list tab in the Oarc GUI. ---@param event EventData.on_gui_click ---@return nil -function PlayerListGuiClick(event) +function PlayerListTabGuiClick(event) if not event.element.valid then return end local player = game.players[event.player_index] local tags = event.element.tags diff --git a/lib/gui_tabs/server_info.lua b/lib/gui_tabs/server_info.lua index 24b53f1..3752d53 100644 --- a/lib/gui_tabs/server_info.lua +++ b/lib/gui_tabs/server_info.lua @@ -92,7 +92,7 @@ end ---Server info gui click event handler ---@param event EventData.on_gui_click ---@return nil -function ServerInfoGuiClick(event) +function ServerInfoTabGuiClick(event) if not event.element.valid then return end local player = game.players[event.player_index] local tags = event.element.tags diff --git a/lib/gui_tabs/spawn_controls.lua b/lib/gui_tabs/spawn_controls.lua index a2243c8..ad87515 100644 --- a/lib/gui_tabs/spawn_controls.lua +++ b/lib/gui_tabs/spawn_controls.lua @@ -252,7 +252,7 @@ end ---Handle the gui checkboxes & radio buttons of the spawn control tab in the Oarc GUI. ---@param event EventData.on_gui_checked_state_changed ---@return nil -function SpawnCtrlGuiOptionsSelect(event) +function SpawnCtrlGuiOptionsCheckedStateChanged(event) if not event.element.valid then return end local player = game.players[event.player_index] local tags = event.element.tags @@ -282,7 +282,7 @@ end ---Handle the gui click of the spawn control tab in the Oarc GUI. ---@param event EventData.on_gui_click ---@return nil -function SpawnCtrlGuiClick(event) +function SpawnCtrlTabGuiClick(event) if not event.element.valid then return end local player = game.players[event.player_index] local tags = event.element.tags diff --git a/lib/gui_tabs/surface_config.lua b/lib/gui_tabs/surface_config.lua new file mode 100644 index 0000000..79c2a7b --- /dev/null +++ b/lib/gui_tabs/surface_config.lua @@ -0,0 +1,530 @@ +--This file will let admins configure the "surfaces_config" table that is NOT available in the mod settings. + +---Creates the tab content, used by AddOarcGuiTab +---@param tab_container LuaGuiElement +---@param player LuaPlayer +---@return nil +function CreateSurfaceConfigTab(tab_container, player) + + local note = AddLabel(tab_container, nil, "This lets you configure the surface settings, it is only available to admins. These settings are NOT available in the mod settings page. If you want to automatically set these on the start of a new game using a custom file, please check out the included template scenario in the mod folder. I really question my sanity for bothering to make this GUI interface. Send help.", my_note_style) -- TODO: Localize + note.style.maximal_width = 700 + + -- Drop down to select surface that you want to configure + local selected_surface_name = CreateSurfaceDropdown(tab_container) + -- AddSpacer(tab_container) + + local content = tab_container.add { + type = "flow", + direction = "vertical", + name = "surface_config_content_flow" + } + CreateSurfaceConfigContent(content, selected_surface_name) +end + +---Create surface config content section below the surface selection dropdown +---@param container LuaGuiElement +---@param surface_name string +---@return nil +function CreateSurfaceConfigContent(container, surface_name) + + -- Vertical scroll pane with dividers for each section for the surface config + local scroll_pane = container.add { + type = "scroll-pane", + direction = "vertical", + vertical_scroll_policy = "always", + } + scroll_pane.style.top_margin = 10 + + -- Add a checkbox to enable/disable the crashed ship. + CreateCrashSiteEnable(scroll_pane, surface_name) + + local starting_items_flow = scroll_pane.add { + type = "flow", + direction = "horizontal" + } + + -- TODO: Localize + CreateItemsSection(starting_items_flow, surface_name, "Starting Items", "player_start_items") + CreateItemsSection(starting_items_flow, surface_name, "Respawn Items", "player_respawn_items") + CreateItemsSection(starting_items_flow, surface_name, "Crashed Ship (Max 5)", "crashed_ship_resources", MAX_CRASHED_SHIP_RESOURCES_ITEMS) + CreateItemsSection(starting_items_flow, surface_name, "Ship Wreckage (Max 1)", "crashed_ship_wreakage", MAX_CRASHED_SHIP_WRECKAGE_ITEMS) + + local spawn_config_flow = scroll_pane.add { + type = "flow", + direction = "horizontal" + } + + -- Create an choose-elem-button for the testing + local button = spawn_config_flow.add { + type = "choose-elem-button", + elem_type = "entity", + elem_filters = {{filter = "type", type = "resource"}, {filter = "minable", mode = "and"}}, + } + + -- Spawn Config (safe area) + -- Spawn Config (water strip) (Note offset from north of spawn.) + -- Spawn Config (shared power pole position) (Note offset from west of spawn.) + -- Spawn Config (shared chest position) (Note offset from west of spawn.) + -- Spawn Config (resources and amounts (and maybe x/y positions)) (Note offset is center and not used if auto place.) + -- Spawn Config (fluid resources) (Note offset from south of spawn.) +end + + +---Create a checkbox to enable/disable the crashed ship +---@param container LuaGuiElement +---@param surface_name string +---@return nil +function CreateCrashSiteEnable(container, surface_name) + local crashed_ship_enabled = global.ocfg.surfaces_config[surface_name].starting_items.crashed_ship + + local crashed_ship_flow = container.add { + type = "flow", + direction = "horizontal" + } + crashed_ship_flow.style.vertical_align = "center" + + AddLabel(crashed_ship_flow, nil, "Enable Crashed Ship: ", "caption_label") -- TODO: Localize + local crashed_ship_enabled_checkbox = crashed_ship_flow.add { + type = "checkbox", + state = crashed_ship_enabled, + tags = { + action = "oarc_surface_config_tab", + setting = "crashed_ship_enabled", + surface_name = surface_name + }, + tooltip = "Enables the factorio style ship crash with items. If this is disabled, the crashed ship items and wreckage won't do anything." -- TODO: Localize + } +end + +---Create surface dropdown selection +---@param container LuaGuiElement +---@return string --The default selected surface name +function CreateSurfaceDropdown(container) + local surface_names = {} + for surface_name,_ in pairs(global.ocfg.surfaces_config) do + table.insert(surface_names, surface_name) + end + table.sort(surface_names) + + local selected_surface_name = surface_names[1] + + local horizontal_flow = container.add { + type = "flow", + direction = "horizontal" + } + horizontal_flow.style.vertical_align = "center" + AddLabel(horizontal_flow, nil, "Select Surface: ", "caption_label") + + local surface_dropdown = horizontal_flow.add { + type = "drop-down", + name = "surface_dropdown", + items = surface_names, + selected_index = 1, + tags = { + action = "oarc_surface_config_tab", + setting = "surface_dropdown" + }, + tooltip = "Select the surface you want to configure." -- TODO: Localize + } + + local dragger = horizontal_flow.add{ type="empty-widget", style="draggable_space_header" } + dragger.style.horizontally_stretchable = true + + -- A button to revert config to default (from OCFG hardcoded.) + local revert_button = horizontal_flow.add { + type = "button", + caption = "Revert", -- TODO: Localize + tooltip = "Revert to default.", -- TODO: Localize + style = "red_button", + tags = { + action = "oarc_surface_config_tab", + setting = "revert_to_default" + } + } + + -- Add button to copy nauvis config to current selected surface (if not nauvis) + local copy_button = horizontal_flow.add { + type = "button", + caption = "Copy Nauvis", -- TODO: Localize + tooltip = "Copy Nauvis settings to this surface.", -- TODO: Localize + style = "red_button", + tags = { + action = "oarc_surface_config_tab", + setting = "copy_nauvis" + } + } + + return selected_surface_name +end + +---Handle the surface dropdown selection +---@param event EventData.on_gui_selection_state_changed +---@return nil +function SurfaceConfigTabGuiSelect(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_surface_config_tab") then + return + end + + if (tags.setting == "surface_dropdown") then + local selected_surface_name = event.element.items[event.element.selected_index] --[[@as string]] + + local content_flow = event.element.parent.parent["surface_config_content_flow"] + if (content_flow == nil) then + error("Content flow is nil? This shouldn't happen on surface dropdown select! " .. selected_surface_name) + end + + -- Recreate the content section + content_flow.clear() + CreateSurfaceConfigContent(content_flow, selected_surface_name) + + player.print("Selected surface: " .. selected_surface_name) + end +end + +---Create an items selection section +---@param container LuaGuiElement +---@param surface_name string +---@param header string +---@param setting_name string +---@param max_count integer? +---@return nil +function CreateItemsSection(container, surface_name, header, setting_name, max_count) + + local items = global.ocfg.surfaces_config[surface_name].starting_items[setting_name] + + if (items == nil) then + error("No items found for setting: " .. setting_name .. " for surface: " .. surface_name) + end + + if (max_count and (table_size(items) > max_count)) then + -- This would only happen with a bad config. + error("Too many items in starting items list!?") + end + + local vertical_flow = container.add { + type = "flow", + direction = "vertical" + } + + AddLabel(vertical_flow, nil, header, my_label_header2_style) + + local table = vertical_flow.add { + type = "table", + column_count = 3, + style = "bordered_table", + tags = { + surface_name = surface_name, + setting = setting_name, + max_count = max_count or 0 + } + } + + --Add headers + AddLabel(table, nil, "Item", "caption_label") + AddLabel(table, nil, "Count", "caption_label") + AddLabel(table, nil, "Remove", "caption_label") + + for item_name, item_count in pairs(items) do + SurfaceConfigItemListDisplayRow(table, item_name, item_count) + end + + -- Add a button to add another row + if (max_count == nil) or (max_count == 0) or (table_size(items) < max_count) then + SurfaceConfigItemListAddRowButton(table) + end +end + + +---Handle elem changed events +---@param event EventData.on_gui_elem_changed +---@return nil +function SurfaceConfigTabGuiElemChanged(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_surface_config_tab") then + return + end + + if (tags.elem_button) then + local new_item_name = event.element.elem_value --[[@as string]] + player.print("Selected item: " .. new_item_name) + + if (new_item_name == nil) then + return + end + + local old_item_name = tags.item_name --[[@as string]] + + -- if the new item name is the same as the old item name, do nothing. + if (new_item_name == tags.item_name) then + return + end + + -- otherwise, check if the new item name is already in the list. + local parent = event.element.parent + local surface_name = parent.tags.surface_name --[[@as string]] + local setting_name = parent.tags.setting --[[@as string]] + + if (global.ocfg.surfaces_config[surface_name].starting_items[setting_name][new_item_name]) then + player.print("Item already exists in list! " .. new_item_name) + event.element.elem_value = nil + return + end + + -- Update the item name in the list, keep the old count. + player.print("Update item: " .. old_item_name .. " to " .. new_item_name .. " for surface " .. surface_name) + global.ocfg.surfaces_config[surface_name].starting_items[setting_name][new_item_name] = global.ocfg.surfaces_config[surface_name].starting_items[setting_name][old_item_name] + global.ocfg.surfaces_config[surface_name].starting_items[setting_name][old_item_name] = nil + + -- Update all tags with the new item name. + for _, child in pairs(event.element.parent.children) do + if (child.tags.item_name == old_item_name) then + local tags_copy = child.tags + tags_copy.item_name = new_item_name + child.tags = tags_copy + end + end + end +end + +---Handle the surface config tab button clicks +---@param event EventData.on_gui_click +---@return nil +function SurfaceConfigTabGuiClick(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_surface_config_tab") then + return + end + + if (tags.remove_row_button) then + player.print("Remove item: " .. tags.item_name) + + local parent = event.element.parent + local surface_name = parent.tags.surface_name --[[@as string]] + local setting_name = parent.tags.setting --[[@as string]] + local item_name = tags.item_name --[[@as string]] + local max_count = parent.tags.max_count --[[@as integer]] + + -- Nil the entry + player.print("Remove item: " .. item_name .. " for surface " .. surface_name) + global.ocfg.surfaces_config[surface_name].starting_items[setting_name][item_name] = nil + + -- Delete the row by removing the child elements from the table. + local parent = event.element.parent --[[@as LuaGuiElement]] -- Ass(u)me that the parent is a table. + for _, child in pairs(parent.children) do + if (child.tags and child.tags.item_name == tags.item_name) then + child.destroy() + end + end + + -- Only add the add row if we haven't reached the max count AND the children count is 1 more than % 3. + local table_modulo_3 = #parent.children % 3 + if table_modulo_3 == 0 then + SurfaceConfigItemListAddRowButton(parent) + end + + + elseif (tags.add_row_button) then + + local parent = event.element.parent + local surface_name = parent.tags.surface_name --[[@as string]] + local setting_name = parent.tags.setting --[[@as string]] + local max_count = parent.tags.max_count --[[@as integer]] + if (parent == nil) then + error("Parent is nil? This shouldn't happen on add row button click! " .. setting_name) + end + + player.print("Add row: " .. setting_name) + + -- Delete the button and add a new row and then add the button back. + event.element.destroy() + SurfaceConfigItemListDisplayRow(parent) + + -- Only add the add row if we haven't reached the max count. + local item_count = (#parent.children - 3) / 3 + if (max_count == nil) or (max_count == 0) or (item_count < max_count) then + SurfaceConfigItemListAddRowButton(parent) + end + + elseif (tags.setting == "crashed_ship_enabled") then + local surface_name = tags.surface_name --[[@as string]] + player.print("Crashed Ship Enabled: " .. tostring(event.element.state)) + global.ocfg.surfaces_config[surface_name].starting_items.crashed_ship = event.element.state + + elseif (tags.setting == "revert_to_default") then + + local surface_name = event.element.parent["surface_dropdown"].items[event.element.parent["surface_dropdown"].selected_index] --[[@as string]] + + player.print("Revert to default: " .. surface_name) + global.ocfg.surfaces_config[surface_name].starting_items = table.deepcopy(NAUVIS_STARTER_ITEMS) + global.ocfg.surfaces_config[surface_name].spawn_config = table.deepcopy(NAUVIS_SPAWN_CONFIG) + + -- Recreate the content section + local content_flow = event.element.parent.parent["surface_config_content_flow"] + if (content_flow == nil) then + error("Content flow is nil? This shouldn't happen on revert to default! " .. surface_name) + end + content_flow.clear() + CreateSurfaceConfigContent(content_flow, surface_name) + + elseif (tags.setting == "copy_nauvis") then + + local surface_name = event.element.parent["surface_dropdown"].items[event.element.parent["surface_dropdown"].selected_index] --[[@as string]] + + if (surface_name == "nauvis") then + player.print("Already on nauvis, select a different surface to copy nauvis settings to!") + return + end + + player.print("Copy Nauvis: " .. surface_name) + global.ocfg.surfaces_config[surface_name].starting_items = global.ocfg.surfaces_config["nauvis"].starting_items + global.ocfg.surfaces_config[surface_name].spawn_config = global.ocfg.surfaces_config["nauvis"].spawn_config + + -- Recreate the content section + local content_flow = event.element.parent.parent["surface_config_content_flow"] + if (content_flow == nil) then + error("Content flow is nil? This shouldn't happen on copy nauvis! " .. surface_name) + end + content_flow.clear() + CreateSurfaceConfigContent(content_flow, surface_name) + end +end + +---Adds a row to a table with an item and count +---@param table LuaGuiElement +---@param item_name string? +---@param item_count integer? +---@return nil +function SurfaceConfigItemListDisplayRow(table, item_name, item_count) + -- Create choose elem button + local button = table.add { + type = "choose-elem-button", + elem_type = "item", + item = item_name, + tags = { + action = "oarc_surface_config_tab", + elem_button = true, + item_name = item_name or "" + }, + } + button.style.width = 28 + button.style.height = 28 + + -- Create number textfield + local textfield = table.add { + type = "textfield", + text = tostring(item_count or 0), + numeric = true, + allow_decimal = false, + tooltip = {"oarc-settings-tab-text-field-enter-tooltip" }, + tags = { + action = "oarc_surface_config_tab", + item_number_textfield = true, + item_name = item_name or "" + } + } + if (item_name == "") then + textfield.style = "invalid_value_textfield" + end + textfield.style.width = 40 + + -- Create a button to remove the row + local remove_button = table.add { + type = "sprite-button", + sprite = "utility/deconstruction_mark", + tooltip = "Remove Item", -- TODO: Localize + tags = { + action = "oarc_surface_config_tab", + remove_row_button = true, + item_name = item_name or "" + } + } + remove_button.style.width = 28 + remove_button.style.height = 28 +end + + +---Add the add row button to the table +---@param table LuaGuiElement +---@return nil +function SurfaceConfigItemListAddRowButton(table) + -- Add a button to add another row + local add_row_button = table.add { + type = "sprite-button", + sprite = "utility/check_mark_green", + tooltip = "Add Item", -- TODO: Localize + tags = { + action = "oarc_surface_config_tab", + add_row_button = true + } + } + add_row_button.style.width = 28 + add_row_button.style.height = 28 +end + + +---Handle on_gui_text_changed events +---@param event EventData.on_gui_text_changed +---@return nil +function SurfaceConfigTabGuiTextChanged(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_surface_config_tab") then + return + end + + if (tags.item_number_textfield) then + player.print("Selected item: " .. tags.item_name .. " count: " .. event.element.text) + + event.element.style = "invalid_value_textfield" + event.element.style.width = 40 + end +end + + +---Handle on_gui_confirmed events +---@param event EventData.on_gui_confirmed +---@return nil +function SurfaceConfigTabGuiConfirmed(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_surface_config_tab") then + return + end + + if (tags.item_number_textfield) then + player.print("Selected item: " .. tags.item_name .. " count: " .. event.element.text) + + local parent = event.element.parent + local surface_name = parent.tags.surface_name --[[@as string]] + local setting_name = parent.tags.setting --[[@as string]] + local item_name = tags.item_name --[[@as string]] + + -- Check if an item is selected first. + if (tags.item_name == "") then + player.print("Please select an item first!") + event.element.text = "0" + return + end + + -- Update the count + local count = tonumber(event.element.text) or 0 + global.ocfg.surfaces_config[surface_name].starting_items[setting_name][item_name] = count + + event.element.style = "textbox" + event.element.style.width = 40 + end +end \ No newline at end of file diff --git a/lib/oarc_gui_tabs.lua b/lib/oarc_gui_tabs.lua index a743280..2e6f0a5 100644 --- a/lib/oarc_gui_tabs.lua +++ b/lib/oarc_gui_tabs.lua @@ -6,6 +6,7 @@ require("lib/gui_tabs/spawn_controls") require("lib/gui_tabs/settings_controls") require("lib/gui_tabs/mod_info_faq") require("lib/gui_tabs/player_list") +require("lib/gui_tabs/surface_config") -------------------------------------------------------------------------------- -- GUI Tab Handler @@ -20,19 +21,22 @@ OARC_SPAWN_CTRL_TAB_NAME = "spawn_controls" OARC_CONFIG_CTRL_TAB_NAME = "settings" OARC_MOD_INFO_CTRL_TAB_NAME = "mod_info" OARC_MOD_PLAYER_LIST_TAB_NAME = "player_list" +OARC_SURFACE_CONFIG_TAB_NAME = "surface_config" OARC_SERVER_INFO_TAB_LOCALIZED = {"oarc-server-info-tab-title"} OARC_SPAWN_CTRL_TAB_LOCALIZED = {"oarc-spawn-ctrls-tab-title"} OARC_CONFIG_CTRL_TAB_LOCALIZED = {"oarc-settings-tab-title"} OARC_MOD_INFO_CTRL_TAB_LOCALIZED = {"oarc-mod-info-tab-title"} OARC_PLAYER_LIST_TAB_LOCALIZED = {"oarc-player-list-tab-title"} +OARC_SURFACE_CONFIG_TAB_LOCALIZED = {"oarc-surface-config-tab-title"} local OARC_GUI_TAB_CONTENT_FUNCTIONS = { [OARC_SERVER_INFO_TAB_NAME] = CreateServerInfoTab, [OARC_SPAWN_CTRL_TAB_NAME] = CreateSpawnControlsTab, [OARC_MOD_INFO_CTRL_TAB_NAME] = CreateModInfoTab, [OARC_CONFIG_CTRL_TAB_NAME] = CreateSettingsControlsTab, - [OARC_MOD_PLAYER_LIST_TAB_NAME] = CreatePlayerListTab + [OARC_MOD_PLAYER_LIST_TAB_NAME] = CreatePlayerListTab, + [OARC_SURFACE_CONFIG_TAB_NAME] = CreateSurfaceConfigTab, } ---@param player LuaPlayer @@ -65,6 +69,12 @@ function InitOarcGuiTabs(player) AddOarcGuiTab(player, OARC_MOD_PLAYER_LIST_TAB_NAME, OARC_PLAYER_LIST_TAB_LOCALIZED) SetOarcGuiTabEnabled(player, OARC_MOD_PLAYER_LIST_TAB_NAME, true) + -- Surface config tab + if (player.admin) then + AddOarcGuiTab(player, OARC_SURFACE_CONFIG_TAB_NAME, OARC_SURFACE_CONFIG_TAB_LOCALIZED) + SetOarcGuiTabEnabled(player, OARC_SURFACE_CONFIG_TAB_NAME, true) + end + HideOarcGui(player) end @@ -150,12 +160,7 @@ function ClickOarcGuiButton(event) end end ----@param event EventData.on_gui_selected_tab_changed ----@return nil -function OarcGuiSelectedTabChanged(event) - if (event.element.name ~= "oarc_tabs") then return end - OarcGuiCreateContentOfTab(game.players[event.player_index]) -end + ---Set tab content to currently selected tab, clears all other tab content and refreshes the selected tab content! ---Safe to call just to refresh the current tab. @@ -306,15 +311,6 @@ function SwitchOarcGuiTab(player, tab_name) end end ----Handles the closing of the OARC GUI. ----@param event EventData.on_gui_closed ----@return nil -function OarcGuiClosed(event) - if (event.element and (event.element.name == "oarc_gui")) then - HideOarcGui(game.players[event.player_index]) - end -end - ---Completely destroys and recreates the OARC GUI for a player. ---@param player LuaPlayer ---@return nil @@ -330,15 +326,92 @@ function RecreateOarcGui(player) InitOarcGuiTabs(player) end +--[[ + _____ _____ _ _ _____ _ _ _ _ _ ___ _ ___ ___ ___ + | __\ \ / / __| \| |_ _| | || | /_\ | \| | \| | | __| _ \/ __| + | _| \ V /| _|| .` | | | | __ |/ _ \| .` | |) | |__| _|| /\__ \ + |___| \_/ |___|_|\_| |_| |_||_/_/ \_\_|\_|___/|____|___|_|_\|___/ ----Server info gui click event handler +]] + +---Handles the closing of the OARC GUI. +---@param event EventData.on_gui_closed +---@return nil +function OarcGuiClosed(event) + if (event.element and (event.element.name == "oarc_gui")) then + HideOarcGui(game.players[event.player_index]) + end +end + +---@param event EventData.on_gui_selected_tab_changed +---@return nil +function OarcGuiTabsSelectedTabChanged(event) + if (event.element.name ~= "oarc_tabs") then return end + OarcGuiCreateContentOfTab(game.players[event.player_index]) +end + +---All gui tabs click event handler ---@param event EventData.on_gui_click ---@return nil function OarcGuiTabsClick(event) if not event.element.valid then return end - ServerInfoGuiClick(event) - SpawnCtrlGuiClick(event) + ClickOarcGuiButton(event) + ServerInfoTabGuiClick(event) + SpawnCtrlTabGuiClick(event) SettingsControlsTabGuiClick(event) SettingsSurfaceControlsTabGuiClick(event) - PlayerListGuiClick(event) -end \ No newline at end of file + PlayerListTabGuiClick(event) + SurfaceConfigTabGuiClick(event) +end + +---All gui tabs on_gui_checked_state_changed event handler +---@param event EventData.on_gui_checked_state_changed +---@return nil +function OarcGuiTabsCheckedStateChanged(event) + if not event.element.valid then return end + SpawnCtrlGuiOptionsCheckedStateChanged(event) +end + + +---Handles the `on_gui_value_changed` event. +---@param event EventData.on_gui_value_changed +---@return nil +function OarcGuiTabsValueChanged(event) + if not event.element.valid then return end + SettingsControlsTabGuiValueChanged(event) +end + +---Handles the `on_gui_selection_state_changed` event. +---@param event EventData.on_gui_selection_state_changed +---@return nil +function OarcGuiTabsSelectionStateChanged(event) + if not event.element.valid then return end + SettingsControlsTabGuiSelectionStateChanged(event) + SurfaceConfigTabGuiSelect(event) +end + +---Handles the `on_gui_text_changed` event. +---@param event EventData.on_gui_text_changed +---@return nil +function OarcGuiTabsTextChanged(event) + if not event.element.valid then return end + SettingsControlsTabGuiTextChanged(event) + SurfaceConfigTabGuiTextChanged(event) +end + +---Handles the `on_gui_confirmed` event. +---@param event EventData.on_gui_confirmed +---@return nil +function OarcGuiTabsConfirmed(event) + if not event.element.valid then return end + SettingsControlsTabGuiTextconfirmed(event) + SurfaceConfigTabGuiConfirmed(event) +end + +---Handles the `on_gui_elem_changed` event. +---@param event EventData.on_gui_elem_changed +---@return nil +function OarcGuiTabsElemChanged(event) + if not event.element.valid then return end + SurfaceConfigTabGuiElemChanged(event) +end diff --git a/lib/oarc_gui_utils.lua b/lib/oarc_gui_utils.lua index b5ea3cd..fff1801 100644 --- a/lib/oarc_gui_utils.lua +++ b/lib/oarc_gui_utils.lua @@ -58,6 +58,7 @@ my_note_style = { top_padding = 0, bottom_padding = 0 } + ---@type LuaStyle ---@diagnostic disable-next-line: missing-fields my_warning_style = { diff --git a/lib/separate_spawns.lua b/lib/separate_spawns.lua index 29a4d9a..06891a3 100644 --- a/lib/separate_spawns.lua +++ b/lib/separate_spawns.lua @@ -141,10 +141,10 @@ function SeparateSpawnsInitSurface(surface_name) global.oarc_surfaces[surface_name] = (surface_name == global.ocfg.gameplay.default_surface) end - -- Make sure it has a surface configuration entry - if (global.oarc_surfaces[surface_name] and global.ocfg.surfaces_config[surface_name] == nil) then + -- Make sure it has a surface configuration entry! + if (global.ocfg.surfaces_config[surface_name] == nil) then log("Surface does NOT have a config entry, defaulting to nauvis entry for new surface: " .. surface_name) - global.ocfg.surfaces_config[surface_name] = global.ocfg.surfaces_config["nauvis"] + global.ocfg.surfaces_config[surface_name] = table.deepcopy(global.ocfg.surfaces_config["nauvis"]) end end diff --git a/locale/en/locale.cfg b/locale/en/locale.cfg index 2fe68e5..b12ad1b 100644 --- a/locale/en/locale.cfg +++ b/locale/en/locale.cfg @@ -182,6 +182,7 @@ oarc-spawn-ctrls-tab-title=Spawn Controls oarc-settings-tab-title=Settings oarc-mod-info-tab-title=Mod Info oarc-player-list-tab-title=Player List +oarc-surface-config-tab-title=Surface Config oarc-server-info-tab-welcome-msg-title=Welcome Message oarc-server-info-tab-discord-invite=Discord Invite: From 245f9860c8d7eb9b84d66c9018f947878309a08f Mon Sep 17 00:00:00 2001 From: Oarcinae Date: Sun, 6 Oct 2024 20:46:32 -0400 Subject: [PATCH 08/16] Got safe area and resources spawn config gui pieces working. Fixed an issue with tree ring not spawning filling in base over water. --- lib/gui_tabs/surface_config.lua | 666 ++++++++++++++++++++++++-------- lib/oarc_utils.lua | 57 ++- 2 files changed, 549 insertions(+), 174 deletions(-) diff --git a/lib/gui_tabs/surface_config.lua b/lib/gui_tabs/surface_config.lua index 79c2a7b..d25d28f 100644 --- a/lib/gui_tabs/surface_config.lua +++ b/lib/gui_tabs/surface_config.lua @@ -55,17 +55,19 @@ function CreateSurfaceConfigContent(container, surface_name) } -- Create an choose-elem-button for the testing - local button = spawn_config_flow.add { - type = "choose-elem-button", - elem_type = "entity", - elem_filters = {{filter = "type", type = "resource"}, {filter = "minable", mode = "and"}}, - } + -- local button = spawn_config_flow.add { + -- type = "choose-elem-button", + -- elem_type = "entity", + -- elem_filters = {{filter = "type", type = "resource"}, {filter = "minable", mode = "and"}}, + -- } -- Spawn Config (safe area) + CreateSafeAreaConfig(spawn_config_flow, surface_name) -- Spawn Config (water strip) (Note offset from north of spawn.) -- Spawn Config (shared power pole position) (Note offset from west of spawn.) -- Spawn Config (shared chest position) (Note offset from west of spawn.) -- Spawn Config (resources and amounts (and maybe x/y positions)) (Note offset is center and not used if auto place.) + CreateSolidResourcesConfig(spawn_config_flow, surface_name) -- Spawn Config (fluid resources) (Note offset from south of spawn.) end @@ -157,33 +159,6 @@ function CreateSurfaceDropdown(container) return selected_surface_name end ----Handle the surface dropdown selection ----@param event EventData.on_gui_selection_state_changed ----@return nil -function SurfaceConfigTabGuiSelect(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_surface_config_tab") then - return - end - - if (tags.setting == "surface_dropdown") then - local selected_surface_name = event.element.items[event.element.selected_index] --[[@as string]] - - local content_flow = event.element.parent.parent["surface_config_content_flow"] - if (content_flow == nil) then - error("Content flow is nil? This shouldn't happen on surface dropdown select! " .. selected_surface_name) - end - - -- Recreate the content section - content_flow.clear() - CreateSurfaceConfigContent(content_flow, selected_surface_name) - - player.print("Selected surface: " .. selected_surface_name) - end -end ---Create an items selection section ---@param container LuaGuiElement @@ -206,16 +181,19 @@ function CreateItemsSection(container, surface_name, header, setting_name, max_c end local vertical_flow = container.add { - type = "flow", - direction = "vertical" + type = "frame", + direction = "vertical", + style = "inside_shallow_frame" } - + vertical_flow.style.padding = 5 + vertical_flow.style.horizontally_stretchable = false + AddLabel(vertical_flow, nil, header, my_label_header2_style) local table = vertical_flow.add { type = "table", column_count = 3, - style = "bordered_table", + -- style = "bordered_table", tags = { surface_name = surface_name, setting = setting_name, @@ -224,9 +202,9 @@ function CreateItemsSection(container, surface_name, header, setting_name, max_c } --Add headers - AddLabel(table, nil, "Item", "caption_label") - AddLabel(table, nil, "Count", "caption_label") - AddLabel(table, nil, "Remove", "caption_label") + AddLabel(table, nil, "Item", my_label_style) + AddLabel(table, nil, "Count", my_label_style) + AddLabel(table, nil, "", my_label_style) for item_name, item_count in pairs(items) do SurfaceConfigItemListDisplayRow(table, item_name, item_count) @@ -239,6 +217,412 @@ function CreateItemsSection(container, surface_name, header, setting_name, max_c end + + +---Adds a row to a table with an item and count +---@param table LuaGuiElement +---@param item_name string? +---@param item_count integer? +---@return nil +function SurfaceConfigItemListDisplayRow(table, item_name, item_count) + -- Create choose elem button + local button = table.add { + type = "choose-elem-button", + elem_type = "item", + item = item_name, + tags = { + action = "oarc_surface_config_tab", + elem_button = true, + item_name = item_name or "" + }, + } + button.style.width = 28 + button.style.height = 28 + + -- Create number textfield + local textfield = table.add { + type = "textfield", + text = tostring(item_count or 0), + numeric = true, + allow_decimal = false, + tooltip = {"oarc-settings-tab-text-field-enter-tooltip" }, + tags = { + action = "oarc_surface_config_tab", + item_number_textfield = true, + item_name = item_name or "" + } + } + if (item_name == "") then + textfield.style = "invalid_value_textfield" + end + textfield.style.width = 40 + + -- Create a button to remove the row + local remove_button = table.add { + type = "sprite-button", + sprite = "utility/deconstruction_mark", + tooltip = "Remove Item", -- TODO: Localize + tags = { + action = "oarc_surface_config_tab", + remove_row_button = true, + item_name = item_name or "" + } + } + remove_button.style.width = 28 + remove_button.style.height = 28 +end + + +---Add the add row button to the table +---@param table LuaGuiElement +---@return nil +function SurfaceConfigItemListAddRowButton(table) + -- Add a button to add another row + local add_row_button = table.add { + type = "sprite-button", + sprite = "utility/check_mark_green", + tooltip = "Add Item", -- TODO: Localize + tags = { + action = "oarc_surface_config_tab", + add_row_button = true + } + } + add_row_button.style.width = 28 + add_row_button.style.height = 28 +end + + + + +---Create the safe area config section +---@param container LuaGuiElement +---@param surface_name string +---@return nil +function CreateSafeAreaConfig(container, surface_name) + + local safe_area_flow = container.add { + type = "frame", + direction = "vertical", + style = "inside_shallow_frame" + } + safe_area_flow.style.padding = 5 + safe_area_flow.style.horizontally_stretchable = false + + local header = AddLabel(safe_area_flow, nil, "Safe Area Config", my_label_header2_style) -- TODO: Localize + header.tooltip = "This controls how safe the area around the spawns is." -- TODO: Localize + + -- TODO: Localize + CreateSpawnConfigIntegerField(safe_area_flow, surface_name, "Safe Area Radius", "safe_area", "safe_radius", "This is the radius in tiles around the spawn in which no enemies will spawn.") + CreateSpawnConfigIntegerField(safe_area_flow, surface_name, "Warn Area Radius", "safe_area", "warn_radius", "This is the radius in tiles around the spawn in which enemies will be significantly reduced.") + CreateSpawnConfigIntegerField(safe_area_flow, surface_name, "Warn Area Reduction", "safe_area", "warn_reduction", "This is the reduction factor to reduce the number of enemies in the warn area. 10 means (1/10)th the number of enemies.") + CreateSpawnConfigIntegerField(safe_area_flow, surface_name, "Danger Area Radius", "safe_area", "danger_radius", "This is the radius in tiles around the spawn in which enemies will be slightly reduced.") + CreateSpawnConfigIntegerField(safe_area_flow, surface_name, "Danger Area Reduction", "safe_area", "danger_reduction", "This is the reduction factor to reduce the number of enemies in the danger area. 10 means (1/10)th the number of enemies.") +end + + +---Create an integer textfield with a label +---@param container LuaGuiElement +---@param surface_name string +---@param label string +---@param setting_name string +---@param entry_name string +---@param tooltip string +---@return nil +function CreateSpawnConfigIntegerField(container, surface_name, label, setting_name, entry_name, tooltip) + + local value = global.ocfg.surfaces_config[surface_name].spawn_config[setting_name][entry_name] + + local flow = container.add { + type = "flow", + direction = "horizontal" + } + + AddLabel(flow, nil, label, my_label_style) + + local dragger = flow.add{ type="empty-widget", style="draggable_space_header" } + dragger.style.horizontally_stretchable = true + + -- Create number textfield + local textfield = flow.add { + type = "textfield", + text = tostring(value), + tooltip = tooltip, + numeric = true, + allow_decimal = false, + tags = { + action = "oarc_surface_config_tab", + surface_name = surface_name, + setting = setting_name, + entry = entry_name, + spawn_config_textfield = true + } + } + textfield.style.width = 50 +end + + +---Create the solid resources config section +---@param container LuaGuiElement +---@param surface_name string +---@return nil +function CreateSolidResourcesConfig(container, surface_name) + + local solid_resources = global.ocfg.surfaces_config[surface_name].spawn_config.solid_resources + + local solid_resources_flow = container.add { + type = "frame", + direction = "vertical", + style = "inside_shallow_frame" + } + solid_resources_flow.style.padding = 5 + solid_resources_flow.style.horizontally_stretchable = false + + local header = AddLabel(solid_resources_flow, nil, "Solid Resources Config", my_label_header2_style) -- TODO: Localize + header.tooltip = "This controls the resources that will spawn around the spawn area." -- TODO: Localize + + -- Create a table to display the resources + local table = solid_resources_flow.add { + type = "table", + column_count = 4, + tags = { + surface_name = surface_name, + setting = "solid_resources" + } + } + + --Add headers + AddLabel(table, nil, "Type", my_label_style) + AddLabel(table, nil, "Amount", my_label_style) + AddLabel(table, nil, "Size", my_label_style) + AddLabel(table, nil, "", my_label_style) + + for resource_name, resource_data in pairs(solid_resources) do + log("Resource: " .. resource_name) + SolidResourcesConfigDisplayRow(table, resource_name, resource_data.amount, resource_data.size) + end + + SurfaceConfigSolidResourcesAddRowButton(table) +end + + +---Adds a row to a table with a resource, amount, and size +---@param table LuaGuiElement +---@param resource_name string? +---@param amount integer +---@param size integer +---@return nil +function SolidResourcesConfigDisplayRow(table, resource_name, amount, size) + -- Create choose elem button + local button = table.add { + type = "choose-elem-button", + elem_type = "entity", + elem_filters = {{filter = "type", type = "resource"}}, + tags = { + action = "oarc_surface_config_tab", + resource_elem_button = true, + resource_name = resource_name or "" + }, + } + button.elem_value = resource_name + button.style.width = 28 + button.style.height = 28 + + -- Create number textfield + local amount_textfield = table.add { + type = "textfield", + text = tostring(amount), + numeric = true, + allow_decimal = false, + tags = { + action = "oarc_surface_config_tab", + resource_amount_textfield = true, + resource_name = resource_name or "" + } + } + amount_textfield.style.width = 50 + + -- Create number textfield + local size_textfield = table.add { + type = "textfield", + text = tostring(size), + numeric = true, + allow_decimal = false, + tags = { + action = "oarc_surface_config_tab", + resource_size_textfield = true, + resource_name = resource_name or "" + } + } + size_textfield.style.width = 50 + + -- Create a button to remove the row + local remove_button = table.add { + type = "sprite-button", + sprite = "utility/deconstruction_mark", + tooltip = "Remove Resource", -- TODO: Localize + tags = { + action = "oarc_surface_config_tab", + resource_remove_row_button = true, + resource_name = resource_name or "" + } + } + remove_button.style.width = 28 + remove_button.style.height = 28 +end + +---Add the add row button to the table for solid resources +---@param table LuaGuiElement +---@return nil +function SurfaceConfigSolidResourcesAddRowButton(table) + -- Add a button to add another row + local add_row_button = table.add { + type = "sprite-button", + sprite = "utility/check_mark_green", + tooltip = "Add Item", -- TODO: Localize + tags = { + action = "oarc_surface_config_tab", + resource_add_row_button = true + } + } + add_row_button.style.width = 28 + add_row_button.style.height = 28 +end + + +--[[ + _____ _____ _ _ _____ _ _ _ _ _ ___ _ ___ ___ ___ + | __\ \ / / __| \| |_ _| | || | /_\ | \| | \| | | __| _ \/ __| + | _| \ V /| _|| .` | | | | __ |/ _ \| .` | |) | |__| _|| /\__ \ + |___| \_/ |___|_|\_| |_| |_||_/_/ \_\_|\_|___/|____|___|_|_\|___/ + +]] + +---Handle the surface dropdown selection +---@param event EventData.on_gui_selection_state_changed +---@return nil +function SurfaceConfigTabGuiSelect(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_surface_config_tab") then + return + end + + if (tags.setting == "surface_dropdown") then + local selected_surface_name = event.element.items[event.element.selected_index] --[[@as string]] + + local content_flow = event.element.parent.parent["surface_config_content_flow"] + if (content_flow == nil) then + error("Content flow is nil? This shouldn't happen on surface dropdown select! " .. selected_surface_name) + end + + -- Recreate the content section + content_flow.clear() + CreateSurfaceConfigContent(content_flow, selected_surface_name) + + player.print("Selected surface: " .. selected_surface_name) + end +end + + +---Handle on_gui_text_changed events +---@param event EventData.on_gui_text_changed +---@return nil +function SurfaceConfigTabGuiTextChanged(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_surface_config_tab") then + return + end + + if (tags.item_number_textfield) then + event.element.style = "invalid_value_textfield" + event.element.style.width = 40 + elseif (tags.resource_amount_textfield or tags.resource_size_textfield or tags.spawn_config_textfield) then + event.element.style = "invalid_value_textfield" + event.element.style.width = 50 + end +end + + +---Handle on_gui_confirmed events +---@param event EventData.on_gui_confirmed +---@return nil +function SurfaceConfigTabGuiConfirmed(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_surface_config_tab") then + return + end + + if (tags.item_number_textfield) then + player.print("Selected item: " .. tags.item_name .. " count: " .. event.element.text) + + local parent = event.element.parent + local surface_name = parent.tags.surface_name --[[@as string]] + local setting_name = parent.tags.setting --[[@as string]] + local item_name = tags.item_name --[[@as string]] + + -- Check if an item is selected first. + if (tags.item_name == "") then + player.print("Please select an item first!") + event.element.text = "0" + return + end + + -- Update the count + local count = tonumber(event.element.text) or 0 + global.ocfg.surfaces_config[surface_name].starting_items[setting_name][item_name] = count + + event.element.style = "textbox" + event.element.style.width = 40 + + elseif (tags.resource_amount_textfield or tags.resource_size_textfield) then + -- player.print("Selected resource: " .. tags.resource_name .. " amount: " .. event.element.text) + + local parent = event.element.parent + local surface_name = parent.tags.surface_name --[[@as string]] + local setting_name = parent.tags.setting --[[@as string]] + local resource_name = tags.resource_name --[[@as string]] + + -- Check if an item is selected first. + if (tags.resource_name == "") then + player.print("Please select a resource first!") + event.element.text = "0" + return + end + + -- Update the count + local count = tonumber(event.element.text) or 0 + + if (tags.resource_amount_textfield) then + global.ocfg.surfaces_config[surface_name].spawn_config[setting_name][resource_name].amount = count + elseif (tags.resource_size_textfield) then + global.ocfg.surfaces_config[surface_name].spawn_config[setting_name][resource_name].size = count + end + + event.element.style = "textbox" + event.element.style.width = 50 + + elseif (tags.spawn_config_textfield) then + local surface_name = tags.surface_name --[[@as string]] + local setting_name = tags.setting --[[@as string]] + local entry_name = tags.entry --[[@as string]] + + local value = tonumber(event.element.text) or 0 + global.ocfg.surfaces_config[surface_name].spawn_config[setting_name][entry_name] = value + + event.element.style = "textbox" + event.element.style.width = 50 + + end +end + ---Handle elem changed events ---@param event EventData.on_gui_elem_changed ---@return nil @@ -278,9 +662,14 @@ function SurfaceConfigTabGuiElemChanged(event) end -- Update the item name in the list, keep the old count. - player.print("Update item: " .. old_item_name .. " to " .. new_item_name .. " for surface " .. surface_name) - global.ocfg.surfaces_config[surface_name].starting_items[setting_name][new_item_name] = global.ocfg.surfaces_config[surface_name].starting_items[setting_name][old_item_name] - global.ocfg.surfaces_config[surface_name].starting_items[setting_name][old_item_name] = nil + if (old_item_name ~= "") then + player.print("Update item: " .. old_item_name .. " to " .. new_item_name .. " for surface " .. surface_name) + global.ocfg.surfaces_config[surface_name].starting_items[setting_name][new_item_name] = global.ocfg.surfaces_config[surface_name].starting_items[setting_name][old_item_name] + global.ocfg.surfaces_config[surface_name].starting_items[setting_name][old_item_name] = nil + else + player.print("Add item: " .. new_item_name .. " for surface " .. surface_name) + global.ocfg.surfaces_config[surface_name].starting_items[setting_name][new_item_name] = 0 + end -- Update all tags with the new item name. for _, child in pairs(event.element.parent.children) do @@ -290,6 +679,51 @@ function SurfaceConfigTabGuiElemChanged(event) child.tags = tags_copy end end + + elseif (tags.resource_elem_button) then + local new_resource_name = event.element.elem_value --[[@as string]] + player.print("Selected resource: " .. event.element.elem_value) + + if (new_resource_name == nil) then + return + end + + local old_resource_name = tags.resource_name --[[@as string]] + + -- if the new resource name is the same as the old resource name, do nothing. + if (new_resource_name == tags.resource_name) then + return + end + + -- otherwise, check if the new resource name is already in the list. + local parent = event.element.parent + local surface_name = parent.tags.surface_name --[[@as string]] + local setting_name = parent.tags.setting --[[@as string]] + + if (global.ocfg.surfaces_config[surface_name].spawn_config[setting_name][new_resource_name]) then + player.print("Resource already exists in list! " .. new_resource_name) + event.element.elem_value = nil + return + end + + -- Update the resource name in the list, keep the old amount and size. + if (old_resource_name ~= "") then + player.print("Update resource: " .. old_resource_name .. " to " .. new_resource_name .. " for surface " .. surface_name) + global.ocfg.surfaces_config[surface_name].spawn_config[setting_name][new_resource_name] = global.ocfg.surfaces_config[surface_name].spawn_config[setting_name][old_resource_name] + global.ocfg.surfaces_config[surface_name].spawn_config[setting_name][old_resource_name] = nil + else + player.print("Add resource: " .. new_resource_name .. " for surface " .. surface_name) + global.ocfg.surfaces_config[surface_name].spawn_config[setting_name][new_resource_name] = {amount=0, size=0, x_offset=0, y_offset=0} + end + + -- Update all tags with the new resource name. + for _, child in pairs(event.element.parent.children) do + if (child.tags.resource_name == old_resource_name) then + local tags_copy = child.tags + tags_copy.resource_name = new_resource_name + child.tags = tags_copy + end + end end end @@ -396,135 +830,43 @@ function SurfaceConfigTabGuiClick(event) end content_flow.clear() CreateSurfaceConfigContent(content_flow, surface_name) - end -end + + elseif (tags.resource_remove_row_button) then + player.print("Remove resource: " .. tags.resource_name) ----Adds a row to a table with an item and count ----@param table LuaGuiElement ----@param item_name string? ----@param item_count integer? ----@return nil -function SurfaceConfigItemListDisplayRow(table, item_name, item_count) - -- Create choose elem button - local button = table.add { - type = "choose-elem-button", - elem_type = "item", - item = item_name, - tags = { - action = "oarc_surface_config_tab", - elem_button = true, - item_name = item_name or "" - }, - } - button.style.width = 28 - button.style.height = 28 - - -- Create number textfield - local textfield = table.add { - type = "textfield", - text = tostring(item_count or 0), - numeric = true, - allow_decimal = false, - tooltip = {"oarc-settings-tab-text-field-enter-tooltip" }, - tags = { - action = "oarc_surface_config_tab", - item_number_textfield = true, - item_name = item_name or "" - } - } - if (item_name == "") then - textfield.style = "invalid_value_textfield" - end - textfield.style.width = 40 - - -- Create a button to remove the row - local remove_button = table.add { - type = "sprite-button", - sprite = "utility/deconstruction_mark", - tooltip = "Remove Item", -- TODO: Localize - tags = { - action = "oarc_surface_config_tab", - remove_row_button = true, - item_name = item_name or "" - } - } - remove_button.style.width = 28 - remove_button.style.height = 28 -end - - ----Add the add row button to the table ----@param table LuaGuiElement ----@return nil -function SurfaceConfigItemListAddRowButton(table) - -- Add a button to add another row - local add_row_button = table.add { - type = "sprite-button", - sprite = "utility/check_mark_green", - tooltip = "Add Item", -- TODO: Localize - tags = { - action = "oarc_surface_config_tab", - add_row_button = true - } - } - add_row_button.style.width = 28 - add_row_button.style.height = 28 -end - - ----Handle on_gui_text_changed events ----@param event EventData.on_gui_text_changed ----@return nil -function SurfaceConfigTabGuiTextChanged(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_surface_config_tab") then - return - end - - if (tags.item_number_textfield) then - player.print("Selected item: " .. tags.item_name .. " count: " .. event.element.text) - - event.element.style = "invalid_value_textfield" - event.element.style.width = 40 - end -end - - ----Handle on_gui_confirmed events ----@param event EventData.on_gui_confirmed ----@return nil -function SurfaceConfigTabGuiConfirmed(event) - if not event.element.valid then return end - local player = game.players[event.player_index] - local tags = event.element.tags + local resource_name = tags.resource_name --[[@as string]] + local parent = event.element.parent + local surface_name = parent.tags.surface_name --[[@as string]] + local setting_name = parent.tags.setting --[[@as string]] - if (tags.action ~= "oarc_surface_config_tab") then - return - end + -- Nil the entry + player.print("Remove resource: " .. resource_name .. " for surface " .. surface_name) + global.ocfg.surfaces_config[surface_name].spawn_config[setting_name][resource_name] = nil - if (tags.item_number_textfield) then - player.print("Selected item: " .. tags.item_name .. " count: " .. event.element.text) + -- Delete the row by removing the child elements from the table. + for _, child in pairs(parent.children) do + if (child.tags.resource_name == resource_name) then + child.destroy() + end + end + + elseif (tags.resource_add_row_button) then local parent = event.element.parent - local surface_name = parent.tags.surface_name --[[@as string]] local setting_name = parent.tags.setting --[[@as string]] - local item_name = tags.item_name --[[@as string]] - -- Check if an item is selected first. - if (tags.item_name == "") then - player.print("Please select an item first!") - event.element.text = "0" - return + if (parent == nil) then + error("Parent is nil? This shouldn't happen on add row button click! " .. setting_name) end - -- Update the count - local count = tonumber(event.element.text) or 0 - global.ocfg.surfaces_config[surface_name].starting_items[setting_name][item_name] = count + player.print("Add resource row: " .. setting_name) - event.element.style = "textbox" - event.element.style.width = 40 + -- Delete the button and add a new row and then add the button back. + event.element.destroy() + SolidResourcesConfigDisplayRow(parent, nil, 0, 0) + + -- Add the add row button back. + SurfaceConfigSolidResourcesAddRowButton(parent) + end end \ No newline at end of file diff --git a/lib/oarc_utils.lua b/lib/oarc_utils.lua index 200684f..af669fd 100644 --- a/lib/oarc_utils.lua +++ b/lib/oarc_utils.lua @@ -1346,10 +1346,10 @@ function CreateCropCircle(surface, centerPos, chunkArea, tileRadius, fillTile, m end end - -- Create a tree ring - if ((distSqr < tree_radius_sqr_outer) and (distSqr > tree_radius_sqr_inner)) then - surface.create_entity({ name = "tree-02", amount = 1, position = { i, j } }) - end + -- -- Create a tree ring + -- if ((distSqr < tree_radius_sqr_outer) and (distSqr > tree_radius_sqr_inner)) then + -- surface.create_entity({ name = "tree-02", amount = 1, position = { i, j } }) + -- end -- Fill moat with water. if (moat) then @@ -1369,6 +1369,16 @@ function CreateCropCircle(surface, centerPos, chunkArea, tileRadius, fillTile, m end surface.set_tiles(dirtTiles) + + --Create trees (needs to be done after setting tiles!) + for i = chunkArea.left_top.x, chunkArea.right_bottom.x, 1 do + for j = chunkArea.left_top.y, chunkArea.right_bottom.y, 1 do + local distSqr = math.floor((centerPos.x - i) ^ 2 + (centerPos.y - j) ^ 2) + if ((distSqr < tree_radius_sqr_outer) and (distSqr > tree_radius_sqr_inner)) then + surface.create_entity({ name = "tree-02", amount = 1, position = { i, j } }) + end + end + end end ---` spawn shape (handles land, trees and moat) (Curtesy of jvmguy) @@ -1404,10 +1414,10 @@ function CreateCropOctagon(surface, centerPos, chunkArea, tileRadius, fillTile, end end - -- Create a tree ring - if ((distVar < tileRadius) and (distVar >= tree_distance_inner)) then - surface.create_entity({ name = "tree-01", amount = 1, position = { i, j } }) - end + -- -- Create a tree ring + -- if ((distVar < tileRadius) and (distVar >= tree_distance_inner)) then + -- surface.create_entity({ name = "tree-01", amount = 1, position = { i, j } }) + -- end -- Fill moat with water if (moat) then @@ -1426,6 +1436,19 @@ function CreateCropOctagon(surface, centerPos, chunkArea, tileRadius, fillTile, end end surface.set_tiles(dirtTiles) + + --Create trees (needs to be done after setting tiles!) + for i = chunkArea.left_top.x, chunkArea.right_bottom.x, 1 do + for j = chunkArea.left_top.y, chunkArea.right_bottom.y, 1 do + local distVar1 = math.floor(math.max(math.abs(centerPos.x - i), math.abs(centerPos.y - j))) + local distVar2 = math.floor(math.abs(centerPos.x - i) + math.abs(centerPos.y - j)) + local distVar = math.max(distVar1, distVar2 * 0.707); + + if ((distVar < tileRadius) and (distVar >= tree_distance_inner)) then + surface.create_entity({ name = "tree-01", amount = 1, position = { i, j } }) + end + end + end end ---Square spawn shape (handles land, trees and moat) @@ -1460,10 +1483,10 @@ function CreateCropSquare(surface, centerPos, chunkArea, tileRadius, fillTile, m end end - -- Create a tree ring - if ((max_distance < tileRadius) and (max_distance >= tree_distance_inner)) then - surface.create_entity({ name = "tree-02", amount = 1, position = { i, j } }) - end + -- -- Create a tree ring + -- if ((max_distance < tileRadius) and (max_distance >= tree_distance_inner)) then + -- surface.create_entity({ name = "tree-02", amount = 1, position = { i, j } }) + -- end -- Fill moat with water if (moat) then @@ -1483,6 +1506,16 @@ function CreateCropSquare(surface, centerPos, chunkArea, tileRadius, fillTile, m end surface.set_tiles(dirtTiles) + + --Create trees (needs to be done after setting tiles!) + for i = chunkArea.left_top.x, chunkArea.right_bottom.x, 1 do + for j = chunkArea.left_top.y, chunkArea.right_bottom.y, 1 do + local max_distance = math.max(math.abs(centerPos.x - i), math.abs(centerPos.y - j)) + if ((max_distance < tileRadius) and (max_distance >= tree_distance_inner)) then + surface.create_entity({ name = "tree-02", amount = 1, position = { i, j } }) + end + end + end end ---Add a circle of water From e6d0d6e2f19f201fb3d9f21962d1966acd3a481e Mon Sep 17 00:00:00 2001 From: Oarcinae Date: Sun, 6 Oct 2024 20:53:13 -0400 Subject: [PATCH 09/16] Extra warning. --- lib/gui_tabs/surface_config.lua | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/gui_tabs/surface_config.lua b/lib/gui_tabs/surface_config.lua index d25d28f..a53fd6f 100644 --- a/lib/gui_tabs/surface_config.lua +++ b/lib/gui_tabs/surface_config.lua @@ -8,6 +8,8 @@ function CreateSurfaceConfigTab(tab_container, player) local note = AddLabel(tab_container, nil, "This lets you configure the surface settings, it is only available to admins. These settings are NOT available in the mod settings page. If you want to automatically set these on the start of a new game using a custom file, please check out the included template scenario in the mod folder. I really question my sanity for bothering to make this GUI interface. Send help.", my_note_style) -- TODO: Localize note.style.maximal_width = 700 + local warn = AddLabel(tab_container, nil, "WARNING: These settings are NOT sanitized, you might crash the game if you pick bad values!", my_warning_style) -- TODO: Localize + warn.style.maximal_width = 700 -- Drop down to select surface that you want to configure local selected_surface_name = CreateSurfaceDropdown(tab_container) @@ -688,6 +690,13 @@ function SurfaceConfigTabGuiElemChanged(event) return end + if (game.entity_prototypes[new_resource_name].resource_category ~= "basic-solid") then + player.print("Resource must be a solid resource! " .. new_resource_name) + event.element.elem_value = nil + return + end + + local old_resource_name = tags.resource_name --[[@as string]] -- if the new resource name is the same as the old resource name, do nothing. From 2aa932f48161b62acc142c59b0de344aaf03a810 Mon Sep 17 00:00:00 2001 From: Oarcinae Date: Mon, 7 Oct 2024 11:52:55 -0400 Subject: [PATCH 10/16] Added a way to export/import full settings via a serialized string. --- lib/config_parser.lua | 84 ++++++++++++++++++----- lib/gui_tabs/settings_controls.lua | 103 +++++++++++++++++++++++++---- locale/en/locale.cfg | 6 +- 3 files changed, 165 insertions(+), 28 deletions(-) diff --git a/lib/config_parser.lua b/lib/config_parser.lua index 93e85bf..91d0495 100644 --- a/lib/config_parser.lua +++ b/lib/config_parser.lua @@ -178,11 +178,58 @@ function ValidateAndLoadConfig() GetScenarioOverrideSettings() -- Get any scenario settings and overwrite both the mod settings and OARC_CFG. + SyncModSettingsToOCFG() -- Make sure mod settings are in sync with global.ocfg table. + ValidateSettings() -- These are validation checks that can't be done within the mod settings natively. end +---DO some basic validation checks on the config settings. +---@return nil function ValidateSettings() + -- Verify the major sections exist. Not exhaustive but should catch missing sections. + if (global.ocfg["server_info"] == nil) then + log("ERROR - Missing server_info section in config! Loading defaults instead!") + SendBroadcastMsg("ERROR - Missing server_info section in config! Loading defaults instead!") + global.ocfg.server_info = table.deepcopy(OCFG.server_info) + end + if (global.ocfg["gameplay"] == nil) then + log("ERROR - Missing gameplay section in config! Loading defaults instead!") + SendBroadcastMsg("ERROR - Missing gameplay section in config! Loading defaults instead!") + global.ocfg.gameplay = table.deepcopy(OCFG.gameplay) + end + if (global.ocfg["regrowth"] == nil) then + log("ERROR - Missing regrowth section in config! Loading defaults instead!") + SendBroadcastMsg("ERROR - Missing regrowth section in config! Loading defaults instead!") + global.ocfg.regrowth = table.deepcopy(OCFG.regrowth) + end + if (global.ocfg["spawn_general"] == nil) then + log("ERROR - Missing spawn_general section in config! Loading defaults instead!") + SendBroadcastMsg("ERROR - Missing spawn_general section in config! Loading defaults instead!") + global.ocfg.spawn_general = table.deepcopy(OCFG.spawn_general) + end + if (global.ocfg["resource_placement"] == nil) then + log("ERROR - Missing resource_placement section in config! Loading defaults instead!") + SendBroadcastMsg("ERROR - Missing resource_placement section in config! Loading defaults instead!") + global.ocfg.resource_placement = table.deepcopy(OCFG.resource_placement) + end + if (global.ocfg["surfaces_config"] == nil) then + log("ERROR - Missing surfaces_config section in config! Loading defaults instead!") + SendBroadcastMsg("ERROR - Missing surfaces_config section in config! Loading defaults instead!") + global.ocfg.surfaces_config = table.deepcopy(OCFG.surfaces_config) + end + if (global.ocfg["surfaces_blacklist"] == nil) then + log("ERROR - Missing surfaces_blacklist section in config! Loading defaults instead!") + SendBroadcastMsg("ERROR - Missing surfaces_blacklist section in config! Loading defaults instead!") + global.ocfg.surfaces_blacklist = table.deepcopy(OCFG.surfaces_blacklist) + end + if (global.ocfg["surfaces_blacklist_match"] == nil) then + log("ERROR - Missing surfaces_blacklist_match section in config! Loading defaults instead!") + SendBroadcastMsg("ERROR - Missing surfaces_blacklist_match section in config! Loading defaults instead!") + global.ocfg.surfaces_blacklist_match = table.deepcopy(OCFG.surfaces_blacklist_match) + end + + -- Validate enable_main_team and enable_separate_teams. -- Force enable_main_team if both are disabled. if (not global.ocfg.gameplay.enable_main_team and not global.ocfg.gameplay.enable_separate_teams) then @@ -229,7 +276,7 @@ function ValidateSettings() end if (table_size(surface_config.starting_items.crashed_ship_wreakage) > MAX_CRASHED_SHIP_WRECKAGE_ITEMS) then - error("Too many items in player_start_items for surface: " .. surface_name) + error("Too many items in crashed_ship_wreakage for surface: " .. surface_name) end end end @@ -252,6 +299,8 @@ function CacheModSettings() global.ocfg.gameplay.main_force_name = settings.startup["oarc-mod-main-force-name"].value --[[@as string]] end +---Get the scenario settings from the scenario if it exists. +---@return nil function GetScenarioOverrideSettings() if remote.interfaces["oarc_scenario"] then @@ -261,25 +310,30 @@ function GetScenarioOverrideSettings() -- Overwrite the non mod settings with the scenario settings. global.ocfg = scenario_settings + else + log("No scenario settings found.") + end +end - -- Override the mod settings with the scenario settings! - for _,entry in pairs(OCFG_KEYS) do - if (entry.type ~= "header") and (entry.type ~= "subheader") then - local mod_key = entry.mod_key - local oarc_key = entry.ocfg_keys - local scenario_value = GetGlobalOarcConfigUsingKeyTable(oarc_key) - if (scenario_value ~= nil) then - local ok,result = pcall(function() settings.global[mod_key] = { value = scenario_value } end) - if not ok then - error("Error setting mod setting: " .. mod_key .. " = " .. tostring(scenario_value) .. "\n" .. "If you see this, you probably picked an invalid value for a setting override in the custom scenario.") - end +---Syncs all mod settings to the OARC config table. +---@return nil +function SyncModSettingsToOCFG() + + -- Override the mod settings with the the global.ocfg settings. + for _,entry in pairs(OCFG_KEYS) do + if (entry.type ~= "header") and (entry.type ~= "subheader") then + local mod_key = entry.mod_key + local oarc_key = entry.ocfg_keys + local scenario_value = GetGlobalOarcConfigUsingKeyTable(oarc_key) + if (scenario_value ~= nil) then + local ok,result = pcall(function() settings.global[mod_key] = { value = scenario_value } end) + if not ok then + error("Error setting mod setting: " .. mod_key .. " = " .. tostring(scenario_value) .. "\n" .. "If you see this, you probably picked an invalid value for a setting override in the custom scenario.") end end end - - else - log("No scenario settings found.") end + end ---Handles the event when a mod setting is changed in the mod settings menu. diff --git a/lib/gui_tabs/settings_controls.lua b/lib/gui_tabs/settings_controls.lua index 507f8b9..0c5129c 100644 --- a/lib/gui_tabs/settings_controls.lua +++ b/lib/gui_tabs/settings_controls.lua @@ -36,7 +36,10 @@ function CreateSettingsControlsTab(tab_container, player) scroll_pane_right.style.maximal_height = GENERIC_GUI_MAX_HEIGHT scroll_pane_right.style.padding = 5 scroll_pane_right.style.left_margin = 2 + CreateSurfaceSettingsSection(scroll_pane_right, player) + AddSpacerLine(scroll_pane_right) + CreateSettingsExportSection(scroll_pane_right, player) end ---Create the content for the mod settings section @@ -98,6 +101,53 @@ function CreateSurfaceSettingsSection(container, player) end +---Create the content for the settings export section. Exports the entire global.ocfg table into a string. +---@param container LuaGuiElement +---@param player LuaPlayer +---@return nil +function CreateSettingsExportSection(container, player) + AddLabel(container, nil, { "oarc-settings-tab-title-export" }, my_label_header2_style) + + local horizontal_flow = container.add { + type = "flow", + direction = "horizontal", + } + + local export_button = horizontal_flow.add { + type = "button", + caption = { "oarc-settings-tab-export-button" }, + style = "green_button", + tooltip = { "oarc-settings-tab-export-button-tooltip" }, + tags = { + action = "oarc_settings_tab_right_pane", + setting = "oarc_settings_export" + }, + } + + local import_button = horizontal_flow.add { + type = "button", + caption = { "oarc-settings-tab-import-button" }, + tooltip = { "oarc-settings-tab-import-button-tooltip" }, + style = "red_button", + tags = { + action = "oarc_settings_tab_right_pane", + setting = "oarc_settings_import" + }, + } + + local export_textfield = container.add { + type = "textfield", + name = "export_textfield", + text = " ", + tags = { + action = "oarc_settings_tab_right_pane", + setting = "oarc_settings_textfield" + }, + } + export_textfield.style.horizontally_stretchable = true + export_textfield.style.maximal_width = 500 +end + ---Handles the click event for the tab used by AddOarcGuiTab ---@param event EventData.on_gui_click ---@return nil @@ -105,7 +155,7 @@ function SettingsControlsTabGuiClick(event) if not (event.element.valid) then return end local gui_elem = event.element - if (gui_elem.tags.action ~= "oarc_settings_tab") then return end + if (gui_elem.tags.action ~= "oarc_settings_tab_left_pane") then return end local index = gui_elem.tags.setting local entry = OCFG_KEYS[index] @@ -121,7 +171,7 @@ function SettingsControlsTabGuiTextChanged(event) if not (event.element.valid) then return end local gui_elem = event.element - if (gui_elem.tags.action ~= "oarc_settings_tab") then return end + if (gui_elem.tags.action ~= "oarc_settings_tab_left_pane") then return end local index = gui_elem.tags.setting local value = gui_elem.text local entry = OCFG_KEYS[index] @@ -141,7 +191,7 @@ function SettingsControlsTabGuiTextconfirmed(event) if not (event.element.valid) then return end local gui_elem = event.element - if (gui_elem.tags.action ~= "oarc_settings_tab") then return end + if (gui_elem.tags.action ~= "oarc_settings_tab_left_pane") then return end local index = gui_elem.tags.setting local value = gui_elem.text local entry = OCFG_KEYS[index] @@ -260,7 +310,7 @@ function AddCheckboxSetting(tab_container, index, entry, enabled) state = GetGlobalOarcConfigUsingKeyTable(entry.ocfg_keys), enabled = enabled, tooltip = { "mod-setting-description."..entry.mod_key }, - tags = { action = "oarc_settings_tab", setting = index }, + tags = { action = "oarc_settings_tab_left_pane", setting = index }, } end @@ -293,7 +343,7 @@ function AddTextfieldSetting(tab_container, index, entry, enabled) text = GetGlobalOarcConfigUsingKeyTable(entry.ocfg_keys), enabled = enabled, tooltip = tooltip, - tags = { action = "oarc_settings_tab", setting = index }, + tags = { action = "oarc_settings_tab_left_pane", setting = index }, } end @@ -340,7 +390,7 @@ function AddIntegerSetting(tab_container, index, entry, enabled) text = GetGlobalOarcConfigUsingKeyTable(entry.ocfg_keys), enabled = enabled, tooltip = tooltip, - tags = { action = "oarc_settings_tab", setting = index }, + tags = { action = "oarc_settings_tab_left_pane", setting = index }, } textfield.style.width = 50 end @@ -389,7 +439,7 @@ function AddDoubleSetting(tab_container, index, entry, enabled) text = string.format("%.2f", GetGlobalOarcConfigUsingKeyTable(entry.ocfg_keys)), enabled = enabled, tooltip = tooltip, - tags = { action = "oarc_settings_tab", setting = index }, + tags = { action = "oarc_settings_tab_left_pane", setting = index }, } textfield.style.width = 50 end @@ -431,7 +481,7 @@ function AddStringListDropdownSetting(tab_container, index, entry, enabled) selected_index = selected_index, enabled = enabled, tooltip = { "mod-setting-description."..entry.mod_key }, - tags = { action = "oarc_settings_tab", setting = index }, + tags = { action = "oarc_settings_tab_left_pane", setting = index }, } end @@ -448,7 +498,7 @@ function AddSurfaceCheckboxSetting(parent, surface_name, setting_name, state, ad name = surface_name.."_"..setting_name, type = "checkbox", state = state, - tags = { action = "oarc_settings_tab_surfaces", setting = setting_name, surface = surface_name }, + tags = { action = "oarc_settings_tab_right_pane", setting = setting_name, surface = surface_name }, enabled = admin, tooltip = tooltip, } @@ -461,11 +511,11 @@ function SettingsSurfaceControlsTabGuiClick(event) if not (event.element.valid) then return end local gui_elem = event.element - if (gui_elem.tags.action ~= "oarc_settings_tab_surfaces") then return end + if (gui_elem.tags.action ~= "oarc_settings_tab_right_pane") then return end local setting_name = gui_elem.tags.setting - local surface_name = gui_elem.tags.surface --[[@as string]] if (setting_name == "spawn_enabled") then + local surface_name = gui_elem.tags.surface --[[@as string]] global.oarc_surfaces[surface_name] = gui_elem.state if (#GetAllowedSurfaces() == 0) then @@ -473,7 +523,9 @@ function SettingsSurfaceControlsTabGuiClick(event) global.oarc_surfaces[global.ocfg.gameplay.default_surface] = true event.element.parent[global.ocfg.gameplay.default_surface.."_spawn_enabled"].state = true end + elseif (setting_name == "regrowth_enabled") then + local surface_name = gui_elem.tags.surface --[[@as string]] if (gui_elem.state) then if not IsRegrowthEnabledOnSurface(surface_name) then @@ -484,7 +536,34 @@ function SettingsSurfaceControlsTabGuiClick(event) RegrowthDisableSurface(surface_name) end end + + elseif (setting_name == "oarc_settings_textfield") then + gui_elem.select_all() -- Select all text when clicked + + elseif (setting_name == "oarc_settings_export") then + + log("Exported settings!") + local export_textfield = gui_elem.parent.parent["export_textfield"] + export_textfield.text = serpent.line(global.ocfg, {compact = true, sparse = true}) + + elseif (setting_name == "oarc_settings_import") then + local player = game.players[event.player_index] + local export_textfield = gui_elem.parent.parent["export_textfield"] + local import_text = export_textfield.text + local ok, copy = serpent.load(import_text) + if (not ok) or (type(copy) ~= "table") or (next(copy) == nil) then + log("Error importing settings!") + player.print("Error importing settings!") + else + global.ocfg = table.deepcopy(copy) + ValidateSettings() -- Some basic validation, not 100% foolproof + SyncModSettingsToOCFG() -- Sync the mod settings. + log("Imported settings!") + player.print("Imported settings!") + OarcGuiRefreshContent(player) + end end + end @@ -495,7 +574,7 @@ function SettingsControlsTabGuiSelectionStateChanged(event) if not (event.element.valid) then return end local gui_elem = event.element - if (gui_elem.tags.action ~= "oarc_settings_tab") then return end + if (gui_elem.tags.action ~= "oarc_settings_tab_left_pane") then return end local index = gui_elem.tags.setting local entry = OCFG_KEYS[index] diff --git a/locale/en/locale.cfg b/locale/en/locale.cfg index b12ad1b..4412253 100644 --- a/locale/en/locale.cfg +++ b/locale/en/locale.cfg @@ -224,7 +224,11 @@ oarc-settings-tab-surface-regrowth-checkbox-tooltip=Enabling this will allow the oarc-settings-tab-surface-column-header=Surface oarc-settings-tab-surface-spawning-enabled=Custom Spawns oarc-settings-tab-surface-regrowth-enabled=Regrowth - +oarc-settings-tab-title-export=Import/Export Settings +oarc-settings-tab-export-button=Export +oarc-settings-tab-export-button-tooltip=Exports all settings to a string that can be shared with other players or saved for later. +oarc-settings-tab-import-button=Import +oarc-settings-tab-import-button-tooltip=Imports settings from a string. This will overwrite all settings with the imported values! oarc-settings-section-header-server-info=Server Info oarc-settings-section-header-gameplay=Gameplay From 0bcff71fe4e19370016a8874596e93b953be6b9f Mon Sep 17 00:00:00 2001 From: Oarcinae Date: Mon, 7 Oct 2024 21:48:28 -0400 Subject: [PATCH 11/16] Saving all tweaks to settings config GUI. Should be mostly done now. Fixed a bug with resource placement angle as well. --- lib/config.lua | 12 ++ lib/gui_tabs/player_list.lua | 1 + lib/gui_tabs/surface_config.lua | 346 ++++++++++++++++++++++++++++---- lib/separate_spawns.lua | 71 ++++--- locale/en/locale.cfg | 2 +- 5 files changed, 364 insertions(+), 68 deletions(-) diff --git a/lib/config.lua b/lib/config.lua index 7f18513..d02f60d 100644 --- a/lib/config.lua +++ b/lib/config.lua @@ -29,6 +29,7 @@ RESOURCES_SHAPE_CHOICE_SQUARE = "square" MAX_CRASHED_SHIP_RESOURCES_ITEMS = 5 MAX_CRASHED_SHIP_WRECKAGE_ITEMS = 1 +-- THIS is used as the default starting items on all surfaces if no other settings are provided! ---@type OarcConfigStartingItems NAUVIS_STARTER_ITEMS = { @@ -57,6 +58,7 @@ NAUVIS_STARTER_ITEMS = }, } +-- THIS is used as the default spawn config on all surfaces if no other settings are provided! ---@type OarcConfigSpawn NAUVIS_SPAWN_CONFIG = { @@ -112,24 +114,32 @@ NAUVIS_SPAWN_CONFIG = ["iron-ore"] = { amount = 1500, size = 21, + + -- These are only used if not using automatic placing. x_offset = -29, y_offset = 16 }, ["copper-ore"] = { amount = 1200, size = 21, + + -- These are only used if not using automatic placing. x_offset = -28, y_offset = -3 }, ["stone"] = { amount = 1200, size = 21, + + -- These are only used if not using automatic placing. x_offset = -27, y_offset = -34 }, ["coal"] = { amount = 1200, size = 21, + + -- These are only used if not using automatic placing. x_offset = -27, y_offset = -20 } @@ -144,6 +154,8 @@ NAUVIS_SPAWN_CONFIG = { num_patches = 2, amount = 900000, + + -- These are only used if not using automatic placing. -- Starting position offset (relative to bottom/south of spawn area) x_offset_start = -3, y_offset_start = -10, diff --git a/lib/gui_tabs/player_list.lua b/lib/gui_tabs/player_list.lua index b3b79a0..1683972 100644 --- a/lib/gui_tabs/player_list.lua +++ b/lib/gui_tabs/player_list.lua @@ -11,6 +11,7 @@ function CreatePlayerListTab(tab_container, player) direction = "vertical", vertical_scroll_policy = "always", } + scroll_pane.style.maximal_height = 500 -- Make a table: player name, force name, home surface, time played, gps button diff --git a/lib/gui_tabs/surface_config.lua b/lib/gui_tabs/surface_config.lua index a53fd6f..97d4c1c 100644 --- a/lib/gui_tabs/surface_config.lua +++ b/lib/gui_tabs/surface_config.lua @@ -7,9 +7,9 @@ function CreateSurfaceConfigTab(tab_container, player) local note = AddLabel(tab_container, nil, "This lets you configure the surface settings, it is only available to admins. These settings are NOT available in the mod settings page. If you want to automatically set these on the start of a new game using a custom file, please check out the included template scenario in the mod folder. I really question my sanity for bothering to make this GUI interface. Send help.", my_note_style) -- TODO: Localize - note.style.maximal_width = 700 + note.style.maximal_width = 600 local warn = AddLabel(tab_container, nil, "WARNING: These settings are NOT sanitized, you might crash the game if you pick bad values!", my_warning_style) -- TODO: Localize - warn.style.maximal_width = 700 + warn.style.maximal_width = 600 -- Drop down to select surface that you want to configure local selected_surface_name = CreateSurfaceDropdown(tab_container) @@ -20,6 +20,7 @@ function CreateSurfaceConfigTab(tab_container, player) direction = "vertical", name = "surface_config_content_flow" } + content.style.maximal_height = 600 CreateSurfaceConfigContent(content, selected_surface_name) end @@ -37,40 +38,31 @@ function CreateSurfaceConfigContent(container, surface_name) } scroll_pane.style.top_margin = 10 - -- Add a checkbox to enable/disable the crashed ship. - CreateCrashSiteEnable(scroll_pane, surface_name) + -- TODO: Localize EVERTYHING? - local starting_items_flow = scroll_pane.add { - type = "flow", - direction = "horizontal" - } - - -- TODO: Localize + AddLabel(scroll_pane, nil, "Starting And Respawn Items", my_label_header2_style) + local starting_items_flow = scroll_pane.add { type = "flow", direction = "horizontal" } CreateItemsSection(starting_items_flow, surface_name, "Starting Items", "player_start_items") CreateItemsSection(starting_items_flow, surface_name, "Respawn Items", "player_respawn_items") - CreateItemsSection(starting_items_flow, surface_name, "Crashed Ship (Max 5)", "crashed_ship_resources", MAX_CRASHED_SHIP_RESOURCES_ITEMS) - CreateItemsSection(starting_items_flow, surface_name, "Ship Wreckage (Max 1)", "crashed_ship_wreakage", MAX_CRASHED_SHIP_WRECKAGE_ITEMS) - - local spawn_config_flow = scroll_pane.add { - type = "flow", - direction = "horizontal" - } + AddSpacerLine(scroll_pane) - -- Create an choose-elem-button for the testing - -- local button = spawn_config_flow.add { - -- type = "choose-elem-button", - -- elem_type = "entity", - -- elem_filters = {{filter = "type", type = "resource"}, {filter = "minable", mode = "and"}}, - -- } + AddLabel(scroll_pane, nil, "Crashed Ship Items", my_label_header2_style) + CreateCrashSiteEnable(scroll_pane, surface_name) + local crash_site_flow = scroll_pane.add { type = "flow", direction = "horizontal" } + CreateItemsSection(crash_site_flow, surface_name, "Crashed Ship (Max 5)", "crashed_ship_resources", MAX_CRASHED_SHIP_RESOURCES_ITEMS) + CreateItemsSection(crash_site_flow, surface_name, "Ship Wreckage (Max 1)", "crashed_ship_wreakage", MAX_CRASHED_SHIP_WRECKAGE_ITEMS) + AddSpacerLine(scroll_pane) - -- Spawn Config (safe area) - CreateSafeAreaConfig(spawn_config_flow, surface_name) - -- Spawn Config (water strip) (Note offset from north of spawn.) - -- Spawn Config (shared power pole position) (Note offset from west of spawn.) - -- Spawn Config (shared chest position) (Note offset from west of spawn.) - -- Spawn Config (resources and amounts (and maybe x/y positions)) (Note offset is center and not used if auto place.) + AddLabel(scroll_pane, nil, "Spawn Area Resources", my_label_header2_style) + local spawn_config_flow = scroll_pane.add { type = "flow", direction = "horizontal" } CreateSolidResourcesConfig(spawn_config_flow, surface_name) - -- Spawn Config (fluid resources) (Note offset from south of spawn.) + CreateFluidResourcesConfig(spawn_config_flow, surface_name) + AddSpacerLine(scroll_pane) + + AddLabel(scroll_pane, nil, "Spawn Area Misc", my_label_header2_style) + local misc_config_flow = scroll_pane.add { type = "flow", direction = "horizontal" } + CreateMiscConfig(misc_config_flow, surface_name) + CreateSafeAreaConfig(misc_config_flow, surface_name) end @@ -185,10 +177,11 @@ function CreateItemsSection(container, surface_name, header, setting_name, max_c local vertical_flow = container.add { type = "frame", direction = "vertical", - style = "inside_shallow_frame" + -- style = "inside_shallow_frame" } vertical_flow.style.padding = 5 vertical_flow.style.horizontally_stretchable = false + vertical_flow.style.vertically_stretchable = true AddLabel(vertical_flow, nil, header, my_label_header2_style) @@ -281,8 +274,10 @@ end function SurfaceConfigItemListAddRowButton(table) -- Add a button to add another row local add_row_button = table.add { - type = "sprite-button", - sprite = "utility/check_mark_green", + type = "choose-elem-button", + elem_type = "entity", + -- type = "sprite-button", + -- sprite = "utility/check_mark_green", tooltip = "Add Item", -- TODO: Localize tags = { action = "oarc_surface_config_tab", @@ -305,10 +300,11 @@ function CreateSafeAreaConfig(container, surface_name) local safe_area_flow = container.add { type = "frame", direction = "vertical", - style = "inside_shallow_frame" + -- style = "inside_shallow_frame" } safe_area_flow.style.padding = 5 safe_area_flow.style.horizontally_stretchable = false + safe_area_flow.style.vertically_stretchable = true local header = AddLabel(safe_area_flow, nil, "Safe Area Config", my_label_header2_style) -- TODO: Localize header.tooltip = "This controls how safe the area around the spawns is." -- TODO: Localize @@ -374,10 +370,11 @@ function CreateSolidResourcesConfig(container, surface_name) local solid_resources_flow = container.add { type = "frame", direction = "vertical", - style = "inside_shallow_frame" + -- style = "inside_shallow_frame" } solid_resources_flow.style.padding = 5 solid_resources_flow.style.horizontally_stretchable = false + solid_resources_flow.style.vertically_stretchable = true local header = AddLabel(solid_resources_flow, nil, "Solid Resources Config", my_label_header2_style) -- TODO: Localize header.tooltip = "This controls the resources that will spawn around the spawn area." -- TODO: Localize @@ -406,6 +403,80 @@ function CreateSolidResourcesConfig(container, surface_name) SurfaceConfigSolidResourcesAddRowButton(table) end +---Create the fluid resources config section +---@param container LuaGuiElement +---@param surface_name string +---@return nil +function CreateFluidResourcesConfig(container, surface_name) + + local fluid_resources = global.ocfg.surfaces_config[surface_name].spawn_config.fluid_resources + + local fluid_resources_flow = container.add { + type = "frame", + direction = "vertical", + -- style = "inside_shallow_frame" + } + fluid_resources_flow.style.padding = 5 + fluid_resources_flow.style.horizontally_stretchable = false + fluid_resources_flow.style.vertically_stretchable = true + + local header = AddLabel(fluid_resources_flow, nil, "Fluid Resources Config", my_label_header2_style) -- TODO: Localize + header.tooltip = "This controls the fluid resources that will spawn around the spawn area." -- TODO: Localize + + -- Create a table to display the resources + local fluid_table = fluid_resources_flow.add { + type = "table", + column_count = 4, + tags = { + surface_name = surface_name, + setting = "fluid_resources" + } + } + + --Add headers + AddLabel(fluid_table, nil, "Type", my_label_style) + AddLabel(fluid_table, nil, "Count", my_label_style) + AddLabel(fluid_table, nil, "Amount", my_label_style) + AddLabel(fluid_table, nil, "", my_label_style) + + for resource_name, resource_data in pairs(fluid_resources) do + FluidResourcesConfigDisplayRow(fluid_table, resource_name, resource_data.num_patches, resource_data.amount) + end + + SurfaceConfigFluidResourcesAddRowButton(fluid_table) +end + +---Create the water strip config section +---@param container LuaGuiElement +---@param surface_name string +---@return nil +function CreateMiscConfig(container, surface_name) + + local misc_flow = container.add { + type = "frame", + direction = "vertical", + -- style = "inside_shallow_frame" + } + misc_flow.style.padding = 5 + misc_flow.style.horizontally_stretchable = false + + AddLabel(misc_flow, nil, "Misc Config", my_label_header2_style) -- TODO: Localize + + AddLabel(misc_flow, nil, "Water", my_player_list_style) + CreateSpawnConfigIntegerField(misc_flow, surface_name, "Water Length", "water", "length", "This is the length in tiles of the water strip around the spawn area.") + CreateSpawnConfigIntegerField(misc_flow, surface_name, "Water X Offset", "water", "x_offset", "This is the x_offset in tiles, from the north of the spawn area.") + CreateSpawnConfigIntegerField(misc_flow, surface_name, "Water Y Offset", "water", "y_offset", "This is the y_offset in tiles, from the north of the spawn area.") + AddSpacerLine(misc_flow) + + AddLabel(misc_flow, nil, "Shared Chest", my_player_list_style) + CreateSpawnConfigIntegerField(misc_flow, surface_name, "Chest X Offset", "shared_chest_position", "x_offset", "This is the x_offset in tiles, from the east of the spawn area.") + CreateSpawnConfigIntegerField(misc_flow, surface_name, "Chest Y Offset", "shared_chest_position", "y_offset", "This is the y_offset in tiles, from the east of the spawn area.") + AddSpacerLine(misc_flow) + + AddLabel(misc_flow, nil, "Shared Power Pole", my_player_list_style) + CreateSpawnConfigIntegerField(misc_flow, surface_name, "Power X Offset", "shared_power_pole_position", "x_offset", "This is the x_offset in tiles, from the east of the spawn area.") + CreateSpawnConfigIntegerField(misc_flow, surface_name, "Power Y Offset", "shared_power_pole_position", "y_offset", "This is the y_offset in tiles, from the east of the spawn area.") +end ---Adds a row to a table with a resource, amount, and size ---@param table LuaGuiElement @@ -478,8 +549,10 @@ end function SurfaceConfigSolidResourcesAddRowButton(table) -- Add a button to add another row local add_row_button = table.add { - type = "sprite-button", - sprite = "utility/check_mark_green", + type = "choose-elem-button", + elem_type = "entity", + -- type = "sprite-button", + -- sprite = "utility/check_mark_green", tooltip = "Add Item", -- TODO: Localize tags = { action = "oarc_surface_config_tab", @@ -490,6 +563,92 @@ function SurfaceConfigSolidResourcesAddRowButton(table) add_row_button.style.height = 28 end +---Adds a row to a table with a fluid resource, amount, count, spacing, and vertical offset +---@param table LuaGuiElement +---@param resource_name string? +---@param count integer +---@param amount integer +---@return nil +function FluidResourcesConfigDisplayRow(table, resource_name, count, amount) + + -- Create choose elem button + local button = table.add { + type = "choose-elem-button", + elem_type = "entity", + elem_filters = {{filter = "type", type = "resource"}}, + tags = { + action = "oarc_surface_config_tab", + fluid_resource_elem_button = true, + resource_name = resource_name or "" + }, + } + button.elem_value = resource_name + button.style.width = 28 + button.style.height = 28 + + + -- Number of fluid patches + local count_textfield = table.add { + type = "textfield", + text = tostring(count), + numeric = true, + allow_decimal = false, + tags = { + action = "oarc_surface_config_tab", + fluid_resource_count_textfield = true, + resource_name = resource_name or "" + } + } + count_textfield.style.width = 40 + + -- Amount of fluid per patch + local amount_textfield = table.add { + type = "textfield", + text = tostring(amount), + numeric = true, + allow_decimal = false, + tags = { + action = "oarc_surface_config_tab", + fluid_resource_amount_textfield = true, + resource_name = resource_name or "" + } + } + amount_textfield.style.width = 60 + + -- Create a button to remove the row + local remove_button = table.add { + type = "sprite-button", + sprite = "utility/deconstruction_mark", + tooltip = "Remove Resource", + tags = { + action = "oarc_surface_config_tab", + resource_remove_row_button = true, + resource_name = resource_name or "" + } + } + remove_button.style.width = 28 + remove_button.style.height = 28 +end + +---Add the add row button to the table for fluid resources +---@param table LuaGuiElement +---@return nil +function SurfaceConfigFluidResourcesAddRowButton(table) + -- Add a button to add another row + local add_row_button = table.add { + type = "choose-elem-button", + elem_type = "entity", + -- type = "sprite-button", + -- sprite = "utility/check_mark_green", + tooltip = "Add Item", -- TODO: Localize + tags = { + action = "oarc_surface_config_tab", + fluid_resource_add_row_button = true + } + } + add_row_button.style.width = 28 + add_row_button.style.height = 28 +end --[[ _____ _____ _ _ _____ _ _ _ _ _ ___ _ ___ ___ ___ @@ -540,12 +699,15 @@ function SurfaceConfigTabGuiTextChanged(event) return end - if (tags.item_number_textfield) then + if (tags.item_number_textfield or tags.fluid_resource_count_textfield) then event.element.style = "invalid_value_textfield" event.element.style.width = 40 - elseif (tags.resource_amount_textfield or tags.resource_size_textfield or tags.spawn_config_textfield) then + elseif (tags.resource_amount_textfield or tags.resource_size_textfield or tags.spawn_config_textfield) then event.element.style = "invalid_value_textfield" event.element.style.width = 50 + elseif tags.fluid_resource_amount_textfield then + event.element.style = "invalid_value_textfield" + event.element.style.width = 60 end end @@ -610,7 +772,35 @@ function SurfaceConfigTabGuiConfirmed(event) event.element.style = "textbox" event.element.style.width = 50 - + + elseif (tags.fluid_resource_count_textfield or tags.fluid_resource_amount_textfield) then + -- player.print("Selected fluid resource: " .. tags.resource_name .. " count: " .. event.element.text) + + local parent = event.element.parent + local surface_name = parent.tags.surface_name --[[@as string]] + local setting_name = parent.tags.setting --[[@as string]] + local resource_name = tags.resource_name --[[@as string]] + + -- Check if an item is selected first. + if (tags.resource_name == "") then + player.print("Please select a resource first!") + event.element.text = "0" + return + end + + -- Update the count + local count = tonumber(event.element.text) or 0 + + event.element.style = "textbox" + if (tags.fluid_resource_count_textfield) then + global.ocfg.surfaces_config[surface_name].spawn_config[setting_name][resource_name].num_patches = count + event.element.style.width = 40 + elseif (tags.fluid_resource_amount_textfield) then + global.ocfg.surfaces_config[surface_name].spawn_config[setting_name][resource_name].amount = count + event.element.style.width = 60 + end + + elseif (tags.spawn_config_textfield) then local surface_name = tags.surface_name --[[@as string]] local setting_name = tags.setting --[[@as string]] @@ -621,7 +811,7 @@ function SurfaceConfigTabGuiConfirmed(event) event.element.style = "textbox" event.element.style.width = 50 - + end end @@ -725,6 +915,57 @@ function SurfaceConfigTabGuiElemChanged(event) global.ocfg.surfaces_config[surface_name].spawn_config[setting_name][new_resource_name] = {amount=0, size=0, x_offset=0, y_offset=0} end + -- Update all tags with the new resource name. + for _, child in pairs(event.element.parent.children) do + if (child.tags.resource_name == old_resource_name) then + local tags_copy = child.tags + tags_copy.resource_name = new_resource_name + child.tags = tags_copy + end + end + + elseif (tags.fluid_resource_elem_button) then + local new_resource_name = event.element.elem_value --[[@as string]] + player.print("Selected fluid resource: " .. event.element.elem_value) + + if (new_resource_name == nil) then + return + end + + if (game.entity_prototypes[new_resource_name].resource_category ~= "basic-fluid") then + player.print("Resource must be a fluid resource! " .. new_resource_name) + event.element.elem_value = nil + return + end + + local old_resource_name = tags.resource_name --[[@as string]] + + -- if the new resource name is the same as the old resource name, do nothing. + if (new_resource_name == tags.resource_name) then + return + end + + -- otherwise, check if the new resource name is already in the list. + local parent = event.element.parent + local surface_name = parent.tags.surface_name --[[@as string]] + local setting_name = parent.tags.setting --[[@as string]] + + if (global.ocfg.surfaces_config[surface_name].spawn_config[setting_name][new_resource_name]) then + player.print("Resource already exists in list! " .. new_resource_name) + event.element.elem_value = nil + return + end + + -- Update the resource name in the list, keep the old amount and size. + if (old_resource_name ~= "") then + player.print("Update resource: " .. old_resource_name .. " to " .. new_resource_name .. " for surface " .. surface_name) + global.ocfg.surfaces_config[surface_name].spawn_config[setting_name][new_resource_name] = global.ocfg.surfaces_config[surface_name].spawn_config[setting_name][old_resource_name] + global.ocfg.surfaces_config[surface_name].spawn_config[setting_name][old_resource_name] = nil + else + player.print("Add resource: " .. new_resource_name .. " for surface " .. surface_name) + global.ocfg.surfaces_config[surface_name].spawn_config[setting_name][new_resource_name] = {num_patches=0, amount=0, x_offset=0, y_offset=0} + end + -- Update all tags with the new resource name. for _, child in pairs(event.element.parent.children) do if (child.tags.resource_name == old_resource_name) then @@ -839,7 +1080,7 @@ function SurfaceConfigTabGuiClick(event) end content_flow.clear() CreateSurfaceConfigContent(content_flow, surface_name) - + elseif (tags.resource_remove_row_button) then player.print("Remove resource: " .. tags.resource_name) @@ -858,7 +1099,7 @@ function SurfaceConfigTabGuiClick(event) child.destroy() end end - + elseif (tags.resource_add_row_button) then local parent = event.element.parent @@ -876,6 +1117,23 @@ function SurfaceConfigTabGuiClick(event) -- Add the add row button back. SurfaceConfigSolidResourcesAddRowButton(parent) - + + elseif (tags.fluid_resource_add_row_button) then + + local parent = event.element.parent + local setting_name = parent.tags.setting --[[@as string]] + + if (parent == nil) then + error("Parent is nil? This shouldn't happen on add row button click! " .. setting_name) + end + + player.print("Add fluid resource row: " .. setting_name) + + -- Delete the button and add a new row and then add the button back. + event.element.destroy() + FluidResourcesConfigDisplayRow(parent, nil, 0, 0) + + -- Add the add row button back. + SurfaceConfigFluidResourcesAddRowButton(parent) end end \ No newline at end of file diff --git a/lib/separate_spawns.lua b/lib/separate_spawns.lua index 06891a3..1ccc3c1 100644 --- a/lib/separate_spawns.lua +++ b/lib/separate_spawns.lua @@ -272,37 +272,62 @@ function GenerateStartingResources(surface, position) local amount_mod = global.ocfg.resource_placement.amount_multiplier -- Generate all resource tile patches - if (not global.ocfg.resource_placement.enabled) then - for r_name, r_data in pairs(global.ocfg.surfaces_config[surface.name].spawn_config.solid_resources --[[@as table]]) do - local pos = { x = position.x + r_data.x_offset, y = position.y + r_data.y_offset } - GenerateResourcePatch(surface, r_name, r_data.size * size_mod, pos, r_data.amount * amount_mod) - end - - -- Generate resources in random order around the spawn point. Tweak in config.lua - else - + -- Generate resources in random order around the spawn point. + if global.ocfg.resource_placement.enabled then if (global.ocfg.spawn_general.shape == SPAWN_SHAPE_CHOICE_CIRCLE) or (global.ocfg.spawn_general.shape == SPAWN_SHAPE_CHOICE_OCTAGON) then PlaceResourcesInSemiCircle(surface, position, size_mod, amount_mod) elseif (global.ocfg.spawn_general.shape == SPAWN_SHAPE_CHOICE_SQUARE) then PlaceResourcesInSquare(surface, position, size_mod, amount_mod) end + + -- Generate resources using specified offsets if auto placement is disabled. + else + for r_name, r_data in pairs(global.ocfg.surfaces_config[surface.name].spawn_config.solid_resources --[[@as table]]) do + local pos = { x = position.x + r_data.x_offset, y = position.y + r_data.y_offset } + GenerateResourcePatch(surface, r_name, r_data.size * size_mod, pos, r_data.amount * amount_mod) + end end -- Generate special fluid resource patches (oil) + -- Autoplace using spacing and vertical offset. -- Reference position is the bottom of the spawn area. - local fluid_ref_pos = { x = position.x, - y = position.y + global.ocfg.spawn_general.spawn_radius_tiles } - for r_name, r_data in pairs(global.ocfg.surfaces_config[surface.name].spawn_config.fluid_resources --[[@as table]]) do - local oil_patch_x = fluid_ref_pos.x + r_data.x_offset_start - local oil_patch_y = fluid_ref_pos.y + r_data.y_offset_start - for i = 1, r_data.num_patches do - surface.create_entity({ - name = r_name, - amount = r_data.amount, - position = { oil_patch_x, oil_patch_y } - }) - oil_patch_x = oil_patch_x + r_data.x_offset_next - oil_patch_y = oil_patch_y + r_data.y_offset_next + if global.ocfg.resource_placement.enabled then + local y_offset = global.ocfg.resource_placement.distance_to_edge + local spacing = 4 -- HARDCODED FLUID PATCH SPACING SIZE! + local fluid_ref_pos = { x = position.x, y = position.y + global.ocfg.spawn_general.spawn_radius_tiles - y_offset } + + for r_name, r_data in pairs(global.ocfg.surfaces_config[surface.name].spawn_config.fluid_resources --[[@as table]]) do + + local oil_patch_x = fluid_ref_pos.x - (((r_data.num_patches-1) * spacing) / 2) + local oil_patch_y = fluid_ref_pos.y + + for i = 1, r_data.num_patches do + surface.create_entity({ + name = "crude-oil", + amount = r_data.amount, + position = { oil_patch_x, oil_patch_y } + }) + oil_patch_x = oil_patch_x + spacing + end + + fluid_ref_pos.y = fluid_ref_pos.y - spacing + end + + -- This places using specified offsets if auto placement is disabled. + else + local fluid_ref_pos = { x = position.x, y = position.y + global.ocfg.spawn_general.spawn_radius_tiles } + for r_name, r_data in pairs(global.ocfg.surfaces_config[surface.name].spawn_config.fluid_resources --[[@as table]]) do + local oil_patch_x = fluid_ref_pos.x + r_data.x_offset_start + local oil_patch_y = fluid_ref_pos.y + r_data.y_offset_start + for i = 1, r_data.num_patches do + surface.create_entity({ + name = r_name, + amount = r_data.amount, + position = { oil_patch_x, oil_patch_y } + }) + oil_patch_x = oil_patch_x + r_data.x_offset_next + oil_patch_y = oil_patch_y + r_data.y_offset_next + end end end end @@ -329,7 +354,7 @@ function PlaceResourcesInSemiCircle(surface, position, size_mod, amount_mod) -- This places resources in a semi-circle local angle_offset = global.ocfg.resource_placement.angle_offset local num_resources = table_size(global.ocfg.surfaces_config[surface.name].spawn_config.solid_resources) - local theta = ((global.ocfg.resource_placement.angle_final - global.ocfg.resource_placement.angle_offset) / num_resources); + local theta = ((global.ocfg.resource_placement.angle_final - global.ocfg.resource_placement.angle_offset) / (num_resources-1)); local count = 0 local radius = global.ocfg.spawn_general.spawn_radius_tiles - global.ocfg.resource_placement.distance_to_edge diff --git a/locale/en/locale.cfg b/locale/en/locale.cfg index 4412253..28f0788 100644 --- a/locale/en/locale.cfg +++ b/locale/en/locale.cfg @@ -216,7 +216,7 @@ oarc-player-list-tab-location-button-tooltip=Click to view map location. oarc-settings-tab-title-mod-settings=Mod Settings oarc-settings-tab-admin-warning=You are an admin. Changing these settings late in the game may cause issues!\nChanging settings will not modify existing spawns. BE CAREFUL! oarc-settings-tab-player-warning=You are not an admin. These settings are read-only for you. -oarc-settings-tab-description=This tab contains the same mod settings in the mod settings menu AND some additional settings that can only be changed in game. +oarc-settings-tab-description=This tab contains the same mod settings in the mod settings menu AND some additional settings that can only be changed in game. Check the Surface Config tab for surface-specific settings. oarc-settings-tab-text-field-enter-tooltip=[color=red]You must press ENTER after typing in a text field to save the value![/color] oarc-settings-tab-title-surface=Surface Settings oarc-settings-tab-surface-checkbox-tooltip=Enabling this will allow custom spawn areas (the main feature of this mod) on this surface. You need at least one of these enabled for the mod to work. From a347c4de33284c6540b2b99267b929d7f43abcac Mon Sep 17 00:00:00 2001 From: Oarcinae Date: Mon, 7 Oct 2024 21:53:56 -0400 Subject: [PATCH 12/16] Make settings import/export by admin only. --- lib/gui_tabs/settings_controls.lua | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/gui_tabs/settings_controls.lua b/lib/gui_tabs/settings_controls.lua index 0c5129c..ea1849d 100644 --- a/lib/gui_tabs/settings_controls.lua +++ b/lib/gui_tabs/settings_controls.lua @@ -39,7 +39,10 @@ function CreateSettingsControlsTab(tab_container, player) CreateSurfaceSettingsSection(scroll_pane_right, player) AddSpacerLine(scroll_pane_right) - CreateSettingsExportSection(scroll_pane_right, player) + + if (player.admin) then + CreateSettingsExportSection(scroll_pane_right, player) + end end ---Create the content for the mod settings section From e806ea43e0147d20c69fced1f6b5e9836de0950d Mon Sep 17 00:00:00 2001 From: Oarcinae Date: Mon, 7 Oct 2024 22:24:08 -0400 Subject: [PATCH 13/16] Change safe area settings from tiles to chunks. closes #162 --- lib/config.lua | 18 +++++++++--------- lib/gui_tabs/surface_config.lua | 6 +++--- lib/scaled_enemies.lua | 18 +++++++++--------- lib/separate_spawns.lua | 4 ++-- migrations/oarc-mod_V2.0.2.lua | 16 ++++++++++++++++ 5 files changed, 39 insertions(+), 23 deletions(-) create mode 100644 migrations/oarc-mod_V2.0.2.lua diff --git a/lib/config.lua b/lib/config.lua index d02f60d..42c8ce1 100644 --- a/lib/config.lua +++ b/lib/config.lua @@ -67,19 +67,19 @@ NAUVIS_SPAWN_CONFIG = safe_area = { -- Safe area has no aliens - -- This is the radius in tiles of safe area. - safe_radius = CHUNK_SIZE*6, + -- This is the radius in chunks of safe area. + safe_radius = 6, -- Warning area has significantly reduced aliens - -- This is the radius in tiles of warning area. - warn_radius = CHUNK_SIZE*12, + -- This is the radius in chunks of warning area. + warn_radius = 12, -- 1 : X (spawners alive : spawners destroyed) in this area warn_reduction = 20, -- Danger area has slightly reduced aliens - -- This is the radius in tiles of danger area. - danger_radius = CHUNK_SIZE*32, + -- This is the radius in chunks of danger area. + danger_radius = 32, -- 1 : X (spawners alive : spawners destroyed) in this area danger_reduction = 5, @@ -505,10 +505,10 @@ OCFG = { ---@field shape SpawnShapeChoice Spawn a circle/octagon/square of trees around this base outline. ---@class OarcConfigSpawnSafeArea ----@field safe_radius number Safe area has no aliens This is the radius in tiles of safe area. ----@field warn_radius number Warning area has significantly reduced aliens This is the radius in tiles of warning area. +---@field safe_radius number Safe area has no aliens This is the radius in chunks of safe area. +---@field warn_radius number Warning area has significantly reduced aliens This is the radius in chunks of warning area. ---@field warn_reduction number 1 : X (spawners alive : spawners destroyed) in this area ----@field danger_radius number Danger area has slightly reduce aliens This is the radius in tiles of danger area. +---@field danger_radius number Danger area has slightly reduce aliens This is the radius in chunks of danger area. ---@field danger_reduction number 1 : X (spawners alive : spawners destroyed) in this area ---@class OarcConfigSpawnWater diff --git a/lib/gui_tabs/surface_config.lua b/lib/gui_tabs/surface_config.lua index 97d4c1c..bd7f9af 100644 --- a/lib/gui_tabs/surface_config.lua +++ b/lib/gui_tabs/surface_config.lua @@ -310,10 +310,10 @@ function CreateSafeAreaConfig(container, surface_name) header.tooltip = "This controls how safe the area around the spawns is." -- TODO: Localize -- TODO: Localize - CreateSpawnConfigIntegerField(safe_area_flow, surface_name, "Safe Area Radius", "safe_area", "safe_radius", "This is the radius in tiles around the spawn in which no enemies will spawn.") - CreateSpawnConfigIntegerField(safe_area_flow, surface_name, "Warn Area Radius", "safe_area", "warn_radius", "This is the radius in tiles around the spawn in which enemies will be significantly reduced.") + CreateSpawnConfigIntegerField(safe_area_flow, surface_name, "Safe Area Radius", "safe_area", "safe_radius", "This is the radius in chunks around the spawn in which no enemies will spawn.") + CreateSpawnConfigIntegerField(safe_area_flow, surface_name, "Warn Area Radius", "safe_area", "warn_radius", "This is the radius in chunks around the spawn in which enemies will be significantly reduced.") CreateSpawnConfigIntegerField(safe_area_flow, surface_name, "Warn Area Reduction", "safe_area", "warn_reduction", "This is the reduction factor to reduce the number of enemies in the warn area. 10 means (1/10)th the number of enemies.") - CreateSpawnConfigIntegerField(safe_area_flow, surface_name, "Danger Area Radius", "safe_area", "danger_radius", "This is the radius in tiles around the spawn in which enemies will be slightly reduced.") + CreateSpawnConfigIntegerField(safe_area_flow, surface_name, "Danger Area Radius", "safe_area", "danger_radius", "This is the radius in chunks around the spawn in which enemies will be slightly reduced.") CreateSpawnConfigIntegerField(safe_area_flow, surface_name, "Danger Area Reduction", "safe_area", "danger_reduction", "This is the reduction factor to reduce the number of enemies in the danger area. 10 means (1/10)th the number of enemies.") end diff --git a/lib/scaled_enemies.lua b/lib/scaled_enemies.lua index 311628a..3bcce0f 100644 --- a/lib/scaled_enemies.lua +++ b/lib/scaled_enemies.lua @@ -132,11 +132,11 @@ function DowngradeAndReduceEnemiesOnChunkGenerate(event) } -- Make chunks near a spawn safe by removing enemies - if (util.distance(closest_spawn.position, chunkAreaCenter) < spawn_config.safe_area.safe_radius) then + if (util.distance(closest_spawn.position, chunkAreaCenter) < spawn_config.safe_area.safe_radius * CHUNK_SIZE) then RemoveEnemiesInArea(surface, chunk_area) -- Create a warning area with heavily reduced enemies - elseif (util.distance(closest_spawn.position, chunkAreaCenter) < spawn_config.safe_area.warn_radius) then + elseif (util.distance(closest_spawn.position, chunkAreaCenter) < spawn_config.safe_area.warn_radius * CHUNK_SIZE) then -- TODO: Refactor this to reduce calls to find_entities_filtered! ReduceEnemiesInArea(surface, chunk_area, spawn_config.safe_area.warn_reduction) @@ -144,7 +144,7 @@ function DowngradeAndReduceEnemiesOnChunkGenerate(event) ConvertEnemiesToOtherForceInArea(surface, chunk_area, ENEMY_FORCE_EASY) -- Create a third area with moderately reduced enemies - elseif (util.distance(closest_spawn.position, chunkAreaCenter) < spawn_config.safe_area.danger_radius) then + elseif (util.distance(closest_spawn.position, chunkAreaCenter) < spawn_config.safe_area.danger_radius * CHUNK_SIZE) then -- TODO: Refactor this to reduce calls to find_entities_filtered! ReduceEnemiesInArea(surface, chunk_area, spawn_config.safe_area.danger_reduction) @@ -287,15 +287,15 @@ function ChangeEnemySpawnersToOtherForceOnBuilt(event) if (closest_spawn == nil) then return end -- No enemies inside safe radius! - if (util.distance(enemy_pos, closest_spawn.position) < global.ocfg.surfaces_config[surface.name].spawn_config.safe_area.safe_radius) then + if (util.distance(enemy_pos, closest_spawn.position) < global.ocfg.surfaces_config[surface.name].spawn_config.safe_area.safe_radius * CHUNK_SIZE) then event.entity.destroy() -- Warn distance should be EASY - elseif (util.distance(enemy_pos, closest_spawn.position) < global.ocfg.surfaces_config[surface.name].spawn_config.safe_area.warn_radius) then + elseif (util.distance(enemy_pos, closest_spawn.position) < global.ocfg.surfaces_config[surface.name].spawn_config.safe_area.warn_radius * CHUNK_SIZE) then event.entity.force = game.forces[ENEMY_FORCE_EASY] -- Danger distance should be MEDIUM - elseif (util.distance(enemy_pos, closest_spawn.position) < global.ocfg.surfaces_config[surface.name].spawn_config.safe_area.danger_radius) then + elseif (util.distance(enemy_pos, closest_spawn.position) < global.ocfg.surfaces_config[surface.name].spawn_config.safe_area.danger_radius * CHUNK_SIZE) then event.entity.force = game.forces[ENEMY_FORCE_MEDIUM] -- Otherwise make sure they are on the base enemy force (stops easy enemies from spreading out too far). @@ -328,11 +328,11 @@ function ModifyEnemySpawnsNearPlayerStartingAreas(event) end -- No enemies inside safe radius! - if (util.distance(enemy_pos, closest_spawn.position) < global.ocfg.surfaces_config[surface.name].spawn_config.safe_area.safe_radius) then + if (util.distance(enemy_pos, closest_spawn.position) < global.ocfg.surfaces_config[surface.name].spawn_config.safe_area.safe_radius * CHUNK_SIZE) then event.entity.destroy() -- Warn distance is all SMALL only. - elseif (util.distance(enemy_pos, closest_spawn.position) < global.ocfg.surfaces_config[surface.name].spawn_config.safe_area.warn_radius) then + elseif (util.distance(enemy_pos, closest_spawn.position) < global.ocfg.surfaces_config[surface.name].spawn_config.safe_area.warn_radius * CHUNK_SIZE) then if ((enemy_name == "biter-spawner") or (enemy_name == "spitter-spawner")) then event.entity.force = game.forces["enemy-easy"] @@ -351,7 +351,7 @@ function ModifyEnemySpawnsNearPlayerStartingAreas(event) end -- Danger distance is MEDIUM max. - elseif (util.distance(enemy_pos, closest_spawn.position) < global.ocfg.surfaces_config[surface.name].spawn_config.safe_area.danger_radius) then + elseif (util.distance(enemy_pos, closest_spawn.position) < global.ocfg.surfaces_config[surface.name].spawn_config.safe_area.danger_radius * CHUNK_SIZE) then if ((enemy_name == "big-biter") or (enemy_name == "behemoth-biter")) then event.entity.destroy() surface.create_entity { name = "medium-biter", position = enemy_pos, force = game.forces.enemy } diff --git a/lib/separate_spawns.lua b/lib/separate_spawns.lua index 1ccc3c1..63035db 100644 --- a/lib/separate_spawns.lua +++ b/lib/separate_spawns.lua @@ -417,7 +417,7 @@ function SendPlayerToNewSpawnAndCreateIt(delayed_spawn) local spawn_config = ocfg.surfaces_config[delayed_spawn.surface].spawn_config -- DOUBLE CHECK and make sure the area is super safe. - ClearNearbyEnemies(delayed_spawn.position, spawn_config.safe_area.safe_radius, + ClearNearbyEnemies(delayed_spawn.position, spawn_config.safe_area.safe_radius * CHUNK_SIZE, game.surfaces[delayed_spawn.surface]) -- Generate water strip only if we don't have a moat. @@ -649,7 +649,7 @@ function DowngradeResourcesDistanceBasedOnChunkGenerate(surface, chunkArea) local distance = util.distance(chunkArea.left_top, closestSpawn.position) -- Adjust multiplier to bring it in or out - local modifier = (distance / (global.ocfg.surfaces_config[surface.name].spawn_config.safe_area.danger_radius * 1)) ^ 3 + local modifier = (distance / (global.ocfg.surfaces_config[surface.name].spawn_config.safe_area.danger_radius * CHUNK_SIZE * 1)) ^ 3 if modifier < 0.1 then modifier = 0.1 end if modifier > 1 then return end diff --git a/migrations/oarc-mod_V2.0.2.lua b/migrations/oarc-mod_V2.0.2.lua new file mode 100644 index 0000000..7f875bf --- /dev/null +++ b/migrations/oarc-mod_V2.0.2.lua @@ -0,0 +1,16 @@ +-- Migrate safe_radius, warn_radius and danger_radius to be chunks instead of tiles. +for surface_name, surface_config in pairs(global.ocfg.surfaces_config) do + + -- If the safe_area is greater than 3 chunks, then it's likely in chunks... + if surface_config.spawn_config.safe_area.safe_radius >= (3 * 32) then + log("Oarc-mod: Migrating safe_radius, warn_radius and danger_radius to be chunks instead of tiles.") + local safe_radius = surface_config.spawn_config.safe_area.safe_radius + global.ocfg.surfaces_config[surface_name].spawn_config.safe_area.safe_radius = math.ceil(safe_radius / 32) + + local warn_radius = surface_config.spawn_config.safe_area.warn_radius + global.ocfg.surfaces_config[surface_name].spawn_config.safe_area.warn_radius = math.ceil(warn_radius / 32) + + local danger_radius = surface_config.spawn_config.safe_area.danger_radius + global.ocfg.surfaces_config[surface_name].spawn_config.safe_area.danger_radius = math.ceil(danger_radius / 32) + end +end \ No newline at end of file From 494af6b6af86577d372b457476e19ee8bef63727 Mon Sep 17 00:00:00 2001 From: Oarcinae Date: Mon, 7 Oct 2024 22:29:33 -0400 Subject: [PATCH 14/16] Change default value for minimum distance to existing chunks from 10 to 20 and up the maximum value allowed in mod settings. Closes #150 --- lib/config.lua | 2 +- settings.lua | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/config.lua b/lib/config.lua index 42c8ce1..58244b0 100644 --- a/lib/config.lua +++ b/lib/config.lua @@ -217,7 +217,7 @@ OCFG = { -- chunks. It ensures the spawn area isn't too near generated/explored/existing -- area. The larger you make this, the further away players will spawn from -- generated map area (even if it is not visible on the map!). - minimum_distance_to_existing_chunks = 10, + minimum_distance_to_existing_chunks = 20, -- The range in which a player can select how close to the center of the map they want to spawn. near_spawn_distance = 100, diff --git a/settings.lua b/settings.lua index 7bcd7ff..f8a30a9 100644 --- a/settings.lua +++ b/settings.lua @@ -80,9 +80,9 @@ data:extend({ type = "int-setting", name = "oarc-mod-minimum-distance-to-existing-chunks", setting_type = "runtime-global", - default_value = 10, + default_value = 20, minimum_value = 5, - maximum_value = 25, + maximum_value = 50, order = "c1" }, { From 1f263a3c182e818f9ce78a56738e756f669a468b Mon Sep 17 00:00:00 2001 From: Oarcinae Date: Mon, 7 Oct 2024 22:52:25 -0400 Subject: [PATCH 15/16] Remove player print spam for testing in surface_config. Update changelog and info.json. Add RSO to hidden dependencies. --- changelog.txt | 14 ++++++++++++++ info.json | 5 +++-- lib/gui_tabs/surface_config.lua | 29 +---------------------------- 3 files changed, 18 insertions(+), 30 deletions(-) diff --git a/changelog.txt b/changelog.txt index 22e1c62..f849fe0 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,4 +1,18 @@ --------------------------------------------------------------------------------------------------- +Version: 2.0.2 +Date: 2024-10-08 + Major Features: + - Added a new GUI config for all surface specific settings that can't be made available in the mod settings. This will let you easily configure all available settings via the in game custom GUI now. It is also possible to import and export settings as a serialized string. (You can still use a custom scenario to configure all settings as well using the template provided.) + - Added a player list tab to the custom GUI so you can see all players on the server, and their locations. + Bugfixes: + - Fixed a minor issue with resource placement not calculating the angle correctly when placing solid resources. + - Removed log spam related to offline enemy protection. + - Fixed an issue with regrowth that was causing log spam about chunks not being tracked properly. + Info: + - Added fish to moats. + - Doubled the default value for "minimum distance to existing chunks". There were some concerns bases might spawn too close together in some cases, this should help alleviate that. + - Changed safe_area radii config to use chunks instead of tiles. Makes more sense for the setting and is easier to visualize distance in chunks. (Older configs should get migrated automatically, but you may want to double check your settings.) +--------------------------------------------------------------------------------------------------- Version: 2.0.1 Date: 2024-09-25 Bugfixes: diff --git a/info.json b/info.json index dcb4578..094c7d3 100644 --- a/info.json +++ b/info.json @@ -1,6 +1,6 @@ { "name": "oarc-mod", - "version": "2.0.1", + "version": "2.0.2", "factorio_version": "1.1", "title": "Oarc Multiplayer Spawn", "author": "Oarcinae", @@ -14,6 +14,7 @@ "(?) space-exploration", "(?) alien-biomes", "(?) sonaxaton-research-queue", - "(?) helmod" + "(?) helmod", + "(?) rso-mod" ] } \ No newline at end of file diff --git a/lib/gui_tabs/surface_config.lua b/lib/gui_tabs/surface_config.lua index bd7f9af..569640f 100644 --- a/lib/gui_tabs/surface_config.lua +++ b/lib/gui_tabs/surface_config.lua @@ -681,8 +681,6 @@ function SurfaceConfigTabGuiSelect(event) -- Recreate the content section content_flow.clear() CreateSurfaceConfigContent(content_flow, selected_surface_name) - - player.print("Selected surface: " .. selected_surface_name) end end @@ -725,7 +723,6 @@ function SurfaceConfigTabGuiConfirmed(event) end if (tags.item_number_textfield) then - player.print("Selected item: " .. tags.item_name .. " count: " .. event.element.text) local parent = event.element.parent local surface_name = parent.tags.surface_name --[[@as string]] @@ -747,7 +744,6 @@ function SurfaceConfigTabGuiConfirmed(event) event.element.style.width = 40 elseif (tags.resource_amount_textfield or tags.resource_size_textfield) then - -- player.print("Selected resource: " .. tags.resource_name .. " amount: " .. event.element.text) local parent = event.element.parent local surface_name = parent.tags.surface_name --[[@as string]] @@ -774,7 +770,6 @@ function SurfaceConfigTabGuiConfirmed(event) event.element.style.width = 50 elseif (tags.fluid_resource_count_textfield or tags.fluid_resource_amount_textfield) then - -- player.print("Selected fluid resource: " .. tags.resource_name .. " count: " .. event.element.text) local parent = event.element.parent local surface_name = parent.tags.surface_name --[[@as string]] @@ -829,7 +824,6 @@ function SurfaceConfigTabGuiElemChanged(event) if (tags.elem_button) then local new_item_name = event.element.elem_value --[[@as string]] - player.print("Selected item: " .. new_item_name) if (new_item_name == nil) then return @@ -855,11 +849,9 @@ function SurfaceConfigTabGuiElemChanged(event) -- Update the item name in the list, keep the old count. if (old_item_name ~= "") then - player.print("Update item: " .. old_item_name .. " to " .. new_item_name .. " for surface " .. surface_name) global.ocfg.surfaces_config[surface_name].starting_items[setting_name][new_item_name] = global.ocfg.surfaces_config[surface_name].starting_items[setting_name][old_item_name] global.ocfg.surfaces_config[surface_name].starting_items[setting_name][old_item_name] = nil else - player.print("Add item: " .. new_item_name .. " for surface " .. surface_name) global.ocfg.surfaces_config[surface_name].starting_items[setting_name][new_item_name] = 0 end @@ -874,7 +866,6 @@ function SurfaceConfigTabGuiElemChanged(event) elseif (tags.resource_elem_button) then local new_resource_name = event.element.elem_value --[[@as string]] - player.print("Selected resource: " .. event.element.elem_value) if (new_resource_name == nil) then return @@ -886,7 +877,6 @@ function SurfaceConfigTabGuiElemChanged(event) return end - local old_resource_name = tags.resource_name --[[@as string]] -- if the new resource name is the same as the old resource name, do nothing. @@ -907,11 +897,9 @@ function SurfaceConfigTabGuiElemChanged(event) -- Update the resource name in the list, keep the old amount and size. if (old_resource_name ~= "") then - player.print("Update resource: " .. old_resource_name .. " to " .. new_resource_name .. " for surface " .. surface_name) global.ocfg.surfaces_config[surface_name].spawn_config[setting_name][new_resource_name] = global.ocfg.surfaces_config[surface_name].spawn_config[setting_name][old_resource_name] global.ocfg.surfaces_config[surface_name].spawn_config[setting_name][old_resource_name] = nil else - player.print("Add resource: " .. new_resource_name .. " for surface " .. surface_name) global.ocfg.surfaces_config[surface_name].spawn_config[setting_name][new_resource_name] = {amount=0, size=0, x_offset=0, y_offset=0} end @@ -926,7 +914,6 @@ function SurfaceConfigTabGuiElemChanged(event) elseif (tags.fluid_resource_elem_button) then local new_resource_name = event.element.elem_value --[[@as string]] - player.print("Selected fluid resource: " .. event.element.elem_value) if (new_resource_name == nil) then return @@ -958,11 +945,9 @@ function SurfaceConfigTabGuiElemChanged(event) -- Update the resource name in the list, keep the old amount and size. if (old_resource_name ~= "") then - player.print("Update resource: " .. old_resource_name .. " to " .. new_resource_name .. " for surface " .. surface_name) global.ocfg.surfaces_config[surface_name].spawn_config[setting_name][new_resource_name] = global.ocfg.surfaces_config[surface_name].spawn_config[setting_name][old_resource_name] global.ocfg.surfaces_config[surface_name].spawn_config[setting_name][old_resource_name] = nil else - player.print("Add resource: " .. new_resource_name .. " for surface " .. surface_name) global.ocfg.surfaces_config[surface_name].spawn_config[setting_name][new_resource_name] = {num_patches=0, amount=0, x_offset=0, y_offset=0} end @@ -990,7 +975,6 @@ function SurfaceConfigTabGuiClick(event) end if (tags.remove_row_button) then - player.print("Remove item: " .. tags.item_name) local parent = event.element.parent local surface_name = parent.tags.surface_name --[[@as string]] @@ -999,7 +983,6 @@ function SurfaceConfigTabGuiClick(event) local max_count = parent.tags.max_count --[[@as integer]] -- Nil the entry - player.print("Remove item: " .. item_name .. " for surface " .. surface_name) global.ocfg.surfaces_config[surface_name].starting_items[setting_name][item_name] = nil -- Delete the row by removing the child elements from the table. @@ -1027,8 +1010,6 @@ function SurfaceConfigTabGuiClick(event) error("Parent is nil? This shouldn't happen on add row button click! " .. setting_name) end - player.print("Add row: " .. setting_name) - -- Delete the button and add a new row and then add the button back. event.element.destroy() SurfaceConfigItemListDisplayRow(parent) @@ -1041,7 +1022,6 @@ function SurfaceConfigTabGuiClick(event) elseif (tags.setting == "crashed_ship_enabled") then local surface_name = tags.surface_name --[[@as string]] - player.print("Crashed Ship Enabled: " .. tostring(event.element.state)) global.ocfg.surfaces_config[surface_name].starting_items.crashed_ship = event.element.state elseif (tags.setting == "revert_to_default") then @@ -1069,7 +1049,7 @@ function SurfaceConfigTabGuiClick(event) return end - player.print("Copy Nauvis: " .. surface_name) + player.print("Copy nauvis to " .. surface_name) global.ocfg.surfaces_config[surface_name].starting_items = global.ocfg.surfaces_config["nauvis"].starting_items global.ocfg.surfaces_config[surface_name].spawn_config = global.ocfg.surfaces_config["nauvis"].spawn_config @@ -1082,15 +1062,12 @@ function SurfaceConfigTabGuiClick(event) CreateSurfaceConfigContent(content_flow, surface_name) elseif (tags.resource_remove_row_button) then - player.print("Remove resource: " .. tags.resource_name) - local resource_name = tags.resource_name --[[@as string]] local parent = event.element.parent local surface_name = parent.tags.surface_name --[[@as string]] local setting_name = parent.tags.setting --[[@as string]] -- Nil the entry - player.print("Remove resource: " .. resource_name .. " for surface " .. surface_name) global.ocfg.surfaces_config[surface_name].spawn_config[setting_name][resource_name] = nil -- Delete the row by removing the child elements from the table. @@ -1109,8 +1086,6 @@ function SurfaceConfigTabGuiClick(event) error("Parent is nil? This shouldn't happen on add row button click! " .. setting_name) end - player.print("Add resource row: " .. setting_name) - -- Delete the button and add a new row and then add the button back. event.element.destroy() SolidResourcesConfigDisplayRow(parent, nil, 0, 0) @@ -1127,8 +1102,6 @@ function SurfaceConfigTabGuiClick(event) error("Parent is nil? This shouldn't happen on add row button click! " .. setting_name) end - player.print("Add fluid resource row: " .. setting_name) - -- Delete the button and add a new row and then add the button back. event.element.destroy() FluidResourcesConfigDisplayRow(parent, nil, 0, 0) From 249b25000f1b3668b3da5bc32e7a97e57da91099 Mon Sep 17 00:00:00 2001 From: Oarcinae Date: Mon, 7 Oct 2024 23:00:19 -0400 Subject: [PATCH 16/16] Fix defaults of solid resource angle placements (after fixing other bug with angle math.) --- lib/config.lua | 4 ++-- settings.lua | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/config.lua b/lib/config.lua index 58244b0..2d07cd9 100644 --- a/lib/config.lua +++ b/lib/config.lua @@ -345,11 +345,11 @@ OCFG = { -- At what angle (in radians) do resources start. -- 0 means starts directly east. -- Resources are placed clockwise from there. - angle_offset = 2.32, -- 2.32 is approx SSW. + angle_offset = 2.09, -- Approx SSW. -- At what andle do we place the last resource. -- angle_offset and angle_final determine spacing and placement. - angle_final = 4.46, -- 4.46 is approx NNW. + angle_final = 4.18, -- Approx NNW. -- Vertical offset in tiles for the deposit resource placement. Starting from top-left corner. -- Only applicable for square spawns. diff --git a/settings.lua b/settings.lua index f8a30a9..83948ef 100644 --- a/settings.lua +++ b/settings.lua @@ -341,7 +341,7 @@ data:extend({ type = "double-setting", name = "oarc-mod-resource-placement-angle-offset", setting_type = "runtime-global", - default_value = 2.32, + default_value = 2.09, minimum_value = 0, maximum_value = 6.28, order = "i3" @@ -350,7 +350,7 @@ data:extend({ type = "double-setting", name = "oarc-mod-resource-placement-angle-final", setting_type = "runtime-global", - default_value = 4.46, + default_value = 4.18, minimum_value = 0, maximum_value = 6.28, order = "i4"