diff --git a/Locales/MultiBotAceLocale-deDE.lua b/Locales/MultiBotAceLocale-deDE.lua
index fb805ec..6b7da67 100644
--- a/Locales/MultiBotAceLocale-deDE.lua
+++ b/Locales/MultiBotAceLocale-deDE.lua
@@ -517,6 +517,7 @@ local deDEValues = {
["tips.quests.alllist"] = "Alle Quests des/der Bot(s)",
["tips.quests.compheader"] = "** Abgeschlossene Quests **",
["tips.quests.incompheader"] = "** Unvollständige Quests **",
+ ["tips.quests.drop"] = "Aufgeben",
["tips.quests.botsword"] = "Bots : ",
["tips.quests.gobsmaster"] = "GameObjects-Menü öffnen\n|cffffffffDieser Button öffnet das GameObjects-Menü.|r\n\n|cffff0000Linksklick zum Öffnen|r\n|cff999999(Ausführungsreihenfolge: System)|r",
["tips.quests.gobenter"] = "GameObject benutzen\n|cffffffffDieser Button öffnet ein Feld zur Eingabe des GameObject-Namens.\n\n|cffff0000Linksklick zum Öffnen des Eingabefeldes|r\n|cff999999(Ausführungsreihenfolge: Bot)|r",
diff --git a/Locales/MultiBotAceLocale-enGB.lua b/Locales/MultiBotAceLocale-enGB.lua
index 3f76274..84fa412 100644
--- a/Locales/MultiBotAceLocale-enGB.lua
+++ b/Locales/MultiBotAceLocale-enGB.lua
@@ -519,6 +519,7 @@ local enGBValues = {
["tips.quests.alllist"] = "All Quests for Bot(s)",
["tips.quests.compheader"] = "** Complete Quests **",
["tips.quests.incompheader"] = "** Incomplete Quests **",
+ ["tips.quests.drop"] = "Abandon",
["tips.quests.botsword"] = "Bots : ",
["tips.quests.gobsmaster"] = "Game Objects Menu\n|cffffffffOpens the Use Game Objects Menu.|r\n\n|cffff0000Left-click to Open|r\n|cff999999(Executed by: System)|r",
["tips.quests.gobenter"] = "Use Game Object\n|cffffffffOpens a prompt to enter Game Object Name.\n\n|cffff0000Left-click to open prompt|r\n|cff999999(Executed by: Bot)|r",
diff --git a/Locales/MultiBotAceLocale-enUS.lua b/Locales/MultiBotAceLocale-enUS.lua
index 543add3..ee5541a 100644
--- a/Locales/MultiBotAceLocale-enUS.lua
+++ b/Locales/MultiBotAceLocale-enUS.lua
@@ -519,6 +519,7 @@ local enUSValues = {
["tips.quests.alllist"] = "All Quests for Bot(s)",
["tips.quests.compheader"] = "** Complete Quests **",
["tips.quests.incompheader"] = "** Incomplete Quests **",
+ ["tips.quests.drop"] = "Abandon",
["tips.quests.botsword"] = "Bots : ",
["tips.quests.gobsmaster"] = "Game Objects Menu\n|cffffffffOpens the Use Game Objects Menu.|r\n\n|cffff0000Left-click to Open|r\n|cff999999(Executed by: System)|r",
["tips.quests.gobenter"] = "Use Game Object\n|cffffffffOpens a prompt to enter Game Object Name.\n\n|cffff0000Left-click to open prompt|r\n|cff999999(Executed by: Bot)|r",
diff --git a/Locales/MultiBotAceLocale-esES.lua b/Locales/MultiBotAceLocale-esES.lua
index a157bae..f879b93 100644
--- a/Locales/MultiBotAceLocale-esES.lua
+++ b/Locales/MultiBotAceLocale-esES.lua
@@ -517,6 +517,7 @@ local esESValues = {
["tips.quests.alllist"] = "Todas las misiones del/de los bot(s)",
["tips.quests.compheader"] = "** Misiones completadas **",
["tips.quests.incompheader"] = "** Misiones incompletas **",
+ ["tips.quests.drop"] = "Abandonar",
["tips.quests.botsword"] = "Bots : ",
["tips.quests.gobsmaster"] = "Menú de Objetos del Juego\n|cffffffffEste botón abre el menú para usar objetos del juego.|r\n\n|cffff0000Clic izquierdo para abrir|r\n|cff999999(Orden de ejecución: Sistema)|r",
["tips.quests.gobenter"] = "Usar objeto del juego\n|cffffffffEste botón abre un cuadro para ingresar el nombre del objeto del juego.\n\n|cffff0000Clic izquierdo para abrir el cuadro|r\n|cff999999(Orden de ejecución: Bot)|r",
diff --git a/Locales/MultiBotAceLocale-frFR.lua b/Locales/MultiBotAceLocale-frFR.lua
index d67e6ac..19ca5a5 100644
--- a/Locales/MultiBotAceLocale-frFR.lua
+++ b/Locales/MultiBotAceLocale-frFR.lua
@@ -517,6 +517,7 @@ local frFRValues = {
["tips.quests.alllist"] = "Toutes les quêtes du/des bot(s)",
["tips.quests.compheader"] = "** Quêtes Terminées **",
["tips.quests.incompheader"] = "** Quêtes Incomplètes **",
+ ["tips.quests.drop"] = "Abandonner",
["tips.quests.botsword"] = "Bots : ",
["tips.quests.gobsmaster"] = "Menu Objets du Jeu\n|cffffffffCe bouton ouvre le menu pour utiliser des objets du jeu.|r\n\n|cffff0000Clic-Gauche pour ouvrir|r\n|cff999999(Ordre d'exécution : Système)|r",
["tips.quests.gobenter"] = "Utiliser un Objet du Jeu\n|cffffffffCe bouton ouvre une fenêtre pour entrer le nom de l'objet du jeu.\n\n|cffff0000Clic-Gauche pour ouvrir la fenêtre|r\n|cff999999(Ordre d'exécution : Bot)|r",
diff --git a/Locales/MultiBotAceLocale-koKR.lua b/Locales/MultiBotAceLocale-koKR.lua
index 757d1e8..f7d3a3f 100644
--- a/Locales/MultiBotAceLocale-koKR.lua
+++ b/Locales/MultiBotAceLocale-koKR.lua
@@ -516,6 +516,7 @@ local koKRValues = {
["tips.quests.alllist"] = "모든 봇의 퀘스트 목록",
["tips.quests.compheader"] = "** 완료한 퀘스트 **",
["tips.quests.incompheader"] = "** 미완료 퀘스트 **",
+ ["tips.quests.drop"] = "포기",
["tips.quests.botsword"] = "봇 : ",
["tips.quests.gobsmaster"] = "게임 오브젝트 메뉴 열기\n|cffffffff이 버튼을 누르면 게임 오브젝트 사용 메뉴를 엽니다.|r\n\n|cffff0000왼쪽 클릭: 열기|r\n|cff999999(실행 순서: 시스템)|r",
["tips.quests.gobenter"] = "게임 오브젝트 사용\n|cffffffff이 버튼을 누르면 게임 오브젝트 이름을 입력할 수 있습니다.\n\n|cffff0000왼쪽 클릭: 입력창 열기|r\n|cff999999(실행 순서: 봇)|r",
diff --git a/Locales/MultiBotAceLocale-ruRU.lua b/Locales/MultiBotAceLocale-ruRU.lua
index c3ff7ec..bb1f789 100644
--- a/Locales/MultiBotAceLocale-ruRU.lua
+++ b/Locales/MultiBotAceLocale-ruRU.lua
@@ -517,6 +517,7 @@ local ruRUValues = {
["tips.quests.alllist"] = "Все квесты бота(ов)",
["tips.quests.compheader"] = "** Выполненные квесты **",
["tips.quests.incompheader"] = "** Невыполненные квесты **",
+ ["tips.quests.drop"] = "Отказаться",
["tips.quests.botsword"] = "Боты : ",
["tips.quests.gobsmaster"] = "Меню игровых объектов\n|cffffffffЭта кнопка открывает меню для использования игровых объектов.|r\n\n|cffff0000Левый клик — открыть|r\n|cff999999(Порядок выполнения: система)|r",
["tips.quests.gobenter"] = "Использовать игровой объект\n|cffffffffЭта кнопка открывает окно для ввода названия игрового объекта.\n\n|cffff0000Левый клик — открыть окно ввода|r\n|cff999999(Порядок выполнения: бот)|r",
diff --git a/Locales/MultiBotAceLocale-zhCN.lua b/Locales/MultiBotAceLocale-zhCN.lua
index 81b1487..09f701b 100644
--- a/Locales/MultiBotAceLocale-zhCN.lua
+++ b/Locales/MultiBotAceLocale-zhCN.lua
@@ -517,6 +517,7 @@ local zhCNValues = {
["tips.quests.alllist"] = "机器人所有任务",
["tips.quests.compheader"] = "** 已完成任务 **",
["tips.quests.incompheader"] = "** 未完成任务 **",
+ ["tips.quests.drop"] = "放弃",
["tips.quests.botsword"] = "机器人:",
["tips.quests.gobsmaster"] = "使用游戏对象菜单\n|cffffffff此按钮打开使用游戏对象的菜单。|r\n\n|cffff0000左键点击打开|r\n|cff999999(执行顺序:系统)|r",
["tips.quests.gobenter"] = "使用游戏对象\n|cffffffff此按钮弹出窗口输入游戏对象名称。\n\n|cffff0000左键点击打开输入窗口|r\n|cff999999(执行顺序:机器人)|r",
diff --git a/README.md b/README.md
index d9e9683..d063a89 100644
--- a/README.md
+++ b/README.md
@@ -211,7 +211,7 @@ The goal is to remove automatic UI-refresh spam.
| Quests |
- Bridge-first incompleted, completed and all quest lists |
+ Bridge-first incompleted, completed and all quest lists with dark result frames and per-bot abandon buttons |
| Game object search |
diff --git a/TODO.md b/TODO.md
index 40917c2..8ed3657 100644
--- a/TODO.md
+++ b/TODO.md
@@ -52,7 +52,6 @@
## Améliorations UI encore ouvertes
-* Uniformiser le template des frames de quêtes avec le style d'Itemus.
* Uniformiser le template de la frame reward avec le style d'Itemus.
* Ajouter une option pour choisir la taille des icônes de la main bar et des Quick Shaman / Quick Hunter.
* Voir quelles autres options utiles peuvent être ajoutées à la frame options de MultiBot.
@@ -102,6 +101,7 @@
* incompleted ;
* completed ;
* all.
+* Frames de quêtes `all`, `completed` et `incompleted` uniformisées avec fond interne sombre, marges cohérentes et bouton `Abandonner` par quête de bot.
* Outfits bridge-first.
* Character Info bridge-first.
* Réputations bridge-first dans la frame Infos personnage.
diff --git a/UI/MultiBotQuestAllFrame.lua b/UI/MultiBotQuestAllFrame.lua
index 1688d6e..156cba6 100644
--- a/UI/MultiBotQuestAllFrame.lua
+++ b/UI/MultiBotQuestAllFrame.lua
@@ -72,6 +72,11 @@ local function createQuestRow(self, questID, text)
row:SetFullWidth(true)
row:SetLayout("Flow")
+ local spacer = self.aceGUI:Create("Label")
+ spacer:SetText("")
+ spacer:SetWidth(Shared.QUEST_ROW_LEFT_PADDING or 12)
+ row:AddChild(spacer)
+
local icon = self.aceGUI:Create("Icon")
icon:SetImage(Shared.ICON_BOT_QUEST or "Interface\\Icons\\inv_misc_note_02")
icon:SetImageSize(12, 12)
@@ -195,6 +200,7 @@ function MultiBot.InitializeQuestAllFrame()
window:SetHeight(460)
window:EnableResize(false)
window:SetLayout("Fill")
+ Shared.ApplyWindowContentStyle(window, 0.90)
local strataLevel = MultiBot.GetGlobalStrataLevel and MultiBot.GetGlobalStrataLevel()
if strataLevel then
window.frame:SetFrameStrata(strataLevel)
@@ -210,6 +216,8 @@ function MultiBot.InitializeQuestAllFrame()
content:SetLayout("List")
window:AddChild(content)
+ Shared.AddTopPadding(aceGUI, content)
+
local summary = aceGUI:Create("Label")
summary:SetFullWidth(true)
summary:SetText("")
@@ -241,4 +249,4 @@ function MultiBot.InitializeQuestAllFrame()
MultiBot.tBotAllPopup = window
return QuestAllFrame
-end
\ No newline at end of file
+end
diff --git a/UI/MultiBotQuestCompletedFrame.lua b/UI/MultiBotQuestCompletedFrame.lua
index a867274..d613ee2 100644
--- a/UI/MultiBotQuestCompletedFrame.lua
+++ b/UI/MultiBotQuestCompletedFrame.lua
@@ -54,6 +54,15 @@ local function resolveBotQuestBucket(store, botName)
return EMPTY_TABLE
end
+local function dropBotQuest(botName, entry)
+ if not Shared.SendDropQuest(botName, entry) then
+ return
+ end
+
+ Shared.RemoveQuestEntryFromBucket(resolveBotQuestBucket(getBotQuestsCompletedStore(), botName), entry)
+ MultiBot.BuildBotCompletedList(botName)
+end
+
function MultiBot.BuildBotCompletedList(botName)
local frame = MultiBot.InitializeQuestCompletedFrame()
local completedStore = getBotQuestsCompletedStore()
@@ -61,7 +70,13 @@ function MultiBot.BuildBotCompletedList(botName)
frame:Show()
Shared.RenderQuestEntries(frame, entries, {
- summaryText = botName and ("|cff80ff80" .. botName .. "|r") or (MultiBot.L("tips.quests.complist") or ""),
+ summaryText = botName and ((Shared.QUEST_SUMMARY_PREFIX or " ") .. "|cff80ff80" .. botName .. "|r") or (MultiBot.L("tips.quests.complist") or ""),
+ rowOptions = botName and {
+ leftPadding = Shared.QUEST_ROW_LEFT_PADDING or 12,
+ onDrop = function(entry)
+ dropBotQuest(botName, entry)
+ end,
+ } or nil,
})
end
@@ -72,6 +87,9 @@ function MultiBot.BuildAggregatedCompletedList()
frame:Show()
Shared.RenderQuestEntries(frame, entries, {
summaryText = "",
+ rowOptions = {
+ leftPadding = Shared.QUEST_ROW_LEFT_PADDING or 12,
+ },
})
end
@@ -97,6 +115,7 @@ function MultiBot.InitializeQuestCompletedFrame()
window:SetHeight(420)
window:EnableResize(false)
window:SetLayout("Fill")
+ Shared.ApplyWindowContentStyle(window, 0.90)
local strataLevel = MultiBot.GetGlobalStrataLevel and MultiBot.GetGlobalStrataLevel()
if strataLevel then
window.frame:SetFrameStrata(strataLevel)
@@ -112,6 +131,8 @@ function MultiBot.InitializeQuestCompletedFrame()
content:SetLayout("List")
window:AddChild(content)
+ Shared.AddTopPadding(aceGUI, content)
+
local summary = aceGUI:Create("Label")
summary:SetFullWidth(true)
summary:SetText("")
@@ -138,4 +159,4 @@ function MultiBot.InitializeQuestCompletedFrame()
MultiBot.tBotCompPopup = window
return QuestCompletedFrame
-end
\ No newline at end of file
+end
diff --git a/UI/MultiBotQuestIncompleteFrame.lua b/UI/MultiBotQuestIncompleteFrame.lua
index 5238b02..4d0ca82 100644
--- a/UI/MultiBotQuestIncompleteFrame.lua
+++ b/UI/MultiBotQuestIncompleteFrame.lua
@@ -54,6 +54,15 @@ local function resolveBotQuestBucket(store, botName)
return EMPTY_TABLE
end
+local function dropBotQuest(botName, entry)
+ if not Shared.SendDropQuest(botName, entry) then
+ return
+ end
+
+ Shared.RemoveQuestEntryFromBucket(resolveBotQuestBucket(getBotQuestsIncompletedStore(), botName), entry)
+ MultiBot.BuildBotQuestList(botName)
+end
+
function MultiBot.BuildBotQuestList(botName)
local frame = MultiBot.InitializeQuestIncompleteFrame and MultiBot.InitializeQuestIncompleteFrame()
if not frame then
@@ -64,7 +73,13 @@ function MultiBot.BuildBotQuestList(botName)
frame:Show()
Shared.RenderQuestEntries(frame, entries, {
- summaryText = botName and ("|cff80ff80" .. botName .. "|r") or (MultiBot.L("tips.quests.incomplist") or ""),
+ summaryText = botName and ((Shared.QUEST_SUMMARY_PREFIX or " ") .. "|cff80ff80" .. botName .. "|r") or (MultiBot.L("tips.quests.incomplist") or ""),
+ rowOptions = botName and {
+ leftPadding = Shared.QUEST_ROW_LEFT_PADDING or 12,
+ onDrop = function(entry)
+ dropBotQuest(botName, entry)
+ end,
+ } or nil,
})
end
@@ -75,6 +90,9 @@ function MultiBot.BuildAggregatedQuestList()
frame:Show()
Shared.RenderQuestEntries(frame, entries, {
summaryText = "",
+ rowOptions = {
+ leftPadding = Shared.QUEST_ROW_LEFT_PADDING or 12,
+ },
})
end
@@ -100,6 +118,7 @@ function MultiBot.InitializeQuestIncompleteFrame()
window:SetHeight(420)
window:EnableResize(false)
window:SetLayout("Fill")
+ Shared.ApplyWindowContentStyle(window, 0.90)
local strataLevel = MultiBot.GetGlobalStrataLevel and MultiBot.GetGlobalStrataLevel()
if strataLevel then
window.frame:SetFrameStrata(strataLevel)
@@ -115,6 +134,8 @@ function MultiBot.InitializeQuestIncompleteFrame()
content:SetLayout("List")
window:AddChild(content)
+ Shared.AddTopPadding(aceGUI, content)
+
local summary = aceGUI:Create("Label")
summary:SetFullWidth(true)
summary:SetText("")
@@ -141,4 +162,4 @@ function MultiBot.InitializeQuestIncompleteFrame()
MultiBot.tBotPopup = window
return QuestIncompleteFrame
-end
\ No newline at end of file
+end
diff --git a/UI/MultiBotQuestUIShared.lua b/UI/MultiBotQuestUIShared.lua
index bcd6669..7d1681b 100644
--- a/UI/MultiBotQuestUIShared.lua
+++ b/UI/MultiBotQuestUIShared.lua
@@ -7,6 +7,11 @@ Shared.ROW_HEIGHT = 24
Shared.DETAIL_ROW_HEIGHT = 16
Shared.PANEL_ALPHA = 0.90
Shared.SUBPANEL_ALPHA = 0.72
+Shared.DROP_BUTTON_WIDTH = 90
+Shared.DROP_LABEL_WIDTH = 210
+Shared.QUEST_ROW_LEFT_PADDING = 12
+Shared.QUEST_SUMMARY_PREFIX = " "
+Shared.QUEST_TOP_PADDING = 16
Shared.ICON_QUEST = "Interface\\Icons\\inv_misc_note_01"
Shared.ICON_BOT_QUEST = "Interface\\Icons\\inv_misc_note_02"
@@ -32,6 +37,24 @@ function Shared.ApplyPanelStyle(frame, bgAlpha)
end
end
+function Shared.ApplyWindowContentStyle(window, bgAlpha)
+ if window and window.content then
+ Shared.ApplyPanelStyle(window.content, bgAlpha or Shared.PANEL_ALPHA)
+ end
+end
+
+function Shared.AddTopPadding(aceGUI, parent, height)
+ if not aceGUI or not parent or not parent.AddChild then
+ return
+ end
+
+ local spacer = aceGUI:Create("SimpleGroup")
+ spacer:SetFullWidth(true)
+ spacer:SetHeight(height or Shared.QUEST_TOP_PADDING)
+ spacer:SetLayout("Flow")
+ parent:AddChild(spacer)
+end
+
function Shared.ApplyEditBoxStyle(widget)
if not widget or not widget.frame or not widget.editbox then
return
@@ -60,6 +83,56 @@ function Shared.ApplyEditBoxStyle(widget)
end
end
+function Shared.GetQuestDropButtonText()
+ return MultiBot.L("tips.quests.drop", ABANDON_QUEST or "Abandon")
+end
+
+function Shared.SendDropQuest(botName, entry)
+ if type(botName) ~= "string" or botName == "" or type(entry) ~= "table" then
+ return false
+ end
+
+ local command = "drop " .. Shared.BuildQuestLink(entry.id, entry.originalName or entry.name)
+ if MultiBot.ActionToTarget then
+ return MultiBot.ActionToTarget(command, botName)
+ end
+
+ if SendChatMessage then
+ SendChatMessage(command, "WHISPER", nil, botName)
+ return true
+ end
+
+ return false
+end
+
+function Shared.RemoveQuestEntryFromBucket(bucket, entry)
+ if type(bucket) ~= "table" or type(entry) ~= "table" then
+ return
+ end
+
+ if entry.id ~= nil then
+ bucket[entry.id] = nil
+ bucket[tostring(entry.id)] = nil
+ end
+
+ local entryName = tostring(entry.originalName or entry.name or "")
+ if entryName == "" then
+ return
+ end
+
+ local removeKeys = {}
+ for questID, questName in pairs(bucket) do
+ local storedName = tostring(questName or "")
+ if storedName == entryName or storedName == tostring(entry.name or "") then
+ table.insert(removeKeys, questID)
+ end
+ end
+
+ for _, questID in ipairs(removeKeys) do
+ bucket[questID] = nil
+ end
+end
+
local function setQuestTooltip(widget, questID)
if not questID then
return
@@ -76,11 +149,20 @@ function Shared.CreateQuestEntryRow(self, entry, opts)
end
opts = opts or {}
+ local hasDropAction = type(opts.onDrop) == "function"
local row = self.aceGUI:Create("SimpleGroup")
row:SetFullWidth(true)
row:SetLayout("Flow")
+ local leftPadding = tonumber(opts.leftPadding or 0) or 0
+ if leftPadding > 0 then
+ local spacer = self.aceGUI:Create("Label")
+ spacer:SetText("")
+ spacer:SetWidth(leftPadding)
+ row:AddChild(spacer)
+ end
+
local icon = self.aceGUI:Create("Icon")
icon:SetImage(opts.iconPath or Shared.ICON_BOT_QUEST or "Interface\\Icons\\inv_misc_note_02")
icon:SetImageSize(opts.iconSize or 14, opts.iconSize or 14)
@@ -88,7 +170,7 @@ function Shared.CreateQuestEntryRow(self, entry, opts)
row:AddChild(icon)
local label = self.aceGUI:Create("InteractiveLabel")
- label:SetWidth(opts.labelWidth or 320)
+ label:SetWidth(opts.labelWidth or (hasDropAction and Shared.DROP_LABEL_WIDTH) or 320)
label:SetText(Shared.BuildQuestLink(entry.id, entry.name))
label:SetCallback("OnEnter", function(widget)
setQuestTooltip(widget, entry.id)
@@ -96,6 +178,19 @@ function Shared.CreateQuestEntryRow(self, entry, opts)
label:SetCallback("OnLeave", GameTooltip_Hide)
row:AddChild(label)
+ if hasDropAction then
+ local dropButton = self.aceGUI:Create("Button")
+ dropButton:SetText(opts.dropButtonText or Shared.GetQuestDropButtonText())
+ dropButton:SetWidth(opts.dropButtonWidth or Shared.DROP_BUTTON_WIDTH)
+ if dropButton.SetHeight then
+ dropButton:SetHeight(opts.dropButtonHeight or 20)
+ end
+ dropButton:SetCallback("OnClick", function(widget)
+ opts.onDrop(entry, widget)
+ end)
+ row:AddChild(dropButton)
+ end
+
self.scroll:AddChild(row)
if opts.showBots ~= false and entry.bots and #entry.bots > 0 then
@@ -262,4 +357,4 @@ function Shared.BuildGameObjectCopyText(bots)
end
return table.concat(lines, "\n")
-end
\ No newline at end of file
+end