diff --git a/LuaMenu/configs/gameConfig/zk/ModOptions.lua b/LuaMenu/configs/gameConfig/zk/ModOptions.lua index f7ad46c4e..db5ceef7f 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", @@ -563,7 +562,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/images/settings.png b/LuaMenu/images/settings.png new file mode 100644 index 000000000..7bed8945f Binary files /dev/null and b/LuaMenu/images/settings.png differ 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_download_handler.lua b/LuaMenu/widgets/api_download_handler.lua index 78da42ac8..c933d0ea5 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 = {} @@ -191,6 +191,15 @@ 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 + end requestUpdate = true return true end @@ -225,6 +234,7 @@ function externalFunctions.QueueDownload(name, fileType, priority) fileType = fileType, priority = priority, id = downloadCount, + retryCount = 0, } requestUpdate = true CallListeners("DownloadQueued", downloadCount, name, fileType) 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/api_user_handler.lua b/LuaMenu/widgets/api_user_handler.lua index 5a1b5e318..03ec07d3b 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, userControls.imSide ~= nil) userControls.imLevel.file = GetUserRankImageName(userName, userControls) userControls.imLevel:Invalidate() @@ -446,12 +452,22 @@ 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 + 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 end @@ -491,6 +507,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 +561,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 +640,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 WG.ReportPanel.OpenReportWindow(userName) elseif selectedName == "Unignore" then @@ -727,6 +763,29 @@ local function GetUserControls(userName, opts) offset = offset + 21 end + 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, + y = offsetY, + width = 20, + height = 20, + parent = userControls.mainControl, + keepAspect = false, + file = file, + } + offset = offset + 22 + if battleStatus.isSpectator or file == nil then + userControls.imSide:Hide() + end + end + offset = offset + 2 userControls.tbName = TextBox:New { name = "tbName", @@ -872,6 +931,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 +950,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/ai_list_window.lua b/LuaMenu/widgets/chobby/components/ai_list_window.lua index 12b8ff47d..e1b6e275b 100644 --- a/LuaMenu/widgets/chobby/components/ai_list_window.lua +++ b/LuaMenu/widgets/chobby/components/ai_list_window.lua @@ -1,10 +1,13 @@ AiListWindow = ListWindow:extends{} -function AiListWindow:init(gameName) +local IMG_SETTINGS = LUA_DIRNAME .. "images/settings.png" + +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 @@ -13,12 +16,13 @@ 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) local order = Configuration.simpleAiList and Configuration.gameConfig.simpleAiOrder if order then @@ -29,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 @@ -69,26 +73,69 @@ function AiListWindow:AddAiToList(ai, blackList, oldAiVersions, isRunning64Bit) if Configuration.gameConfig.aiTooltip then tooltip = Configuration.gameConfig.aiTooltip[displayName] end - local addAIButton = Button:New { + + 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[#buttonList + 1] = self:MakeAiOptionsButton(displayName, tooltip, shortName, ai.version, path) + btnWidth = "80%" + end + 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 optionsButton = Button:New { + x = "80%", + y = 0, + width = "20%", + height = "100%", + caption = "", + font = Configuration:GetFont(3), + OnClick = { + function() + local successFunc = function(aioptions) + self:AddAi(displayName, shortName, version, aioptions) + self:HideWindow() + end + WG.Chobby.AiOptionsWindow(displayName, path, successFunc) + end + }, + } + local optionsImage = Image:New { + x = "10%", + y = "10%", + width = "80%", + height = "80%", + file = IMG_SETTINGS, + parent = optionsButton, + } + return optionsButton +end + +function AiListWindow:MakeAiButton(btnWidth, displayName, tooltip, shortName, version) + return Button:New { classname = "button_rounded", x = 0, y = 0, - width = "100%", + width = btnWidth, height = "100%", caption = displayName, font = Configuration:GetFont(3), tooltip = tooltip, OnClick = { function() - self:AddAi(displayName, shortName, ai.version) + self:AddAi(displayName, shortName, version) self:HideWindow() end }, } - self:AddRow({addAIButton}, displayName) end -function AiListWindow:AddAi(displayName, shortName, version) +function AiListWindow:AddAi(displayName, shortName, version, options) local aiName local counter = 1 local found = true @@ -107,7 +154,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, options) Configuration:SetConfigValue("lastAddedAiName", shortName) end @@ -118,7 +165,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/chobby/components/aioptions_window.lua b/LuaMenu/widgets/chobby/components/aioptions_window.lua new file mode 100644 index 000000000..c4c6368af --- /dev/null +++ b/LuaMenu/widgets/chobby/components/aioptions_window.lua @@ -0,0 +1,224 @@ +AiOptionsWindow = ListWindow:extends{} + +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) + + 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() + successFunc(self.aioptions) + self:HideWindow() + end + }, + } + + -- AIOptions + local options = VFS.Include(optionsPath) + 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 +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/components/battle/battle_list_window.lua b/LuaMenu/widgets/chobby/components/battle/battle_list_window.lua index 91de0e769..42c610b79 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,10 +74,11 @@ function BattleListWindow:init(parent) OnChange = { function (obj, newState) Configuration:SetConfigValue("battleFilterPassworded2", newState) - SoftUpdate() + self:SoftUpdate() end }, parent = self.window, + tooltip = "Hides all battles that require a password to join", } local checkNonFriend = Checkbox:New { x = 280, @@ -97,10 +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 don't have your friends in them", } local checkRunning = Checkbox:New { x = 435, @@ -115,10 +112,11 @@ 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", } local function UpdateCheckboxes() @@ -145,7 +143,7 @@ function BattleListWindow:init(parent) return end self:AddBattle(battleID, lobby:GetBattle(battleID)) - SoftUpdate() + self:SoftUpdate() end lobby:AddListener("OnBattleOpened", self.onBattleOpened) @@ -154,7 +152,7 @@ function BattleListWindow:init(parent) return end self:RemoveRow(battleID) - SoftUpdate() + self:SoftUpdate() end lobby:AddListener("OnBattleClosed", self.onBattleClosed) @@ -163,7 +161,7 @@ function BattleListWindow:init(parent) return end self:JoinedBattle(battleID) - SoftUpdate() + self:SoftUpdate() end lobby:AddListener("OnJoinedBattle", self.onJoinedBattle) @@ -172,7 +170,7 @@ function BattleListWindow:init(parent) return end self:LeftBattle(battleID) - SoftUpdate() + self:SoftUpdate() end lobby:AddListener("OnLeftBattle", self.onLeftBattle) @@ -181,7 +179,7 @@ function BattleListWindow:init(parent) return end self:OnUpdateBattleInfo(battleID) - SoftUpdate() + self:SoftUpdate() end lobby:AddListener("OnUpdateBattleInfo", self.onUpdateBattleInfo) @@ -190,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) @@ -222,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() @@ -235,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 @@ -600,12 +615,71 @@ function BattleListWindow:ItemInFilter(id) return false end end + if Configuration.battleFilterRunning and battle.isRunning then return false 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 + if hostCountry == nil then + return nil + end + + 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 + + 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) local battle1, battle2 = lobby:GetBattle(id1), lobby:GetBattle(id2) if id1 and id2 then diff --git a/LuaMenu/widgets/chobby/components/chat_windows.lua b/LuaMenu/widgets/chobby/components/chat_windows.lua index 0c175dde3..1c40f8c69 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 diff --git a/LuaMenu/widgets/chobby/components/configuration.lua b/LuaMenu/widgets/chobby/components/configuration.lua index aad7f6bf1..4402cfaea 100644 --- a/LuaMenu/widgets/chobby/components/configuration.lua +++ b/LuaMenu/widgets/chobby/components/configuration.lua @@ -220,6 +220,7 @@ function Configuration:init() self.hideInterface = false self.enableTextToSpeech = true self.showOldAiVersions = false + self.showAiOptions = false self.drawAtFullSpeed = false self.lobbyIdleSleep = false self.rememberQueuesOnStart2 = true @@ -561,6 +562,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, @@ -856,6 +858,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/chobby/components/console.lua b/LuaMenu/widgets/chobby/components/console.lua index c256f1c4f..d22ff5ea9 100644 --- a/LuaMenu/widgets/chobby/components/console.lua +++ b/LuaMenu/widgets/chobby/components/console.lua @@ -5,6 +5,13 @@ function Console:init(channelName, sendMessageListener, noHistoryLoad, onResizeF 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 @@ -90,7 +97,12 @@ function Console:init(channelName, sendMessageListener, noHistoryLoad, onResizeF 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 @@ -103,9 +115,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 +157,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,10 +238,16 @@ end function Console:SendMessage() if self.ebInputText.text ~= "" then message = self.ebInputText.text + -- 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 @@ -276,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/chobby/core.lua b/LuaMenu/widgets/chobby/core.lua index 18ea7fb0c..d08c49eff 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/mode_list_window.lua", "components/confirmation_popup.lua", diff --git a/LuaMenu/widgets/dbg_img_preload.lua b/LuaMenu/widgets/dbg_img_preload.lua index 79fcd17ea..06cde3675 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_battle_room_window.lua b/LuaMenu/widgets/gui_battle_room_window.lua index be22dceaf..bfca4d4c8 100644 --- a/LuaMenu/widgets/gui_battle_room_window.lua +++ b/LuaMenu/widgets/gui_battle_room_window.lua @@ -2230,8 +2230,7 @@ function BattleRoomWindow.SetSingleplayerGame(ToggleShowFunc, battleroomObj, tab 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 diff --git a/LuaMenu/widgets/gui_campaign_codex_handler.lua b/LuaMenu/widgets/gui_campaign_codex_handler.lua index f678f4363..25ccac4fa 100644 --- a/LuaMenu/widgets/gui_campaign_codex_handler.lua +++ b/LuaMenu/widgets/gui_campaign_codex_handler.lua @@ -157,7 +157,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 @@ -165,9 +165,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 @@ -180,7 +180,7 @@ local function PopulateCodexTree(parent, codexText, codexImage) categoryNode:Expand() entryButtons[entryName].OnClick[1](entryButtons[entryName]) end - + return externalFunctions end @@ -274,7 +274,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 6c1b20771..e2c217aaf 100644 --- a/LuaMenu/widgets/gui_campaign_handler.lua +++ b/LuaMenu/widgets/gui_campaign_handler.lua @@ -512,7 +512,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, extraCodexUnlocks}}, cullUnlocked, 3.96, 2) then bottom = bottom + 98 - + local singleplayerMenu = WG.Chobby.interfaceRoot.GetSingleplayerSubmenu() if singleplayerMenu then local campaignMenu = singleplayerMenu.GetSubmenuByName("campaign") @@ -680,7 +680,7 @@ local function MakeWinPopup(planetData, bonusObjectiveSuccess, difficulty, extra openCommanderWindowOnContinue = true end end - + function externalFunctions.CloseWinPopup(cancelCommPopup) if cancelCommPopup and openCommanderWindowOnContinue then openCommanderWindowOnContinue = false @@ -805,7 +805,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{ @@ -837,10 +837,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, @@ -1016,7 +1016,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() @@ -1315,7 +1315,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_download_window.lua b/LuaMenu/widgets/gui_download_window.lua index fb75da205..bff48fdc6 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.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, } 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 diff --git a/LuaMenu/widgets/gui_popup_preloader.lua b/LuaMenu/widgets/gui_popup_preloader.lua index 33baac69b..347c64f5a 100644 --- a/LuaMenu/widgets/gui_popup_preloader.lua +++ b/LuaMenu/widgets/gui_popup_preloader.lua @@ -10,22 +10,24 @@ function widget:GetInfo() } end +local oldLobby local oldGameName local aiListWindow local aiPopup local showOldAiVersions = false +local showAiOptions = false 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 @@ -45,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) @@ -58,8 +61,9 @@ local function InitializeListeners(battleLobby) return end + oldLobby = battleLobby oldGameName = newGameName - UpdateAiListWindow(newGameName) + UpdateAiListWindow(battleLobby, newGameName) end battleLobby:AddListener("OnUpdateBattleInfo", OnUpdateBattleInfo) @@ -74,14 +78,18 @@ 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 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 diff --git a/LuaMenu/widgets/gui_queue_list_window.lua b/LuaMenu/widgets/gui_queue_list_window.lua index a24dd30cd..9e510a6d2 100644 --- a/LuaMenu/widgets/gui_queue_list_window.lua +++ b/LuaMenu/widgets/gui_queue_list_window.lua @@ -555,7 +555,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 = {} @@ -577,7 +577,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_settings_window.lua b/LuaMenu/widgets/gui_settings_window.lua index 9a41a8714..9a31e6300 100644 --- a/LuaMenu/widgets/gui_settings_window.lua +++ b/LuaMenu/widgets/gui_settings_window.lua @@ -1051,6 +1051,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, 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/LuaMenu/widgets/gui_tutorial_handler.lua b/LuaMenu/widgets/gui_tutorial_handler.lua index 34212e2da..a16dbca1f 100644 --- a/LuaMenu/widgets/gui_tutorial_handler.lua +++ b/LuaMenu/widgets/gui_tutorial_handler.lua @@ -101,7 +101,7 @@ local function CheckTutorialPopup() draggable = false, classname = "main_window", } - + TextBox:New { x = 95, right = 15, @@ -174,9 +174,9 @@ local function CheckTutorialPopup() }, parent = tutorialWindow, } - + local popupHolder = WG.Chobby.PriorityPopup(tutorialWindow, CancelFunc, CancelFunc) - + return true end @@ -196,7 +196,7 @@ function DelayedInitialize() return end CheckTutorialPopup() - + local function onConfigurationChange(listener, key, value) if key ~= "firstBattleStarted" then return @@ -205,7 +205,6 @@ function DelayedInitialize() tutorialPrompt.Remove() end end - WG.Chobby.Configuration:AddListener("OnConfigurationChange", onConfigurationChange) end 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 117664a13..41a1694e5 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 @@ -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 @@ -199,6 +201,9 @@ function Interface:RejoinBattle(battleID) end function Interface:JoinBattle(battleID, password, scriptPassword) + 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 @@ -275,7 +280,7 @@ end function Interface:AddAi(aiName, aiLib, allyNumber, version) local battleStatus = { isReady = true, - teamNumber = allyNumber, + teamNumber = self:GetUnusedTeamID(), allyNumber = allyNumber, playMode = true, sync = true, @@ -471,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) @@ -611,6 +618,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 @@ -642,11 +652,41 @@ 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 + + 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() + }) + 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/interface_skirmish.lua b/libs/liblobby/lobby/interface_skirmish.lua index 34f3b4c50..e6effde30 100644 --- a/libs/liblobby/lobby/interface_skirmish.lua +++ b/libs/liblobby/lobby/interface_skirmish.lua @@ -7,25 +7,33 @@ 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) - local str = '[Game]\n{\n\n' + local str = '[Game]\n{\n' -- 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 @@ -84,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 @@ -107,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 @@ -149,6 +159,7 @@ function InterfaceSkirmish:_StartScript(gameName, mapName, playerName, friendLis IsFromDemo = 0, ShortName = data.aiLib, Version = data.aiVersion, + options = data.aiOptions, Host = 0, } end @@ -157,6 +168,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) @@ -422,13 +434,14 @@ 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, options) + self:super("AddAi", aiName, aiLib, allyNumber, version, options) self:_OnAddAi(self:GetMyBattleID(), aiName, { aiLib = aiLib, allyNumber = allyNumber, owner = self:GetMyUserName(), aiVersion = version, + aiOptions = options, }) end diff --git a/libs/liblobby/lobby/interface_zerok.lua b/libs/liblobby/lobby/interface_zerok.lua index 9e8a8044b..dc67efa8b 100644 --- a/libs/liblobby/lobby/interface_zerok.lua +++ b/libs/liblobby/lobby/interface_zerok.lua @@ -936,28 +936,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 @@ -1380,7 +1363,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 9f3ea0078..e9cdd6d47 100644 --- a/libs/liblobby/lobby/lobby.lua +++ b/libs/liblobby/lobby/lobby.lua @@ -236,7 +236,7 @@ function Lobby:SetBattleStatus(status) return self end -function Lobby:AddAi(aiName, aiLib, allyNumber, version) +function Lobby:AddAi(aiName, aiLib, allyNumber, version, options) return self end @@ -604,7 +604,24 @@ function Lobby:_OnUnfriend(userName) self:_CallListeners("OnUnfriend", userName) end -function Lobby:_OnFriendList() +function Lobby:_OnFriendList(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 + if not newFriendMap[userName] then + self:_OnUnfriend(userName) + self:_OnRemoveIgnoreUser(userName) + end + end + self:_CallListeners("OnFriendList", self:GetFriends()) end @@ -876,8 +893,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 userData.joinTime = status.joinTime or userData.JoinTime @@ -887,12 +906,15 @@ 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.joinTime = userData.joinTime status.queueOrder = userData.queueOrder + self:_CallListeners("OnUpdateUserBattleStatus", userName, status) if changedSpectator or changedAllyTeam then @@ -1378,8 +1400,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 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