diff --git a/.luacheckrc b/.luacheckrc index 160778e..4103bfb 100644 --- a/.luacheckrc +++ b/.luacheckrc @@ -36,7 +36,8 @@ globals = { "TooltipBackdropTemplateMixin", "NORMAL_FONT_COLOR", "HIGHLIGHT_FONT_COLOR", "GameTooltip_SetDefaultAnchor", "ChatFrame1", "UISpecialFrames", "GetMouseFocus", "ShowUIPanel", "tremove", "min", "max", "GetMinimapShape", "GetMinimapShape", "PanelTemplates_TabResize", "GetGuildRosterShowOffline", "SetGuildRosterShowOffline", "IsInGuild", "GetGuildInfo", "SetGuildRosterShowOffline", "PLAYER", "INVENTORY_TOOLTIP", "BAGSLOT", "UNKNOWN", "UnitIsDead", "ShowPrompt", "_MB_GetOrCreateShamanPos", "ensureHiddenTooltip", "MB_TAB_TITLE_DEFAULT", "SPELLBOOK", "MB_PAGE_DEFAULT", "SPELLBOOK_END_NON_SPELL_STREAK", "sendInventoryItemCommand", - "RAID_CLASS_COLORS", "INSPECT", "MB_INVENTORY_LABEL", "LOADING", "ITEM", "ITEMS", "SEARCH", "NO_QUESTS_LABEL", "QUESTS_LABEL", "QUEST_LOG", "UnitIsUnit" + "RAID_CLASS_COLORS", "INSPECT", "MB_INVENTORY_LABEL", "LOADING", "ITEM", "ITEMS", "SEARCH", "NO_QUESTS_LABEL", "QUESTS_LABEL", "QUEST_LOG", "UnitIsUnit", "ITEM_STARTS_QUEST", "TRACKER_HEADER_QUESTS", + "GetItemInfoInstant", "LE_ITEM_CLASS_QUESTITEM" } read_globals = { diff --git a/Core/MultiBotConfig.lua b/Core/MultiBotConfig.lua index 840778f..0992846 100644 --- a/Core/MultiBotConfig.lua +++ b/Core/MultiBotConfig.lua @@ -20,6 +20,7 @@ local THROTTLE_DEFAULTS = { local UI_DEFAULTS = { mainBar = { moveLocked = true, + disableAutoCollapse = false, }, } @@ -79,6 +80,9 @@ local function migrateLegacyConfigIntoProfile(profile) if type(profile.ui.mainBar.moveLocked) ~= "boolean" then profile.ui.mainBar.moveLocked = UI_DEFAULTS.mainBar.moveLocked end + if type(profile.ui.mainBar.disableAutoCollapse) ~= "boolean" then + profile.ui.mainBar.disableAutoCollapse = UI_DEFAULTS.mainBar.disableAutoCollapse + end end local function getConfigStore(createIfMissing) @@ -140,6 +144,9 @@ function MultiBot.Config_Ensure() if type(config.ui.mainBar.moveLocked) ~= "boolean" then config.ui.mainBar.moveLocked = UI_DEFAULTS.mainBar.moveLocked end + if type(config.ui.mainBar.disableAutoCollapse) ~= "boolean" then + config.ui.mainBar.disableAutoCollapse = UI_DEFAULTS.mainBar.disableAutoCollapse + end end -- Copy saved values into runtime timers. @@ -251,5 +258,26 @@ function MultiBot.SetMainBarMoveLocked(value) config.ui = config.ui or {} config.ui.mainBar = config.ui.mainBar or {} config.ui.mainBar.moveLocked = value and true or false + if MultiBot.ApplyMainBarMoveLockState then + MultiBot.ApplyMainBarMoveLockState(config.ui.mainBar.moveLocked) + end return config.ui.mainBar.moveLocked +end + +function MultiBot.GetDisableAutoCollapse() + local config = getConfigStore(false) + local value = config and config.ui and config.ui.mainBar and config.ui.mainBar.disableAutoCollapse + if type(value) == "boolean" then + return value + end + + return UI_DEFAULTS.mainBar.disableAutoCollapse +end + +function MultiBot.SetDisableAutoCollapse(value) + local config = getConfigStore(true) + config.ui = config.ui or {} + config.ui.mainBar = config.ui.mainBar or {} + config.ui.mainBar.disableAutoCollapse = value and true or false + return config.ui.mainBar.disableAutoCollapse end \ No newline at end of file diff --git a/Core/MultiBotEngine.lua b/Core/MultiBotEngine.lua index 7cc8985..2262618 100644 --- a/Core/MultiBotEngine.lua +++ b/Core/MultiBotEngine.lua @@ -563,16 +563,90 @@ end MultiBot.ShowHideSwitch = function(pFrame) if(pFrame:IsVisible()) then + if MultiBot.RestoreCollapsedUnitBarsFromDropdown then + MultiBot.RestoreCollapsedUnitBarsFromDropdown(pFrame) + end pFrame:Hide() if(MultiBot.RequestClickBlockerUpdate) then MultiBot.RequestClickBlockerUpdate(pFrame) end return false end + if MultiBot.CollapseOtherUnitBarsForDropdown then + MultiBot.CollapseOtherUnitBarsForDropdown(pFrame) + end + pFrame:Show() if(MultiBot.RequestClickBlockerUpdate) then MultiBot.RequestClickBlockerUpdate(pFrame) end return true end +MultiBot.RestoreCollapsedUnitBarsFromDropdown = function(targetFrame) + if not targetFrame then + return + end + + local collapsedBars = targetFrame._mbCollapsedBars + if type(collapsedBars) ~= "table" then + return + end + + for index = 1, #collapsedBars do + local frame = collapsedBars[index] + if frame and frame.Show then + frame:Show() + end + end + + targetFrame._mbCollapsedBars = nil +end + +MultiBot.CollapseOtherUnitBarsForDropdown = function(targetFrame) + if not targetFrame or not targetFrame.parent then + return + end + + if MultiBot.GetDisableAutoCollapse and MultiBot.GetDisableAutoCollapse() then + targetFrame._mbDropdownManaged = nil + targetFrame._mbCollapsedBars = nil + return + end + + local unitsFrame = MultiBot.frames + and MultiBot.frames["MultiBar"] + and MultiBot.frames["MultiBar"].frames + and MultiBot.frames["MultiBar"].frames["Units"] + if not unitsFrame or not unitsFrame.frames then + return + end + + local ownerBar = targetFrame.parent + while ownerBar and ownerBar.parent and ownerBar.parent ~= unitsFrame do + ownerBar = ownerBar.parent + end + + if not ownerBar or ownerBar.parent ~= unitsFrame then + return + end + + -- On ne collapse les autres barres que pour l'ouverture d'un sous-menu + -- (pas lors de l'ouverture/fermeture de la barre du bot elle-même). + if targetFrame == ownerBar then + return + end + + local collapsedBars = {} + for key, frame in pairs(unitsFrame.frames) do + if frame ~= ownerBar and key ~= "Alliance" and key ~= "Control" + and frame and frame.Hide and frame.IsShown and frame:IsShown() then + table.insert(collapsedBars, frame) + frame:Hide() + end + end + + targetFrame._mbDropdownManaged = true + targetFrame._mbCollapsedBars = collapsedBars +end + MultiBot.OnOffActionToTarget = function(pButton, pOn, pOff, pTarget) if(pButton.state) then MultiBot.ActionToTarget(pOff, pTarget) @@ -1080,6 +1154,14 @@ MultiBot.newButton = function(pParent, pX, pY, pSize, pTexture, pTip, oTemplate) if(pEvent == "RightButton" and button.doRight ~= nil) then button.doRight(button) end if(pEvent == "LeftButton" and button.doLeft ~= nil) then button.doLeft(button) end + + if button.parent and button.parent._mbDropdownManaged then + if MultiBot.RestoreCollapsedUnitBarsFromDropdown then + MultiBot.RestoreCollapsedUnitBarsFromDropdown(button.parent) + end + button.parent:Hide() + if(MultiBot.RequestClickBlockerUpdate) then MultiBot.RequestClickBlockerUpdate(button.parent) end + end end) return button diff --git a/Core/MultiBotEvery.lua b/Core/MultiBotEvery.lua index d784d8e..6bb6878 100644 --- a/Core/MultiBotEvery.lua +++ b/Core/MultiBotEvery.lua @@ -26,11 +26,7 @@ MultiBot.addEvery = function(pFrame, pCombat, pNormal) -- Bouton parent « Misc » local btnMisc = pFrame.addButton("Misc", 64, 0, "inv_misc_enggizmos_swissarmy", MultiBot.L("tips.every.misc")) btnMisc.doLeft = function(self) - if tMisc:IsShown() then - tMisc:Hide() - else - tMisc:Show() - end + MultiBot.ShowHideSwitch(tMisc) end -- Texture étoile diff --git a/Locales/MultiBotAceLocale-deDE.lua b/Locales/MultiBotAceLocale-deDE.lua index 6eae9e8..503b9dd 100644 --- a/Locales/MultiBotAceLocale-deDE.lua +++ b/Locales/MultiBotAceLocale-deDE.lua @@ -7,6 +7,7 @@ local deDEValues = { ["info.itemdestroyalert"] = "Möchtest du diesen Gegenstand WIRKLICH zerstören?\n%s", ["info.keydestroyalert"] = "Ich verkaufe keine Schlüssel.", ["info.itemsellalert"] = "Ich kann diesen Gegenstand nicht verkaufen.", + ["info.questitemsellalert"] = "Ich kann Questgegenstände nicht verkaufen.", ["info.inventoryvendortarget"] = "Sie müssen zuerst einen Händler auswählen.", ["info.butttitle"] = "|cffffd100MultiBot|r", ["info.buttontoggle"] = "|cff00ff00Linksklick: UI umschalten|r", @@ -197,6 +198,8 @@ local deDEValues = { ["options.minimap.explainer"] = "Blendet den MultiBot-Minimap-Button ein oder aus.", ["options.layout.lock_mainbar"] = "Bewegung der Hauptleiste sperren", ["options.layout.lock_mainbar_desc"] = "Aktiviert: Strg + Rechtsklick zum Verschieben der Leiste. Deaktiviert: Rechtsklick genügt.", + ["options.layout.disable_autocollapse"] = "Automatisches Einklappen für Bot-Leisten deaktivieren", + ["options.layout.disable_autocollapse_desc"] = "Aktiviert: Das Öffnen von Bot-Untermenüs klappt andere Bot-Leisten nicht ein.", ["options.layout.owner_import"] = "Spieler-Layout zum Importieren", ["options.layout.export"] = "Layout exportieren", ["options.layout.import"] = "Layout importieren", diff --git a/Locales/MultiBotAceLocale-enGB.lua b/Locales/MultiBotAceLocale-enGB.lua index 890e77c..af1a002 100644 --- a/Locales/MultiBotAceLocale-enGB.lua +++ b/Locales/MultiBotAceLocale-enGB.lua @@ -7,6 +7,7 @@ local enGBValues = { ["info.itemdestroyalert"] = "Do you REALLY want to destroy this item?\n%s", ["info.keydestroyalert"] = "I will not sell Keys.", ["info.itemsellalert"] = "I cant sell this Item.", + ["info.questitemsellalert"] = "I cannot sell quest items.", ["info.inventoryvendortarget"] = "You must select a vendor first.", ["info.butttitle"] = "|cffffd100MultiBot|r", ["info.buttontoggle"] = "|cff00ff00Left-click: toggle UI|r", @@ -199,6 +200,8 @@ local enGBValues = { ["options.minimap.explainer"] = "Hide or show the MultiBot minimap button.", ["options.layout.lock_mainbar"] = "Lock main bar movement", ["options.layout.lock_mainbar_desc"] = "Checked: Ctrl + right-click to move the bar. Unchecked: right-click is enough.", + ["options.layout.disable_autocollapse"] = "Disable auto-collapse for bot bars", + ["options.layout.disable_autocollapse_desc"] = "Checked: opening bot submenus will not collapse other bot bars.", ["options.layout.owner_import"] = "Player layout to import", ["options.layout.export"] = "Export layout", ["options.layout.import"] = "Import layout", diff --git a/Locales/MultiBotAceLocale-enUS.lua b/Locales/MultiBotAceLocale-enUS.lua index a2f6619..878936f 100644 --- a/Locales/MultiBotAceLocale-enUS.lua +++ b/Locales/MultiBotAceLocale-enUS.lua @@ -7,6 +7,7 @@ local enUSValues = { ["info.itemdestroyalert"] = "Do you REALLY want to destroy this item?\n%s", ["info.keydestroyalert"] = "I will not sell Keys.", ["info.itemsellalert"] = "I cant sell this Item.", + ["info.questitemsellalert"] = "I cannot sell quest items.", ["info.inventoryvendortarget"] = "You must select a vendor first.", ["info.butttitle"] = "|cffffd100MultiBot|r", ["info.buttontoggle"] = "|cff00ff00Left-click: toggle UI|r", @@ -199,6 +200,8 @@ local enUSValues = { ["options.minimap.explainer"] = "Hide or show the MultiBot minimap button.", ["options.layout.lock_mainbar"] = "Lock main bar movement", ["options.layout.lock_mainbar_desc"] = "Checked: Ctrl + right-click to move the bar. Unchecked: right-click is enough.", + ["options.layout.disable_autocollapse"] = "Disable auto-collapse for bot bars", + ["options.layout.disable_autocollapse_desc"] = "Checked: opening bot submenus will not collapse other bot bars.", ["options.layout.owner_import"] = "Player layout to import", ["options.layout.export"] = "Export layout", ["options.layout.import"] = "Import layout", diff --git a/Locales/MultiBotAceLocale-esES.lua b/Locales/MultiBotAceLocale-esES.lua index 892ca76..71bd8fe 100644 --- a/Locales/MultiBotAceLocale-esES.lua +++ b/Locales/MultiBotAceLocale-esES.lua @@ -7,6 +7,7 @@ local esESValues = { ["info.itemdestroyalert"] = "¿REALMENTE quieres destruir este objeto?\n%s", ["info.keydestroyalert"] = "No venderé llaves.", ["info.itemsellalert"] = "No puedo vender este objeto.", + ["info.questitemsellalert"] = "No puedo vender objetos de misión.", ["info.inventoryvendortarget"] = "Primero debes seleccionar un vendedor.", ["info.butttitle"] = "|cffffd100MultiBot|r", ["info.buttontoggle"] = "|cff00ff00Clic izquierdo: alternar la interfaz|r", @@ -197,6 +198,8 @@ local esESValues = { ["options.minimap.explainer"] = "Muestra u oculta el botón del minimapa de MultiBot.", ["options.layout.lock_mainbar"] = "Bloquear movimiento de la barra principal", ["options.layout.lock_mainbar_desc"] = "Marcado: Ctrl + clic derecho para mover la barra. Desmarcado: clic derecho suficiente.", + ["options.layout.disable_autocollapse"] = "Desactivar el auto-colapso de las barras de bots", + ["options.layout.disable_autocollapse_desc"] = "Marcado: al abrir submenús de bots no se colapsarán otras barras de bots.", ["options.layout.owner_import"] = "Layout de jugador para importar", ["options.layout.export"] = "Exportar diseño", ["options.layout.import"] = "Importar diseño", diff --git a/Locales/MultiBotAceLocale-frFR.lua b/Locales/MultiBotAceLocale-frFR.lua index 3a51071..1a5a86a 100644 --- a/Locales/MultiBotAceLocale-frFR.lua +++ b/Locales/MultiBotAceLocale-frFR.lua @@ -7,6 +7,7 @@ local frFRValues = { ["info.itemdestroyalert"] = "Voulez-vous VRAIMENT détruire cet objet ?\n%s", ["info.keydestroyalert"] = "Je ne peux pas vendre des clés.", ["info.itemsellalert"] = "Je ne peux pas vendre cet item.", + ["info.questitemsellalert"] = "Je ne peux pas vendre les objets de quête.", ["info.inventoryvendortarget"] = "Vous devez dabord sélectionner un vendeur.", ["info.butttitle"] = "|cffffd100MultiBot|r", ["info.buttontoggle"] = "|cff00ff00Clic gauche : afficher/masquer l’interface|r", @@ -197,6 +198,8 @@ local frFRValues = { ["options.minimap.explainer"] = "Affiche ou masque le bouton minimap de MultiBot.", ["options.layout.lock_mainbar"] = "Verrouiller déplacement barre principale", ["options.layout.lock_mainbar_desc"] = "Coché : Ctrl + clic droit pour déplacer la barre. Décoché : clic droit suffit.", + ["options.layout.disable_autocollapse"] = "Désactiver l'auto-repli des barres bots", + ["options.layout.disable_autocollapse_desc"] = "Coché : l'ouverture d'un sous-menu bot ne replie plus les autres barres bots.", ["options.layout.owner_import"] = "Layout joueur à importer", ["options.layout.export"] = "Exporter le layout", ["options.layout.import"] = "Importer le layout", diff --git a/Locales/MultiBotAceLocale-koKR.lua b/Locales/MultiBotAceLocale-koKR.lua index bf1de3e..cab522a 100644 --- a/Locales/MultiBotAceLocale-koKR.lua +++ b/Locales/MultiBotAceLocale-koKR.lua @@ -7,6 +7,7 @@ local koKRValues = { ["info.itemdestroyalert"] = "이 아이템을 정말로 파기하시겠습니까?\n%s", ["info.keydestroyalert"] = "열쇠는 판매하지 않습니다.", ["info.itemsellalert"] = "이 아이템은 판매할 수 없습니다.", + ["info.questitemsellalert"] = "퀘스트 아이템은 판매할 수 없습니다.", ["info.inventoryvendortarget"] = "먼저 판매자를 선택해야 합니다.", ["info.butttitle"] = "|cffffd100MultiBot|r", ["info.buttontoggle"] = "|cff00ff00좌클릭: UI 전환|r", @@ -196,6 +197,8 @@ local koKRValues = { ["options.minimap.explainer"] = "MultiBot 미니맵 버튼을 숨기거나 표시합니다.", ["options.layout.lock_mainbar"] = "기본 바 이동 잠금", ["options.layout.lock_mainbar_desc"] = "체크: Ctrl + 우클릭으로 바 이동. 해제: 우클릭만으로 이동.", + ["options.layout.disable_autocollapse"] = "봇 바 자동 접기 비활성화", + ["options.layout.disable_autocollapse_desc"] = "선택 시: 봇 하위 메뉴를 열어도 다른 봇 바가 접히지 않습니다.", ["options.layout.owner_import"] = "가져올 플레이어 레이아웃", ["options.layout.export"] = "레이아웃 내보내기", ["options.layout.import"] = "레이아웃 가져오기", diff --git a/Locales/MultiBotAceLocale-ruRU.lua b/Locales/MultiBotAceLocale-ruRU.lua index 0ee35ed..7fe9234 100644 --- a/Locales/MultiBotAceLocale-ruRU.lua +++ b/Locales/MultiBotAceLocale-ruRU.lua @@ -7,6 +7,7 @@ local ruRUValues = { ["info.itemdestroyalert"] = "Вы ДЕЙСТВИТЕЛЬНО хотите уничтожить этот предмет?\n%s", ["info.keydestroyalert"] = "Я не продаю ключи.", ["info.itemsellalert"] = "Я не могу продать этот предмет.", + ["info.questitemsellalert"] = "Я не могу продавать предметы заданий.", ["info.inventoryvendortarget"] = "Сначала вы должны выбрать продавца.", ["info.butttitle"] = "|cffffd100MultiBot|r", ["info.buttontoggle"] = "|cff00ff00ЛКМ: переключить интерфейс|r", @@ -197,6 +198,8 @@ local ruRUValues = { ["options.minimap.explainer"] = "Скрывает или показывает кнопку миникарты MultiBot.", ["options.layout.lock_mainbar"] = "Заблокировать перемещение главной панели", ["options.layout.lock_mainbar_desc"] = "Включено: Ctrl + ПКМ для перемещения панели. Выключено: достаточно ПКМ.", + ["options.layout.disable_autocollapse"] = "Отключить авто-сворачивание панелей ботов", + ["options.layout.disable_autocollapse_desc"] = "Включено: при открытии подменю ботов другие панели ботов не будут сворачиваться.", ["options.layout.owner_import"] = "Макет игрока для импорта", ["options.layout.export"] = "Экспорт макета", ["options.layout.import"] = "Импорт макета", diff --git a/Locales/MultiBotAceLocale-zhCN.lua b/Locales/MultiBotAceLocale-zhCN.lua index 10b8d8d..7b453cb 100644 --- a/Locales/MultiBotAceLocale-zhCN.lua +++ b/Locales/MultiBotAceLocale-zhCN.lua @@ -7,6 +7,7 @@ local zhCNValues = { ["info.itemdestroyalert"] = "你真的要销毁这个物品吗?\n%s", ["info.keydestroyalert"] = "我不会出售钥匙。", ["info.itemsellalert"] = "我无法出售该物品。", + ["info.questitemsellalert"] = "无法出售任务物品。", ["info.inventoryvendortarget"] = "您必须先选择一位商人。", ["info.butttitle"] = "|cffffd100MultiBot|r", ["info.buttontoggle"] = "|cff00ff00左键:切换界面|r", @@ -197,6 +198,8 @@ local zhCNValues = { ["options.minimap.explainer"] = "显示或隐藏 MultiBot 小地图按钮。", ["options.layout.lock_mainbar"] = "锁定主动作条移动", ["options.layout.lock_mainbar_desc"] = "勾选:Ctrl + 右键拖动动作条。取消勾选:仅右键即可。", + ["options.layout.disable_autocollapse"] = "禁用机器人栏的自动折叠", + ["options.layout.disable_autocollapse_desc"] = "勾选:打开机器人子菜单时不会折叠其他机器人栏。", ["options.layout.owner_import"] = "要导入的玩家布局", ["options.layout.export"] = "导出布局", ["options.layout.import"] = "导入布局", diff --git a/TODO.md b/TODO.md index 06ae089..0a2aa7b 100644 --- a/TODO.md +++ b/TODO.md @@ -1,133 +1,12 @@ TODO -* Voir si y'a pas d'autres appels à pageLabel:SetText(MB_PAGE_DEFAULT) dans les fichiers et remplacer par : + pageLabel:SetText(MultiBot.MB_PAGE_DEFAULT or "0/0") * Uniformiser le template des frame quetes comme celle de Itemus * Uniformiser le template de la frame reward comme celle de itemus * Essayer de faire disparaitre la barre multibots au bout d'un temps et la faire apparaitre quand on passe la souris dessus. -* Quand on deplace ou fait quelque chose dans l'ui il faudrait que ça se sauvegarde tout de suite dans les variables dans deco reco * Raidus doit se rafraichir à l'ouverture et fermeture * dans la liste des quêtes des fois c'est l'ID de la queête qui apparait et pas le tritre * Mettre une option pour choisir la tailles des icones de la main barre et des quickhunter/shaman * Voir si il y'a pas d'autres option que l'on peut ajouter à la frame options de multibot * creer le multilangue pour le tooltip: setTooltip(self, "Show / Hide / Move Quick Shaman") des fichiers quickshaman et quickhunter * Finir les options de déplacement des boutons -* Debuguer le blocage de la barre principale en déplacement ça a l'air de ne pas persister apres une deco reco - - - Ajouter la fonction unequipe à Multibit: -“unequip” est une action orientée équipement, donc elle colle naturellement à une vue d’inspection / slots d’équipement, alors que la réorganisation des sacs demande une logique de bag/slot bien plus lourde. -Pourquoi c’est un bon candidat pour la fenêtre d’inspection - -1) L’inspection est déjà centrée sur les slots d’équipement -Le code existant manipule déjà très bien la notion de slot d’équipement : -dans le calcul d’ilvl, on parcourt explicitement les slots 1..18 ; -dans itemus, il existe déjà une cartographie claire des slots d’équipement (S00, S01, etc.). -Donc si la commande ue fonctionne par slot ou peut être reliée à un slot, l’intégration UI est très naturelle. - -2) On a déjà un point d’entrée “Inspect” -L’addon sait déjà lancer l’inspection d’un bot via InspectUnit(...) : -depuis le bouton Inspect dans la Reward frame, et ailleurs dans l’addon. -Donc graphiquement, il y a déjà un flux utilisateur existant : -ouvrir l’inspection du bot, -voir son équipement, -déclencher une action sur un slot équipé. - -Là où il faut être prudent -Le vrai point clé : comment fonctionne exactement ue -C’est ça qui détermine la qualité de l’intégration. - -Cas A — si ue fonctionne par slot -Exemple conceptuel : -ue head -ue 1 -ue S01 - -Dans ce cas, c’est idéal. -Parce que la fenêtre d’inspection affiche précisément des slots. Tu peux donc faire une UI très propre : -clic droit sur un slot équipé → unequip ; -ou petit bouton contextuel sur chaque slot ; -ou mode “Unequip” activable, puis clic sur le slot. - -Cas B — si ue fonctionne par item -Exemple conceptuel : -ue [ItemLink] -C’est encore faisable, mais un peu moins robuste : -s’il y a ambiguïté, -si deux objets identiques existent, -ou si la commande backend attend autre chose qu’un lien standard. - -Cas C — si ue a une syntaxe spéciale côté playerbots -Alors il faudra juste aligner l’UI sur cette syntaxe. -Mais dans tous les cas, le concept UI reste pertinent. - -“unequip” est une action sur : -un slot équipé, -ou un item actuellement porté. - -Donc conceptuellement, la fenêtre d’inspection est le meilleur endroit : -plus logique pour l’utilisateur ; -plus lisible ; -moins ambigu ; -plus proche du modèle métier. - -Est-ce que l’addon actuel est déjà prêt pour ça ? -Partiellement oui, mais pas complètement -Ce qui existe déjà : -l’addon sait ouvrir une inspection ; -l’addon sait envoyer des commandes whisper à un bot ; -l’addon a déjà des représentations de slots d’équipement dans d’autres zones du code. - -Ce qui manque encore : -une action UI dédiée “unequip” dans la vue d’inspection ; -un mapping propre entre slot UI et payload ue ; -et probablement un refresh fiable après l’action. - -Le point technique le plus important à ne pas oublier -Le refresh après ue -Aujourd’hui, le handler refresh l’inventaire lorsqu’il détecte des messages du bot du genre : -equipping -using -destroyed -etc. - -Donc si la commande ue renvoie un message différent, par exemple : -unequipping -removed -taking off -ou autre -alors il faudra penser à raccrocher ce retour au refresh. -Sinon l’action pourra marcher côté bot, mais l’UI ne se resynchronisera pas proprement. - -C’est probablement le principal piège de cette feature. - -UX recommandé -Je verrais plutôt : - -Option 1 — clic droit sur slot équipé -Très naturel : -clic gauche = comportement standard / tooltip ; -clic droit = ue sur le slot. - -Option 2 — mode “Unequip” -Comme dans INVENTORY avec les modes d’action : -tu actives “Unequip” ; -puis tu cliques un slot inspecté. -C’est cohérent avec la philosophie existante de MultiBot, mais probablement un peu plus lourd que nécessaire. - -Option 3 — petit bouton contextuel / menu sur slot -Plus explicite, mais visuellement plus chargé. -Mon avis -Le clic droit sur le slot équipé est probablement la meilleure UX : -rapide, -lisible, -très cohérent avec une frame d’inspection. - -Au final -Condition indispensable -Il faut juste confirmer précisément : -la syntaxe réelle de ue, -si elle cible un slot ou un item, -quel message de retour elle produit, pour rebrancher le refresh. -Si ces 3 points sont clairs, alors oui, ça vaut complètement le coup de l’exposer graphiquement dans l’inspection d’un bot. - - +* faire en sorte que les menus déroulants de la main barre se ferment quand on on ouvre un autre \ No newline at end of file diff --git a/UI/MultiBotInventoryFrame.lua b/UI/MultiBotInventoryFrame.lua index 2e9dd7c..33aece9 100644 --- a/UI/MultiBotInventoryFrame.lua +++ b/UI/MultiBotInventoryFrame.lua @@ -426,10 +426,8 @@ end local function formatMoneyLabel(gold, silver, copper) local g = tonumber(gold) or 0 - local s = tonumber(silver) or 0 - local c = tonumber(copper) or 0 local moneyLabel = MultiBot.L("info.inventory.money_label", "Money") - return string.format("|cffffff00%s:|r %d|cffffd700g|r %d|cffc7c7cfs|r %d|cffb87333c|r", moneyLabel, g, s, c) + return string.format("|cffffff00%s:|r %d|cffffd700g|r", moneyLabel, g) end local function formatBagSlotsLabel(used, total) @@ -795,6 +793,72 @@ local function runInventoryInstantAction(botName, command, options) setInventoryActionState(nil, { cancelTrade = false }) end + local function isBulkSellCommand(cmd) + return cmd == "s *" or cmd == "s vendor" + end + + local function shouldSellButtonForBulk(button, cmd) + local item = button and button.item + if not item then + return false + end + + if MultiBot.InventoryIsProtectedSellItem and MultiBot.InventoryIsProtectedSellItem(item) then + return false + end + + if cmd == "s *" then + return tonumber(item.rare or -1) == 0 + end + + return true + end + + local function runFilteredBulkSell(cmd) + local inventory = MultiBot.inventory + local itemsFrame = inventory and inventory.frames and inventory.frames.Items + local itemButtons = itemsFrame and itemsFrame.buttons + if type(itemButtons) ~= "table" then + return false + end + + local sellCount = 0 + local protectedFound = false + for _, itemButton in pairs(itemButtons) do + if itemButton and itemButton.item then + if MultiBot.InventoryIsProtectedSellItem and MultiBot.InventoryIsProtectedSellItem(itemButton.item) then + protectedFound = true + elseif shouldSellButtonForBulk(itemButton, cmd) then + SendChatMessage("s " .. itemButton.tip, "WHISPER", nil, botName) + if itemButton.Hide then + itemButton:Hide() + end + sellCount = sellCount + 1 + end + end + end + + if protectedFound then + SendChatMessage(MultiBot.L("info.questitemsellalert", "I cannot sell quest items."), "SAY") + end + + if sellCount < 1 and not protectedFound then + return false + end + + if options.refreshDelay ~= nil and MultiBot.RefreshInventory then + MultiBot.RefreshInventory(options.refreshDelay) + elseif options.refresh and MultiBot.RefreshInventory then + MultiBot.RefreshInventory() + end + + return true + end + + if isBulkSellCommand(command) then + return runFilteredBulkSell(command) + end + SendChatMessage(command, "WHISPER", nil, botName) if options.refreshDelay ~= nil and MultiBot.RefreshInventory then diff --git a/UI/MultiBotInventoryItem.lua b/UI/MultiBotInventoryItem.lua index dd94cf3..2d4c329 100644 --- a/UI/MultiBotInventoryItem.lua +++ b/UI/MultiBotInventoryItem.lua @@ -78,7 +78,11 @@ local function buildInventoryItemRecord(itemInfo) end local itemIcon = GetItemIcon(itemId) - local itemName, itemLink, itemRare = GetItemInfo(itemId) + local itemName, itemLink, itemRare, _, _, itemType, _, _, _, _, _, itemClassID = GetItemInfo(itemId) + if (itemClassID == nil) and GetItemInfoInstant then + local _, _, _, _, _, instantClassID = GetItemInfoInstant(tonumber(itemId) or itemId) + itemClassID = instantClassID + end return { id = itemId, @@ -86,6 +90,8 @@ local function buildInventoryItemRecord(itemInfo) name = resolveInventoryItemName(parts, itemName), link = resolveInventoryItemLink(parts, itemLink), rare = resolveInventoryItemRarity(itemRare), + classID = itemClassID, + type = itemType, count = extractInventoryItemCount(parts), info = itemInfo, parts = parts, @@ -139,6 +145,28 @@ local function isInventoryProtectedHearthstone(item) return item and item.id == "6948" end +local function isInventoryProtectedQuestItem(item) + if not item then + return false + end + + if type(item.classID) == "number" then + local questClassID = (type(LE_ITEM_CLASS_QUESTITEM) == "number") and LE_ITEM_CLASS_QUESTITEM or 12 + return item.classID == questClassID + end + + return false +end + +MultiBot.InventoryIsProtectedQuestItem = isInventoryProtectedQuestItem + +MultiBot.InventoryIsProtectedSellItem = function(item) + return isInventoryProtectedQuestItem(item) + or isInventoryProtectedHearthstone(item) + or isInventoryProtectedKey(item) +end + + local function needsInventoryDestroyConfirmation(item) return isInventoryProtectedHearthstone(item) or isInventoryProtectedKey(item) @@ -186,6 +214,11 @@ local function handleInventoryItemClick(button) return end + if isInventoryProtectedQuestItem(item) then + sendInventoryFeedback("questitemsellalert", "I cannot sell quest items.") + return + end + if isInventoryProtectedHearthstone(item) then sendInventoryFeedback("itemsellalert", "You cannot sell this item") return diff --git a/UI/MultiBotMainUI.lua b/UI/MultiBotMainUI.lua index 318916b..cf811ae 100644 --- a/UI/MultiBotMainUI.lua +++ b/UI/MultiBotMainUI.lua @@ -315,19 +315,6 @@ local function createMainActionButton(mainFrame, definition) return button end -local function isMainBarMoveAllowed() - local moveLocked = MultiBot.GetMainBarMoveLocked and MultiBot.GetMainBarMoveLocked() - if moveLocked == nil then - moveLocked = true - end - - if moveLocked then - return IsControlKeyDown() - end - - return true -end - local function saveMultiBarPosition() local multiBar = MultiBot.frames and MultiBot.frames["MultiBar"] if not multiBar or not MultiBot.SetSavedLayoutValue or not MultiBot.toPoint then @@ -410,8 +397,24 @@ function MultiBot.InitializeMainUI(tMultiBar) local mainButton = tMultiBar.addButton(MAIN_BUTTON_NAME, 0, 0, MAIN_BUTTON_ICON, MultiBot.L("tips.main.master")) mainButton:RegisterForDrag("RightButton") + + local function applyMoveLockState(moveLocked) + local locked = moveLocked + if locked == nil and MultiBot.GetMainBarMoveLocked then + locked = MultiBot.GetMainBarMoveLocked() + end + if locked == nil then + locked = true + end + mainButton.__mbMoveLocked = locked and true or false + end + + MultiBot.ApplyMainBarMoveLockState = applyMoveLockState + applyMoveLockState() + mainButton:SetScript("OnDragStart", function() - if not isMainBarMoveAllowed() then + local moveLocked = mainButton.__mbMoveLocked + if moveLocked and not IsControlKeyDown() then if UIErrorsFrame then UIErrorsFrame:AddMessage(MultiBot.L("mainbar.swap.locked"), 1, 0.25, 0.25, 1) end diff --git a/UI/MultiBotOptions.lua b/UI/MultiBotOptions.lua index ee671a1..4809434 100644 --- a/UI/MultiBotOptions.lua +++ b/UI/MultiBotOptions.lua @@ -153,6 +153,7 @@ local function buildLegacyOptionsContent(panel) local minimapConfig = MultiBot.GetMinimapConfig and MultiBot.GetMinimapConfig() or { hide = false } local mainBarMoveLocked = MultiBot.GetMainBarMoveLocked and MultiBot.GetMainBarMoveLocked() or true + local disableAutoCollapse = MultiBot.GetDisableAutoCollapse and MultiBot.GetDisableAutoCollapse() or false local strataDropDown = CreateFrame("Frame", "MultiBotStrataDropDown", scrollChild, "UIDropDownMenuTemplate") @@ -187,15 +188,27 @@ local function buildLegacyOptionsContent(panel) end end) + local chkDisableAutoCollapse = CreateFrame("CheckButton", "MultiBot_DisableAutoCollapseCheck", scrollChild, "InterfaceOptionsCheckButtonTemplate") + chkDisableAutoCollapse:SetPoint("TOPLEFT", chkMainBarMoveLocked, "BOTTOMLEFT", 0, -8) + _G[chkDisableAutoCollapse:GetName() .. "Text"]:SetText(optL("options.layout.disable_autocollapse")) + chkDisableAutoCollapse.tooltipText = optL("options.layout.disable_autocollapse_desc") + chkDisableAutoCollapse:SetChecked(disableAutoCollapse and true or false) + chkDisableAutoCollapse:SetScript("OnClick", function(btn) + if MultiBot.SetDisableAutoCollapse then + MultiBot.SetDisableAutoCollapse(btn:GetChecked() and true or false) + end + end) + panel.chkMinimapHide = chkMinimapHide panel.chkMainBarMoveLocked = chkMainBarMoveLocked + panel.chkDisableAutoCollapse = chkDisableAutoCollapse local selectedOwnerKey = nil local refreshOwnerDropdown local exportBtn = CreateFrame("Button", nil, scrollChild, "UIPanelButtonTemplate") exportBtn:SetSize(110, 22) - exportBtn:SetPoint("TOPLEFT", chkMainBarMoveLocked, "BOTTOMLEFT", 0, -14) + exportBtn:SetPoint("TOPLEFT", chkDisableAutoCollapse, "BOTTOMLEFT", 0, -14) exportBtn:SetText(optL("options.layout.export")) exportBtn:SetScript("OnClick", function() if MultiBot.SaveMainBarLayoutForCurrentPlayer then @@ -516,6 +529,7 @@ function MultiBot.BuildOptionsPanel() local function buildLayoutTab(tabGroup) local scroll = addTabScroll(tabGroup) local mainBarMoveLocked = MultiBot.GetMainBarMoveLocked and MultiBot.GetMainBarMoveLocked() or true + local disableAutoCollapse = MultiBot.GetDisableAutoCollapse and MultiBot.GetDisableAutoCollapse() or false local chkMainBarMoveLocked = AceGUI:Create("CheckBox") chkMainBarMoveLocked:SetLabel(mainBarMoveLockLabel) @@ -532,6 +546,21 @@ function MultiBot.BuildOptionsPanel() scroll:AddChild(chkMainBarMoveLocked) panel.chkMainBarMoveLocked = chkMainBarMoveLocked + local chkDisableAutoCollapse = AceGUI:Create("CheckBox") + chkDisableAutoCollapse:SetLabel(optL("options.layout.disable_autocollapse")) + if chkDisableAutoCollapse.SetDescription then + chkDisableAutoCollapse:SetDescription(optL("options.layout.disable_autocollapse_desc")) + end + chkDisableAutoCollapse:SetValue(disableAutoCollapse and true or false) + chkDisableAutoCollapse:SetFullWidth(true) + chkDisableAutoCollapse:SetCallback("OnValueChanged", function(_, _, value) + if MultiBot.SetDisableAutoCollapse then + MultiBot.SetDisableAutoCollapse(value and true or false) + end + end) + scroll:AddChild(chkDisableAutoCollapse) + panel.chkDisableAutoCollapse = chkDisableAutoCollapse + local ownerTitle = AceGUI:Create("Label") ownerTitle:SetFullWidth(true) ownerTitle:SetText(layoutOwnerLabel) diff --git a/UI/MultiBotQuestsMenu.lua b/UI/MultiBotQuestsMenu.lua index 1fd708e..77a45d2 100644 --- a/UI/MultiBotQuestsMenu.lua +++ b/UI/MultiBotQuestsMenu.lua @@ -3,15 +3,63 @@ if not MultiBot then return end local QuestsMenu = MultiBot.QuestsMenu or {} MultiBot.QuestsMenu = QuestsMenu -local function toggleButtons(buttonA, buttonB) - if buttonA:IsShown() then - buttonA:doHide() - buttonB:doHide() +local function setSubButtonsVisible(buttonA, buttonB, visible) + if visible then + buttonA:doShow() + buttonB:doShow() return end - buttonA:doShow() - buttonB:doShow() + buttonA:doHide() + buttonB:doHide() +end + +local function shouldAutoCollapseQuestGroups() + if MultiBot.GetDisableAutoCollapse then + return not MultiBot.GetDisableAutoCollapse() + end + return true +end + +local function collapseOtherQuestGroups(activeGroup) + if not shouldAutoCollapseQuestGroups() then + return + end + + local groups = QuestsMenu.expandableGroups + if type(groups) ~= "table" then + return + end + + for index = 1, #groups do + local group = groups[index] + if group ~= activeGroup then + setSubButtonsVisible(group.buttonA, group.buttonB, false) + end + end +end + +local function registerExpandableGroup(rootButton, buttonA, buttonB) + QuestsMenu.expandableGroups = QuestsMenu.expandableGroups or {} + local group = { + root = rootButton, + buttonA = buttonA, + buttonB = buttonB, + } + table.insert(QuestsMenu.expandableGroups, group) + + rootButton.doLeft = function() + local isOpen = buttonA:IsShown() or buttonB:IsShown() + if isOpen then + setSubButtonsVisible(buttonA, buttonB, false) + return + end + + collapseOtherQuestGroups(group) + setSubButtonsVisible(buttonA, buttonB, true) + end + + return group end local function sendIncomplete(method) @@ -133,6 +181,7 @@ function MultiBot.InitializeQuestsMenu(tRight) local button = tRight.addButton("Quests Menu", 0, 0, "achievement_quests_completed_06", MultiBot.L("tips.quests.main")) local menu = tRight.addFrame("QuestMenu", -2, 64) menu:Hide() + QuestsMenu.expandableGroups = {} button.doLeft = function(owner) MultiBot.ShowHideSwitch(owner.parent.frames["QuestMenu"]) @@ -161,7 +210,7 @@ function MultiBot.InitializeQuestsMenu(tRight) local incompWhisper = menu.addButton("BotQuestsIncompWhisper", 61, 90, "Interface\\Icons\\INV_Crate_08", MultiBot.L("tips.quests.sendwhisp")) incompGroup:doHide() incompWhisper:doHide() - incompButton.doLeft = function() toggleButtons(incompGroup, incompWhisper) end + registerExpandableGroup(incompButton, incompGroup, incompWhisper) incompGroup.doLeft = function() sendIncomplete("GROUP") end incompWhisper.doLeft = function() sendIncomplete("WHISPER") end tRight.buttons["BotQuestsIncomp"] = incompButton @@ -173,7 +222,7 @@ function MultiBot.InitializeQuestsMenu(tRight) local completedWhisper = menu.addButton("BotQuestsCompWhisper", 61, 60, "Interface\\Icons\\INV_Crate_09", MultiBot.L("tips.quests.sendwhisp")) completedGroup:doHide() completedWhisper:doHide() - completedButton.doLeft = function() toggleButtons(completedGroup, completedWhisper) end + registerExpandableGroup(completedButton, completedGroup, completedWhisper) completedGroup.doLeft = function() sendCompleted("GROUP") end completedWhisper.doLeft = function() sendCompleted("WHISPER") end tRight.buttons["BotQuestsComp"] = completedButton @@ -195,7 +244,7 @@ function MultiBot.InitializeQuestsMenu(tRight) local allWhisper = menu.addButton("BotQuestsAllWhisper", 61, 120, "Interface\\Icons\\INV_Misc_Book_09", MultiBot.L("tips.quests.sendwhisp")) allGroup:doHide() allWhisper:doHide() - allButton.doLeft = function() toggleButtons(allGroup, allWhisper) end + registerExpandableGroup(allButton, allGroup, allWhisper) allGroup.doLeft = function() sendAll("GROUP") end allWhisper.doLeft = function() sendAll("WHISPER") end tRight.buttons["BotQuestsAll"] = allButton @@ -207,7 +256,7 @@ function MultiBot.InitializeQuestsMenu(tRight) local gobSearchButton = menu.addButton("BotUseGOBSearch", 61, 150, "Interface\\Icons\\inv_misc_spyglass_02", MultiBot.L("tips.quests.gobsearch")) gobNameButton:doHide() gobSearchButton:doHide() - gobButton.doLeft = function() toggleButtons(gobNameButton, gobSearchButton) end + registerExpandableGroup(gobButton, gobNameButton, gobSearchButton) gobNameButton.doLeft = function() if not ShowPrompt then return