From 9c59f2408bee1f2998d173c472c20433e166b778 Mon Sep 17 00:00:00 2001 From: MasterBel2 <39206414+MasterBel2@users.noreply.github.com> Date: Sun, 10 May 2020 12:39:37 +1000 Subject: [PATCH 01/31] Uparrow/downarrow in console autofills sent messages. The console maintains an index where index == 1 refers to the message being typed, and index >= 2 refers to previously sent messages. Messages are inserted at index == 2 after send (excluding adjacent duplicates). Uparrow/downarrow adjusts the index and fills the new index's corresponding value. There is no limit to the number of stored sent messages. Also replaced Console.MessageListener with Console.sendMessageActions.default /.ircStyle for reduced code duplication. --- .../chobby/components/chat_windows.lua | 32 +++++----- LuaMenu/widgets/chobby/components/console.lua | 64 +++++++++++++++++-- LuaMenu/widgets/gui_battle_room_window.lua | 14 ++-- 3 files changed, 82 insertions(+), 28 deletions(-) diff --git a/LuaMenu/widgets/chobby/components/chat_windows.lua b/LuaMenu/widgets/chobby/components/chat_windows.lua index ec80f2828..548e2afae 100644 --- a/LuaMenu/widgets/chobby/components/chat_windows.lua +++ b/LuaMenu/widgets/chobby/components/chat_windows.lua @@ -728,17 +728,16 @@ function ChatWindows:GetChannelConsole(chanName) local channelConsole = self.channelConsoles[chanName] if channelConsole == nil then - local function MessageListener(message) - if message:starts("/me ") then - lobby:SayEx(chanName, message:sub(5)) - else - lobby:Say(chanName, message) - end - end + + local sendMessageActions = { + default = function(message) lobby:Say(chanName, message) end, + ircStyle = function(message) lobby:SayEx(chanName, message) end, + } + local function Resize(obj) self:UpdateOldChatLinePosition(obj) end - channelConsole = Console(chanName, MessageListener, nil, Resize, false) + channelConsole = Console(chanName, sendMessageActions, nil, Resize, false) self.channelConsoles[chanName] = channelConsole Configuration.channels[chanName] = true @@ -818,17 +817,18 @@ function ChatWindows:GetPrivateChatConsole(userName, switchTo) local privateChatConsole = self.privateChatConsoles[chanName] if privateChatConsole == nil then - local function MessageListener(message) - if message:starts("/me ") then - lobby:SayPrivateEx(userName, message:sub(5)) - else - lobby:SayPrivate(userName, message) - end - end + + local sendPrivateMessageActions = { + default = function(message) lobby:SayPrivate(userName, message) end, + ircStyle = function(message) lobby:SayPrivateEx(userName, message) end, + } + + channelConsole = Console(chanName, sendPrivateMessageActions, nil, Resize, false) + local function Resize(obj) self:UpdateOldChatLinePosition(obj) end - privateChatConsole = Console(chanName, MessageListener, nil, Resize, false) + privateChatConsole = Console(chanName, sendPrivateMessageActions, nil, Resize, false) self.privateChatConsoles[chanName] = privateChatConsole local caption = "@" .. userName diff --git a/LuaMenu/widgets/chobby/components/console.lua b/LuaMenu/widgets/chobby/components/console.lua index 31a4c4a20..f89918554 100644 --- a/LuaMenu/widgets/chobby/components/console.lua +++ b/LuaMenu/widgets/chobby/components/console.lua @@ -1,10 +1,17 @@ Console = LCS.class{} -function Console:init(channelName, sendMessageListener, noHistoryLoad, onResizeFunc, isBattleChat) - self.listener = sendMessageListener +function Console:init(channelName, sendMessageActions, noHistoryLoad, onResizeFunc, isBattleChat) + self.sendMessageActions = sendMessageActions self.showDate = true self.dateFormat = "%H:%M" + -- List of sent messages sent by the viewer. self.sentMessages[1] will be the message the user was typing. + -- self.sentMessages[2] is the start of history. + self.sentMessages = {""} + -- The index of the sent message currently being shown in the editbox. + -- An index of 1 indicates the current message, index >= 2 indicates message history. + self.sentMessageIndex = 1 + self.channelName = channelName local onResize @@ -103,9 +110,20 @@ function Console:init(channelName, sendMessageListener, noHistoryLoad, onResizeF key == Spring.GetKeyCode("numpad_enter") then self:SendMessage() return true + elseif key == Spring.GetKeyCode("up") then + self:FillPreviousSentMessage() + return true + elseif key == Spring.GetKeyCode("down") then + self:FillNextSentMessage() + return true end end } + self.ebInputText.OnTextInput = { + function(utf8char, ...) + self.sentMessageIndex = 1 + end + } self.fakeImage = Image:New { x = 0, y = 0, bottom = 0, right = 0, @@ -134,6 +152,36 @@ function Console:init(channelName, sendMessageListener, noHistoryLoad, onResizeF end end +-- Changes the current console text entry to message sent after the one currently shown. +-- Shows the message that was being typed before retrieving past messages if there are no +-- messages sent since the one currently shown in the EditBox. +function Console:FillNextSentMessage() + -- Only move forward if not looking at the past. + if self.sentMessageIndex > 1 then + self:FillSentMessage(self.sentMessageIndex - 1) + end +end + +-- Changes the current console text entry to the message sent further in the past than the one currently shown. +function Console:FillPreviousSentMessage() + if self.sentMessageIndex == #self.sentMessages then + -- Bail out if there's no previous history to see. + return + elseif self.sentMessageIndex == 1 then + -- Save current message before we move into the past. + self.sentMessages[1] = self.ebInputText.text + end + -- Move the index, and update the editBox + self:FillSentMessage(self.sentMessageIndex + 1) +end + +-- Changes the current console text entry to the specified sent message. +-- sentMessageIndex must be >= 0 +function Console:FillSentMessage(sentMessageIndex) + self.ebInputText:SetText(self.sentMessages[sentMessageIndex]) + self.sentMessageIndex = sentMessageIndex +end + function Console:Autocomplete(textSoFar) if not self.subword then local start = 0 @@ -185,8 +233,16 @@ end function Console:SendMessage() if self.ebInputText.text ~= "" then message = self.ebInputText.text - if self.listener then - self.listener(message) + if self.sendMessageActions then + if message:starts("/me ") then + self.sendMessageActions.ircStyle(message:sub(5)) + else + self.sendMessageActions.default(message) + end + end + -- If the message is different than the last sent message, save the message for retrieval by uparrow. + if self.sentMessages[2] ~= self.ebInputText.text then + table.insert(self.sentMessages, 2, self.ebInputText.text) end self.ebInputText:SetText("") end diff --git a/LuaMenu/widgets/gui_battle_room_window.lua b/LuaMenu/widgets/gui_battle_room_window.lua index 9c333ded8..039c08b6a 100644 --- a/LuaMenu/widgets/gui_battle_room_window.lua +++ b/LuaMenu/widgets/gui_battle_room_window.lua @@ -1821,14 +1821,12 @@ local function InitializeControls(battleID, oldLobby, topPoportion, setupData) end UpdateBattleTitle() - local function MessageListener(message) - if message:starts("/me ") then - battleLobby:SayBattleEx(message:sub(5)) - else - battleLobby:SayBattle(message) - end - end - local battleRoomConsole = WG.Chobby.Console("Battleroom Chat", MessageListener, true, nil, true) + local sendBattleMessageActions = { + default = function(message) lobby:SayBattle(message) end, + ircStyle = function(message) lobby:SayBattleEx(message) end, + } + + local battleRoomConsole = WG.Chobby.Console("Battleroom Chat", sendBattleMessageActions, true, nil, true) local chatPanel = Control:New { x = 0, From 5b6147b48e9a06d48b244ee17b5e4d76269a9006 Mon Sep 17 00:00:00 2001 From: MasterBel2 <39206414+MasterBel2@users.noreply.github.com> Date: Wed, 20 May 2020 11:51:55 +1000 Subject: [PATCH 02/31] Changes requested by PR: - Revert `MessageListener` changes. For future discusion/its own PR. - Console updates sentMessageIndex on TAB and sending messages. - Fixed inconsistent spacing - Fixed extraneous line due to copy-paste --- .../chobby/components/chat_windows.lua | 28 +++++++++++-------- LuaMenu/widgets/chobby/components/console.lua | 24 +++++++++------- LuaMenu/widgets/gui_battle_room_window.lua | 14 ++++++---- 3 files changed, 38 insertions(+), 28 deletions(-) diff --git a/LuaMenu/widgets/chobby/components/chat_windows.lua b/LuaMenu/widgets/chobby/components/chat_windows.lua index 548e2afae..af5dca323 100644 --- a/LuaMenu/widgets/chobby/components/chat_windows.lua +++ b/LuaMenu/widgets/chobby/components/chat_windows.lua @@ -729,15 +729,18 @@ function ChatWindows:GetChannelConsole(chanName) if channelConsole == nil then - local sendMessageActions = { - default = function(message) lobby:Say(chanName, message) end, - ircStyle = function(message) lobby:SayEx(chanName, message) end, - } + local function MessageListener(message) + if message:starts("/me ") then + lobby:SayEx(chanName, message:sub(5)) + else + lobby:Say(chanName, message) + end + end local function Resize(obj) self:UpdateOldChatLinePosition(obj) end - channelConsole = Console(chanName, sendMessageActions, nil, Resize, false) + channelConsole = Console(chanName, MessageListener, nil, Resize, false) self.channelConsoles[chanName] = channelConsole Configuration.channels[chanName] = true @@ -818,17 +821,18 @@ function ChatWindows:GetPrivateChatConsole(userName, switchTo) if privateChatConsole == nil then - local sendPrivateMessageActions = { - default = function(message) lobby:SayPrivate(userName, message) end, - ircStyle = function(message) lobby:SayPrivateEx(userName, message) end, - } - - channelConsole = Console(chanName, sendPrivateMessageActions, nil, Resize, false) + local function MessageListener(message) + if message:starts("/me ") then + lobby:SayPrivateEx(userName, message:sub(5)) + else + lobby:SayPrivate(userName, message) + end + end local function Resize(obj) self:UpdateOldChatLinePosition(obj) end - privateChatConsole = Console(chanName, sendPrivateMessageActions, nil, Resize, false) + privateChatConsole = Console(chanName, MessageListener, nil, Resize, false) self.privateChatConsoles[chanName] = privateChatConsole local caption = "@" .. userName diff --git a/LuaMenu/widgets/chobby/components/console.lua b/LuaMenu/widgets/chobby/components/console.lua index f89918554..0e3b9dd84 100644 --- a/LuaMenu/widgets/chobby/components/console.lua +++ b/LuaMenu/widgets/chobby/components/console.lua @@ -1,6 +1,7 @@ Console = LCS.class{} -function Console:init(channelName, sendMessageActions, noHistoryLoad, onResizeFunc, isBattleChat) +function Console:init(channelName, sendMessageListener, noHistoryLoad, onResizeFunc, isBattleChat) + self.listener = sendMessageListener self.sendMessageActions = sendMessageActions self.showDate = true self.dateFormat = "%H:%M" @@ -97,7 +98,12 @@ function Console:init(channelName, sendMessageActions, noHistoryLoad, onResizeFu self.ebInputText.KeyPress = function(something, key, ...) if key == Spring.GetKeyCode("tab") then + local before = self.ebInputText.text self:Autocomplete(self.ebInputText.text) + -- If text changes, reset the index. + if before ~= self.ebInputText.text then + self.sentMessageIndex = 1 + end return false else self.subword = nil @@ -178,8 +184,8 @@ end -- Changes the current console text entry to the specified sent message. -- sentMessageIndex must be >= 0 function Console:FillSentMessage(sentMessageIndex) - self.ebInputText:SetText(self.sentMessages[sentMessageIndex]) - self.sentMessageIndex = sentMessageIndex + self.ebInputText:SetText(self.sentMessages[sentMessageIndex]) + self.sentMessageIndex = sentMessageIndex end function Console:Autocomplete(textSoFar) @@ -233,18 +239,16 @@ end function Console:SendMessage() if self.ebInputText.text ~= "" then message = self.ebInputText.text - if self.sendMessageActions then - if message:starts("/me ") then - self.sendMessageActions.ircStyle(message:sub(5)) - else - self.sendMessageActions.default(message) - end - end + -- Listener handles sending the message. + if self.listener then + self.listener(message) + end -- If the message is different than the last sent message, save the message for retrieval by uparrow. if self.sentMessages[2] ~= self.ebInputText.text then table.insert(self.sentMessages, 2, self.ebInputText.text) end self.ebInputText:SetText("") + self.sentMessageIndex = 1 end end diff --git a/LuaMenu/widgets/gui_battle_room_window.lua b/LuaMenu/widgets/gui_battle_room_window.lua index 039c08b6a..6ac549397 100644 --- a/LuaMenu/widgets/gui_battle_room_window.lua +++ b/LuaMenu/widgets/gui_battle_room_window.lua @@ -1821,12 +1821,14 @@ local function InitializeControls(battleID, oldLobby, topPoportion, setupData) end UpdateBattleTitle() - local sendBattleMessageActions = { - default = function(message) lobby:SayBattle(message) end, - ircStyle = function(message) lobby:SayBattleEx(message) end, - } - - local battleRoomConsole = WG.Chobby.Console("Battleroom Chat", sendBattleMessageActions, true, nil, true) + local function MessageListener(message) + if message:starts("/me ") then + battleLobby:SayBattleEx(message:sub(5)) + else + battleLobby:SayBattle(message) + end + end + local battleRoomConsole = WG.Chobby.Console("Battleroom Chat", MessageListener, true, nil, true) local chatPanel = Control:New { x = 0, From ead0c9cb582f3a4aeb2837bcca4f9d0ab312f696 Mon Sep 17 00:00:00 2001 From: MasterBel2 <39206414+MasterBel2@users.noreply.github.com> Date: Wed, 20 May 2020 11:58:00 +1000 Subject: [PATCH 03/31] Fix whitespace --- LuaMenu/widgets/chobby/components/chat_windows.lua | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/LuaMenu/widgets/chobby/components/chat_windows.lua b/LuaMenu/widgets/chobby/components/chat_windows.lua index af5dca323..79215cc16 100644 --- a/LuaMenu/widgets/chobby/components/chat_windows.lua +++ b/LuaMenu/widgets/chobby/components/chat_windows.lua @@ -730,12 +730,12 @@ function ChatWindows:GetChannelConsole(chanName) if channelConsole == nil then local function MessageListener(message) - if message:starts("/me ") then - lobby:SayEx(chanName, message:sub(5)) - else - lobby:Say(chanName, message) - end - end + if message:starts("/me ") then + lobby:SayEx(chanName, message:sub(5)) + else + lobby:Say(chanName, message) + end + end local function Resize(obj) self:UpdateOldChatLinePosition(obj) From a1adaabbf17c7ab1ad977b75915c9fe2a065eafd Mon Sep 17 00:00:00 2001 From: MasterBel2 <39206414+MasterBel2@users.noreply.github.com> Date: Wed, 20 May 2020 12:19:26 +1000 Subject: [PATCH 04/31] Fix whitespace --- LuaMenu/widgets/chobby/components/chat_windows.lua | 12 ++++++------ LuaMenu/widgets/chobby/components/console.lua | 4 ++-- LuaMenu/widgets/gui_battle_room_window.lua | 14 +++++++------- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/LuaMenu/widgets/chobby/components/chat_windows.lua b/LuaMenu/widgets/chobby/components/chat_windows.lua index 79215cc16..61f90ec12 100644 --- a/LuaMenu/widgets/chobby/components/chat_windows.lua +++ b/LuaMenu/widgets/chobby/components/chat_windows.lua @@ -822,12 +822,12 @@ function ChatWindows:GetPrivateChatConsole(userName, switchTo) if privateChatConsole == nil then local function MessageListener(message) - if message:starts("/me ") then - lobby:SayPrivateEx(userName, message:sub(5)) - else - lobby:SayPrivate(userName, message) - end - end + if message:starts("/me ") then + lobby:SayPrivateEx(userName, message:sub(5)) + else + lobby:SayPrivate(userName, message) + end + end local function Resize(obj) self:UpdateOldChatLinePosition(obj) diff --git a/LuaMenu/widgets/chobby/components/console.lua b/LuaMenu/widgets/chobby/components/console.lua index 0e3b9dd84..088ec3d14 100644 --- a/LuaMenu/widgets/chobby/components/console.lua +++ b/LuaMenu/widgets/chobby/components/console.lua @@ -241,8 +241,8 @@ function Console:SendMessage() message = self.ebInputText.text -- Listener handles sending the message. if self.listener then - self.listener(message) - end + self.listener(message) + end -- If the message is different than the last sent message, save the message for retrieval by uparrow. if self.sentMessages[2] ~= self.ebInputText.text then table.insert(self.sentMessages, 2, self.ebInputText.text) diff --git a/LuaMenu/widgets/gui_battle_room_window.lua b/LuaMenu/widgets/gui_battle_room_window.lua index 6ac549397..9c333ded8 100644 --- a/LuaMenu/widgets/gui_battle_room_window.lua +++ b/LuaMenu/widgets/gui_battle_room_window.lua @@ -1822,13 +1822,13 @@ local function InitializeControls(battleID, oldLobby, topPoportion, setupData) UpdateBattleTitle() local function MessageListener(message) - if message:starts("/me ") then - battleLobby:SayBattleEx(message:sub(5)) - else - battleLobby:SayBattle(message) - end - end - local battleRoomConsole = WG.Chobby.Console("Battleroom Chat", MessageListener, true, nil, true) + if message:starts("/me ") then + battleLobby:SayBattleEx(message:sub(5)) + else + battleLobby:SayBattle(message) + end + end + local battleRoomConsole = WG.Chobby.Console("Battleroom Chat", MessageListener, true, nil, true) local chatPanel = Control:New { x = 0, From 1c55e2979974a6771a139ca72d55dd9204dd5c15 Mon Sep 17 00:00:00 2001 From: MasterBel2 <39206414+MasterBel2@users.noreply.github.com> Date: Wed, 20 May 2020 16:11:29 +1000 Subject: [PATCH 05/31] Removed extraneous changes that should have already been reverted --- LuaMenu/widgets/chobby/components/chat_windows.lua | 4 ---- LuaMenu/widgets/chobby/components/console.lua | 1 - 2 files changed, 5 deletions(-) diff --git a/LuaMenu/widgets/chobby/components/chat_windows.lua b/LuaMenu/widgets/chobby/components/chat_windows.lua index 61f90ec12..ec80f2828 100644 --- a/LuaMenu/widgets/chobby/components/chat_windows.lua +++ b/LuaMenu/widgets/chobby/components/chat_windows.lua @@ -728,7 +728,6 @@ function ChatWindows:GetChannelConsole(chanName) local channelConsole = self.channelConsoles[chanName] if channelConsole == nil then - local function MessageListener(message) if message:starts("/me ") then lobby:SayEx(chanName, message:sub(5)) @@ -736,7 +735,6 @@ function ChatWindows:GetChannelConsole(chanName) lobby:Say(chanName, message) end end - local function Resize(obj) self:UpdateOldChatLinePosition(obj) end @@ -820,7 +818,6 @@ function ChatWindows:GetPrivateChatConsole(userName, switchTo) local privateChatConsole = self.privateChatConsoles[chanName] if privateChatConsole == nil then - local function MessageListener(message) if message:starts("/me ") then lobby:SayPrivateEx(userName, message:sub(5)) @@ -828,7 +825,6 @@ function ChatWindows:GetPrivateChatConsole(userName, switchTo) lobby:SayPrivate(userName, message) end end - local function Resize(obj) self:UpdateOldChatLinePosition(obj) end diff --git a/LuaMenu/widgets/chobby/components/console.lua b/LuaMenu/widgets/chobby/components/console.lua index 088ec3d14..4b5bdd235 100644 --- a/LuaMenu/widgets/chobby/components/console.lua +++ b/LuaMenu/widgets/chobby/components/console.lua @@ -2,7 +2,6 @@ Console = LCS.class{} function Console:init(channelName, sendMessageListener, noHistoryLoad, onResizeFunc, isBattleChat) self.listener = sendMessageListener - self.sendMessageActions = sendMessageActions self.showDate = true self.dateFormat = "%H:%M" From 0aab90d43cd02b557efa94500c7799fa61349713 Mon Sep 17 00:00:00 2001 From: MasterBel2 Date: Fri, 10 Jul 2020 16:28:45 +1000 Subject: [PATCH 06/31] Remove extraneous whitespace to fix build. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plus adding a newline at the end of a single file, because that’s necessary too. --- LuaMenu/configs/gameConfig/zk/ModOptions.lua | 4 +- .../stable/config/behaviour.json | 2 +- .../stable/config/build_chain.json | 2 +- .../stable/config/commander.json | 2 +- .../widgets/api_battle_proposal_handler.lua | 42 +++++++++---------- LuaMenu/widgets/api_chili.lua | 4 +- LuaMenu/widgets/api_limit_fps.lua | 2 +- LuaMenu/widgets/chobby/components/console.lua | 2 +- LuaMenu/widgets/dbg_img_preload.lua | 2 +- .../widgets/gui_campaign_codex_handler.lua | 10 ++--- LuaMenu/widgets/gui_campaign_handler.lua | 14 +++---- LuaMenu/widgets/gui_queue_list_window.lua | 4 +- LuaMenu/widgets/gui_tutorial_handler.lua | 10 ++--- 13 files changed, 49 insertions(+), 51 deletions(-) diff --git a/LuaMenu/configs/gameConfig/zk/ModOptions.lua b/LuaMenu/configs/gameConfig/zk/ModOptions.lua index 6a382b3c6..68276f534 100644 --- a/LuaMenu/configs/gameConfig/zk/ModOptions.lua +++ b/LuaMenu/configs/gameConfig/zk/ModOptions.lua @@ -1,4 +1,3 @@ - -- $Id: ModOptions.lua 4642 2009-05-22 05:32:36Z carrepairer $ @@ -83,7 +82,7 @@ local options = { { key='none', name = "Off", desc = 'Turns commsharing off.' }, }, }, - + { key = "noelo", name = "No Elo", @@ -555,7 +554,6 @@ local options = { -- -- } -- }, -- }, - { key = 'chicken', name = 'Chicken', diff --git a/LuaMenu/configs/gameConfig/zk/defaultSettings/AI/Skirmish/DevCircuitEconomist/stable/config/behaviour.json b/LuaMenu/configs/gameConfig/zk/defaultSettings/AI/Skirmish/DevCircuitEconomist/stable/config/behaviour.json index c6b037ac1..10826fcf5 100644 --- a/LuaMenu/configs/gameConfig/zk/defaultSettings/AI/Skirmish/DevCircuitEconomist/stable/config/behaviour.json +++ b/LuaMenu/configs/gameConfig/zk/defaultSettings/AI/Skirmish/DevCircuitEconomist/stable/config/behaviour.json @@ -555,7 +555,7 @@ }, "hoverraid": { "role": ["raider"], - "attribute": ["melee","scout"], + "attribute": ["melee","scout"], "pwr_mod": 0.9, "pwr_mod": 0.8, "limit": 20, diff --git a/LuaMenu/configs/gameConfig/zk/defaultSettings/AI/Skirmish/DevCircuitEconomist/stable/config/build_chain.json b/LuaMenu/configs/gameConfig/zk/defaultSettings/AI/Skirmish/DevCircuitEconomist/stable/config/build_chain.json index 6bf30ada6..79f8e560e 100644 --- a/LuaMenu/configs/gameConfig/zk/defaultSettings/AI/Skirmish/DevCircuitEconomist/stable/config/build_chain.json +++ b/LuaMenu/configs/gameConfig/zk/defaultSettings/AI/Skirmish/DevCircuitEconomist/stable/config/build_chain.json @@ -190,4 +190,4 @@ } } } -} \ No newline at end of file +} diff --git a/LuaMenu/configs/gameConfig/zk/defaultSettings/AI/Skirmish/DevCircuitEconomist/stable/config/commander.json b/LuaMenu/configs/gameConfig/zk/defaultSettings/AI/Skirmish/DevCircuitEconomist/stable/config/commander.json index f6c1b5dcb..c4fd75dc8 100644 --- a/LuaMenu/configs/gameConfig/zk/defaultSettings/AI/Skirmish/DevCircuitEconomist/stable/config/commander.json +++ b/LuaMenu/configs/gameConfig/zk/defaultSettings/AI/Skirmish/DevCircuitEconomist/stable/config/commander.json @@ -376,4 +376,4 @@ } } } -} +} diff --git a/LuaMenu/widgets/api_battle_proposal_handler.lua b/LuaMenu/widgets/api_battle_proposal_handler.lua index 30c27b362..09a68aca2 100644 --- a/LuaMenu/widgets/api_battle_proposal_handler.lua +++ b/LuaMenu/widgets/api_battle_proposal_handler.lua @@ -48,7 +48,7 @@ local function CheckCancelProposal(message) }) end currentProposal = nil - + return true end @@ -56,7 +56,7 @@ local function GetProposalFromString(message) if string.sub(message, 1, 1) ~= "!" or string.sub(message, 1, 14) ~= "!proposebattle"then return false end - + local data = message:split(" ") local paramValues = {} for i = 1, #data do @@ -69,14 +69,14 @@ local function GetProposalFromString(message) end end end - + local proposalValues = { minelo = paramValues[1] or false, maxelo = paramValues[2] or false, minsize = math.max(1, math.floor(paramValues[3] or 4)), } proposalValues.maxsize = math.max(proposalValues.minsize, paramValues[4] or 8) - + return true, proposalValues end @@ -91,12 +91,12 @@ local function CheckProposalSent(prop) }) return false end - + currentProposal = prop - + currentProposal.currentPlayers = 1 currentProposal.acceptedPlayers = {} - + Chotify:Post({ title = "Battle Proposal", body = "New proposal sent.\nUse !endproposal to cancel.", @@ -121,17 +121,17 @@ function BattleProposalHandler.AddClickableInvites(userName, preMessage, message if myProposal and CheckCancelProposal(message) then return onTextClick, textTooltip end - + local hasProposal, prop = GetProposalFromString(message) if not hasProposal then return onTextClick, textTooltip end - + local myInfo = WG.LibLobby.lobby:GetMyInfo() local effectiveSkill = math.max(myInfo.skill or 1500, myInfo.casualSkill or 1500) local skillTooLow = (prop.minelo and effectiveSkill < prop.minelo) local skillTooHigh = (prop.maxelo and effectiveSkill > prop.maxelo) - + if myProposal then if skillTooLow then Chotify:Post({ @@ -146,13 +146,13 @@ function BattleProposalHandler.AddClickableInvites(userName, preMessage, message }) return onTextClick, textTooltip end - + CheckProposalSent(prop) end - + local startIndex = string.len(preMessage) local endIndex = startIndex + string.len(message) + 1 - + if not (skillTooLow or skillTooLow) then onTextClick[#onTextClick + 1] = { startIndex = startIndex, @@ -171,7 +171,7 @@ function BattleProposalHandler.AddClickableInvites(userName, preMessage, message } } end - + local proposalString if skillTooLow then proposalString = "Your skill rating is too low for this proposal." @@ -191,7 +191,7 @@ function BattleProposalHandler.AddClickableInvites(userName, preMessage, message end proposalString = proposalString .. "\nA battle will open when " .. prop.minsize .. " players accept." end - + textTooltip[#textTooltip + 1] = { startIndex = startIndex, endIndex = endIndex, @@ -223,7 +223,7 @@ function DelayedInitialize() if (currentProposal.minelo and effectiveSkill < currentProposal.minelo) or (currentProposal.maxelo and effectiveSkill > currentProposal.maxelo) then return end - + if currentProposal.battleHostComplete then lobby:BattleProposalBattleInvite(userName, currentProposal.battleID, currentProposal.password) Chotify:Post({ @@ -232,14 +232,14 @@ function DelayedInitialize() }) return end - + currentProposal.currentPlayers = currentProposal.currentPlayers + 1 currentProposal.acceptedPlayers[userName] = true Chotify:Post({ title = "Battle Proposal", body = userName .. " accepted.\nPlayers: " .. currentProposal.currentPlayers .. "/" .. currentProposal.minsize, }) - + if currentProposal.currentPlayers >= currentProposal.minsize and not currentProposal.openingBattleName then -- Check for users leaving for acceptedUserName, _ in pairs(currentProposal.acceptedPlayers) do @@ -249,7 +249,7 @@ function DelayedInitialize() currentProposal.currentPlayers = currentProposal.currentPlayers - 1 end end - + -- Host the battle if currentProposal.currentPlayers >= currentProposal.minsize then WG.BattleRoomWindow.LeaveBattle() @@ -272,7 +272,7 @@ function DelayedInitialize() if battleInfo.title ~= currentProposal.openingBattleName then return end - + for acceptedUserName, _ in pairs(currentProposal.acceptedPlayers) do lobby:BattleProposalBattleInvite(acceptedUserName, battleID, currentProposal.password) end @@ -294,7 +294,7 @@ function DelayedInitialize() body = "Joining " .. userName .. "'s battle", }) end - + lobby:AddListener("OnBattleProposalResponse", OnBattleProposalResponse) lobby:AddListener("OnJoinedBattle", OnJoinedBattle) lobby:AddListener("OnBattleProposalBattleInvite", OnBattleProposalBattleInvite) diff --git a/LuaMenu/widgets/api_chili.lua b/LuaMenu/widgets/api_chili.lua index 51f4c4b94..5e811b280 100644 --- a/LuaMenu/widgets/api_chili.lua +++ b/LuaMenu/widgets/api_chili.lua @@ -107,14 +107,14 @@ function widget:DrawScreen() gl.PopMatrix() end gl.Color(1,1,1,1) - + if loadFade then local vsx,vsy = gl.GetViewSizes() gl.Color(1,1,1,loadFade) gl.Texture(loadTex) gl.TexRect(0,0,vsx,vsy) gl.Color(1,1,1,1) - + if not hideInterface then loadFade = loadFade - 0.18 if loadFade <= 0 then diff --git a/LuaMenu/widgets/api_limit_fps.lua b/LuaMenu/widgets/api_limit_fps.lua index 773af4188..6cd3c8b77 100644 --- a/LuaMenu/widgets/api_limit_fps.lua +++ b/LuaMenu/widgets/api_limit_fps.lua @@ -101,7 +101,7 @@ function widget:AllowDraw() framesInBuffer = oldFramesInBuffer + 1 return true end - + return false end diff --git a/LuaMenu/widgets/chobby/components/console.lua b/LuaMenu/widgets/chobby/components/console.lua index 0dd969e1c..d22ff5ea9 100644 --- a/LuaMenu/widgets/chobby/components/console.lua +++ b/LuaMenu/widgets/chobby/components/console.lua @@ -335,7 +335,7 @@ function Console:AddMessage(message, userName, dateOverride, color, thirdPerson, end onTextClick, textTooltip = WG.BattleProposalHandler.AddClickableInvites(userName, txt, message, onTextClick or {}, textTooltip or {}) - + txt = txt .. message onTextClick, textTooltip = WG.BrowserHandler.AddClickableUrls(txt, onTextClick or {}, textTooltip or {}) diff --git a/LuaMenu/widgets/dbg_img_preload.lua b/LuaMenu/widgets/dbg_img_preload.lua index 00ecb3820..6fca749c3 100644 --- a/LuaMenu/widgets/dbg_img_preload.lua +++ b/LuaMenu/widgets/dbg_img_preload.lua @@ -24,7 +24,7 @@ local SCALE = 1 local holder local function MaybeAddFile(fileName) - if (string.find(fileName, "%.dds") or string.find(fileName, "%.png") or string.find(fileName, "%.jpg")) + if (string.find(fileName, "%.dds") or string.find(fileName, "%.png") or string.find(fileName, "%.jpg")) and not (string.find(fileName, "MinimapThumbnails"))then files[#files+1] = fileName end diff --git a/LuaMenu/widgets/gui_campaign_codex_handler.lua b/LuaMenu/widgets/gui_campaign_codex_handler.lua index b1e74fb28..36faf246a 100644 --- a/LuaMenu/widgets/gui_campaign_codex_handler.lua +++ b/LuaMenu/widgets/gui_campaign_codex_handler.lua @@ -155,7 +155,7 @@ local function PopulateCodexTree(parent, codexText, codexImage) nodes = nodes, --{"wtf", "lololol", {"omg"}}, } codexText:SetText("") - + for i = 1, #nodes do local catID = nodes[i][1] if categoryNewEntries[catID] > 0 then @@ -163,9 +163,9 @@ local function PopulateCodexTree(parent, codexText, codexImage) nodeObj:SetHighlight(true) end end - + local externalFunctions = {} - + function externalFunctions.OpenEntry(entryName) local entry = entryName and codexEntries[entryName] if not (entry and entryButtons[entryName]) then @@ -178,7 +178,7 @@ local function PopulateCodexTree(parent, codexText, codexImage) categoryNode:Expand() entryButtons[entryName].OnClick[1](entryButtons[entryName]) end - + return externalFunctions end @@ -272,7 +272,7 @@ local function InitializeControls(parentControl) codexFuncs.OpenEntry(entryName) end end - + return externalFunctions end diff --git a/LuaMenu/widgets/gui_campaign_handler.lua b/LuaMenu/widgets/gui_campaign_handler.lua index 494cdd9bf..11e8c3715 100644 --- a/LuaMenu/widgets/gui_campaign_handler.lua +++ b/LuaMenu/widgets/gui_campaign_handler.lua @@ -498,7 +498,7 @@ local function MakeRewardsPanel(parent, bottom, planetData, cullUnlocked, showCo if showCodex then if MakeRewardList(parent, bottom, "Codex", {{rewards.codexEntries, WG.CampaignData.GetCodexEntryInfo, WG.CampaignData.GetCodexEntryIsUnlocked, false, CodexClick}}, cullUnlocked, 3.96, 2) then bottom = bottom + 98 - + local singleplayerMenu = WG.Chobby.interfaceRoot.GetSingleplayerSubmenu() if singleplayerMenu then local campaignMenu = singleplayerMenu.GetSubmenuByName("campaign") @@ -666,7 +666,7 @@ local function MakeWinPopup(planetData, bonusObjectiveSuccess, difficulty) openCommanderWindowOnContinue = true end end - + function externalFunctions.CloseWinPopup(cancelCommPopup) if cancelCommPopup and openCommanderWindowOnContinue then openCommanderWindowOnContinue = false @@ -791,7 +791,7 @@ local function SelectPlanet(popupOverlay, planetHandler, planetID, planetData, s padding = {0, 0, 10, 0}, text = ((startable or Configuration.debugMode) and planetData.infoDisplay.text) or "This planet will need to be approached for further study.", font = Configuration:GetFont(3), - } + } local subPanel = Panel:New{ @@ -823,10 +823,10 @@ local function SelectPlanet(popupOverlay, planetHandler, planetID, planetData, s if planetData.infoDisplay.feedbackLink then MakeFeedbackButton(buttonHolder, planetData.infoDisplay.feedbackLink, nil, 0, 85, nil) end - + difficultyWindow = difficultyWindow or InitializeDifficultySetting() buttonHolder:AddChild(difficultyWindow) - + local startButton = Button:New{ right = 0, bottom = 0, @@ -987,7 +987,7 @@ local function SelectPlanet(popupOverlay, planetHandler, planetID, planetData, s local function SizeUpdate() local fluffFont = Configuration:GetFont(((planetHandler.height < 720) and 2) or 3) - local descFont = Configuration:GetFont(((planetHandler.height < 720) and 1) or 2) + local descFont = Configuration:GetFont(((planetHandler.height < 720) and 1) or 2) planetDesc.font.size = descFont.size planetDesc:Invalidate() @@ -1251,7 +1251,7 @@ local function GetPlanet(popupOverlay, planetListHolder, planetID, planetData, a local externalFunctions = {} externalFunctions.OpenPlanetScreen = OpenPlanetScreen - + function externalFunctions.StartPlanetMission() if not startable then return diff --git a/LuaMenu/widgets/gui_queue_list_window.lua b/LuaMenu/widgets/gui_queue_list_window.lua index daf14727b..08dd94e15 100644 --- a/LuaMenu/widgets/gui_queue_list_window.lua +++ b/LuaMenu/widgets/gui_queue_list_window.lua @@ -537,7 +537,7 @@ local function InitializeControls(window) queueHolders[queueName] = MakeQueueControl(listPanel, queues, queueName, queueDescription, queueData.playersIngame or "?", queueData.playersWaiting or "?", maxPartySize, GetBanTime) queues = queues + 1 - + local possibleQueues = lobby:GetQueues() local sortedQueues = {} @@ -559,7 +559,7 @@ local function InitializeControls(window) for name, data in pairs(possibleQueues) do sortedQueues[#sortedQueues + 1] = data end - + table.sort(sortedQueues, QueueSortFunc) local added = {} for i = 1, #sortedQueues do diff --git a/LuaMenu/widgets/gui_tutorial_handler.lua b/LuaMenu/widgets/gui_tutorial_handler.lua index cab5e0837..e479a0401 100644 --- a/LuaMenu/widgets/gui_tutorial_handler.lua +++ b/LuaMenu/widgets/gui_tutorial_handler.lua @@ -100,7 +100,7 @@ local function CheckTutorialPopup() draggable = false, classname = "main_window", } - + TextBox:New { x = 95, right = 15, @@ -173,9 +173,9 @@ local function CheckTutorialPopup() }, parent = tutorialWindow, } - + local popupHolder = WG.Chobby.PriorityPopup(tutorialWindow, CancelFunc, CancelFunc) - + return true end @@ -195,7 +195,7 @@ function DelayedInitialize() return end CheckTutorialPopup() - + local function onConfigurationChange(listener, key, value) if key ~= "firstBattleStarted" then return @@ -204,7 +204,7 @@ function DelayedInitialize() tutorialPrompt.Remove() end end - + Configuration:AddListener("OnConfigurationChange", onConfigurationChange) end From 026442c8caaff0c93a8edc912114fe1617d00b2a Mon Sep 17 00:00:00 2001 From: MasterBel2 Date: Fri, 10 Jul 2020 15:53:17 +1000 Subject: [PATCH 07/31] Store friends on `FRIENDLIST` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `Interface` had been forwarding the command to `Lobby` but `Lobby` wasn’t handling the list. Now: - updates `self.friends`, `self.friendCount`, and `self.isFriend[userName]` properties - updates `userInfo.isFriend` for the associated user object if they are online. - Hands the friends list to listeners (before, this was the only thing it did, resulting in an un-updated list being handed off) Also, for completeness, `Interface:FriendList()` and `:FriendRequestList()` now forward the calls to `self:super()`. Although this has no meaningful effect, a precedent for this is set with other calls, so this should prevent certain errors should `Lobby` ever care to use these calls. --- libs/liblobby/lobby/interface.lua | 2 ++ libs/liblobby/lobby/lobby.lua | 11 ++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/libs/liblobby/lobby/interface.lua b/libs/liblobby/lobby/interface.lua index 117664a13..1ce2f0846 100644 --- a/libs/liblobby/lobby/interface.lua +++ b/libs/liblobby/lobby/interface.lua @@ -49,11 +49,13 @@ end ------------------------ function Interface:FriendList() + self:super("FriendList") self:_SendCommand("FRIENDLIST", true) return self end function Interface:FriendRequestList() + self:super("FriendRequestList") self:_SendCommand("FRIENDREQUESTLIST", true) return self end diff --git a/libs/liblobby/lobby/lobby.lua b/libs/liblobby/lobby/lobby.lua index 90a916b37..9a9276ff9 100644 --- a/libs/liblobby/lobby/lobby.lua +++ b/libs/liblobby/lobby/lobby.lua @@ -596,7 +596,16 @@ function Lobby:_OnUnfriend(userName) self:_CallListeners("OnUnfriend", userName) end -function Lobby:_OnFriendList() +function Lobby:_OnFriendList(friends) + self.friends = friends + self.friendCount = #friends + + for _, userName in pairs(self.friends) do + self.isFriend[userName] = true + local userInfo = self:TryGetUser(userName) + userInfo.isFriend = true + end + self:_CallListeners("OnFriendList", self:GetFriends()) end From 6d300bf1f669af5ca6fd3390c6b285ee5dcb885f Mon Sep 17 00:00:00 2001 From: Gajo Petrovic Date: Mon, 14 Sep 2020 02:38:20 +0900 Subject: [PATCH 08/31] enforce unique teamID, close https://github.com/beyond-all-reason/BYAR-Chobby/issues/39 --- libs/liblobby/lobby/interface.lua | 25 +++++++++++++++++++++++++ libs/liblobby/lobby/lobby.lua | 4 ++-- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/libs/liblobby/lobby/interface.lua b/libs/liblobby/lobby/interface.lua index 1ce2f0846..6c678a9f9 100644 --- a/libs/liblobby/lobby/interface.lua +++ b/libs/liblobby/lobby/interface.lua @@ -644,11 +644,36 @@ Interface.commandPattern["UPDATEBATTLEINFO"] = "(%d+)%s+(%S+)%s+(%S+)%s+(%S+)%s+ function Interface:_OnClientBattleStatus(userName, battleStatus, teamColor) local status = ParseBattleStatus(battleStatus) status.teamColor = ParseTeamColor(teamColor) + self:_OnUpdateUserBattleStatus(userName, status) + if userName == self.myUserName then + self:_EnsureMyTeamNumberIsUnique() + end end Interface.commands["CLIENTBATTLESTATUS"] = Interface._OnClientBattleStatus Interface.commandPattern["CLIENTBATTLESTATUS"] = "(%S+)%s+(%S+)%s+(%S+)" +function Interface:_EnsureMyTeamNumberIsUnique() + local myBattleStatus = self.userBattleStatus[self.myUserName] + if myBattleStatus == nil then + return + end + + if myBattleStatus.isSpectator then + return + end + + for name, data in pairs(self.userBattleStatus) do + if name ~= self.myUserName and data.teamNumber == myBattleStatus.teamNumber and not data.isSpectator then + -- need to change teamID so it's unique + self:SetBattleStatus({ + teamNumber = self:GetUnusedTeamID() + }) + break + end + end +end + function Interface:_OnAddBot(battleID, name, owner, battleStatus, teamColor, aiDll) battleID = tonumber(battleID) local status = ParseBattleStatus(battleStatus) diff --git a/libs/liblobby/lobby/lobby.lua b/libs/liblobby/lobby/lobby.lua index 9a9276ff9..be35320cb 100644 --- a/libs/liblobby/lobby/lobby.lua +++ b/libs/liblobby/lobby/lobby.lua @@ -1359,8 +1359,8 @@ function Lobby:GetUnusedTeamID() local unusedTeamID = 0 local takenTeamID = {} for name, data in pairs(self.userBattleStatus) do - if data.TeamNumber and not data.isSpectator then - local teamID = data.teamNumber + local teamID = data.teamNumber + if teamID and not data.isSpectator then takenTeamID[teamID] = true while takenTeamID[unusedTeamID] do unusedTeamID = unusedTeamID + 1 From c3d6f2ebbe356ae41ff31caa6a59cc22f1739363 Mon Sep 17 00:00:00 2001 From: Gajo Petrovic Date: Sat, 3 Oct 2020 02:25:13 +0900 Subject: [PATCH 09/31] misc: - implement sp flag, close https://github.com/Spring-Chobby/Chobby/issues/462 - attempt (fail - what's missing?) to address https://github.com/beyond-all-reason/BYAR-Chobby/issues/1 --- libs/chiliui/chili/controls/screen.lua | 4 ++-- libs/liblobby/lobby/interface.lua | 9 ++++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/libs/chiliui/chili/controls/screen.lua b/libs/chiliui/chili/controls/screen.lua index 260caec93..9152bb664 100644 --- a/libs/chiliui/chili/controls/screen.lua +++ b/libs/chiliui/chili/controls/screen.lua @@ -42,7 +42,7 @@ local inherited = this.inherited function Screen:New(obj) local vsx, vsy = Spring.GetViewSizes() - + if ((obj.width or -1) <= 0) then obj.width = vsx end @@ -172,7 +172,7 @@ function Screen:IsAbove(x, y, ...) return end -- What is this for? - + local activeControl = UnlinkSafe(self.activeControl) if activeControl then self.currentTooltip = activeControl.tooltip diff --git a/libs/liblobby/lobby/interface.lua b/libs/liblobby/lobby/interface.lua index 6c678a9f9..5f9054286 100644 --- a/libs/liblobby/lobby/interface.lua +++ b/libs/liblobby/lobby/interface.lua @@ -32,7 +32,7 @@ function Interface:Login(user, password, cpu, localIP, lobbyVersion) localIP = "*" end password = VFS.CalculateHash(password, 0) - sentence = "LuaLobby " .. lobbyVersion .. "\t" .. self.agent .. "\t" .. "b" + sentence = "LuaLobby " .. lobbyVersion .. "\t" .. self.agent .. "\t" .. "b sp" cmd = concat("LOGIN", user, password, "0", localIP, sentence) self:_SendCommand(cmd) return self @@ -201,6 +201,10 @@ function Interface:RejoinBattle(battleID) end function Interface:JoinBattle(battleID, password, scriptPassword) + if scriptPassword == nil then + scriptPassword = tostring(math.floor(math.random() * 65536)) .. tostring(math.floor(math.random() * 65536)) + end + password = password or "" self:super("JoinBattle", battleID, password, scriptPassword) self:_SendCommand(concat("JOINBATTLE", battleID, password, scriptPassword)) return self @@ -613,6 +617,9 @@ Interface.commandPattern["JOINBATTLE"] = "(%d+)%s+(%S+)" function Interface:_OnJoinedBattle(battleID, userName, scriptPassword) battleID = tonumber(battleID) + if userName == self.myUserName then + self.scriptPassword = scriptPassword + end self:super("_OnJoinedBattle", battleID, userName, scriptPassword) end Interface.commands["JOINEDBATTLE"] = Interface._OnJoinedBattle From 3c947b30ed5e5ec1e546cfd5f5760db5f4e34962 Mon Sep 17 00:00:00 2001 From: rlcevg Date: Mon, 5 Oct 2020 18:56:22 +0300 Subject: [PATCH 10/31] StartScript with Side and AIOptions --- libs/liblobby/lobby/interface_skirmish.lua | 30 +++++++++++++++------- libs/liblobby/lobby/lobby.lua | 8 ++++-- 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/libs/liblobby/lobby/interface_skirmish.lua b/libs/liblobby/lobby/interface_skirmish.lua index 20cc26277..79e78076c 100644 --- a/libs/liblobby/lobby/interface_skirmish.lua +++ b/libs/liblobby/lobby/interface_skirmish.lua @@ -7,16 +7,24 @@ function InterfaceSkirmish:init() self.useTeamColor = true end -function InterfaceSkirmish:WriteTable(key, value) - local str = '\t['..key..']\n\t{\n' +function InterfaceSkirmish:WriteTable(key, value, tabs) + local str = tabs..'['..key..']\n'..tabs..'{\n' + + -- First write Tables for k, v in pairs(value) do if type(v) == 'table' then - str = str .. self:WriteTable(k, v) - else - str = str..'\t\t'..k..' = '..v..';\n' + str = str .. self:WriteTable(k, v, tabs .. '\t') + end + end + + -- Then the rest (purely for aesthetics) + for k, v in pairs(value) do + if type(v) ~= 'table' then + str = str..tabs..'\t'..k..' = '..v..';\n' end end - return str .. '\t}\n\n' + + return str .. tabs .. '}\n' end function InterfaceSkirmish:MakeScriptTXT(script) @@ -25,7 +33,7 @@ function InterfaceSkirmish:MakeScriptTXT(script) -- First write Tables for key, value in pairs(script) do if type(value) == 'table' then - str = str .. self:WriteTable(key, value) + str = str .. self:WriteTable(key, value, '\t') .. '\n' end end @@ -149,6 +157,7 @@ function InterfaceSkirmish:_StartScript(gameName, mapName, playerName, friendLis IsFromDemo = 0, ShortName = data.aiLib, Version = data.aiVersion, + options = data.aiOptions, Host = 0, } end @@ -157,6 +166,7 @@ function InterfaceSkirmish:_StartScript(gameName, mapName, playerName, friendLis TeamLeader = 0, AllyTeam = data.allyNumber, RgbColor = getTeamColor(userName), + Side = data.side, } maxAllyTeamID = math.max(maxAllyTeamID, data.allyNumber) @@ -408,13 +418,15 @@ end -- BEGIN Client commands ------------------------------------------------- -function InterfaceSkirmish:AddAi(aiName, aiLib, allyNumber, version) - self:super("AddAi", aiName, aiLib, allyNumber, version) +function InterfaceSkirmish:AddAi(aiName, aiLib, allyNumber, version, side, options) + self:super("AddAi", aiName, aiLib, allyNumber, version, side, options) self:_OnAddAi(self:GetMyBattleID(), aiName, { aiLib = aiLib, allyNumber = allyNumber, owner = self:GetMyUserName(), aiVersion = version, + side = side, + aiOptions = options, }) end diff --git a/libs/liblobby/lobby/lobby.lua b/libs/liblobby/lobby/lobby.lua index be35320cb..920853e5f 100644 --- a/libs/liblobby/lobby/lobby.lua +++ b/libs/liblobby/lobby/lobby.lua @@ -228,7 +228,7 @@ function Lobby:SetBattleStatus(status) return self end -function Lobby:AddAi(aiName, aiLib, allyNumber, version) +function Lobby:AddAi(aiName, aiLib, allyNumber, version, side, options) return self end @@ -861,8 +861,10 @@ function Lobby:_OnUpdateUserBattleStatus(userName, status) userData.isSpectator = status.isSpectator end userData.sync = status.sync or userData.sync + userData.side = status.side or userData.side userData.aiLib = status.aiLib or userData.aiLib userData.aiVersion = status.aiVersion or userData.aiVersion + userData.aiOptions = status.aiOptions or userData.aiOptions userData.owner = status.owner or userData.owner userData.teamColor = status.teamColor or userData.teamColor @@ -870,10 +872,12 @@ function Lobby:_OnUpdateUserBattleStatus(userName, status) status.teamNumber = userData.teamNumber status.isSpectator = userData.isSpectator status.sync = userData.sync + status.side = userData.side status.aiLib = userData.aiLib status.aiVersion = userData.aiVersion + status.aiOptions = userData.aiOptions status.owner = userData.owner - status.teamColor = userData.teamColor + status.teamColor = userData.teamColor self:_CallListeners("OnUpdateUserBattleStatus", userName, status) if changedSpectator or changedAllyTeam then From d388d7454e99c52719900e249f3f25d5875d6de3 Mon Sep 17 00:00:00 2001 From: rlcevg Date: Tue, 6 Oct 2020 16:39:19 +0300 Subject: [PATCH 11/31] AIOptions window --- .../chobby/components/ai_list_window.lua | 14 +- .../chobby/components/aioptions_window.lua | 226 ++++++++++++++++++ LuaMenu/widgets/chobby/core.lua | 1 + libs/liblobby/lobby/interface_skirmish.lua | 2 +- 4 files changed, 238 insertions(+), 5 deletions(-) create mode 100644 LuaMenu/widgets/chobby/components/aioptions_window.lua diff --git a/LuaMenu/widgets/chobby/components/ai_list_window.lua b/LuaMenu/widgets/chobby/components/ai_list_window.lua index 0d3509f6a..d6365e1c6 100644 --- a/LuaMenu/widgets/chobby/components/ai_list_window.lua +++ b/LuaMenu/widgets/chobby/components/ai_list_window.lua @@ -19,6 +19,7 @@ function AiListWindow:init(gameName) end end + function AiListWindow:CompareItems(id1, id2) local order = Configuration.simpleAiList and Configuration.gameConfig.simpleAiOrder if order then @@ -79,15 +80,20 @@ function AiListWindow:AddAiToList(ai, blackList, oldAiVersions, isRunning64Bit) tooltip = tooltip, OnClick = { function() - self:AddAi(displayName, shortName, ai.version) - self:HideWindow() + local path = "AI/Skirmish/"..ai.shortName.."/"..ai.version.."/AIOptions.lua" + if VFS.FileExists(path) then + WG.Chobby.AiOptionsWindow(self, ai, displayName, path) + else + self:AddAi(displayName, shortName, ai.version) + self:HideWindow() + end end }, } self:AddRow({addAIButton}, displayName) end -function AiListWindow:AddAi(displayName, shortName, version) +function AiListWindow:AddAi(displayName, shortName, version, side, options) local aiName local counter = 1 local found = true @@ -106,7 +112,7 @@ function AiListWindow:AddAi(displayName, shortName, version) end counter = counter + 1 end - self.lobby:AddAi(aiName, shortName, self.allyTeam, version) + self.lobby:AddAi(aiName, shortName, self.allyTeam, version, side, options) Configuration:SetConfigValue("lastAddedAiName", shortName) end diff --git a/LuaMenu/widgets/chobby/components/aioptions_window.lua b/LuaMenu/widgets/chobby/components/aioptions_window.lua new file mode 100644 index 000000000..89248e8eb --- /dev/null +++ b/LuaMenu/widgets/chobby/components/aioptions_window.lua @@ -0,0 +1,226 @@ +AiOptionsWindow = ListWindow:extends{} + +function AiOptionsWindow:init(parent, ai, displayName, path) + self:super('init', lobbyInterfaceHolder, ai.shortName.." Options", false, "main_window", nil, {6, 7, 7, 4}) + self.window:SetPos(nil, nil, 650, 700) + WG.Chobby.PriorityPopup(self.window, nil, nil, nil, true) + + self.aioptions = {} + + local applyBtn = Button:New { + right = 120, + y = 7, + width = 80, + height = 45, + caption = i18n("apply"), + font = WG.Chobby.Configuration:GetFont(3), + parent = self.window, + classname = "action_button", + OnClick = { + function() + parent:AddAi(displayName, ai.shortName, ai.version, nil, self.aioptions) + self:HideWindow() + parent:HideWindow() + end + }, + } + + local options = VFS.Include(path) + for i = #options, 1, -1 do + self:AddEntry(options[i], i) + end +end + +function AiOptionsWindow:AddEntry(data, index) + if data.hide or data.type == "section" then + return + end + + self.aioptions[data.key] = tostring(data.def) + + if data.type == "list" then + self:AddRow({self:MakeList(data)}, index) + elseif data.type == "bool" then + self:AddRow({self:MakeBool(data)}, index) + elseif data.type == "number" then + self:AddRow({self:MakeNumber(data)}, index) + elseif data.type == "string" then + self:AddRow({self:MakeString(data)}, index) + end + + return +end + +function AiOptionsWindow:MakeList(data) + local label = Label:New { + x = 5, + y = 0, + width = 350, + height = 30, + valign = "center", + align = "left", + caption = data.name, + font = WG.Chobby.Configuration:GetFont(2), + } + + local defaultItem = 1 + local keyList = {} + local nameList = {} + for i, itemData in pairs(data.items) do + keyList[i] = itemData.key + nameList[i] = itemData.name + + if itemData.key == data.def then + defaultItem = i + end + end + + local list = ComboBox:New { + x = 340, + y = 1, + width = 250, + height = 30, + items = nameList, + tooltip = data.desc, + font = WG.Chobby.Configuration:GetFont(2), + itemFontSize = WG.Chobby.Configuration:GetFont(2).size, + selected = defaultItem, + OnSelect = { + function (obj) + self.aioptions[data.key] = keyList[obj.selected] + end + }, + } + + return Control:New { + x = 0, + y = 0, + width = 600, + height = 32, + padding = {0, 0, 0, 0}, + children = { + label, + list + } + } +end + +function AiOptionsWindow:MakeBool(data) + local checkBox = Checkbox:New { + x = 5, + y = 0, + width = 355, + height = 40, + boxalign = "right", + boxsize = 20, + caption = data.name, + checked = data.def, + tooltip = data.desc, + font = WG.Chobby.Configuration:GetFont(2), + + OnChange = { + function (obj, newState) + self.aioptions[data.key] = tostring(newState) + end + }, + } + + return checkBox +end + +function AiOptionsWindow:MakeNumber(data) + local label = Label:New { + x = 5, + y = 0, + width = 350, + height = 30, + valign = "center", + align = "left", + caption = data.name, + font = WG.Chobby.Configuration:GetFont(2), + } + + local oldText = tostring(data.def); + + local numberBox = EditBox:New { + x = 340, + y = 1, + width = 250, + height = 30, + text = oldText, + useIME = false, + tooltip = data.desc, + fontSize = WG.Chobby.Configuration:GetFont(2).size, + OnFocusUpdate = { + function (obj) + if obj.focused then + return + end + + if not tonumber(obj.text) then + obj:SetText(oldText) + return + end + + oldText = obj.text + self.aioptions[data.key] = obj.text + end + } + } + + return Control:New { + x = 0, + y = 0, + width = 600, + height = 32, + padding = {0, 0, 0, 0}, + children = { + label, + numberBox + } + } +end + +function AiOptionsWindow:MakeString(data) + local label = Label:New { + x = 5, + y = 0, + width = 350, + height = 30, + valign = "center", + align = "left", + caption = data.name, + font = WG.Chobby.Configuration:GetFont(2), + } + + local textBox = EditBox:New { + x = 340, + y = 1, + width = 250, + height = 30, + text = data.def, + useIME = false, + tooltip = data.desc, + fontSize = WG.Chobby.Configuration:GetFont(2).size, + OnFocusUpdate = { + function (obj) + if obj.focused then + return + end + self.aioptions[data.key] = obj.text + end + } + } + + return Control:New { + x = 0, + y = 0, + width = 600, + height = 32, + padding = {0, 0, 0, 0}, + children = { + label, + textBox + } + } +end diff --git a/LuaMenu/widgets/chobby/core.lua b/LuaMenu/widgets/chobby/core.lua index c10fb4904..52dddeffd 100644 --- a/LuaMenu/widgets/chobby/core.lua +++ b/LuaMenu/widgets/chobby/core.lua @@ -33,6 +33,7 @@ local includes = { "components/submenu_handler.lua", "components/priority_popup.lua", "components/ai_list_window.lua", + "components/aioptions_window.lua", "components/game_list_window.lua", "components/confirmation_popup.lua", "components/information_popup.lua", diff --git a/libs/liblobby/lobby/interface_skirmish.lua b/libs/liblobby/lobby/interface_skirmish.lua index 79e78076c..39bdc5d8d 100644 --- a/libs/liblobby/lobby/interface_skirmish.lua +++ b/libs/liblobby/lobby/interface_skirmish.lua @@ -28,7 +28,7 @@ function InterfaceSkirmish:WriteTable(key, value, tabs) end function InterfaceSkirmish:MakeScriptTXT(script) - local str = '[Game]\n{\n\n' + local str = '[Game]\n{\n' -- First write Tables for key, value in pairs(script) do From 9ca626c53ca27876d42c4b4561a37a8b819595e1 Mon Sep 17 00:00:00 2001 From: rlcevg Date: Tue, 6 Oct 2020 23:58:33 +0300 Subject: [PATCH 12/31] AI side selection and gameConfig.skirmishDefault.AIOptionsEnabled option --- .../chobby/components/ai_list_window.lua | 37 +++++++--- .../chobby/components/aioptions_window.lua | 70 +++++++++++++++++-- LuaMenu/widgets/gui_battle_room_window.lua | 18 ++++- 3 files changed, 105 insertions(+), 20 deletions(-) diff --git a/LuaMenu/widgets/chobby/components/ai_list_window.lua b/LuaMenu/widgets/chobby/components/ai_list_window.lua index d6365e1c6..e7eaad8c4 100644 --- a/LuaMenu/widgets/chobby/components/ai_list_window.lua +++ b/LuaMenu/widgets/chobby/components/ai_list_window.lua @@ -78,21 +78,36 @@ function AiListWindow:AddAiToList(ai, blackList, oldAiVersions, isRunning64Bit) caption = displayName, font = Configuration:GetFont(3), tooltip = tooltip, - OnClick = { - function() - local path = "AI/Skirmish/"..ai.shortName.."/"..ai.version.."/AIOptions.lua" - if VFS.FileExists(path) then - WG.Chobby.AiOptionsWindow(self, ai, displayName, path) - else - self:AddAi(displayName, shortName, ai.version) - self:HideWindow() - end - end - }, + OnClick = { self:GetOnAddAiFunc(ai, displayName, shortName) }, } self:AddRow({addAIButton}, displayName) end +function AiListWindow:GetOnAddAiFunc(ai, displayName, shortName) + local function defaultAction() + self:AddAi(displayName, shortName, ai.version) + self:HideWindow() + end + + local singleplayerDefault = WG.Chobby.Configuration.gameConfig.skirmishDefault + if not singleplayerDefault or not singleplayerDefault.AIOptionsEnabled then + return defaultAction + end + + return function() + local path = "AI/Skirmish/"..ai.shortName.."/"..ai.version.."/AIOptions.lua" + if VFS.FileExists(path) then + local successFunc = function(side, aioptions) + self:AddAi(displayName, shortName, ai.version, side, aioptions) + self:HideWindow() + end + WG.Chobby.AiOptionsWindow(displayName, path, successFunc) + else + defaultAction() + end + end +end + function AiListWindow:AddAi(displayName, shortName, version, side, options) local aiName local counter = 1 diff --git a/LuaMenu/widgets/chobby/components/aioptions_window.lua b/LuaMenu/widgets/chobby/components/aioptions_window.lua index 89248e8eb..0b7bd294d 100644 --- a/LuaMenu/widgets/chobby/components/aioptions_window.lua +++ b/LuaMenu/widgets/chobby/components/aioptions_window.lua @@ -1,7 +1,7 @@ AiOptionsWindow = ListWindow:extends{} -function AiOptionsWindow:init(parent, ai, displayName, path) - self:super('init', lobbyInterfaceHolder, ai.shortName.." Options", false, "main_window", nil, {6, 7, 7, 4}) +function AiOptionsWindow:init(displayName, optionsPath, successFunc) + self:super('init', lobbyInterfaceHolder, displayName.." Options", false, "main_window", nil, {6, 7, 7, 4}) self.window:SetPos(nil, nil, 650, 700) WG.Chobby.PriorityPopup(self.window, nil, nil, nil, true) @@ -18,17 +18,33 @@ function AiOptionsWindow:init(parent, ai, displayName, path) classname = "action_button", OnClick = { function() - parent:AddAi(displayName, ai.shortName, ai.version, nil, self.aioptions) + successFunc(self.side, self.aioptions) self:HideWindow() - parent:HideWindow() end }, } - local options = VFS.Include(path) + -- AIOptions + local options = VFS.Include(optionsPath) for i = #options, 1, -1 do self:AddEntry(options[i], i) end + + -- AI side + local singleplayer = WG.Chobby.Configuration.singleplayer + if singleplayer then + local items = {} + for i, side in pairs(singleplayer.sidedata) do + items[i] = side.name + end + + local data = { + name = "Select side", + def = 1, + nameList = items, + } + self:AddRow({self:MakeSideList(data)}, #options + 1) + end end function AiOptionsWindow:AddEntry(data, index) @@ -47,8 +63,6 @@ function AiOptionsWindow:AddEntry(data, index) elseif data.type == "string" then self:AddRow({self:MakeString(data)}, index) end - - return end function AiOptionsWindow:MakeList(data) @@ -224,3 +238,45 @@ function AiOptionsWindow:MakeString(data) } } end + +function AiOptionsWindow:MakeSideList(data) + local label = Label:New { + x = 5, + y = 0, + width = 350, + height = 30, + valign = "center", + align = "left", + caption = data.name, + font = WG.Chobby.Configuration:GetFont(3), + } + + local list = ComboBox:New { + x = 340, + y = 1, + width = 250, + height = 30, + items = data.nameList, + font = WG.Chobby.Configuration:GetFont(3), + itemFontSize = WG.Chobby.Configuration:GetFont(3).size, + selectByName = true, + selected = 1, + OnSelectName = { + function (obj, selectedName) + self.side = selectedName + end + }, + } + + return Control:New { + x = 0, + y = 0, + width = 600, + height = 32, + padding = {0, 0, 0, 0}, + children = { + label, + list + } + } +end diff --git a/LuaMenu/widgets/gui_battle_room_window.lua b/LuaMenu/widgets/gui_battle_room_window.lua index 9c333ded8..17a96ca93 100644 --- a/LuaMenu/widgets/gui_battle_room_window.lua +++ b/LuaMenu/widgets/gui_battle_room_window.lua @@ -2150,13 +2150,27 @@ function BattleRoomWindow.SetSingleplayerGame(ToggleShowFunc, battleroomObj, tab local function SetGameSucess(name) singleplayerGame = name ToggleShowFunc(battleroomObj, tabData) + + local singleplayerDefault = WG.Chobby.Configuration.gameConfig.skirmishDefault + if not singleplayerDefault or not singleplayerDefault.AIOptionsEnabled then + return + end + + local singleplayer = WG.Chobby.Configuration.singleplayer + if (not singleplayer or singleplayer.game ~= name) and VFS.MapArchive(name) then + singleplayer = { + game = name, + sidedata = VFS.Include("gamedata/sidedata.lua"), + } + WG.Chobby.Configuration.singleplayer = singleplayer + VFS.UnmapArchive(name) + end end local config = WG.Chobby.Configuration local skirmishGame = config:GetDefaultGameName() if skirmishGame then - singleplayerGame = skirmishGame - ToggleShowFunc(battleroomObj, tabData) + SetGameSucess(skirmishGame) else WG.Chobby.GameListWindow(SetGameFail, SetGameSucess) end From 1d8bbd2e81fcac2f325f92f54e73feb14912b4a2 Mon Sep 17 00:00:00 2001 From: rlcevg Date: Sat, 10 Oct 2020 00:18:59 +0300 Subject: [PATCH 13/31] Remove Side from AIOptions --- .../chobby/components/ai_list_window.lua | 56 ++++++++--------- .../chobby/components/aioptions_window.lua | 60 +------------------ LuaMenu/widgets/gui_battle_room_window.lua | 15 ----- libs/liblobby/lobby/interface_skirmish.lua | 5 +- libs/liblobby/lobby/lobby.lua | 2 +- 5 files changed, 32 insertions(+), 106 deletions(-) diff --git a/LuaMenu/widgets/chobby/components/ai_list_window.lua b/LuaMenu/widgets/chobby/components/ai_list_window.lua index e7eaad8c4..8d963edb0 100644 --- a/LuaMenu/widgets/chobby/components/ai_list_window.lua +++ b/LuaMenu/widgets/chobby/components/ai_list_window.lua @@ -78,37 +78,37 @@ function AiListWindow:AddAiToList(ai, blackList, oldAiVersions, isRunning64Bit) caption = displayName, font = Configuration:GetFont(3), tooltip = tooltip, - OnClick = { self:GetOnAddAiFunc(ai, displayName, shortName) }, + OnClick = { + function() + local function defaultAction() + self:AddAi(displayName, shortName, ai.version) + self:HideWindow() + end + + local skirmishDefault = WG.Chobby.Configuration.gameConfig.skirmishDefault + if not skirmishDefault or not skirmishDefault.AIOptionsEnabled then + defaultAction() + return + end + + local path = "AI/Skirmish/" .. ai.shortName .. "/" .. ai.version .. "/AIOptions.lua" + if not VFS.FileExists(path) then + defaultAction() + return + end + + local successFunc = function(aioptions) + self:AddAi(displayName, shortName, ai.version, aioptions) + self:HideWindow() + end + WG.Chobby.AiOptionsWindow(displayName, path, successFunc) + end + }, } self:AddRow({addAIButton}, displayName) end -function AiListWindow:GetOnAddAiFunc(ai, displayName, shortName) - local function defaultAction() - self:AddAi(displayName, shortName, ai.version) - self:HideWindow() - end - - local singleplayerDefault = WG.Chobby.Configuration.gameConfig.skirmishDefault - if not singleplayerDefault or not singleplayerDefault.AIOptionsEnabled then - return defaultAction - end - - return function() - local path = "AI/Skirmish/"..ai.shortName.."/"..ai.version.."/AIOptions.lua" - if VFS.FileExists(path) then - local successFunc = function(side, aioptions) - self:AddAi(displayName, shortName, ai.version, side, aioptions) - self:HideWindow() - end - WG.Chobby.AiOptionsWindow(displayName, path, successFunc) - else - defaultAction() - end - end -end - -function AiListWindow:AddAi(displayName, shortName, version, side, options) +function AiListWindow:AddAi(displayName, shortName, version, options) local aiName local counter = 1 local found = true @@ -127,7 +127,7 @@ function AiListWindow:AddAi(displayName, shortName, version, side, options) end counter = counter + 1 end - self.lobby:AddAi(aiName, shortName, self.allyTeam, version, side, options) + self.lobby:AddAi(aiName, shortName, self.allyTeam, version, options) Configuration:SetConfigValue("lastAddedAiName", shortName) end diff --git a/LuaMenu/widgets/chobby/components/aioptions_window.lua b/LuaMenu/widgets/chobby/components/aioptions_window.lua index 0b7bd294d..c4c6368af 100644 --- a/LuaMenu/widgets/chobby/components/aioptions_window.lua +++ b/LuaMenu/widgets/chobby/components/aioptions_window.lua @@ -18,7 +18,7 @@ function AiOptionsWindow:init(displayName, optionsPath, successFunc) classname = "action_button", OnClick = { function() - successFunc(self.side, self.aioptions) + successFunc(self.aioptions) self:HideWindow() end }, @@ -29,22 +29,6 @@ function AiOptionsWindow:init(displayName, optionsPath, successFunc) for i = #options, 1, -1 do self:AddEntry(options[i], i) end - - -- AI side - local singleplayer = WG.Chobby.Configuration.singleplayer - if singleplayer then - local items = {} - for i, side in pairs(singleplayer.sidedata) do - items[i] = side.name - end - - local data = { - name = "Select side", - def = 1, - nameList = items, - } - self:AddRow({self:MakeSideList(data)}, #options + 1) - end end function AiOptionsWindow:AddEntry(data, index) @@ -238,45 +222,3 @@ function AiOptionsWindow:MakeString(data) } } end - -function AiOptionsWindow:MakeSideList(data) - local label = Label:New { - x = 5, - y = 0, - width = 350, - height = 30, - valign = "center", - align = "left", - caption = data.name, - font = WG.Chobby.Configuration:GetFont(3), - } - - local list = ComboBox:New { - x = 340, - y = 1, - width = 250, - height = 30, - items = data.nameList, - font = WG.Chobby.Configuration:GetFont(3), - itemFontSize = WG.Chobby.Configuration:GetFont(3).size, - selectByName = true, - selected = 1, - OnSelectName = { - function (obj, selectedName) - self.side = selectedName - end - }, - } - - return Control:New { - x = 0, - y = 0, - width = 600, - height = 32, - padding = {0, 0, 0, 0}, - children = { - label, - list - } - } -end diff --git a/LuaMenu/widgets/gui_battle_room_window.lua b/LuaMenu/widgets/gui_battle_room_window.lua index 17a96ca93..5130ca23c 100644 --- a/LuaMenu/widgets/gui_battle_room_window.lua +++ b/LuaMenu/widgets/gui_battle_room_window.lua @@ -2150,21 +2150,6 @@ function BattleRoomWindow.SetSingleplayerGame(ToggleShowFunc, battleroomObj, tab local function SetGameSucess(name) singleplayerGame = name ToggleShowFunc(battleroomObj, tabData) - - local singleplayerDefault = WG.Chobby.Configuration.gameConfig.skirmishDefault - if not singleplayerDefault or not singleplayerDefault.AIOptionsEnabled then - return - end - - local singleplayer = WG.Chobby.Configuration.singleplayer - if (not singleplayer or singleplayer.game ~= name) and VFS.MapArchive(name) then - singleplayer = { - game = name, - sidedata = VFS.Include("gamedata/sidedata.lua"), - } - WG.Chobby.Configuration.singleplayer = singleplayer - VFS.UnmapArchive(name) - end end local config = WG.Chobby.Configuration diff --git a/libs/liblobby/lobby/interface_skirmish.lua b/libs/liblobby/lobby/interface_skirmish.lua index 39bdc5d8d..2c0a999ba 100644 --- a/libs/liblobby/lobby/interface_skirmish.lua +++ b/libs/liblobby/lobby/interface_skirmish.lua @@ -418,14 +418,13 @@ end -- BEGIN Client commands ------------------------------------------------- -function InterfaceSkirmish:AddAi(aiName, aiLib, allyNumber, version, side, options) - self:super("AddAi", aiName, aiLib, allyNumber, version, side, options) +function InterfaceSkirmish:AddAi(aiName, aiLib, allyNumber, version, options) + self:super("AddAi", aiName, aiLib, allyNumber, version, options) self:_OnAddAi(self:GetMyBattleID(), aiName, { aiLib = aiLib, allyNumber = allyNumber, owner = self:GetMyUserName(), aiVersion = version, - side = side, aiOptions = options, }) end diff --git a/libs/liblobby/lobby/lobby.lua b/libs/liblobby/lobby/lobby.lua index 920853e5f..967be1637 100644 --- a/libs/liblobby/lobby/lobby.lua +++ b/libs/liblobby/lobby/lobby.lua @@ -228,7 +228,7 @@ function Lobby:SetBattleStatus(status) return self end -function Lobby:AddAi(aiName, aiLib, allyNumber, version, side, options) +function Lobby:AddAi(aiName, aiLib, allyNumber, version, options) return self end From 39b03e7e2dcd49bfc6550d63ef975b7344525b51 Mon Sep 17 00:00:00 2001 From: Gajo Petrovic Date: Sun, 25 Oct 2020 09:59:45 +0900 Subject: [PATCH 14/31] close https://github.com/Spring-Chobby/Chobby/issues/517 : give AIs a unique teamID --- libs/liblobby/lobby/interface.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/liblobby/lobby/interface.lua b/libs/liblobby/lobby/interface.lua index 5f9054286..48d02d05d 100644 --- a/libs/liblobby/lobby/interface.lua +++ b/libs/liblobby/lobby/interface.lua @@ -281,7 +281,7 @@ end function Interface:AddAi(aiName, aiLib, allyNumber, version) local battleStatus = { isReady = true, - teamNumber = allyNumber, + teamNumber = self:GetUnusedTeamID(), allyNumber = allyNumber, playMode = true, sync = true, From 405f1866932066485b1e2417b9e47dccd7dbd106 Mon Sep 17 00:00:00 2001 From: Gajo Petrovic Date: Sun, 25 Oct 2020 16:55:14 +0900 Subject: [PATCH 15/31] - try to prevent the client from forcing the playerID too many times close https://github.com/beyond-all-reason/BYAR-Chobby/issues/54 - also do a probably-irrelevant change to how "empty" passwords are being sent (https://github.com/beyond-all-reason/BYAR-Chobby/issues/1) --- libs/liblobby/lobby/interface.lua | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/libs/liblobby/lobby/interface.lua b/libs/liblobby/lobby/interface.lua index 48d02d05d..d2094d53f 100644 --- a/libs/liblobby/lobby/interface.lua +++ b/libs/liblobby/lobby/interface.lua @@ -201,10 +201,9 @@ function Interface:RejoinBattle(battleID) end function Interface:JoinBattle(battleID, password, scriptPassword) - if scriptPassword == nil then - scriptPassword = tostring(math.floor(math.random() * 65536)) .. tostring(math.floor(math.random() * 65536)) - end - password = password or "" + scriptPassword = scriptPassword or (tostring(math.floor(math.random() * 65536)) .. tostring(math.floor(math.random() * 65536))) + password = password or "empty" + self.changedTeamIDOnceAfterJoin = false self:super("JoinBattle", battleID, password, scriptPassword) self:_SendCommand(concat("JOINBATTLE", battleID, password, scriptPassword)) return self @@ -670,9 +669,14 @@ function Interface:_EnsureMyTeamNumberIsUnique() return end + if self.changedTeamIDOnceAfterJoin then + return + end + for name, data in pairs(self.userBattleStatus) do if name ~= self.myUserName and data.teamNumber == myBattleStatus.teamNumber and not data.isSpectator then -- need to change teamID so it's unique + self.changedTeamIDOnceAfterJoin = true self:SetBattleStatus({ teamNumber = self:GetUnusedTeamID() }) From 01f81b03b7c0df2bdc3a0d4e6ed5d7f4b00e405d Mon Sep 17 00:00:00 2001 From: Beherith Date: Fri, 6 Nov 2020 12:34:49 +0100 Subject: [PATCH 16/31] SAIDPRIVATE can activate chat panel and tab on gameConfig.sayPrivateSelectAndActivateChatTab --- LuaMenu/widgets/chobby/components/chat_windows.lua | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/LuaMenu/widgets/chobby/components/chat_windows.lua b/LuaMenu/widgets/chobby/components/chat_windows.lua index ecb1bf624..e009ba422 100644 --- a/LuaMenu/widgets/chobby/components/chat_windows.lua +++ b/LuaMenu/widgets/chobby/components/chat_windows.lua @@ -544,6 +544,10 @@ end function ChatWindows:_NotifyTab(tabName, userName, chanName, nameMentioned, message, sound, popupDuration) if tabName ~= self.currentTab then -- TODO: Fix naming of self.tabbars (these are consoles) + if WG.Chobby.Configuration.gameConfig.sayPrivateSelectAndActivateChatTab then + WG.Chobby.interfaceRoot.OpenRightPanelTab("chat") + self.tabPanel.tabBar:Select(tabName) + end local console = self.tabbars[tabName] local oldMessages = console.unreadMessages console.unreadMessages = console.unreadMessages + 1 From 66104476bbe25d53b24a4d9c9d1f3975211e4fed Mon Sep 17 00:00:00 2001 From: Beherith Date: Wed, 25 Nov 2020 12:09:36 +0100 Subject: [PATCH 17/31] Add option to shorten download names --- LuaMenu/widgets/gui_download_window.lua | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/LuaMenu/widgets/gui_download_window.lua b/LuaMenu/widgets/gui_download_window.lua index fb75da205..70f76c40f 100644 --- a/LuaMenu/widgets/gui_download_window.lua +++ b/LuaMenu/widgets/gui_download_window.lua @@ -127,6 +127,10 @@ local function CreateDownloadEntry(downloadData) parent = holder, } + local downloadDataname = downloadData.name + if Configuration.gameConfig and Configuration.gameConfig.ShortenNameString then + downloadDataname = Configuration.gameConfig.ShortenNameString(downloadDataname) + end TextBox:New { x = 15 + BUTTON_WIDTH*2, y = 12, @@ -134,7 +138,7 @@ local function CreateDownloadEntry(downloadData) height = 20, valign = 'center', fontsize = Configuration:GetFont(2).size, - text = downloadData.name, + text = downloadDataname, parent = holder, } From bfe6993fb11da2d1519161305cfe7534adb438c8 Mon Sep 17 00:00:00 2001 From: rlcevg Date: Mon, 30 Nov 2020 00:13:24 +0200 Subject: [PATCH 18/31] Add faction selector --- LuaMenu/widgets/api_user_handler.lua | 78 +++++++++-- .../chobby/components/configuration.lua | 18 +++ LuaMenu/widgets/gui_side_change_window.lua | 132 ++++++++++++++++++ libs/liblobby/lobby/interface_skirmish.lua | 4 +- 4 files changed, 219 insertions(+), 13 deletions(-) create mode 100644 LuaMenu/widgets/gui_side_change_window.lua diff --git a/LuaMenu/widgets/api_user_handler.lua b/LuaMenu/widgets/api_user_handler.lua index c95dfe89c..d44324f33 100644 --- a/LuaMenu/widgets/api_user_handler.lua +++ b/LuaMenu/widgets/api_user_handler.lua @@ -149,7 +149,7 @@ local function GetUserClanImage(userName, userControl) return file, needDownload end -local function GetUserComboBoxOptions(userName, isInBattle, userControl, showTeamColor) +local function GetUserComboBoxOptions(userName, isInBattle, userControl, showTeamColor, showSide) local userInfo = userControl.lobby:GetUser(userName) or {} local userBattleInfo = userControl.lobby:GetUserBattleStatus(userName) or {} local myUserName = userControl.lobby:GetMyUserName() @@ -217,10 +217,14 @@ local function GetUserComboBoxOptions(userName, isInBattle, userControl, showTea comboOptions[#comboOptions + 1] = "User Page" end - if showTeamColor and - (userName == myUserName or userBattleInfo.aiLib) and - not userBattleInfo.isSpectator then - comboOptions[#comboOptions + 1] = "Change Color" + if (userName == myUserName or userBattleInfo.aiLib) and + not userBattleInfo.isSpectator then + if showTeamColor then + comboOptions[#comboOptions + 1] = "Change Color" + end + if showSide then + comboOptions[#comboOptions + 1] = "Change Side" + end end -- userControl.lobby:GetMyIsAdmin() @@ -393,7 +397,8 @@ local function UpdateUserComboboxOptions(_, userName) local userList = userListList[i] local data = userList[userName] if data then - data.mainControl.items = GetUserComboBoxOptions(userName, data.isInBattle, data, data.imTeamColor ~= nil) + data.mainControl.items = GetUserComboBoxOptions(userName, data.isInBattle, data, + data.imTeamColor ~= nil, data.imSide ~= nil) end end end @@ -403,7 +408,8 @@ local function UpdateUserActivity(listener, userName) local userList = userListList[i] local userControls = userList[userName] if userControls then - userControls.mainControl.items = GetUserComboBoxOptions(userName, userControls.isInBattle, userControls, userControls.imTeamColor ~= nil) + userControls.mainControl.items = GetUserComboBoxOptions(userName, userControls.isInBattle, userControls, + userControls.imTeamColor ~= nil, data.imSide ~= nil) userControls.imLevel.file = GetUserRankImageName(userName, userControls) userControls.imLevel:Invalidate() @@ -446,12 +452,19 @@ local function UpdateUserBattleStatus(listener, userName) data.imSyncStatus.file = GetUserSyncStatus(userName, data) data.imSyncStatus:Invalidate() end + local battleStatus = data.lobby:GetUserBattleStatus(userName) or {} + local imageVisible = not battleStatus.isSpectator if data.imTeamColor then - local battleStatus = data.lobby:GetUserBattleStatus(userName) or {} - local colorVisible = not battleStatus.isSpectator data.imTeamColor.color = battleStatus.teamColor - data.imTeamColor:SetVisibility(colorVisible) - if colorVisible then + data.imTeamColor:SetVisibility(imageVisible) + if imageVisible then + data.imTeamColor:Invalidate() + end + end + if data.imSide then + data.imSide.file = WG.Chobby.Configuration:GetSideById(battleStatus.side).logo + data.imSide:SetVisibility(imageVisible) + if imageVisible then data.imTeamColor:Invalidate() end end @@ -491,6 +504,7 @@ local function GetUserControls(userName, opts) local showModerator = opts.showModerator local comboBoxOnly = opts.comboBoxOnly local showTeamColor = opts.showTeamColor + local showSide = opts.showSide local userControls = reinitialize or {} @@ -544,7 +558,7 @@ local function GetUserControls(userName, opts) maxDropDownWidth = large and 220 or 150, minDropDownHeight = 0, maxDropDownHeight = 300, - items = GetUserComboBoxOptions(userName, isInBattle, userControls, showTeamColor), + items = GetUserComboBoxOptions(userName, isInBattle, userControls, showTeamColor, showSide), OnOpen = { function (obj) obj.tooltip = nil @@ -623,6 +637,25 @@ local function GetUserControls(userName, opts) end end }) + elseif selectedName == "Change Side" then + local battleStatus = userControls.lobby:GetUserBattleStatus(userName) or {} + if battleStatus.isSpectator then + return + end + WG.SideChangeWindow.CreateSideChangeWindow({ + initialSide = battleStatus.side or 0, + OnAccepted = function(sideId) + if userName == userControls.lobby:GetMyUserName() then + userControls.lobby:SetBattleStatus({ + side = sideId + }) + else + userControls.lobby:UpdateAi(userName, { + side = sideId + }) + end + end + }) elseif selectedName == "Report" and Configuration.gameConfig.link_reportPlayer ~= nil then local userInfo = userControls.lobby:GetUser(userName) or {} if userInfo.accountID then @@ -703,6 +736,25 @@ local function GetUserControls(userName, opts) offset = offset + 21 end + if showSide then + local battleStatus = userControls.lobby:GetUserBattleStatus(userName) or {} + offset = offset + 2 + userControls.imSide = Image:New { + name = "imSide", + x = offset, + y = offsetY, + width = 20, + height = 20, + parent = userControls.mainControl, + keepAspect = false, + file = WG.Chobby.Configuration:GetSideById(battleStatus.side or 0).logo, + } + offset = offset + 22 + if battleStatus.isSpectator then + userControls.imSide:Hide() + end + end + offset = offset + 2 userControls.tbName = TextBox:New { name = "tbName", @@ -872,6 +924,7 @@ function userHandler.GetBattleUser(userName, isSingleplayer) showModerator = true, showFounder = true, showTeamColor = not WG.Chobby.Configuration.gameConfig.disableColorChoosing, + showSide = WG.Chobby.Configuration:GetSideData() ~= nil, }) end @@ -890,6 +943,7 @@ function userHandler.GetSingleplayerUser(userName) isInBattle = true, isSingleplayer = true, showTeamColor = not WG.Chobby.Configuration.gameConfig.disableColorChoosing, + showSide = WG.Chobby.Configuration:GetSideData() ~= nil, }) end diff --git a/LuaMenu/widgets/chobby/components/configuration.lua b/LuaMenu/widgets/chobby/components/configuration.lua index 490cd56fb..2ba3fe7d4 100644 --- a/LuaMenu/widgets/chobby/components/configuration.lua +++ b/LuaMenu/widgets/chobby/components/configuration.lua @@ -841,6 +841,24 @@ function Configuration:GetDefaultGameName() return self.gameConfig._defaultGameArchiveName end +function Configuration:GetSideData() + if not self.gameConfig then + return nil + end + return self.gameConfig.sidedata +end + +function Configuration:GetSideById(sideId) + if sideId == nil then + return { name = nil, logo = nil } + end + local sidedata = Configuration:GetSideData() + if sidedata == nil or sideId < 0 or sideId > #sidedata - 1 then + return { name = nil, logo = nil } + end + return sidedata[sideId + 1] +end + function Configuration:GetIsRunning64Bit() if self.isRunning64Bit ~= nil then return self.isRunning64Bit diff --git a/LuaMenu/widgets/gui_side_change_window.lua b/LuaMenu/widgets/gui_side_change_window.lua new file mode 100644 index 000000000..83a924e2b --- /dev/null +++ b/LuaMenu/widgets/gui_side_change_window.lua @@ -0,0 +1,132 @@ +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- + +function widget:GetInfo() + return { + name = "Faction change window", + desc = "Displays a faction change window popup.", + author = "escaped", + date = "2nd wave of new world re-order", + license = "GNU LGPL, v2.1 or later", + layer = 0, + enabled = true -- loaded by default? + } +end + +local function CreateSideChangeWindow(opts) + opts = opts or {} + local selectedFaction = opts.initialSide + + local Configuration = WG.Chobby.Configuration + local sidedata = Configuration:GetSideData() + + local factionMap = {} + local factionNames = {} + for index, data in ipairs(sidedata) do + factionMap[data.name] = index - 1 + table.insert(factionNames, data.name) + end + + local sideChangeWindow = Window:New { + caption = "", + name = "sideChangeWindow", + parent = screen0, + width = 280, + height = 330, + resizable = false, + draggable = false, + classname = "main_window", + } + + local function ChangeAccepted() + if opts.OnAccepted then + opts.OnAccepted(selectedFaction) + end + end + local function CloseFunction() + sideChangeWindow:Dispose() + sideChangeWindow = nil + end + + local lblTitle = Label:New { + x = 0, + y = 15, + width = sideChangeWindow.width - sideChangeWindow.padding[1] - sideChangeWindow.padding[3], + height = 35, + align = "center", + font = Configuration:GetFont(4), + caption = "Choose Faction", + parent = sideChangeWindow, + } + + local btnOK = Button:New { + x = "10%", + width = "30%", + bottom = 1, + height = 40, + caption = i18n("ok"), + font = Configuration:GetFont(2), + classname = "action_button", + OnClick = { CloseFunction, ChangeAccepted }, + parent = sideChangeWindow, + } + + local btnCancel = Button:New { + right = "10%", + width = "30%", + bottom = 1, + height = 40, + caption = i18n("cancel"), + font = Configuration:GetFont(2), + classname = "action_button", + OnClick = { CloseFunction }, + parent = sideChangeWindow, + } + + local imTeamFaction + local cmbFactions = ComboBox:New { + x = sideChangeWindow.width * 0.05, + y = 150, + width = sideChangeWindow.width * 0.5, + height = 40, + items = factionNames, + parent = sideChangeWindow, + font = Configuration:GetFont(2), + itemFontSize = Configuration:GetFont(2).size, + itemHeight = 30, + selected = selectedFaction + 1, + selectByName = true, + OnSelectName = { + function (obj, name) + local faction = factionMap[name] + if faction == nil then + return + end + selectedFaction = faction + imTeamFaction.file = Configuration:GetSideById(faction).logo + imTeamFaction:Invalidate() + end + }, + } + + imTeamFaction = Image:New { + name = "imTeamFaction", + x = cmbFactions.x + cmbFactions.width + 20, + y = 150, + width = 40, + height = 40, + parent = sideChangeWindow, + keepAspect = false, + file = Configuration:GetSideById(selectedFaction).logo, + } + + WG.Chobby.PriorityPopup(sideChangeWindow, CloseFunction, CloseFunction, screen0) +end + +function widget:Initialize() + VFS.Include(LUA_DIRNAME .. "widgets/chobby/headers/exports.lua", nil, VFS.RAW_FIRST) + + WG.SideChangeWindow = { + CreateSideChangeWindow = CreateSideChangeWindow + } +end diff --git a/libs/liblobby/lobby/interface_skirmish.lua b/libs/liblobby/lobby/interface_skirmish.lua index 2c0a999ba..1c37ad59c 100644 --- a/libs/liblobby/lobby/interface_skirmish.lua +++ b/libs/liblobby/lobby/interface_skirmish.lua @@ -92,6 +92,7 @@ function InterfaceSkirmish:_StartScript(gameName, mapName, playerName, friendLis TeamLeader = 0, AllyTeam = data.allyNumber, RgbColor = getTeamColor(userName), + Side = WG.Chobby.Configuration:GetSideById(data.side).name, } maxAllyTeamID = math.max(maxAllyTeamID, data.allyNumber) teamCount = teamCount + 1 @@ -115,6 +116,7 @@ function InterfaceSkirmish:_StartScript(gameName, mapName, playerName, friendLis TeamLeader = playerCount, AllyTeam = data.allyNumber, RgbColor = getTeamColor(userName), + Side = WG.Chobby.Configuration:GetSideById(data.side).name, } teamCount = teamCount + 1 if friendsReplaceAI then @@ -166,7 +168,7 @@ function InterfaceSkirmish:_StartScript(gameName, mapName, playerName, friendLis TeamLeader = 0, AllyTeam = data.allyNumber, RgbColor = getTeamColor(userName), - Side = data.side, + Side = WG.Chobby.Configuration:GetSideById(data.side).name, } maxAllyTeamID = math.max(maxAllyTeamID, data.allyNumber) From 91a0b4b5e05a03897e69efbdb33e4acab66b273d Mon Sep 17 00:00:00 2001 From: Gajo Petrovic Date: Mon, 30 Nov 2020 23:53:25 +0900 Subject: [PATCH 19/31] typo --- LuaMenu/widgets/api_user_handler.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LuaMenu/widgets/api_user_handler.lua b/LuaMenu/widgets/api_user_handler.lua index d44324f33..4e3c109bd 100644 --- a/LuaMenu/widgets/api_user_handler.lua +++ b/LuaMenu/widgets/api_user_handler.lua @@ -409,7 +409,7 @@ local function UpdateUserActivity(listener, userName) local userControls = userList[userName] if userControls then userControls.mainControl.items = GetUserComboBoxOptions(userName, userControls.isInBattle, userControls, - userControls.imTeamColor ~= nil, data.imSide ~= nil) + userControls.imTeamColor ~= nil, userControls.imSide ~= nil) userControls.imLevel.file = GetUserRankImageName(userName, userControls) userControls.imLevel:Invalidate() From 558a0fcf55f058f59da744d2b4c9340f2a5576e7 Mon Sep 17 00:00:00 2001 From: Gajo Petrovic Date: Tue, 1 Dec 2020 00:15:37 +0900 Subject: [PATCH 20/31] don't show side if none is assigned --- LuaMenu/widgets/api_user_handler.lua | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/LuaMenu/widgets/api_user_handler.lua b/LuaMenu/widgets/api_user_handler.lua index 4e3c109bd..3583a92da 100644 --- a/LuaMenu/widgets/api_user_handler.lua +++ b/LuaMenu/widgets/api_user_handler.lua @@ -462,8 +462,11 @@ local function UpdateUserBattleStatus(listener, userName) end end if data.imSide then - data.imSide.file = WG.Chobby.Configuration:GetSideById(battleStatus.side).logo - data.imSide:SetVisibility(imageVisible) + local sideSelected = battleStatus.side ~= nil + if sideSelected then + data.imSide.file = WG.Chobby.Configuration:GetSideById(battleStatus.side).logo + end + data.imSide:SetVisibility(imageVisible and sideSelected) if imageVisible then data.imTeamColor:Invalidate() end @@ -739,6 +742,10 @@ local function GetUserControls(userName, opts) if showSide then local battleStatus = userControls.lobby:GetUserBattleStatus(userName) or {} offset = offset + 2 + local file = nil + if battleStatus.side ~= nil then + file = WG.Chobby.Configuration:GetSideById(battleStatus.side or 0).logo + end userControls.imSide = Image:New { name = "imSide", x = offset, @@ -747,10 +754,10 @@ local function GetUserControls(userName, opts) height = 20, parent = userControls.mainControl, keepAspect = false, - file = WG.Chobby.Configuration:GetSideById(battleStatus.side or 0).logo, + file = file, } offset = offset + 22 - if battleStatus.isSpectator then + if battleStatus.isSpectator or file == nil then userControls.imSide:Hide() end end From 3ea03a2d6319a2f14552128847a0b5fd8bcd3b3e Mon Sep 17 00:00:00 2001 From: Gajo Petrovic Date: Tue, 1 Dec 2020 00:19:54 +0900 Subject: [PATCH 21/31] fix codex.lua --- campaign/sample/codex.lua | 236 +++++++++++++++++++------------------- 1 file changed, 118 insertions(+), 118 deletions(-) diff --git a/campaign/sample/codex.lua b/campaign/sample/codex.lua index d655c12e2..3c893e469 100644 --- a/campaign/sample/codex.lua +++ b/campaign/sample/codex.lua @@ -6,11 +6,11 @@ local entries = { category = "3. Factions", text = [[Official name: the Union of Sovereign Star-Systems Several acronyms were used on occasion, but the variety of official languages between the varied systems-states made it impossible for a majority to agree on a single one. - + "To each its own" - + This polity seems to have started as a defensive alliance, as the old empire was falling apart. Many systems in the region had long-suppressed desires for independence, and banded together to maintain a semblance in the slow disappearance of imperial law. With time, trade and law enforcement agreements completed the military treaties, and the Union slowly became a political entity in its own right, if a very decentralized one constituted of very autonomous members. - + As it grew in size and strength, it also started to run into rivals, both over strategic places and ideology. This drove them to create an unified military and foreign service, with the occasional bout of expansionism. It seems to have fared relatively well, until they were were faced with a much stronger enemy against whom they started to loose system after system. With the enemy at the gates of their core worlds, there was little hope of repelling them without of a miracle - instead of what, everyone disappeared.]] @@ -21,11 +21,11 @@ With the enemy at the gates of their core worlds, there was little hope of repel category = "3. Factions", text = [[Official name: the Ninth Galactic State, Second Restoration As they started winning, everyone called it the Galactic Empire, or simply the Empire - + "Peace through unity" - + The origin of this new Restoration is unclear. They claim that as the previous empire disintegrated, it retained its traditions and a core of systems, from which it started to rebuild and reassert itself and. They based the legitimacy of their grand conquest by turning it into a reclamation of its rightful place as the sole ruler of the galaxy. As such, it is unsurprising that their enemies would have less flattering histories, the most popular being that an ambitious warlord conquered the fallen empire's homeworlds before having delusions of grandeur. - + Whatever the truth is, they did retain many of the traditions of the previous empire, and initially based their legal system and political organization on it. By the force of arms, they managed to slowly but surely conquer the galaxy again, with more and more resources and autonomy given to their formidable military machine. In the end, there were only a few factions still resisting them, with little hope of repelling their armies. However, with so much of the empire's efforts being diverted toward the armies, it appears to have been growing unrest on many conquered worlds across the galaxy.]] }, @@ -34,10 +34,10 @@ However, with so much of the empire's efforts being diverted toward the armies, image = "campaign/sample/graphics/icons/Rebels.png", category = "3. Factions", text = [["Death to the tyrants!" - + Unrest was steadily growing across the Empire, both on wealthy peripheral worlds and poor, isolated ones, mostly from the resources and attention diverted towards their war machine, and the rule of law becoming both harsher and less effective at keeping order. The Empire thought they could hold enough authority to prevent any serious challenge to their rule, at least for long enough to finish pacifying the galaxy. It appears they were wrong. Several uprisings started on varied worlds in a large portion of the Empire. Unprepared to such a large rebellion, faced with an enemy relying more on subversion and deception than military control of territory, it quickly lost control of entire regions. The Empire was prompt to turn its war machine inward and crush the rebellion by the force of arms, as daunting a task as it was. - + The goal of the Rebels was not direct victory so much as mortally injuring the Empire from the inside, and holding long enough to survive it. What plans did they have for the aftermath is unclear, given how many disparate groups participated. However, for such coordinated uprisings to take place, a central organization had to be overseeing it. Was it an ad-hoc coalition of mutually hostile forces against a greater common enemy, or did they have their own agenda?]] }, faction_haven = { -- planet31 @@ -45,10 +45,10 @@ The goal of the Rebels was not direct victory so much as mortally injuring the E image = "campaign/sample/graphics/icons/SynPact.png", category = "3. Factions", text = [["Many as one" - + As the previous galactic order fell apart, many long-repressed sectarian tensions flared, particularly between free machines and biosupremacists. As conflicts increased in violence, a self-defense group of free machines carved a safe-haven for themselves, before harboring more endangered groups and allying with other self-defense groups as time went by and the whole region slid into anarchy. During the interregnum, they slowly grew up in territory and influence, until they became a regional hegemon. This put them in rivalry with the Union over both strategic and ideological points, having become a highly centralized, harmonist regime. This cold war marred by proxy conflicts was only ended by the greater threat of the Empire. - + Realizing that even their uneasy alliance with the Union would not be enough to repel the Empire, they threw every resource they had on the defensive effort, hoping to either outlast the Empire, or maybe find another avenue to victory entirely. At the time of the event, they were slowly loosing ground, holding onto strategic points with all their strength and making the Empire pay a surprisingly heavy toll for each conquered world. Given their tight organization, formidable defenses and the series of strategic choke-points that were their last worlds, they may have held for a very long time.]] }, @@ -57,7 +57,7 @@ At the time of the event, they were slowly loosing ground, holding onto strategi image = "campaign/sample/graphics/icons/Lawless.png", category = "3. Factions", text = [[Spread too thin, with much of its attention and resources dedicated to the war machine, and a number of violent, organized uprising, the Empire's rule of law was crumbling on many worlds. Some, impoverished by high taxation and falling trade, turned to crime, piracy and smuggling of all kinds. Governors without oversight nor control became local tyrants. Military and law enforcement groups became warlords and took over the worlds they were supposed to protect. - + The Empire, while conscious of those problems, decided that it had more pressing issues, namely uniting the galaxy and dealing with the Rebels. Presumably, its plan was to leave this problem for later, when it would be free to reconquer the seceding worlds and reinstate its rule by force. I wonder if it could have worked, or if it would have been too little too late.]] }, @@ -66,13 +66,13 @@ I wonder if it could have worked, or if it would have been too little too late.] image = "campaign/sample/graphics/icons/Dynasty.png", category = "3. Factions", text = [["Élan vital" - + Something about the Rebels have been nagging me for a long time. They were too well-prepared, well-organized, and managed to coordinate simultaneous uprisings among groups of malcontents that often hated each-other. And something about their whole modus operandi kept reminding me of something. As it turns out, it appears that the Dynasty was behind it all. The oldest known organization in the galaxy, they were thought to have been destroyed by the Anarchai at the fall of Chatka, millennia before. Somehow, they appear to have survived. - + Tracing back to Earth, they were a shadowy group of biosupremacists, obsessed with creating superior humans through genetic and biological modifications, and ruling over humanity as its greatest representatives. They shunned cybernetic enhancements, and hated non-human synths and free machines as anathema. They were divided into rival families, united only in their goal and against common menaces. They only acted in broad daylight when they were certain of their strength, preferring to subvert those they could, and secretly organizing rebellions against those they couldn't. They were the one behind the Rebels, hoping to destabilize the Empire and take over in the resulting chaos. Even if the Empire won, it would have been weakened enough for them to grow their influence - assuming they would not have been discovered. - + And yet, by their historical standards, the whole operation feels botched and amateurish. They may have survived against all odds, but as a mere shadow of themselves.]] }, faction_dynasty_restored = { -- planet58, planet59 @@ -81,10 +81,10 @@ And yet, by their historical standards, the whole operation feels botched and am category = "3. Factions", text = [[It has always been thought that the Dynasty was finally destroyed at Chatka, when they fought the last battle of the galaxy against the Anarchai. As it turns out, it was true. - + It was during archaeological digs that the legendary Dynasty's Main Vaults were found. Their discoverers decided to keep the secret of their existence for themselves, and use the vast knowledge and data it contained to recreate the Dynasty. However, even with so much lost knowledge from the ancient times, they had little of the traditions of the original Dynasty, and were less like a giant among children than a child having found the giant's weapon. Despite having planned it for a long time, the rebellion they set off against the Empire was ultimately rushed and too difficult to manage, leading ultimately to its failure. While it did help destabilize the Empire, I have the feeling that the ancient Dynasty, with their immense experience and institutional memory, would have fared much better, possibly well enough to emerge on the stage directly. - + Still, something feels wrong with the whole affair. They had to know it had such little chance of success, and may even expose them in the end. Why do it anyway? Why take such a foolish risk?]] }, faction_anarchai = { -- planet32 @@ -93,14 +93,14 @@ Still, something feels wrong with the whole affair. They had to know it had such category = "3. Factions", text = [[Little is known, let alone understood, about the Anarchai who brought the ancient times to an end. Those alien-thinking, god-like supermachines simply appeared one day across a quadrant with no warning. Hitting the galaxy like a hurricane, they smashed all resistance, systematically dismantling any higher form of organization and advanced installations they found, before continuing to the next system. - + Taken aback, the Celestial Dominion, Ghost Mandate and Dynasty put their longstanding cold war on hold to band together against this new menace, but to no avail. Within months, both the mighty Ghost Fleet and the Four Thrones had been destroyed, a few survivors only managing to join Dynasty space before the Anarchai scatterships. - + It would be the only time in known history where the Dynasties broke their principle of human supremacy, making large-scale use of tech from Celestial and Ghost remnants. Against all odds, this unholy alliance of desperation did manage to slow down the ineluctable Anarchai advance - though not for long. Three years after their emergence, Chatka, the Dynasty homeworld and last bastion of resistance, would be burned to cinder. - + Then, they turned their scatterships against each-other, destroying themselves to the last. As suddenly as they had appeared, the Anarchai were gone - leaving the galaxy stunned, ruined, utterly disorganized - but to their own surprise, still alive. - + Haven was fascinated by the Anarchai. Located in their presumed birthplace, they spent considerable effort trying to pierce the mystery of their origins, even as the war against the Empire was taking a turn for the worse.]] -- ed note: Nothing to do with the Zero-K contributor Anarchid, the name resemblance is just a coincidence. Here, Anarchai is constructed from Archai (plural of Arche). }, @@ -109,26 +109,26 @@ Haven was fascinated by the Anarchai. Located in their presumed birthplace, they image = "campaign/sample/graphics/icons/Survivors.png", category = "3. Factions", text = [[There is a message broadcast looping across the system. Most of the transmitters have stopped working, and the broadcast itself is weak, garbled and corrupt, but there were enough emitters to reconstruct most of it. - + As it turns out, I wasn't the only one to escape the event. A handful among those in deep hibernation, in a teleportation accident, or even a freak hyperspace misjump at the moment it swept them by, were not affected. - + The whole infrastructure was intact, so they rarely had difficulties to survive. Some had system rights for communications and space travel for them to find each-other, others found ways to acquire them. This was enough for them to find each-other, and organize as they could. - + At first, they scoured what they could of the galaxy, trying to find as many fellow survivors as they could. They set up those boradcast stations for stagglers, as well as those weird backdoors I keep finding in war systems around here. None of them had combat system rights, and while all those war automata were mostly waiting for orders, they knew they would grow more dangerous with time. Then they chose to follow the refugee trails, deeper in the Empire's heartlands. They knew the Empire had tried to find a way to escape the event, and went searching for it. - + After all this time, no-one went back to resettle the galaxy, so I have little hope for their success. But I have to find out.]] }, - + -- Threats threat_automata = { -- planet69 name = "Automata", image = "campaign/sample/graphics/unitpics/cloakriot.png", category = "2. Threats", text = [[Left to themselves, most armies will fall dormant to minimize energy and maintenance requirements. With proper settings and their own nanolathe arrays, they can stay functional for a very long time. And they will leave enough sensors active to detect threats, then awaken and engage them until new orders or supervision are received. - + Unfortunately, it seems I lack the proper identification codes to be recognized by most of those damn automata, or enough time to find a flaw in their code and hack them - so they are engaging me on sight. There may not be sapient minds behind them, but tactical AIs should not be underestimated, especially when they have the home advantage. - + I will need to be careful, choose the time and place of battle, and not wait for reinforcements from everywhere on the planet to overwhelm me, but I can make it. Not that I have a choice...]] }, threat_zombies = { -- planet43, planet59 @@ -136,13 +136,13 @@ I will need to be careful, choose the time and place of battle, and not wait for image = "campaign/sample/graphics/icons/ZombiePlague.png", category = "2. Threats", text = [[Suspected to be an ancient terror weapon for the defense by mutually-assured destruction of a long-forgotten polity, the zombie nanoplague was for a long time the most feared contagion in existence. - + Extraordinarily virulent, it will contaminate an entire planet in less than a week from a single carrier, and cause the death of any organic lifeform in a few minutes at most. Only the most advanced antinanite barriers will stop it, and it will take over any civilian or insufficiently protected military machines. And what gave it its name is how even the most advanced military systems will be taken over and resurrected. The only way to neutralize for good an infected unit is to also destroy its wreck. - + Some degree of coordination has been observed between infected units, but nothing like a collective intelligence seem to exist, and infected units are only driven by basic instructions to seek and destroy uninfected hardware, so it can be taken over in turn. - + Left to itself, a contaminated world will see its units fall dormant and slowly degrade as nanites cannibalize more and more of them to renew themselves. Fortunately, there is no programming for interplanetary or interstellar contamination, even when space-capable hardware is infected - which often degrades too fast to be capable of reaching other worlds in any cases, so quarantine is effective as containment method. - + However, reclaiming contaminated worlds is extremely difficult, as those are much more resilient than any nanite should be able to. In dormant spore mode, it has been known to survive nuclear explosions. And while effective if painstakingly laborious methods were devised with time, tracking and destroying every secret laboratory having kept a sample proved to be a Sisyphean task, never to be quite over.]] }, threat_chickens = { -- planet21, planet38, planet63 @@ -150,13 +150,13 @@ However, reclaiming contaminated worlds is extremely difficult, as those are muc image = "campaign/sample/graphics/unitpics/chickens.png", category = "2. Threats", text = [[Official name: Gallinuloides Horribilis - + How the hell is that their official name? There is practically no biological link between those things and old Earth galliformes! In fact, those things are less birds than even mammals. - + The so-called chicken are a xenoform species of unknown origin, based on a hive-like social structure with specialized zooids with little to no individuality, and what is assumed to be a collective mind centered around a Queen. Whether they possess organic technology or simply extreme adaptation, the organisms forming a collective vary from tiny workers, light scouts and flyers the size of a small bombers to immobile spore-throwers, gigantic White Dragon and finally the Queen itself, a terrifying war machine that will act as final military reserves to an angered colony. - + They are invariably hostile when active, with no rumors of successful cohabitation with humans ever confirmed. They can however stay dormant for long periods in deep, near-undetectable underground chambers to which they are suspected to retreat upon the death of their Queen. This has made their complete eradication from a planet extremely challenging, especially if infrastracture or terraforming efforts are to be preserved. - + Hypotheses about their origins run from ancient dormant aliens awakened by human activity to secret weapon gone rogue to results of experiment on accelerated evolution that went wrong - or horribly right."]] -- ed note: The chickens are actually a secret project by a family of the early Dynasty. Observing the deficiencies of even regular modded humans, they sought to create a Humans 2.0 with traits such as extreme adaptation, collective intelligence over many zooids instead of singular body, ability to metabolize any CHON substrate, and other such fantastic abilities. They tried to keep it secret from rival families, recognizing correctly that they would not accept being displaced by Humans 2.0, but they ended up being discovered. The Dynasty panicked and eradicated the family, erasing every bit of data about it they could find so it couldn't be linked to them - fearing that humanity would turn against them in the same panic. It wouldn't be before centuries had passed that they would realize that they had missed some of the subjects. }, @@ -165,9 +165,9 @@ Hypotheses about their origins run from ancient dormant aliens awakened by human image = "campaign/sample/graphics/unitpics/chicken_rafflesia.png", category = "2. Threats", text = [[Little is known or understood about the life-cycle of chicken. Colonies are centered around a Queen, which will be abandoned upon its death. Whether the colony is destroyed, its dormant remains taken over by a new one or if it will produce a new Queen after a long enough time is unknown, as is how Queens themselves are born and form new colonies. - + Dormant chicken can endure millennia in extremely deep stealth underground chambers, while active colonies form bewildering tunnel complexes, with little surface activity - though some cases of what may be surface agriculture have been observed. Size and activity of individual colonies vary wildly, from lone mountains to entire continents, and ranging from a few scattered zooids to subterranean metropolis. Given time, their activities will inevitably cover he entire planet. - + Chicken biology seem relatively close to Earth-native biology, but with significant, inexplicable differences, which may be sign of convergent evolution, Earth ancestry or an ability to copy and reuse foreign biological processes. Unsettlingly, human DNA markers have been found on what acts as their core genetic system.]] }, threat_chickens_travel = { -- planet21 @@ -175,7 +175,7 @@ Chicken biology seem relatively close to Earth-native biology, but with signific image = "campaign/sample/graphics/icons/StarSpread.png", category = "2. Threats", text = [[No chicken space organism has ever been detected, nor stowaway zooid or biological material that could have started a new colony. Despite this, new colonies have regularly been found on worlds with no previously known chicken presence. While some could be explained by undetected dormant elements, some had ruled it out with near-certainty. As such, it has generally been accepted that chicken have means to either move or seed new colonies over interstellar distances. Whether by slower-than-light dormant seeds, incredibly stealthy starships, extremely sophisticated detection systems to launch far from human sensors, or even deep underground warp portals working by unknown physical principles, no concrete element has been found. - + Chicken have existed for at least as long as the early days of the human galactic age and their capabilities to live on almost any type of planet without any need for terraforming. Despite this and their demonstrated interstellar capabilities, they have never settled on more than a proportionally a handful of worlds, even including those ignored by humans as unsuitable for colonization or exploitation. Why haven't they long overrun has been said to be the key to understand what they really are.]] }, threat_chickens_intelligence = { -- planet63 @@ -183,21 +183,21 @@ Chicken have existed for at least as long as the early days of the human galacti image = "campaign/sample/graphics/unitpics/chickenflyerqueen.png", category = "2. Threats", text = [[Chicken thought processes, or even whether they are even sapient, is unknown. They have however proven themselves to be remarkably good at planning, adaptation and long-term resource management. Their degree of understanding of human societies is unknown, but they have sometimes been eerily good at striking unsuspecting or unprepared settlements at the worst possible time and place. Though some attribute this to exceptional pattern-recognition, others have hypothesized an ability to spy on and understand human communications and societies. - + Inter-colony skirmishes have been observed, often limited to underground tunnel fighting and nowhere near with the level of violence seen against humans, or with a Queen directly intervening. Similarly, while colonies don't always cooperate against humans and some prefer to go dormant than fight, no skirmish has ever been observed on a conflict where a colony was engaged against humans. Long-range coordination of chicken forces also hint at sophisticated inter-colony communications, though by which mechanisms is unknown. Controversial evidence of interstellar communication have been presented, but has always been judged invalid or inconclusive. - + No successful communicating with a collective mind has ever been demonstrated, however most have ended up in catastrophe, considerably limiting the number of latter attempts. This includes attempts at tacit understanding between settlers and local colonies for division of lands or resources. Conversely, no communication attempt from a collective mind have ever been recorded. - + Contrasting with their sophistication in many other domains, their strangely primitive warfare tactics has puzzled many scientists. Through history, mentions have been made of contact being lost with entire worlds, with nothing but ruins being discovered afterwards, and no explanation about what had happened - some have hypothesized that it could be the result of chicken colonies attacking with their full potential and intelligence.]] }, - + -- Entries entry_first = { -- planet69 name = "What am I doing here?", image = "campaign/sample/graphics/icons/ErrorMissingData.png", category = "1. Entries", text = [[What am I doing on a hostile fortress world? Was I captured? But then why didn't they dismantle me prior to transport? There is no trace of planetary assault - then were those subverted by deep agents? A mistimed diversion? Why hasn't anyone intervened yet? Something feels very wrong. - + Somehow the automated defense grid is still on high alert. Something must be keeping everyone busy and a starship has answered my distress call. This is my chance to jump out of the system.]] }, entry_commander = { -- planet1 @@ -205,13 +205,13 @@ Somehow the automated defense grid is still on high alert. Something must be kee image = "campaign/sample/graphics/icons/HeroCommander.png", category = "1. Entries", text = [[Commanders are an old concept. Put all the mining and manufacturing required to build an army on a compact chassis, slap a weapon and some armor, and harden it all for fast insertion on a hostile planet. Hopefully they send you on a less defended part of the world, where you are left alone long enough to entrench yourself, and launch an assault on strategic locations - or open a gate for the real assault forces to get in. Such was their effectiveness that many planets opted to use them in defense. Simply send your own commander to wherever the enemy decides to land, then try and kill them before they can build enough of an army to kill you. - + A few tried and true models, perfected for cost, effectiveness and reliability over many wars, and pretty much no surprise for many centuries. My memories are still blurred, but I remember extensively training on those. - + And yet, this Commander of mine is unlike anything I have ever seen. - + One of the biggest limitations to Commander design is that they cannot jump with field improvements such as extra weapons, armor or system. Many have tried, and no-one is known to get even close to it, even in the old days. But, this one can. For each field upgrade I recover, it stays intact at a jump. - + I never trained for it, or even heard of such a thing. And yet, it feels oddly familiar...]] }, entry_event = { -- planet2 @@ -220,7 +220,7 @@ I never trained for it, or even heard of such a thing. And yet, it feels oddly f category = "1. Entries", text = [[It is not just those worlds that are empty. It is the entire galaxy. Again, old ruins from what could be the same time litter the planet. But when I try to pick up long-range signals, detect hyperspace movements or any other sort of activity, the galaxy is silent. If someone is still out there, they either lost all interstellar capabilities, or they are hiding very well. - + How long has it been? What little star charts are left from the database are useless due to star drift, and I have neither the tools nor the knowledge required for dating the ruins. It could have been millennia. It could have been millions of years. But some recording survived, enough to prove that whatever the event was, it happened in an instant. One moment everyone was there, a day like any other. The next moment, they were all gone. Baselines, modified, cyborgs, synths, uplifts, free machines - everyone, no exception, and nothing else...]] }, @@ -229,26 +229,26 @@ But some recording survived, enough to prove that whatever the event was, it hap image = "campaign/sample/graphics/icons/Homeworld.png", category = "1. Entries", text = [[Caderical. The Glinting City of Caslaar, or what's left of it, under the desert sand. This is where I grew up, where I was born - or rather made. - + How strange to find out the whole truth, after all that time. - + This was the homeworld of the new Dynasty. Even after centuries, they were still but children, compared to their legendary forebears - but they were driven by the same fire. Obsessed by creating superior humans, worthy of ruling the galaxy, they started a project of engineering the ultimate human warrior, a new Demuirge army that would conquer all of humanity in one glorious campaign, and reign as its true, natural lords! - + They didn't tell us what we were. Were they wary of leaks? Of how it may twist us? Of loosing control over us? We only knew we were a new type of modified humans, and a bright future was waiting for us. Sent to military academies, we all performed reasonably well. But reasonably well wasn't what they were hoping for. In truth, we were well-made. With no implants, no biomods, not even tools, we were as capable as the best cyborgs and synths. But we were no Demuirges. - + Sometimes, when we went to checkups, some of us didn't come back - particularly the least-performing of us. Sudden sickness, we were told. Unplanned complications, to be expected from a first batch. No need to worry, statistics were with us now. The last defects had been fixed. Unfortunate for those they couldn't have saved. They knew we were growing suspicious, and it made them panic. They decided that the entire generation would be recalled, to be destructively analyzed, and hope to do better next time. - + Ironically, they had underestimated us. At the next checkup, seeing how the procedures had been changed, we knew what to expect. And we had long since prepared escape plans. As for me, I had been separated from the others, and was slowly being cornered by security when I felt something connect to my mind. As it turns out, I was enough of a Demuirge after all - this Commander, after being impervious to all orders and analyses, was responding to me. Powering up in the middle of its laboratory, with security half-compromised, it easily tore through several perimeters, to my position. - + Once on board, I somehow managed to commandeer a dropship in the confusion, and take control of the Commander's support starship from a small tech station. But right before I could jump out-system, the space defense grid scored a hit on the hyperdrive generator. The resulting misjump should have dismantled the starship and its hold into constituent atoms, but this was the tech of the ancient Dynasty on its final days. Somehow, the ship managed to correct it enough to emerge halfway across the galaxy, in deep space near a Union system-state. The Union salvage teams never realized there was a pilot on board the Commander: the shock had been so harsh, I had to been put into deep hibernation, to be awakened in an adequately-equipped Demuirge medical facility. So, not knowing what this strange technology was, they sent us to Folsom to be stored and studied to a later date... - + Here, with our escape attempt, and me fleeing so violently with this Commander, they knew the Empire would investigate. They knew it was too early, but they had just run out of time. - + I ignore how many of my siblings escaped. Even knowing what happened next, I still hope that at least a few made it out.]] }, entry_starsong = { -- planet67 @@ -256,18 +256,18 @@ I ignore how many of my siblings escaped. Even knowing what happened next, I sti image = "campaign/sample/graphics/icons/Starsong.png", category = "1. Entries", text = [[Fortress world Zhurou, last redoubt of Haven. Where it all started. - + I don't even know where to begin... - + Strange, according to their archaeological findings, there was a massive observatory here, millennia ago. Its core was buried deep under the crust of the planet, but it actually spanned the entire star system. They were looking for extragalactic hypersignals - but I have never heard of such a gargantuan hypersignal detector... - + And they had found something. Something coming from an extremely distant galaxy. A repeating signal, with a period of about eight thousand years. Something... artificial? They called it the Starsong. Whatever it was, it set the Anarchai off. - + Haven wanted to know more about the signal, but they feared its content. They knew what they were doing, and were experts in data handling: they used draconian information quarantine measures, and studied what records they had recovered with extreme caution. - + And yet, it was not enough. One moment they are running an indirect test in a black box system on a fragment of the signal, and the next - everyone in the facility is gone. One second later, there is no-one left on the entire planet. Then, it hits nearby systems... - + The data itself has long decayed beyond recovery, and the Starsong itself went silent, at some point since the event. There is nothing left to be found, on how it all started. But perhaps this is for the better. If Haven could not deal with it, who knows what I may have done.]] }, entry_eternity_gate = { -- planet68 @@ -275,24 +275,24 @@ The data itself has long decayed beyond recovery, and the Starsong itself went s image = "campaign/sample/graphics/icons/EternityGate.png", category = "1. Entries", text = [[This planet was never meant to house a large population. It had been the Empire's last redoubt, an mighty fortress world for a glorious last stand, came the day of their fall. Which is what happened, in a way. But the refugees never settled here. - + They never intended to settle on this world. Instead, they poured all their efforts, time and resources grasping at straws, looking for an old legend. And I suspect to their own surprise, they found it. - + In the ancient times, a young Ghost Mandate stumbled upon a discovery made by a forgotten galactic power, something called the Eternity Gate. An immense hyperspace structure, almost half as large as the galaxy, spans the near-starless expanse beyond this rim. In its heart exists a rift, that connects to the other end of the universe both across space and time. A complex, diaphanous structure had been built, spanning many systems, to serve as a jump amplifier and reach for the rift. The Mandate restored it and carefully started exploring it. - + After millennia, they received their first reports from the other side. Their first surprise was the time shift: for days on this side, barely a second would have passed on the other - which had only been the first of many hurdles to transmit data back. It had been theorized that as both ends drifted toward each-other time-wise, so would they in space, until they would meet and disappear in an impossibly distant future. Or this was the point of their birth, sending them drifting backwards in time... The other surprise was that despite being long past the heat death of the universe, and across a mangled, nearly incomprehensibly distorted space-time, it was somewhat inhabitable. And, it would seem, possibly inhabited. - + This is when the Anarchai overran the galaxy, cutting this region off from fallback Dynasty worlds. Faced with destruction, local Mandate authorities strengthened the Gate to the point that it could support a mass-exodus, and evacuated as many as they could. It had long been thought that the Anarchai had destroyed the Gate itself, but strangely enough, they only took the control system out. Somehow, the Empire found a way to rebuild it. And as the Mandate before them, they fled across the Gate. - + When the survivors arrived, the Eternity Gate was fully working, and they all crossed it, in the end. But now, after such a long time, it has fallen into disrepair - I restored what self-repair systems I could, but it will be decades, maybe centuries before it can operate again. Maybe I will tidy up what I can in this galaxy. Maybe there are others like me, still waiting in deep slumber. And I can always skip time in hibernation, if needs be. - + It seems the Empire had also found an incomplete Mandate project. They lacked time for detailed studies, but they thought it was an receptor node, made to invert the Gate operation and guide backward jumps across the rift. Let's see what I can make of it...]] }, - + -- Locations --- Storyline locations location_im_jaleth = { -- planet1 @@ -301,7 +301,7 @@ It seems the Empire had also found an incomplete Mandate project. They lacked ti image = "campaign/sample/graphics/icons/RuinsFromAbove.png", text = [[This world has been abandoned for a very, very long time. What little ruins I had time to unearth were buried very deep, and all from the same geological strata. For some reason, the entire planet seem to have been abandoned at once, and never repopulated Was it kept empty as a buffer before the Folsom fortress world? Depriving themselves of a good inhabitable world like this one for a small strategic gain feels wasteful. - + And again, no one has challenged me beyond automated defenses. No hails, no communications. Automata can be left to their own devices pretty much indefinitely, but why keep an empty buffer world and not leave overseers in case of surprise?]] }, location_chatka = { -- planet58 @@ -309,14 +309,14 @@ And again, no one has challenged me beyond automated defenses. No hails, no comm image = "campaign/sample/graphics/icons/DynastyAnarchaiBattle.png", category = "4. Locations", text = [[This is where the greatest battle of the ancient times took place. - + The Anarchai had conquered most of the galaxy, smashing all resistance on their path. Both the Celestial Dominion and the Ghost Mandate had been destroyed, and the Dynasty had only their homeworld Chatka left. In a strange turn of fate, the human-supremacist Dynasty, oldest and longest-lived political force in the galaxy, would hold the last bastion of the free galaxy against the alien-thinking Anarchai supermachines. - + Faced with annihilation, not only of them but of the entire galaxy, the Dynasty renounced its founding principle, and installed Celestial cybernetic enhancements on their Demuirge battalion, creating in desperation what would be the greatest warriors in galactic history, and the only one to ever stand ground, if only for a moment, against the Anarchai. - + They would hold two years, repelling many planetary assaults, but loosing almost as many Demuirges to late cybernetic incompatibilities than to enemy action. Ultimately though, it was not them who would fail. Concentrating all their forces on the lone system, the Anarchai shut down the system's hyperspace barriers and triggered a starpulse, destroying all space defenses. Then sent their immense starships to break the planetary shield, overwhelm the anti-aerospace defenses, and burn the planet to the mantle. - + The rest, as they said, is History.]] }, location_tempest = { -- planet59 @@ -325,10 +325,10 @@ The rest, as they said, is History.]] category = "4. Locations", text = [[This was one of the last worlds to fall during the Dynasty's last stand against the Anarchai, and appears to have been their main military research and development site, especially for research too dangerous to be conducted on their homeworld. This Artefact was one of the weapons they were studying in desperation. It significantly differs from Dynasty technology, however. Did they build it from Ghost or Celestial tech? Or was it something older, whose secrets they were trying to unlock? Whatever it was, I suspect the zombie nanoplague release was more of a side-effect than its true purpose. I was lucky it responded to my shutdown order. From what little sense I can make of those readings, it would have been a very bad idea to let it activate. - + It was also here that my Commander was found. It was an experimental auxiliary Demuirge unit, a cheaper version of the mainline fast-responder. When the site was destroyed by an Anarchai raid, time was too short to transport it to Chatka. As such, it was powered down and buried in deep vaults, along with its dedicated support starship, and all that couldn't be or wasn't worth being destroyed. In a testament of the prowess of those final ancient days, it was still functional after both the Anarchai bombing and millennia of abandon in its vault. - + Unable to analyze such advanced archeotech on site, the researchers installed it on its starship, who was then towed to their headquarters on Caderical.]] }, location_karuwal = { -- planet62 @@ -337,9 +337,9 @@ Unable to analyze such advanced archeotech on site, the researchers installed it category = "4. Locations", text = [[While the Rebels had initially managed to take over many worlds through political subversion and uprisings, the ponderous war machine of the Empire was now facing inward, increasingly turning the conflict into military engagements. Eager to capitalize on early successes, where misdirection, clever maneuvering and guerrilla tactics had let them defeat much larger forces in several key engagements, the Rebels decided to launch a large-scale assault against the heartlands of the Empire before it had time to recover. This turned out to be a mistake. - + While the newly-unified Rebel military was adept at raids and information warfare, they had little experience in large-scale frontal combat. In launching such an attack, the Rebel Expeditionary Force pitted their own weaknesses against the Empire's key strength. Having long since prepared for such an eventuality, the Second Home Army used the string of fortress worlds as a bottleneck, to force the Rebel forces into a decisive battle at Karuwal. Against superiorly trained forces with, for once, the home advantage, the Rebel Expeditionary Force suffered a catastrophic defeat from which only a few survivors managed to retreat. - + The loss of the army in which the Rebels had poured so much of their resources broke their military, which would never recover. Following it, and despite occasional successes in resisting the Empire's advance, the Rebels would not see another key victory, only loosing ground from then on. By the time of the event, only a few worlds still held on against the Empire's armies, with resistance movements on many others mercilessly hunted down. Had everyone not disappeared, it would have been a question of time before their destruction.]] }, @@ -348,11 +348,11 @@ By the time of the event, only a few worlds still held on against the Empire's a image = "campaign/sample/graphics/unitpics/shipaa.png", category = "4. Locations", text = [[Why would efficiency-obsessed Haven enact such large-scale test battles, let alone dedicate so much of a well-terraformed planet for it? There are few things learned that way that couldn't be discovered for much less, with numerous simulations and a few small-scale battles. What was really going on here? - + Well, for a surprise... - + This was the Anarchai homeworld. The founders of what would become Haven discovered it as the old Empire was crumbling away - the whole thing started as an archeotech effort, in fact. This would certainly explain Haven's obsession with the Anarchai. Whether they were afraid of what they would find, something truly spooked them or they were simply paranoid, they did their best to keep the whole thing secret. Which included turning the entire continent into a high-activity military exercise area, both to cover up their archeotech activities and have convenient armies to deal with interlopers. - + Most of the archives I could find were too well-encrypted, but the little I could decipher indicates that even after all that time, they still had more questions than answers. The Anarchai themselves apparently destroyed a lot of evidence from their origins when they remade themselves. They originally were a small technologist settlement, exploring cybernetic and free machine self-modifications on a remote world, both to avoid what they saw as stifling regulations, and in case something went wrong to the point of quarantine. Their last intelligible log evoked a data sample from Zhurou. What follows, I suspect, is so heavily encrypted at least in part because Haven thought the data itself was so dangerous...]] }, @@ -361,12 +361,12 @@ They originally were a small technologist settlement, exploring cybernetic and f image = "campaign/sample/graphics/icons/CapitalPlanet.png", category = "4. Locations", text = [[Haven cities often had a functional, deliberate beauty to them. Pendust, however, was different. - + This world is ancient. It has been inhabited since the dawn of time. And Haven took care of preserving as much of its history as they could. Andrezi domes and Oroi spires, Akkanian sprawls dotted with monolithic Sovereignty acrologies, glorious Celestial palaces overlooking Myriadic crater-temples to forgotten gods... - + I thought they had turned the entire globe into a war machine, but not quite. They sacrificed a quadrant of the planet to military defenses, after moving every archaeological site they had found out of the way. The entire strategy revolved around forcing a battle for the control of the planet to take place there, where collateral damage would be minimum. Ironically, their capital was the only world over which they were not ready to fight to the death. All their plans revolved over delaying actions and massive evacuations to the Zhurou redoubt. Their defenses were truly formidable, but they would have stopped well short of endangering the planet itself and its historical treasures. - + To this day, the maintenance systems kept the city intact, not caring whether people were left to admire the ancient works.]] }, location_hibiliha = { -- planet61 @@ -374,9 +374,9 @@ To this day, the maintenance systems kept the city intact, not caring whether pe image = "campaign/sample/graphics/icons/wormhole.png", category = "4. Locations", text = [[There was an ancient warp station in this system. A massive installation, that could generate hyperspace highways across the entire galaxy. A few survivors managed to restore it, and used it to bring all the scattered survivor groups here, before continuing on their way to the Empire's heartlands. - + Before leaving, they left it running, with an expert system and a communicator array, so anyone could contact it to ask for a transfer. They knew that, despite their best efforts, it could not run without proper supervision forever. According to the log backups I found, it ran for an impressive four centuries, and was repeatedly used, before failing due to a core malfunction - + So this is why a planet is missing from the system...]] }, location_intrepid = { -- planet64 @@ -384,9 +384,9 @@ So this is why a planet is missing from the system...]] image = "campaign/sample/graphics/icons/DeadGardens.png", category = "4. Locations", text = [[Intrepid had been the seat of most galactic governemnts for a long time, dating back from even before the Ghost Mandate. It was said to be the most beautiful world in the galaxy, a jewel of the old days, carefully tended for even across wars and chaos. - + Alas, left to itself, even those fantastically well-crafted ancient systems fell to entropy in the end. Small, extremely long-term variations that the unthinking expert systems could not have been programmed to correct for, slowly causing it to be caught in a death spiral of desertification. - + Incredibly enough, the machine themselves are still functional. I reprogrammed them as best as I could, using the logs to correct for those longer cycles and variations, and rare cataclysms. It will take centuries, but the garden will be reborn, even if no-one will be there to see it. It won't last forever, of course. But hopefully it will last a bit longer, this time. Ten, fifteen million years...]] }, location_mannia = { -- planet65 @@ -394,9 +394,9 @@ Incredibly enough, the machine themselves are still functional. I reprogrammed t image = "campaign/sample/graphics/icons/TransitCamps.png", category = "4. Locations", text = [[This is where all the refugees of the Empire - of the entire galaxy, in fact - fled towards. The second-to-last world to be hit, it was hospitable enough to harbor the countless refugees in temporary shelters. Building those with so little time and resources would have been an outstanding feat of engineering and logistics in its own right. - + The last world, Cipher, appears to have been less inhabitable, and most resources appears to have been funneled towards it. Were they really hoping that one more jump would make the difference? Or did they choose to hold for the longest, defiant to the end? That would have certainly been in character for the Empire. - + The survivors appears to have used the ruins of the shelters as their base. Even after such a long time, there was enough to build lavish housings for such a small number of individuals. After a while, though, they left in turn for Cipher, leaving infrastructure for latecomers, and what must have been an invitation to follow them.]] }, -- Smuggled data @@ -405,9 +405,9 @@ The survivors appears to have used the ruins of the shelters as their base. Even image = "campaign/sample/graphics/icons/Folder.png", category = "4. Locations", -- planet13, planet46, planet18, planet17, planet21, planet56, planet28, planet7, planet33, planet63, planet68 text = [[Corrupt officials, criminal contacts, shady financial deals... This would have been a treasure trove for law enforcement groups. Some of the code vulnerabilities could be more useful to me though, assuming they haven't been patched or replaced. - + There is also a list of sensitive facilities across the Empire. Not much beyond the names, but it is still impressive that they had access to that kind of data... - + - Unicom network on Phisnet-3617 - good data source (see contacts) - Dynacom networks on Hastus - security too tight, not worth it - Centercom network on Kirdipan - still in progress, good opportunities (see contacts) @@ -426,7 +426,7 @@ There is also a list of sensitive facilities across the Empire. Not much beyond image = "campaign/sample/graphics/unitpics/pw_interception.png", category = "4. Locations", text = [[This interception network was for detecting enemy strategic movements and coordinating forces in the region, but its original role was for intercepting interstellar communications. Not very useful now as the entire galaxy is silent, but at least I could get those blockade forces to stand down. - + The military in this region was given a surprising amount of autonomy. They even raised their own taxes on local civilian centers and trade ships, blurring the line between military force, regional state and a bunch of pirates.]] }, location_kirdipan = { -- planet18 @@ -434,7 +434,7 @@ The military in this region was given a surprising amount of autonomy. They even image = "campaign/sample/graphics/unitpics/pw_interception.png", category = "4. Locations", text = [[This was the keystone of the entire galactic signal intelligence network of the Empire - or should have been, had it been completed on time. Whether mismanagement, cost overruns, mid-project changes of plan, corruption, sabotage or even plain bad luck, the project seems to have kept on stalling again and again. - + At some point, someone decided to re-terraform the entire planet in order to get rid of some unpleasant local condition that was causing too much trouble with the project, but that project also stalled...]] }, location_hastus = { -- planet46 @@ -442,16 +442,16 @@ At some point, someone decided to re-terraform the entire planet in order to get image = "campaign/sample/graphics/unitpics/pw_interception.png", category = "4. Locations", text = [[Even after the Empire shattered the Rebel military, those continued to wage a remarkably successful campaign of guerrilla warfare and political uprisings, despite considerable efforts, resources and violence used against them. It was only with the completion of this interception network that the Empire gained an edge. - + They knew it was not a mere rebellion of malcontents as they and many others had faced in the past, but it was only thanks to this network that they realized who really was behind it all. This seems to have rattled them to their core, and may explain why they suddenly panicked and started a full-blown terror campaign against what was left of the Rebels.]] }, - --- Other locations + --- Other locations location_musashi = { -- planet71 name = "Musashi rally", image = "campaign/sample/graphics/unitpics/tankraid.png", category = "4. Locations", text = [[It feels so nostalgic to see this place again, I had loved watching those so much... And I wasn't the only one, they must have been some of the most popular entertainment in the galaxy. We had betting pools at the academy, and one wargame was even rescheduled so it wouldn't conflict with the season's finale. - + Oh right, I was student at an Imperial Academy of War. Funny thing, to have forgotten that. I was pretty good actually, top of my class half the time. It never felt quite real though, as if never really expecting to ever see combat. And, ultimately, I didn't even graduate...]] }, -- Anomalies @@ -522,7 +522,7 @@ Here. You are the only one left on this side of Eternity. Now go, continue your little quest elsewhere. There is nothing for you here. Your friends thought they could contain me, the poor little things. They never understood how futile were their little metal boxes, had I wanted to leave. But worry not, my time has not come yet. When the last stars have gone out and the last world have frozen, only then will I wake. - + See you then, little one.]] }, anomaly_lovaza_jira = { -- planet28 @@ -530,9 +530,9 @@ See you then, little one.]] image = "campaign/sample/graphics/icons/MemeticHazard.png", category = "5. Anomalies", text = [[It made sense to have put two armies guarding that artefact: it had been almost constantly been fought over, for as long as it had been discovered a few centuries before. Even after the Empire took control of it, raids and attempted theft continued with surprising regularity, only to be repelled by the two guarding forces. Everyone seemed to know how valuable the artefact was, but the constant fighting made it difficult to study it. - + When the Empire's order started to decay in the region, the turmoil made raids on this remote planet less frequent, to the point that the two armies could finally stand down and take a breadth. Which is precisely when they decided to fight each-other over the artefact. - + What they could not find at the time, but what became clear once the fighting stopped and automated systems could finally do their thing, was that this damn thing is an ancient interstellar-range memetic weapon, driving everyone to fight for its possession. In a strange turn of events, I am unaffected due to being the last person in the galaxy, as there is no-one left to fight the artefact over with. Still, better make sure it is stopped for good before leaving the planet...]] }, anomaly_leopard = { -- planet33 @@ -540,13 +540,13 @@ What they could not find at the time, but what became clear once the fighting st image = "campaign/sample/graphics/icons/EmpireHavenBattle.png", category = "5. Anomalies", text = [[No wonder they fought so hard over it, this artifact was a freaking Anarchai scattership! - + When the Ghost Fleet hit the Anarchai, they were completely unprepared to what they were actually facing. However, it is a testament to the might of the Mandate's military that they still managed to destroy several scatterships during the engagement. - + This particular scattership phased right through Leopard after sustaining heavy damage, ending up trapped in its mantle. The few self-repair systems were barely enough to keep its integrity, but its gestalt had been irremediably destroyed - which is presumably why the Anarchai didn't bother recovering or destroying it afterwards. - + Even in its mindless, damaged state, had its self-repair systems kicked in and made it spaceworthy again, it would have had enough firepower to endanger the entire galaxy again. And its technology was so advanced and different from what we know today, who knows what could happen, had someone tried studying it... Haven was terrified that the Empire would be careless enough to try, and the Empire that Haven was desperate enough for it. And so they fought, not to gain control of it, but to make sure no-one would. - + Ultimately, the scattership's internal systems have stopped working one after another, and it is now little more than a wreck full of exotic materials. Still, I am going to leave it alone, just in case..]] }, anomaly_estann_all = { -- planet43 @@ -554,9 +554,9 @@ Ultimately, the scattership's internal systems have stopped working one after an image = "campaign/sample/graphics/icons/Nanite.png", category = "5. Anomalies", text = [[Unsurprisingly, they didn't develop such advanced nanotech themselves. Any record has long been lost to the grey goo, but it isn't too difficult to guess what happened. - + At some point after this planet was settled, probably at a time it was already a developed world, they found this artefact. They understood its potential, both as an incredible archeotech source and an incredible danger. So instead of simply turning it on, they studied it very carefully, and slowly reverse-engineered the simplest of its nanotech. - + They managed to tame the nasty little things, and programmed them for building their metropolis of all things. The artefact's builders would probably have laughed at so crude an use of their subtle technology, but they were long gone anyway. And surprisingly, it seems to have worked without incident - until everyone disappeared, that is. Left to themselves, the nanites seem to have interfered with the artefact itself, causing them to degenerate and switch to an earlier program...]] }, --- Ancient trees @@ -565,11 +565,11 @@ They managed to tame the nasty little things, and programmed them for building t image = "campaign/sample/graphics/icons/SpaceElevatorTree.png", category = "5. Anomalies", text = [[The research facilities weren't so much for studying the skytrees themselves than for unearthing ancient research facilities and their own findings on those trees. - + Unfortunately, being on a strategic crossroads between several warring powers meant that more time and resources were put into defending (or attacking) the place than studying archeotech. Still, a few things were rediscovered. To start with, tree was a misnomer, those things had little to do with Earth plants beyond vaguely similar shapes. - + Their seeds impacted the ground with the force of a nuclear missile, burying themselves deep under the surface. Then, growing over eons to the width of mountains, higher than the atmosphere, they seem to have grown some sort of space elevator, possibly with a counterweight in distant orbit, where new seeds would grow. - + They were thought to have naturally evolved. How and from what, however, remains a mystery.]] }, anomaly_old_falsell = { -- planet45 @@ -577,12 +577,12 @@ They were thought to have naturally evolved. How and from what, however, remains image = "campaign/sample/graphics/icons/NonEquatorialSpaceElevator.png", category = "5. Anomalies", text = [[Neither Old Falsell nore Waliche have traces of large indigenous life apart from the skytrees, and it seems impossible that they evolved on either planet. In fact, complex life was thought to be impossible in the early galaxy, cosmic extinction events being too frequent to let it have time to evolve. - + The trees reproduced by launching their seeds from orbit, and letting them crash back into the ground. They must have traveled across star systems by launching them in outer space instead, and somehow reached adequate planets. No seed flaoting in space or crashed on an inhospitable planet was ever found, so they must have had some way to guide themselves. The trees here are about twenty million years older than those of Waliche, which was consistent with some of the seed migration models that were developed. - + As to where they came from in the first place, it seems to have been a distant, probably very different galaxy. They don't seem to have thrived here, and after briefly taking root on a few worlds, they left as they arrived, throwing their new seeds across intergalactic space. - + Who knows, maybe they are still there, in some remote corner of the universe...]] }, --- Ancient tech and research @@ -591,7 +591,7 @@ Who knows, maybe they are still there, in some remote corner of the universe...] image = "campaign/sample/graphics/unitpics/pw_metal.png", category = "5. Anomalies", text = [[Once common on wealthy worlds, knowledge of how to manufacture those ancient fabricators has been lost for millennia. Now, only a handful still operate across the galaxy - or at least, did when this one was last studied. - + Previous empires have tried to replicate these marvels, even carefully dismantling several over time, and they spared on expense on Asjulohi. They found out how to maintain them, even repairing some of the less decrepit non-functioning ones. But while the theoretical principles behind their operation was better and better understood, they were still far from even thinking about building a new one from scratch.]] }, anomaly_deuliah = { -- planet56 @@ -599,9 +599,9 @@ Previous empires have tried to replicate these marvels, even carefully dismantli image = "campaign/sample/graphics/unitpics/striderdetriment.png", category = "5. Anomalies", text = [[When this R&D site was abandoned, its facilities and material were not shipped off-world or disposed of, apart from the most sensitive works. This inevitably attracted varied scavengers, hoping to make a profit off all the valuables left, from scrap and hardware to data and expert systems. - + Unfortunately for them, defenses and military experiments had been left as well. In particular, one Detriment that had been used as a test platform, had simply been reverted to its original configuration and let loose, apart from extensive self-repair and maintenance upgrades... - + Supposedly a R&D site of the Empire like many others, it had actually been infiltrated by Rebels, and used for research the Empire would never have approved of - such military human genetic modifications beyond anything deemed acceptable by modified or augmented, let alone xenoform. Hardly a surprise though, considering who was behind the Rebels.]] }, anomaly_lalata = { -- planet51 @@ -609,11 +609,11 @@ Supposedly a R&D site of the Empire like many others, it had actually been infil image = "campaign/sample/graphics/icons/EventReport.png", category = "5. Anomalies", text = [[According to their research, the event appears to have started at the extreme end of the Anarchai Arm. Some hypothesized an extragalactic origin based on this, but the spread pattern showed that it had started on a specific region of the galaxy, not propagated from a distant source. - + It propagated through the arm in a matter of days, but had considerably slowed down by the time it reached the Inner Disc. Its progression then became asymmetric, progressing through the Celestial Arm in an estimated two weeks - though an exact time cannot be given due to the current conflict with the Union, then a loss of communication as it was cut off from the Empire. The wavefronts themselves appeared to disrupt hyperspace in a way that made interstellar communication, let alone travel, impossible through their wake. - + The Inner Disc and Dynastic Quadrant were both slowly taken over in a matter of months. By that time, the Empire had ordered a total evacuation towards the Mandate Arm, hoping that at least some worlds would be spared as the advance slowed down. However, later calculations showed that Cipher, the furthest world that could be traveled to, would be overtaken five to fifteen years later. - + They found no way of resist or bypass it, nor even slowing it down. Maybe the data that automated systems recorded when it hit Lalata, but they never found a way to recover it across the event's wake.]] }, } From cccc7695bf325f253789ecaa778f95e857a44f8a Mon Sep 17 00:00:00 2001 From: rlcevg Date: Mon, 7 Dec 2020 23:14:50 +0200 Subject: [PATCH 22/31] Add 'Show AIOptions' toggle. Separate button for AIOptions in ai_list_window --- LuaMenu/images/settings.png | Bin 0 -> 2349 bytes .../chobby/components/ai_list_window.lua | 82 ++++++++++++++---- .../chobby/components/configuration.lua | 2 + LuaMenu/widgets/gui_popup_preloader.lua | 6 +- LuaMenu/widgets/gui_settings_window.lua | 1 + 5 files changed, 73 insertions(+), 18 deletions(-) create mode 100644 LuaMenu/images/settings.png diff --git a/LuaMenu/images/settings.png b/LuaMenu/images/settings.png new file mode 100644 index 0000000000000000000000000000000000000000..7bed8945f33011aafd7d67a944d41d6d2dc08f1e GIT binary patch literal 2349 zcmV+|3DWk7P)E3j!{WO4-gDn&ANqF!XRg0udtOSV2 zbP*X>sWTC|hna5)QMpw_?n+>PyogMXGsY+%1n@|df|)I? z#Be&DZU)c|;IN21*V585%w-%!DTv5$0IvX;KS1;>fR(=Q7hN2Q$TR?l0E~!G{SSb< zecwOfVz;HGWmqbe+DJsp28j0d^z+E}?f0UPk?$pgUSs`{#kd_KxRYisKy052nY z@&GVORrj>Ew$?={ib!h0gbDixnLGg8pGu{kj@2XK~%N@h0M%oZ~9M2E4xmoHzgU%Phg zhd~OF-+=b^_J^4HS8*b~Sy0u5*=%-Cm`+WUk*=<;?xv=uu>ih$-6E?3X0|??%|0Kc z=eiGAsj9Cf3#odj>b_&gj;(UhbxMHm`$cB{Ci*{2H#Mqyu23i}-o1Nw$wl9JC+PeB z1v7gxL10Ayd(CX6sx|?ryL9Q&Eda(8i^YkmI?v30q^kQ=^;4^fD@3$>&6+juJL|_W zE+VX|r)rc6~uKqN2&(XMAV6hAI!{7#q|;UIBaI2OJ{lVOOj6hS~8i;S^(cc#G_3_k<0o( zVke-y!wZwI$Ye4v#?aXwF1y1|P)R|gDMa?`>-ozMB$LTJt*WmC$yIf3 zT$`~HP(IiM?d?AT@cp;}#Kcr}nW|nIOvudlipYXE2Ava7KGN<8QQ7SK{<%2LDz`+lrPFDdQq?RjRN9VA!P%S5z=h+go0{|EvS=84EiRh?Px%1l9j zY5MkZ^){@4c`bj4JAtGy^Iiaf31H@t0G0z-E+QYQ>Tza%*UZiUc#DXRT)cSkbST3cJYb>K3H{zm1kj<#k1cr9r_aUde++a#*`9y1>Y zaMsMu5Yb6hJ<{9Td&n!dj{a2s_X$MgE;CzNuFQ-I@v#8F`nZ!wf|)J2c1atEs$OE| zO{G%lg^rGnV?laO6(JG%f~xLe=AauKr9z=lS83%ZE+R4!z}pCjUsbzRbzv@-i(H;v ztHLK#bsmDN!Zn`f{m{kM^}x)YK=9FV;Sw+^9Soqh_y{Xz1G*aoGNo#5FB`FasqQi0u2(&_Yfi6|SULquod+O4E08r5A}IiG!r{8ijYL(?7mLN|ot>TkaM5@A2$t{My@Z>5@&Lfhso}$i?-CKG@0(Ks zQmNEN0AEWKS#_CfX6sxOBVU1ZI^9e}FC~wu`l#wRvf1o!!gQjp$&E+>~%bh8eN{dwW za+I#BUQ*SCE{)dmQn$d&HVz{GEr6$@Y((CuIC$`&*4NkX8a;aS7$Uk4zy(!ZoXuvR zKYH}2^Ny>ltLy!yrl#>k6nf#3h&E)i+1;*o^ZC5y^ZC8AXU{%tX7kK!6cMcl(Bg8F zJ=Sikt*z~gg+k$M*xlPOMC5J&e+knml}gjXYItF+TD5Ad=Xt3(<15;3CV)ib0|0~8 z^i}n}Y&Kif%~rKLL#C?7gM{VMbyc|$e>fR-BCP1xoP??;pxmF2EgLFsM0515AOR62 zZh6P0>IopCL95CDpsIngp`z*uxOnm6>t^`bt(00000NkvXXu0mjf+~0$e literal 0 HcmV?d00001 diff --git a/LuaMenu/widgets/chobby/components/ai_list_window.lua b/LuaMenu/widgets/chobby/components/ai_list_window.lua index 8d963edb0..4f5693dc1 100644 --- a/LuaMenu/widgets/chobby/components/ai_list_window.lua +++ b/LuaMenu/widgets/chobby/components/ai_list_window.lua @@ -1,5 +1,7 @@ AiListWindow = ListWindow:extends{} +local IMG_SETTINGS = LUA_DIRNAME .. "images/settings.png" + function AiListWindow:init(gameName) self:super('init', lobbyInterfaceHolder, "Choose AI", false, "main_window", nil, {6, 7, 7, 4}) @@ -70,42 +72,88 @@ function AiListWindow:AddAiToList(ai, blackList, oldAiVersions, isRunning64Bit) if Configuration.gameConfig.aiTooltip then tooltip = Configuration.gameConfig.aiTooltip[displayName] end + + local buttonList = nil + if Configuration.showAiOptions then + local path = "AI/Skirmish/" .. shortName .. "/" .. ai.version .. "/AIOptions.lua" + if VFS.FileExists(path) then + buttonList = self:MakeAiOptionsButton(displayName, tooltip, shortName, ai.version, path) + end + end + if buttonList == nil then + buttonList = self:MakeAiButton(displayName, tooltip, shortName, ai.version) + end + self:AddRow(buttonList, displayName) +end + +function AiListWindow:MakeAiOptionsButton(displayName, tooltip, shortName, version, path) local addAIButton = Button:New { x = 0, y = 0, - width = "100%", + width = "80%", height = "100%", caption = displayName, font = Configuration:GetFont(3), tooltip = tooltip, OnClick = { function() - local function defaultAction() - self:AddAi(displayName, shortName, ai.version) + self:AddAi(displayName, shortName, version) + self:HideWindow() + end + }, + } + local optionsButton = Button:New { + x = "80%", + y = 0, + width = "20%", + height = "100%", + caption = "", + font = Configuration:GetFont(3), + OnClick = { + function() + if self.lobby.name ~= "singleplayer" then + -- Disable AIOptions in multiplayer: + -- no protocol command exists to allow creation of startscript with AIOptions by autohost + self:AddAi(displayName, shortName, version) self:HideWindow() - end - - local skirmishDefault = WG.Chobby.Configuration.gameConfig.skirmishDefault - if not skirmishDefault or not skirmishDefault.AIOptionsEnabled then - defaultAction() - return - end - - local path = "AI/Skirmish/" .. ai.shortName .. "/" .. ai.version .. "/AIOptions.lua" - if not VFS.FileExists(path) then - defaultAction() return end - local successFunc = function(aioptions) - self:AddAi(displayName, shortName, ai.version, aioptions) + self:AddAi(displayName, shortName, version, aioptions) self:HideWindow() end WG.Chobby.AiOptionsWindow(displayName, path, successFunc) end }, } - self:AddRow({addAIButton}, displayName) + local optionsImage = Image:New { + x = "10%", + y = "10%", + width = "80%", + height = "80%", + file = IMG_SETTINGS, + parent = optionsButton, + } + return {addAIButton, optionsButton} +end + +function AiListWindow:MakeAiButton(displayName, tooltip, shortName, version) + local addAIButton = Button:New { + x = 0, + y = 0, + width = "100%", + height = "100%", + caption = displayName, + font = Configuration:GetFont(3), + tooltip = tooltip, + OnClick = { + function() + self:AddAi(displayName, shortName, version) + self:HideWindow() + end + }, + } + return {addAIButton} end function AiListWindow:AddAi(displayName, shortName, version, options) diff --git a/LuaMenu/widgets/chobby/components/configuration.lua b/LuaMenu/widgets/chobby/components/configuration.lua index 2ba3fe7d4..988416463 100644 --- a/LuaMenu/widgets/chobby/components/configuration.lua +++ b/LuaMenu/widgets/chobby/components/configuration.lua @@ -215,6 +215,7 @@ function Configuration:init() self.hideInterface = false self.enableTextToSpeech = true self.showOldAiVersions = false + self.showAiOptions = false self.drawAtFullSpeed = false self.lobbyIdleSleep = false self.rememberQueuesOnStart = false @@ -546,6 +547,7 @@ function Configuration:GetConfigData() matchmakerPopupTime = self.matchmakerPopupTime, enableTextToSpeech = self.enableTextToSpeech, showOldAiVersions = self.showOldAiVersions, + showAiOptions = self.showAiOptions, chatFontSize = self.chatFontSize, myAccountID = self.myAccountID, lastAddedAiName = self.lastAddedAiName, diff --git a/LuaMenu/widgets/gui_popup_preloader.lua b/LuaMenu/widgets/gui_popup_preloader.lua index 33baac69b..f2dd4a749 100644 --- a/LuaMenu/widgets/gui_popup_preloader.lua +++ b/LuaMenu/widgets/gui_popup_preloader.lua @@ -15,6 +15,7 @@ local aiListWindow local aiPopup local showOldAiVersions = false +local showAiOptions = false local simpleAiList = true -------------------------------------------------------------------------- @@ -74,9 +75,12 @@ local PopupPreloader = {} function PopupPreloader.ShowAiListWindow(battleLobby, newGameName, teamIndex, quickAddAi) local conf = WG.Chobby.Configuration - if newGameName ~= oldGameName or conf.showOldAiVersions ~= showOldAiVersions or conf.simpleAiList ~= simpleAiList then + if newGameName ~= oldGameName or conf.simpleAiList ~= simpleAiList + or conf.showOldAiVersions ~= showOldAiVersions or conf.showAiOptions ~= showAiOptions + then oldGameName = newGameName showOldAiVersions = conf.showOldAiVersions + showAiOptions = conf.showAiOptions simpleAiList = conf.simpleAiList UpdateAiListWindow(newGameName) end diff --git a/LuaMenu/widgets/gui_settings_window.lua b/LuaMenu/widgets/gui_settings_window.lua index f9d0f6186..a0879e1eb 100644 --- a/LuaMenu/widgets/gui_settings_window.lua +++ b/LuaMenu/widgets/gui_settings_window.lua @@ -1044,6 +1044,7 @@ local function GetVoidTabControls() children[#children + 1], offset = AddCheckboxSetting(offset, "Agressive Set Borderless", "agressivelySetBorderlessWindowed", false) children[#children + 1], offset = AddCheckboxSetting(offset, "Use wrong engine", "useWrongEngine", false) children[#children + 1], offset = AddCheckboxSetting(offset, "Show old AI versions", "showOldAiVersions", false) + children[#children + 1], offset = AddCheckboxSetting(offset, "Show AIOptions", "showAiOptions", false) children[#children + 1] = Label:New { x = 20, From cf7036c859b5f112e845f9f6d53f511955ac493b Mon Sep 17 00:00:00 2001 From: Beherith Date: Wed, 9 Dec 2020 10:19:59 +0100 Subject: [PATCH 23/31] Automatically retry downloads up to WG.Chobby.Configuration.downloadRetryCount times Because very often the download itself actually succeeds, but VFS does not pick it up yet. So a retry in these cases usually does not result in a network transfer, just a vfs recheck, one frame later. --- LuaMenu/widgets/api_download_handler.lua | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/LuaMenu/widgets/api_download_handler.lua b/LuaMenu/widgets/api_download_handler.lua index e6e2c9ded..c6d944e80 100644 --- a/LuaMenu/widgets/api_download_handler.lua +++ b/LuaMenu/widgets/api_download_handler.lua @@ -18,7 +18,7 @@ local externalFunctions = {} local listeners = {} local wrapperFunctions = {} -local downloadQueue = {} -- {name, fileType, priority, id} +local downloadQueue = {} -- {name, fileType, priority, id, retryCount} local downloadCount = 0 local topPriority = 0 local removedDownloads = {} @@ -169,6 +169,17 @@ local function RemoveDownload(name, fileType, putInRemoveList, removalType) end downloadQueue[index] = downloadQueue[#downloadQueue] downloadQueue[#downloadQueue] = nil + + if putInRemoveList and removalType == "fail" and WG.Chobby.Configuration.downloadRetryCount then + local lastFailed = removedDownloads[#removedDownloads] + if lastFailed.retryCount < WG.Chobby.Configuration.downloadRetryCount then + Spring.Echo("Downloading of ",name,fileType,"failed, retryCount=", lastFailed.retryCount) + lastFailed.retryCount = lastFailed.retryCount + 1 + externalFunctions.RetryDownload(name,fileType) + end + else + + end requestUpdate = true return true end @@ -203,6 +214,7 @@ function externalFunctions.QueueDownload(name, fileType, priority) fileType = fileType, priority = priority, id = downloadCount, + retryCount = 0, } requestUpdate = true CallListeners("DownloadQueued", downloadCount, name, fileType) From 55ed83daef8ef27c28391d9086d0b787acc168de Mon Sep 17 00:00:00 2001 From: Beherith Date: Wed, 9 Dec 2020 10:42:53 +0100 Subject: [PATCH 24/31] Create an Integer popup window type --- LuaMenu/widgets/gui_integer_popup_window.lua | 107 +++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 LuaMenu/widgets/gui_integer_popup_window.lua diff --git a/LuaMenu/widgets/gui_integer_popup_window.lua b/LuaMenu/widgets/gui_integer_popup_window.lua new file mode 100644 index 000000000..03e9cecd5 --- /dev/null +++ b/LuaMenu/widgets/gui_integer_popup_window.lua @@ -0,0 +1,107 @@ +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- + +function widget:GetInfo() + return { + name = "Integer Selector Window", + desc = "Displays an integer selector window popup.", + author = "Beherith", + date = "2020.11", + license = "GNU LGPL, v2.1 or later", + layer = 0, + enabled = true -- loaded by default? + } +end + + +local function CreateIntegerSelectorWindow(opts) + opts = opts or {} + + local integerTrackBarValue = opts.defaultValue or 0 + local Configuration = WG.Chobby.Configuration + + local IntegerSelectorWindow = Window:New { + caption = opts.caption or "", + name = "IntegerSelectorWindow", + parent = screen0, + width = 280, + height = 330, + resizable = false, + draggable = false, + classname = "main_window", + } + + local function ChangeAccepted() + if opts.OnAccepted then + opts.OnAccepted(integerTrackBarValue) + end + end + + local function CloseFunction() + IntegerSelectorWindow:Dispose() + IntegerSelectorWindow = nil + end + + local lblTitle = TextBox:New { + x = "5%", + y = "10%", + width = IntegerSelectorWindow.width - IntegerSelectorWindow.padding[1] - IntegerSelectorWindow.padding[3], + height = 35, + align = "center", + font = Configuration:GetFont(2), + text = opts.labelCaption or "", + parent = IntegerSelectorWindow, + } + + local btnOK = Button:New { + x = "10%", + width = "30%", + bottom = 1, + height = 40, + caption = i18n("ok"), + font = Configuration:GetFont(2), + classname = "action_button", + OnClick = { CloseFunction, ChangeAccepted }, + parent = IntegerSelectorWindow, + } + + local btnCancel = Button:New { + right = "10%", + width = "30%", + bottom = 1, + height = 40, + caption = i18n("cancel"), + font = Configuration:GetFont(2), + classname = "action_button", + OnClick = { CloseFunction }, + parent = IntegerSelectorWindow, + } + + + local integerTrackBar = Trackbar:New { + x = 0, + width = IntegerSelectorWindow.width * 0.90, + height = 40, + bottom = 45, + value = opts.defaultValue or 0, + min = opts.minValue or 0, + max = opts.maxValue or 100, + step = opts.step or 1, + parent = IntegerSelectorWindow, + OnChange = { + function(obj, value) + integerTrackBarValue = value + end + } + } + + WG.Chobby.PriorityPopup(IntegerSelectorWindow, CloseFunction, CloseFunction, screen0) +end + +function widget:Initialize() + VFS.Include(LUA_DIRNAME .. "widgets/chobby/headers/exports.lua", nil, VFS.RAW_FIRST) + + WG.IntegerSelectorWindow = { + CreateIntegerSelectorWindow = CreateIntegerSelectorWindow + } +end From 7df1ef42155cd9ba35213f70c214b50a1a0cce4a Mon Sep 17 00:00:00 2001 From: Beherith Date: Wed, 9 Dec 2020 19:40:46 +0100 Subject: [PATCH 25/31] Enable filtering of redundant empty hosts --- .../components/battle/battle_list_window.lua | 89 ++++++++++++++++++- .../widgets/chobby/components/list_window.lua | 9 +- 2 files changed, 95 insertions(+), 3 deletions(-) diff --git a/LuaMenu/widgets/chobby/components/battle/battle_list_window.lua b/LuaMenu/widgets/chobby/components/battle/battle_list_window.lua index e3e448bb4..ba93b5c3b 100644 --- a/LuaMenu/widgets/chobby/components/battle/battle_list_window.lua +++ b/LuaMenu/widgets/chobby/components/battle/battle_list_window.lua @@ -120,11 +120,34 @@ function BattleListWindow:init(parent) }, parent = self.window, } + if Configuration.battleFilterRedundant then + local checkRedundant = Checkbox:New { + x = 590, + width = 21, + bottom = 4, + height = 30, + boxalign = "left", + boxsize = 20, + caption = " Redundant", + checked = Configuration.battleFilterRedundant or false, + font = Configuration:GetFont(2), + OnChange = { + function (obj, newState) + Configuration:SetConfigValue("battleFilterRedundant", newState) + SoftUpdate() + end + }, + parent = self.window, + } + end local function UpdateCheckboxes() checkPassworded:SetToggle(Configuration.battleFilterPassworded2) checkNonFriend:SetToggle(Configuration.battleFilterNonFriend) checkRunning:SetToggle(Configuration.battleFilterRunning) + if Configuration.battleFilterRedundant then + checkRedundant:SetToggle(Configuration.battleFilterRedundant) + end end WG.Delay(UpdateCheckboxes, 0.2) @@ -581,7 +604,7 @@ function BattleListWindow:AddBattle(battleID, battle) self:AddRow({button}, battle.battleID) end -function BattleListWindow:ItemInFilter(id) +function BattleListWindow:ItemInFilter(id, allbattles) local battle = lobby:GetBattle(id) local filterString = Configuration.gameConfig.battleListOnlyShow if filterString ~= nil then @@ -598,9 +621,73 @@ function BattleListWindow:ItemInFilter(id) return false end end + if Configuration.battleFilterRunning and battle.isRunning then return false end + + if Configuration.battleFilterRedundant and allbattles then + local myplayercount = lobby:GetBattlePlayerCount(id) + --Spring.Echo("redundancy filter checking for",battle.isRunning, battle.spectatorCount,myplayercount) + -- for each non-empty battle, only display EU-AUS-USA- hosts first number that is empty + if battle.isRunning then return true end + if myplayercount and myplayercount > 0 then return true end + if battle.spectatorCount and battle.spectatorCount > 1 then return true end + + function parseBattleNumber(btitle) + battlekeys = Configuration.battleFilterRedundantRegions or {} + local hostcountry = nil + for k,battlekey in pairs(battlekeys) do + if string.find( btitle,battlekey ) == 1 then + hostcountry = battlekey + end + end + if hostcountry == nil then + return nil + else + local numbertext = string.sub(btitle,string.len(hostcountry),-1) + if pcall(tonumber, numbertext) == false then return nil end + local hostnumber = tonumber(numbertext) + if hostnumber == nil then + return nil + else + return hostcountry, hostnumber + end + end + end + + local myBattleTitle = battle.title + local mycountry, mynumber = parseBattleNumber(battle.title) + --Spring.Echo("redundancy filter checking for", mycountry,mynumber) + if mycountry == nil then return true end + + local lowestemptybattleindex = 100000000 + local lowestemptybattleID = nil + for k,otherbattleID in pairs(allbattles) do + local otherbattle = lobby:GetBattle(otherbattleID) + local ob_hostcountry, ob_hostnumber = parseBattleNumber(otherbattle.title) + local otherbattleplayercount = lobby:GetBattlePlayerCount(otherbattleID) + + --Spring.Echo("Other battle", ob_hostcountry, ob_hostnumber,otherbattleplayercount ,otherbattle.spectatorCount) + if ob_hostcountry and + ob_hostnumber < lowestemptybattleindex and + otherbattleplayercount == 0 and + otherbattle.spectatorCount == 1 and + mycountry == ob_hostcountry then + + lowestemptybattleID = otherbattleID + lowestemptybattleindex = ob_hostnumber + end + end + if lowestemptybattleID == nil then return true end + + if lowestemptybattleID == id then + return true + else + return false + end + end + return true end diff --git a/LuaMenu/widgets/chobby/components/list_window.lua b/LuaMenu/widgets/chobby/components/list_window.lua index 07934c659..5610d5d0b 100644 --- a/LuaMenu/widgets/chobby/components/list_window.lua +++ b/LuaMenu/widgets/chobby/components/list_window.lua @@ -215,13 +215,18 @@ function ListWindow:CompareItems(id1, id2) return true end -function ListWindow:ItemInFilter(id) +function ListWindow:ItemInFilter(id, allbattleids) return true end function ListWindow:UpdateFilters() + local allbattleids = {} for i = 1, self.scrollChildren do - self.orderPanelMapping[i].inFilter = self:ItemInFilter(self.orderPanelMapping[i].id) + allbattleids[#allbattleids+1] = self.orderPanelMapping[i].id + end + + for i = 1, self.scrollChildren do + self.orderPanelMapping[i].inFilter = self:ItemInFilter(self.orderPanelMapping[i].id, allbattleids) end for id, _ in pairs(self.itemPanelMapping) do self:RecalculateOrder(id) From 68404703aba05c92c6d4d2cf481cbff2e9ce4377 Mon Sep 17 00:00:00 2001 From: Beherith Date: Thu, 10 Dec 2020 14:44:21 +0100 Subject: [PATCH 26/31] Make travis not cry --- LuaMenu/widgets/api_download_handler.lua | 2 -- 1 file changed, 2 deletions(-) diff --git a/LuaMenu/widgets/api_download_handler.lua b/LuaMenu/widgets/api_download_handler.lua index c6d944e80..a9eb48f2c 100644 --- a/LuaMenu/widgets/api_download_handler.lua +++ b/LuaMenu/widgets/api_download_handler.lua @@ -177,8 +177,6 @@ local function RemoveDownload(name, fileType, putInRemoveList, removalType) lastFailed.retryCount = lastFailed.retryCount + 1 externalFunctions.RetryDownload(name,fileType) end - else - end requestUpdate = true return true From 4f13c8fb5a086a545afb34c5d271160ebbd7c033 Mon Sep 17 00:00:00 2001 From: Beherith Date: Thu, 10 Dec 2020 14:46:11 +0100 Subject: [PATCH 27/31] white space --- .../chobby/components/battle/battle_list_window.lua | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/LuaMenu/widgets/chobby/components/battle/battle_list_window.lua b/LuaMenu/widgets/chobby/components/battle/battle_list_window.lua index ba93b5c3b..d7e11cf87 100644 --- a/LuaMenu/widgets/chobby/components/battle/battle_list_window.lua +++ b/LuaMenu/widgets/chobby/components/battle/battle_list_window.lua @@ -648,14 +648,13 @@ function BattleListWindow:ItemInFilter(id, allbattles) local numbertext = string.sub(btitle,string.len(hostcountry),-1) if pcall(tonumber, numbertext) == false then return nil end local hostnumber = tonumber(numbertext) - if hostnumber == nil then + if hostnumber == nil then return nil else return hostcountry, hostnumber end end end - local myBattleTitle = battle.title local mycountry, mynumber = parseBattleNumber(battle.title) --Spring.Echo("redundancy filter checking for", mycountry,mynumber) @@ -669,8 +668,8 @@ function BattleListWindow:ItemInFilter(id, allbattles) local otherbattleplayercount = lobby:GetBattlePlayerCount(otherbattleID) --Spring.Echo("Other battle", ob_hostcountry, ob_hostnumber,otherbattleplayercount ,otherbattle.spectatorCount) - if ob_hostcountry and - ob_hostnumber < lowestemptybattleindex and + if ob_hostcountry and + ob_hostnumber < lowestemptybattleindex and otherbattleplayercount == 0 and otherbattle.spectatorCount == 1 and mycountry == ob_hostcountry then @@ -681,7 +680,7 @@ function BattleListWindow:ItemInFilter(id, allbattles) end if lowestemptybattleID == nil then return true end - if lowestemptybattleID == id then + if lowestemptybattleID == id then return true else return false From be5c79ce94c2e5d58fe6df95f0cdd59722e9ce8d Mon Sep 17 00:00:00 2001 From: Beherith Date: Thu, 10 Dec 2020 17:59:32 +0100 Subject: [PATCH 28/31] Tooltips to battle filters --- .../widgets/chobby/components/battle/battle_list_window.lua | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/LuaMenu/widgets/chobby/components/battle/battle_list_window.lua b/LuaMenu/widgets/chobby/components/battle/battle_list_window.lua index d7e11cf87..60acf1d80 100644 --- a/LuaMenu/widgets/chobby/components/battle/battle_list_window.lua +++ b/LuaMenu/widgets/chobby/components/battle/battle_list_window.lua @@ -83,6 +83,7 @@ function BattleListWindow:init(parent) end }, parent = self.window, + tooltip = "Hides all private battles that require a password to join", } local checkNonFriend = Checkbox:New { x = 280, @@ -101,6 +102,7 @@ function BattleListWindow:init(parent) end }, parent = self.window, + tooltip = "Hides all battles that dont have your friends in them", } local checkRunning = Checkbox:New { x = 435, @@ -119,6 +121,7 @@ function BattleListWindow:init(parent) end }, parent = self.window, + tooltip = "Hides all battles that are in progress", } if Configuration.battleFilterRedundant then local checkRedundant = Checkbox:New { @@ -138,6 +141,7 @@ function BattleListWindow:init(parent) end }, parent = self.window, + tooltip = "Hides empty regional autohosts", } end From 2e7c238fcb36f397302279e30a5a1810dffd89ed Mon Sep 17 00:00:00 2001 From: rlcevg Date: Sat, 12 Dec 2020 15:10:57 +0200 Subject: [PATCH 29/31] Hide AIOptions button in multiplayer --- .../chobby/components/ai_list_window.lua | 55 ++++++------------- LuaMenu/widgets/gui_popup_preloader.lua | 18 +++--- 2 files changed, 27 insertions(+), 46 deletions(-) diff --git a/LuaMenu/widgets/chobby/components/ai_list_window.lua b/LuaMenu/widgets/chobby/components/ai_list_window.lua index 4f5693dc1..4351d7544 100644 --- a/LuaMenu/widgets/chobby/components/ai_list_window.lua +++ b/LuaMenu/widgets/chobby/components/ai_list_window.lua @@ -2,11 +2,12 @@ AiListWindow = ListWindow:extends{} local IMG_SETTINGS = LUA_DIRNAME .. "images/settings.png" -function AiListWindow:init(gameName) +function AiListWindow:init(lobby, gameName) self:super('init', lobbyInterfaceHolder, "Choose AI", false, "main_window", nil, {6, 7, 7, 4}) self.window:SetPos(nil, nil, 500, 700) + self.lobby = lobby or self.lobby self.validAiNames = {} -- Disable game-specific AIs for now since it breaks /luaui reload @@ -15,11 +16,11 @@ function AiListWindow:init(gameName) local blackList = Configuration.gameConfig.aiBlacklist local oldAiVersions = (not Configuration.showOldAiVersions) and Configuration.gameConfig.oldAiVersions local isRunning64Bit = Configuration:GetIsRunning64Bit() + local isSingleplayer = lobby.name == "singleplayer" for i, ai in pairs(ais) do - self:AddAiToList(ai, blackList, oldAiVersions, isRunning64Bit) + self:AddAiToList(ai, blackList, oldAiVersions, isRunning64Bit, isSingleplayer) end - end function AiListWindow:CompareItems(id1, id2) @@ -32,7 +33,7 @@ function AiListWindow:CompareItems(id1, id2) return true end -function AiListWindow:AddAiToList(ai, blackList, oldAiVersions, isRunning64Bit) +function AiListWindow:AddAiToList(ai, blackList, oldAiVersions, isRunning64Bit, isSingleplayer) local shortName = ai.shortName or "Unknown" if blackList and blackList[shortName] then @@ -73,35 +74,20 @@ function AiListWindow:AddAiToList(ai, blackList, oldAiVersions, isRunning64Bit) tooltip = Configuration.gameConfig.aiTooltip[displayName] end - local buttonList = nil - if Configuration.showAiOptions then + local buttonList = {} + local btnWidth = "100%" + if Configuration.showAiOptions and isSingleplayer then local path = "AI/Skirmish/" .. shortName .. "/" .. ai.version .. "/AIOptions.lua" if VFS.FileExists(path) then - buttonList = self:MakeAiOptionsButton(displayName, tooltip, shortName, ai.version, path) + buttonList[#buttonList + 1] = self:MakeAiOptionsButton(displayName, tooltip, shortName, ai.version, path) + btnWidth = "80%" end end - if buttonList == nil then - buttonList = self:MakeAiButton(displayName, tooltip, shortName, ai.version) - end + buttonList[#buttonList + 1] = self:MakeAiButton(btnWidth, displayName, tooltip, shortName, ai.version) self:AddRow(buttonList, displayName) end function AiListWindow:MakeAiOptionsButton(displayName, tooltip, shortName, version, path) - local addAIButton = Button:New { - x = 0, - y = 0, - width = "80%", - height = "100%", - caption = displayName, - font = Configuration:GetFont(3), - tooltip = tooltip, - OnClick = { - function() - self:AddAi(displayName, shortName, version) - self:HideWindow() - end - }, - } local optionsButton = Button:New { x = "80%", y = 0, @@ -111,13 +97,6 @@ function AiListWindow:MakeAiOptionsButton(displayName, tooltip, shortName, versi font = Configuration:GetFont(3), OnClick = { function() - if self.lobby.name ~= "singleplayer" then - -- Disable AIOptions in multiplayer: - -- no protocol command exists to allow creation of startscript with AIOptions by autohost - self:AddAi(displayName, shortName, version) - self:HideWindow() - return - end local successFunc = function(aioptions) self:AddAi(displayName, shortName, version, aioptions) self:HideWindow() @@ -134,14 +113,14 @@ function AiListWindow:MakeAiOptionsButton(displayName, tooltip, shortName, versi file = IMG_SETTINGS, parent = optionsButton, } - return {addAIButton, optionsButton} + return optionsButton end -function AiListWindow:MakeAiButton(displayName, tooltip, shortName, version) - local addAIButton = Button:New { +function AiListWindow:MakeAiButton(btnWidth, displayName, tooltip, shortName, version) + return Button:New { x = 0, y = 0, - width = "100%", + width = btnWidth, height = "100%", caption = displayName, font = Configuration:GetFont(3), @@ -153,7 +132,6 @@ function AiListWindow:MakeAiButton(displayName, tooltip, shortName, version) end }, } - return {addAIButton} end function AiListWindow:AddAi(displayName, shortName, version, options) @@ -186,7 +164,6 @@ function AiListWindow:QuickAdd(shortName) end end -function AiListWindow:SetLobbyAndAllyTeam(lobby, allyTeam) - self.lobby = lobby or self.lobby +function AiListWindow:SetAllyTeam(allyTeam) self.allyTeam = allyTeam or self.allyTeam end diff --git a/LuaMenu/widgets/gui_popup_preloader.lua b/LuaMenu/widgets/gui_popup_preloader.lua index f2dd4a749..347c64f5a 100644 --- a/LuaMenu/widgets/gui_popup_preloader.lua +++ b/LuaMenu/widgets/gui_popup_preloader.lua @@ -10,6 +10,7 @@ function widget:GetInfo() } end +local oldLobby local oldGameName local aiListWindow local aiPopup @@ -22,11 +23,11 @@ local simpleAiList = true -------------------------------------------------------------------------- -- AI List window updating -local function UpdateAiListWindow(gameName) +local function UpdateAiListWindow(battleLobby, gameName) if aiPopup then aiPopup:ClosePopup() end - aiListWindow = WG.Chobby.AiListWindow(gameName) + aiListWindow = WG.Chobby.AiListWindow(battleLobby, gameName) aiListWindow.window:Hide() end @@ -46,8 +47,9 @@ local function InitializeListeners(battleLobby) return end + oldLobby = battleLobby oldGameName = newGameName - UpdateAiListWindow(newGameName) + UpdateAiListWindow(battleLobby, newGameName) end local function OnJoinedBattle(listener, joinedBattleId, userName) @@ -59,8 +61,9 @@ local function InitializeListeners(battleLobby) return end + oldLobby = battleLobby oldGameName = newGameName - UpdateAiListWindow(newGameName) + UpdateAiListWindow(battleLobby, newGameName) end battleLobby:AddListener("OnUpdateBattleInfo", OnUpdateBattleInfo) @@ -75,17 +78,18 @@ local PopupPreloader = {} function PopupPreloader.ShowAiListWindow(battleLobby, newGameName, teamIndex, quickAddAi) local conf = WG.Chobby.Configuration - if newGameName ~= oldGameName or conf.simpleAiList ~= simpleAiList + if newGameName ~= oldGameName or conf.simpleAiList ~= simpleAiList or oldLobby ~= battleLobby or conf.showOldAiVersions ~= showOldAiVersions or conf.showAiOptions ~= showAiOptions then + oldLobby = battleLobby oldGameName = newGameName showOldAiVersions = conf.showOldAiVersions showAiOptions = conf.showAiOptions simpleAiList = conf.simpleAiList - UpdateAiListWindow(newGameName) + UpdateAiListWindow(battleLobby, newGameName) end - aiListWindow:SetLobbyAndAllyTeam(battleLobby, teamIndex) + aiListWindow:SetAllyTeam(teamIndex) if quickAddAi and aiListWindow:QuickAdd(quickAddAi) then return end From d58721f75d397a10254d8e30d9649a7b6a3ffce7 Mon Sep 17 00:00:00 2001 From: Gajo Petrovic Date: Sun, 13 Dec 2020 15:43:59 +0900 Subject: [PATCH 30/31] - remove modifications in list_window.lua - DRY battle_list_window's SoftUpdate - fix spelling & tweak tooltip text - move "hide redundant battlerooms" to a dev-only checkbox --- LuaMenu/widgets/api_download_handler.lua | 4 +- .../components/battle/battle_list_window.lua | 176 ++++++++---------- .../widgets/chobby/components/list_window.lua | 9 +- LuaMenu/widgets/gui_download_window.lua | 8 +- LuaMenu/widgets/gui_settings_window.lua | 4 + 5 files changed, 92 insertions(+), 109 deletions(-) diff --git a/LuaMenu/widgets/api_download_handler.lua b/LuaMenu/widgets/api_download_handler.lua index a9eb48f2c..01c43a958 100644 --- a/LuaMenu/widgets/api_download_handler.lua +++ b/LuaMenu/widgets/api_download_handler.lua @@ -173,8 +173,8 @@ local function RemoveDownload(name, fileType, putInRemoveList, removalType) if putInRemoveList and removalType == "fail" and WG.Chobby.Configuration.downloadRetryCount then local lastFailed = removedDownloads[#removedDownloads] if lastFailed.retryCount < WG.Chobby.Configuration.downloadRetryCount then - Spring.Echo("Downloading of ",name,fileType,"failed, retryCount=", lastFailed.retryCount) - lastFailed.retryCount = lastFailed.retryCount + 1 + Spring.Echo("Downloading of ", name, fileType, "failed, retryCount=", lastFailed.retryCount) + lastFailed.retryCount = lastFailed.retryCount + 1 externalFunctions.RetryDownload(name,fileType) end end diff --git a/LuaMenu/widgets/chobby/components/battle/battle_list_window.lua b/LuaMenu/widgets/chobby/components/battle/battle_list_window.lua index 60acf1d80..60bf0a004 100644 --- a/LuaMenu/widgets/chobby/components/battle/battle_list_window.lua +++ b/LuaMenu/widgets/chobby/components/battle/battle_list_window.lua @@ -27,11 +27,6 @@ function BattleListWindow:init(parent) } end - local function SoftUpdate() - self:UpdateFilters() - self:UpdateInfoPanel() - end - local function update() self:Update() end @@ -79,11 +74,11 @@ function BattleListWindow:init(parent) OnChange = { function (obj, newState) Configuration:SetConfigValue("battleFilterPassworded2", newState) - SoftUpdate() + self:SoftUpdate() end }, parent = self.window, - tooltip = "Hides all private battles that require a password to join", + tooltip = "Hides all battles that require a password to join", } local checkNonFriend = Checkbox:New { x = 280, @@ -98,11 +93,11 @@ function BattleListWindow:init(parent) OnChange = { function (obj, newState) Configuration:SetConfigValue("battleFilterNonFriend", newState) - SoftUpdate() + self:SoftUpdate() end }, parent = self.window, - tooltip = "Hides all battles that dont have your friends in them", + tooltip = "Hides all battles that don't have your friends in them", } local checkRunning = Checkbox:New { x = 435, @@ -117,41 +112,17 @@ function BattleListWindow:init(parent) OnChange = { function (obj, newState) Configuration:SetConfigValue("battleFilterRunning", newState) - SoftUpdate() + self:SoftUpdate() end }, parent = self.window, tooltip = "Hides all battles that are in progress", } - if Configuration.battleFilterRedundant then - local checkRedundant = Checkbox:New { - x = 590, - width = 21, - bottom = 4, - height = 30, - boxalign = "left", - boxsize = 20, - caption = " Redundant", - checked = Configuration.battleFilterRedundant or false, - font = Configuration:GetFont(2), - OnChange = { - function (obj, newState) - Configuration:SetConfigValue("battleFilterRedundant", newState) - SoftUpdate() - end - }, - parent = self.window, - tooltip = "Hides empty regional autohosts", - } - end local function UpdateCheckboxes() checkPassworded:SetToggle(Configuration.battleFilterPassworded2) checkNonFriend:SetToggle(Configuration.battleFilterNonFriend) checkRunning:SetToggle(Configuration.battleFilterRunning) - if Configuration.battleFilterRedundant then - checkRedundant:SetToggle(Configuration.battleFilterRedundant) - end end WG.Delay(UpdateCheckboxes, 0.2) @@ -172,7 +143,7 @@ function BattleListWindow:init(parent) return end self:AddBattle(battleID, lobby:GetBattle(battleID)) - SoftUpdate() + self:SoftUpdate() end lobby:AddListener("OnBattleOpened", self.onBattleOpened) @@ -181,7 +152,7 @@ function BattleListWindow:init(parent) return end self:RemoveRow(battleID) - SoftUpdate() + self:SoftUpdate() end lobby:AddListener("OnBattleClosed", self.onBattleClosed) @@ -190,7 +161,7 @@ function BattleListWindow:init(parent) return end self:JoinedBattle(battleID) - SoftUpdate() + self:SoftUpdate() end lobby:AddListener("OnJoinedBattle", self.onJoinedBattle) @@ -199,7 +170,7 @@ function BattleListWindow:init(parent) return end self:LeftBattle(battleID) - SoftUpdate() + self:SoftUpdate() end lobby:AddListener("OnLeftBattle", self.onLeftBattle) @@ -208,7 +179,7 @@ function BattleListWindow:init(parent) return end self:OnUpdateBattleInfo(battleID) - SoftUpdate() + self:SoftUpdate() end lobby:AddListener("OnUpdateBattleInfo", self.onUpdateBattleInfo) @@ -217,13 +188,15 @@ function BattleListWindow:init(parent) return end self:OnBattleIngameUpdate(battleID, isRunning) - SoftUpdate() + self:SoftUpdate() end lobby:AddListener("OnBattleIngameUpdate", self.onBattleIngameUpdate) local function onConfigurationChange(listener, key, value) if key == "displayBadEngines2" then update() + elseif key == "battleFilterRedundant" then + self:SoftUpdate() end end Configuration:AddListener("OnConfigurationChange", onConfigurationChange) @@ -249,6 +222,13 @@ function BattleListWindow:RemoveListeners() lobby:RemoveListener("DownloadFinished", self.downloadFinished) end +function BattleListWindow:UpdateAllBattleIDs() + self.allBattleIDs = {} + for i = 1, self.scrollChildren do + self.allBattleIDs[i] = self.orderPanelMapping[i].id + end +end + function BattleListWindow:Update() self:Clear() @@ -262,6 +242,14 @@ function BattleListWindow:Update() for _, battle in pairs(battles) do self:AddBattle(battle.battleID, battle) end + + self:SoftUpdate() +end + +function BattleListWindow:SoftUpdate() + if Configuration.battleFilterRedundant then + self:UpdateAllBattleIDs() + end self:UpdateFilters() self:UpdateInfoPanel() end @@ -608,7 +596,7 @@ function BattleListWindow:AddBattle(battleID, battle) self:AddRow({button}, battle.battleID) end -function BattleListWindow:ItemInFilter(id, allbattles) +function BattleListWindow:ItemInFilter(id) local battle = lobby:GetBattle(id) local filterString = Configuration.gameConfig.battleListOnlyShow if filterString ~= nil then @@ -630,68 +618,64 @@ function BattleListWindow:ItemInFilter(id, allbattles) return false end - if Configuration.battleFilterRedundant and allbattles then - local myplayercount = lobby:GetBattlePlayerCount(id) - --Spring.Echo("redundancy filter checking for",battle.isRunning, battle.spectatorCount,myplayercount) - -- for each non-empty battle, only display EU-AUS-USA- hosts first number that is empty - if battle.isRunning then return true end - if myplayercount and myplayercount > 0 then return true end - if battle.spectatorCount and battle.spectatorCount > 1 then return true end - - function parseBattleNumber(btitle) - battlekeys = Configuration.battleFilterRedundantRegions or {} - local hostcountry = nil - for k,battlekey in pairs(battlekeys) do - if string.find( btitle,battlekey ) == 1 then - hostcountry = battlekey - end - end - if hostcountry == nil then - return nil - else - local numbertext = string.sub(btitle,string.len(hostcountry),-1) - if pcall(tonumber, numbertext) == false then return nil end - local hostnumber = tonumber(numbertext) - if hostnumber == nil then - return nil - else - return hostcountry, hostnumber - end + if Configuration.battleFilterRedundant then + return self:FilterRedundantBattle(battle, id) + end + + return true +end + +function BattleListWindow:FilterRedundantBattle(battle, id) + -- for each non-empty battle, only display EU-AUS-USA- hosts first number that is empty + if battle.isRunning + or lobby:GetBattlePlayerCount(id) > 0 + or (battle.spectatorCount and battle.spectatorCount > 1) then + return true + end + + function parseBattleNumber(battleTitle) + battleKeys = Configuration.battleFilterRedundantRegions or {} + local hostCountry = nil + for k, battleKey in pairs(battleKeys) do + if string.find(battleTitle, battleKey) == 1 then + hostCountry = battleKey end end - local myBattleTitle = battle.title - local mycountry, mynumber = parseBattleNumber(battle.title) - --Spring.Echo("redundancy filter checking for", mycountry,mynumber) - if mycountry == nil then return true end - - local lowestemptybattleindex = 100000000 - local lowestemptybattleID = nil - for k,otherbattleID in pairs(allbattles) do - local otherbattle = lobby:GetBattle(otherbattleID) - local ob_hostcountry, ob_hostnumber = parseBattleNumber(otherbattle.title) - local otherbattleplayercount = lobby:GetBattlePlayerCount(otherbattleID) - - --Spring.Echo("Other battle", ob_hostcountry, ob_hostnumber,otherbattleplayercount ,otherbattle.spectatorCount) - if ob_hostcountry and - ob_hostnumber < lowestemptybattleindex and - otherbattleplayercount == 0 and - otherbattle.spectatorCount == 1 and - mycountry == ob_hostcountry then - - lowestemptybattleID = otherbattleID - lowestemptybattleindex = ob_hostnumber - end + if hostCountry == nil then + return nil end - if lowestemptybattleID == nil then return true end - if lowestemptybattleID == id then - return true - else - return false + local hostnumber = tonumber(string.sub(battleTitle, string.len(hostCountry), -1)) + if hostnumber == nil then + return nil end + + return hostCountry, hostnumber + end + local myCountry, myNumber = parseBattleNumber(battle.title) + if myCountry == nil then + return true end - return true + local lowestEmptyBattleIndex = math.huge + local lowestEmptyBattleID = nil + for k, otherBattleID in pairs(self.allBattleIDs) do + local otherBattle = lobby:GetBattle(otherBattleID) + local ob_hostCountry, ob_hostnumber = parseBattleNumber(otherBattle.title) + local otherBattlePlayerCount = lobby:GetBattlePlayerCount(otherBattleID) + + if ob_hostCountry and + ob_hostnumber < lowestEmptyBattleIndex and + otherBattlePlayerCount == 0 and + otherBattle.spectatorCount == 1 and + myCountry == ob_hostCountry then + + lowestEmptyBattleID = otherBattleID + lowestEmptyBattleIndex = ob_hostnumber + end + end + + return lowestEmptyBattleID == nil or lowestEmptyBattleID == id end function BattleListWindow:CompareItems(id1, id2) diff --git a/LuaMenu/widgets/chobby/components/list_window.lua b/LuaMenu/widgets/chobby/components/list_window.lua index 5610d5d0b..07934c659 100644 --- a/LuaMenu/widgets/chobby/components/list_window.lua +++ b/LuaMenu/widgets/chobby/components/list_window.lua @@ -215,18 +215,13 @@ function ListWindow:CompareItems(id1, id2) return true end -function ListWindow:ItemInFilter(id, allbattleids) +function ListWindow:ItemInFilter(id) return true end function ListWindow:UpdateFilters() - local allbattleids = {} for i = 1, self.scrollChildren do - allbattleids[#allbattleids+1] = self.orderPanelMapping[i].id - end - - for i = 1, self.scrollChildren do - self.orderPanelMapping[i].inFilter = self:ItemInFilter(self.orderPanelMapping[i].id, allbattleids) + self.orderPanelMapping[i].inFilter = self:ItemInFilter(self.orderPanelMapping[i].id) end for id, _ in pairs(self.itemPanelMapping) do self:RecalculateOrder(id) diff --git a/LuaMenu/widgets/gui_download_window.lua b/LuaMenu/widgets/gui_download_window.lua index 70f76c40f..bff48fdc6 100644 --- a/LuaMenu/widgets/gui_download_window.lua +++ b/LuaMenu/widgets/gui_download_window.lua @@ -127,9 +127,9 @@ local function CreateDownloadEntry(downloadData) parent = holder, } - local downloadDataname = downloadData.name - if Configuration.gameConfig and Configuration.gameConfig.ShortenNameString then - downloadDataname = Configuration.gameConfig.ShortenNameString(downloadDataname) + local downloadDataName = downloadData.name + if Configuration.gameConfig.ShortenNameString then + downloadDataName = Configuration.gameConfig.ShortenNameString(downloadDataName) end TextBox:New { x = 15 + BUTTON_WIDTH*2, @@ -138,7 +138,7 @@ local function CreateDownloadEntry(downloadData) height = 20, valign = 'center', fontsize = Configuration:GetFont(2).size, - text = downloadDataname, + text = downloadDataName, parent = holder, } diff --git a/LuaMenu/widgets/gui_settings_window.lua b/LuaMenu/widgets/gui_settings_window.lua index f9d0f6186..cf329acf5 100644 --- a/LuaMenu/widgets/gui_settings_window.lua +++ b/LuaMenu/widgets/gui_settings_window.lua @@ -1044,6 +1044,10 @@ local function GetVoidTabControls() children[#children + 1], offset = AddCheckboxSetting(offset, "Agressive Set Borderless", "agressivelySetBorderlessWindowed", false) children[#children + 1], offset = AddCheckboxSetting(offset, "Use wrong engine", "useWrongEngine", false) children[#children + 1], offset = AddCheckboxSetting(offset, "Show old AI versions", "showOldAiVersions", false) + children[#children + 1], offset = AddCheckboxSetting(offset, "Show AIOptions", "showAiOptions", true) + if Configuration.gameConfig.filterEmptyRegionalAutohosts then + children[#children + 1], offset = AddCheckboxSetting(offset, "Filter redundant battles", "battleFilterRedundant", true, nil, "Hides redundant empty regional autohosts.") + end children[#children + 1] = Label:New { x = 20, From 3bfc4109e0f5798ab5be4a5cafaf7f3dbd9ff6cb Mon Sep 17 00:00:00 2001 From: Gajo Petrovic Date: Sat, 19 Dec 2020 14:30:09 +0900 Subject: [PATCH 31/31] fix uber's friend list and make it not conflict with ZK's implementation --- libs/liblobby/lobby/interface.lua | 14 ++++++----- libs/liblobby/lobby/interface_zerok.lua | 29 +++++----------------- libs/liblobby/lobby/lobby.lua | 18 ++++++++++---- libs/liblobby/lobby/utilities.lua | 32 +++++++++++++++---------- 4 files changed, 47 insertions(+), 46 deletions(-) diff --git a/libs/liblobby/lobby/interface.lua b/libs/liblobby/lobby/interface.lua index d2094d53f..41a1694e5 100644 --- a/libs/liblobby/lobby/interface.lua +++ b/libs/liblobby/lobby/interface.lua @@ -476,20 +476,22 @@ Interface.commands["CLIENTSTATUS"] = Interface._OnClientStatus Interface.commandPattern["CLIENTSTATUS"] = "(%S+)%s+(%S+)" --friends -function Interface:_OnFriend(tags) +-- NB: added the _Uber suffix so not to conflict with Lobby:_OnFriend +function Interface:_OnFriend_Uber(tags) local tags = parseTags(tags) local userName = getTag(tags, "userName", true) - self:super("_OnFriend", userName) + self:_OnFriend(userName) end -Interface.commands["FRIEND"] = Interface._OnFriend +Interface.commands["FRIEND"] = Interface._OnFriend_Uber Interface.commandPattern["FRIEND"] = "(.+)" -function Interface:_OnUnfriend(tags) +-- NB: added the _Uber suffix so not to conflict with Lobby:_OnUnfriend +function Interface:_OnUnfriend_Uber(tags) local tags = parseTags(tags) local userName = getTag(tags, "userName", true) - self:super("_OnUnfriend", userName) + self:_OnUnfriend(userName) end -Interface.commands["UNFRIEND"] = Interface._OnUnfriend +Interface.commands["UNFRIEND"] = Interface._OnUnfriend_Uber Interface.commandPattern["UNFRIEND"] = "(.+)" function Interface:_OnFriendList(tags) diff --git a/libs/liblobby/lobby/interface_zerok.lua b/libs/liblobby/lobby/interface_zerok.lua index 05f397de3..3bb310e99 100644 --- a/libs/liblobby/lobby/interface_zerok.lua +++ b/libs/liblobby/lobby/interface_zerok.lua @@ -893,28 +893,11 @@ Interface.jsonCommands["UserDisconnected"] = Interface._UserDisconnected ------------------------ function Interface:_FriendList(data) - --if self.friendListRecieved then - local newFriendMap = {} - for i = 1, #data.Friends do - local userName = data.Friends[i].Name - if not self.isFriend[userName] then - self:_OnFriend(userName) - self:_OnRemoveIgnoreUser(userName) - end - newFriendMap[userName] = true - end - - for _, userName in pairs(self.friends) do - if not newFriendMap[userName] then - self:_OnUnfriend(userName) - self:_OnRemoveIgnoreUser(userName) - end - end - --return - --end - --self.friendListRecieved = true - - self:_OnFriendList(data.Friends) + local friends = {} + for i = 1, #data.Friends do + friends[i] = data.Friends[i].Name + end + self:_OnFriendList(friends) end Interface.jsonCommands["FriendList"] = Interface._FriendList @@ -1324,7 +1307,7 @@ function Interface:_HandleBattleProposalMessages(userName, message, doAction) end return true end - + if string.sub(message, 1, 21) == "!inviteProposedBattle" then local data = message:split(" ") local battleID = data and data[2] and tonumber(data[2]) diff --git a/libs/liblobby/lobby/lobby.lua b/libs/liblobby/lobby/lobby.lua index 967be1637..56e2648c0 100644 --- a/libs/liblobby/lobby/lobby.lua +++ b/libs/liblobby/lobby/lobby.lua @@ -597,13 +597,21 @@ function Lobby:_OnUnfriend(userName) end function Lobby:_OnFriendList(friends) - self.friends = friends - self.friendCount = #friends + local newFriendMap = {} + for i = 1, #friends do + local userName = friends[i] + if not self.isFriend[userName] then + self:_OnFriend(userName) + self:_OnRemoveIgnoreUser(userName) + end + newFriendMap[userName] = true + end for _, userName in pairs(self.friends) do - self.isFriend[userName] = true - local userInfo = self:TryGetUser(userName) - userInfo.isFriend = true + if not newFriendMap[userName] then + self:_OnUnfriend(userName) + self:_OnRemoveIgnoreUser(userName) + end end self:_CallListeners("OnFriendList", self:GetFriends()) diff --git a/libs/liblobby/lobby/utilities.lua b/libs/liblobby/lobby/utilities.lua index 45fdca7bb..55dfa92b3 100644 --- a/libs/liblobby/lobby/utilities.lua +++ b/libs/liblobby/lobby/utilities.lua @@ -8,15 +8,21 @@ function dumpConfig() end function explode(div,str) -if (div=='') then return false end -local pos,arr = 0,{} --- for each divider found -for st,sp in function() return string.find(str,div,pos,true) end do - table.insert(arr,string.sub(str,pos,st-1)) -- Attach chars left of current divider - pos = sp + 1 -- Jump past current divider -end -table.insert(arr,string.sub(str,pos)) -- Attach chars right of last divider -return arr + if div == '' then + return false + end + + local pos, arr = 0, {} + -- for each divider found + for st, sp in function() return string.find(str, div, pos, true) end do + -- Attach chars left of current divider + table.insert(arr, string.sub(str, pos, st-1)) + -- Jump past current divider + pos = sp + 1 + end + -- Attach chars right of last divider + table.insert(arr, string.sub(str,pos)) + return arr end function ShallowCopy(orig) @@ -50,9 +56,11 @@ function parseTags(tags) local tagsMap = {} for _, tag in pairs(tags) do local indx = string.find(tag, "=") - local key = string.sub(tag, 1, indx-1) - local value = string.sub(tag, indx+1) - tagsMap[key] = value + if indx ~= nil then + local key = string.sub(tag, 1, indx - 1) + local value = string.sub(tag, indx + 1) + tagsMap[key] = value + end end return tagsMap end