Skip to content

Commit b338b2a

Browse files
committed
Add chatless group Roll UI
1 parent 6224be7 commit b338b2a

10 files changed

Lines changed: 462 additions & 11 deletions

Core/MultiBotComm.lua

Lines changed: 140 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ local OUTFIT_CAPABILITY = "OUTFIT_V1"
1717
local INVENTORY_CAPABILITY = "INVENTORY_V1"
1818
local INVENTORY_BULK_SELL_CAPABILITY = "INVENTORY_BULK_SELL_V1"
1919
local INVENTORY_OPEN_CAPABILITY = "INVENTORY_OPEN_V1"
20+
local GROUP_ROLL_CAPABILITY = "GROUP_ROLL_V1"
21+
local GROUP_ROLL_TIMEOUT_SECONDS = 5.0
22+
local GROUP_ROLL_MAX_ITEM_LINK_LENGTH = 160
2023
local STATE_TIMEOUT_SECONDS = 5.0
2124
local STATES_TIMEOUT_SECONDS = 15.0
2225
local STRATEGY_MUTATION_TIMEOUT_SECONDS = 5.0
@@ -235,6 +238,9 @@ local function ensureBridgeState()
235238
state.inventoryCapable = state.inventoryCapable or false
236239
state.inventoryBulkSellCapable = state.inventoryBulkSellCapable or false
237240
state.inventoryOpenCapable = state.inventoryOpenCapable or false
241+
state.groupRollCapable = state.groupRollCapable or false
242+
state.groupRollSeq = state.groupRollSeq or 0
243+
state.groupRollCommands = state.groupRollCommands or {}
238244
state.strategyMutationSeq = state.strategyMutationSeq or 0
239245
state.strategyMutationCommands = state.strategyMutationCommands or {}
240246
state.weaponEnchantDebugSeq = state.weaponEnchantDebugSeq or 0
@@ -1733,6 +1739,79 @@ function Comm.RunProfessionRecipeCraft(name, skillId, spellId, itemId)
17331739
return token
17341740
end
17351741

1742+
local function finishGroupRollCommand(token, result)
1743+
local state = ensureBridgeState()
1744+
local pending = state.groupRollCommands[token]
1745+
if not pending then
1746+
return false
1747+
end
1748+
1749+
state.groupRollCommands[token] = nil
1750+
result = type(result) == "table" and result or {}
1751+
result.token = token
1752+
result.mode = result.mode or pending.mode
1753+
1754+
if type(pending.callback) == "function" then
1755+
pending.callback(result)
1756+
end
1757+
1758+
if MultiBot.OnGroupRollResult then
1759+
MultiBot.OnGroupRollResult(result)
1760+
end
1761+
1762+
return true
1763+
end
1764+
1765+
function Comm.RunGroupRoll(itemLink, callback)
1766+
local state = ensureBridgeState()
1767+
if not state.connected or state.groupRollCapable ~= true then
1768+
return false
1769+
end
1770+
1771+
itemLink = trim(itemLink or "")
1772+
local mode = "NORMAL"
1773+
if itemLink ~= "" then
1774+
if #itemLink > GROUP_ROLL_MAX_ITEM_LINK_LENGTH or not string.find(itemLink, "|Hitem:", 1, true) then
1775+
return false
1776+
end
1777+
mode = "ITEM"
1778+
end
1779+
1780+
state.groupRollSeq = (tonumber(state.groupRollSeq) or 0) + 1
1781+
local token = tostring(math.floor(safeNow() * 1000)) .. "-roll-" .. tostring(state.groupRollSeq)
1782+
state.groupRollCommands[token] = {
1783+
mode = mode,
1784+
callback = type(callback) == "function" and callback or nil,
1785+
startedAt = safeNow(),
1786+
}
1787+
1788+
local payload = "GROUP_ROLL~" .. token .. "~" .. mode
1789+
if mode == "ITEM" then
1790+
payload = payload .. "~" .. urlEncodeField(itemLink)
1791+
end
1792+
1793+
if not Comm.Send("RUN", payload) then
1794+
state.groupRollCommands[token] = nil
1795+
return false
1796+
end
1797+
1798+
safeDelay(GROUP_ROLL_TIMEOUT_SECONDS, function()
1799+
local bridge = ensureBridgeState()
1800+
if not bridge.groupRollCommands[token] then
1801+
return
1802+
end
1803+
1804+
finishGroupRollCommand(token, {
1805+
status = "timeout",
1806+
matched = 0,
1807+
invoked = 0,
1808+
reason = "TIMEOUT",
1809+
})
1810+
end)
1811+
1812+
return token
1813+
end
1814+
17361815
function Comm.RunInventoryItemAction(name, action, itemId, count)
17371816
local state = ensureBridgeState()
17381817
name = trim(name)
@@ -1793,6 +1872,7 @@ function Comm.MarkDisconnected(reason)
17931872
state.bankActive = nil
17941873
state.guildBankActive = nil
17951874
state.inventoryItemActions = {}
1875+
state.groupRollCommands = {}
17961876
state.spellbookActive = nil
17971877
state.botSkillActive = nil
17981878
state.botReputationActive = nil
@@ -1810,6 +1890,7 @@ function Comm.MarkDisconnected(reason)
18101890
state.inventoryCapable = false
18111891
state.inventoryBulkSellCapable = false
18121892
state.inventoryOpenCapable = false
1893+
state.groupRollCapable = false
18131894
state.stateFramingCapable = false
18141895
state.capabilityFallbackDeadline = 0
18151896
state.capabilityFallbackGeneration = 0
@@ -3500,6 +3581,7 @@ function Comm.HandleAddonMessage(prefix, message, distribution, sender)
35003581
state.inventoryCapable = false
35013582
state.inventoryBulkSellCapable = false
35023583
state.inventoryOpenCapable = false
3584+
state.groupRollCapable = false
35033585
for capability in string.gmatch(payload or "", "([^,]+)") do
35043586
capability = trim(capability)
35053587
if capability == STATE_FRAMING_CAPABILITY then
@@ -3514,6 +3596,8 @@ function Comm.HandleAddonMessage(prefix, message, distribution, sender)
35143596
state.inventoryBulkSellCapable = true
35153597
elseif capability == INVENTORY_OPEN_CAPABILITY then
35163598
state.inventoryOpenCapable = true
3599+
elseif capability == GROUP_ROLL_CAPABILITY then
3600+
state.groupRollCapable = true
35173601
end
35183602
end
35193603
state.capabilityFallbackDeadline = 0
@@ -4665,6 +4749,52 @@ function Comm.HandleAddonMessage(prefix, message, distribution, sender)
46654749
return true
46664750
end
46674751

4752+
if opcode == "GROUP_ROLL_ACK" then
4753+
local fields = splitFields(payload or "")
4754+
if #fields ~= 7 then
4755+
state.lastError = "GROUP_ROLL_ACK_BAD_FIELD_COUNT"
4756+
return true
4757+
end
4758+
4759+
local token = trim(fields[1])
4760+
local status = string.upper(trim(fields[2]))
4761+
local mode = string.upper(trim(fields[3]))
4762+
local scope = string.upper(trim(fields[4]))
4763+
local matched = parseBoundedInteger(fields[5], 0, 128)
4764+
local invoked = parseBoundedInteger(fields[6], 0, 128)
4765+
local reason = urlDecodeFieldStrict(fields[7], 64, false)
4766+
local pending = state.groupRollCommands[token]
4767+
4768+
if not isValidStateToken(token)
4769+
or (status ~= "OK" and status ~= "ERR")
4770+
or (mode ~= "NORMAL" and mode ~= "ITEM")
4771+
or (scope ~= "PARTY" and scope ~= "RAID" and scope ~= "NONE")
4772+
or matched == nil
4773+
or invoked == nil
4774+
or invoked > matched
4775+
or reason == nil
4776+
or type(pending) ~= "table"
4777+
or pending.mode ~= mode then
4778+
state.lastError = "GROUP_ROLL_ACK_INVALID"
4779+
return true
4780+
end
4781+
4782+
state.connected = true
4783+
state.lastError = nil
4784+
debugPrint("ADDON:RX", "GROUP_ROLL_ACK", payload or "")
4785+
4786+
finishGroupRollCommand(token, {
4787+
status = status == "OK" and "ok" or "error",
4788+
mode = mode,
4789+
scope = scope,
4790+
matched = matched,
4791+
invoked = invoked,
4792+
reason = reason,
4793+
})
4794+
4795+
return true
4796+
end
4797+
46684798
if opcode == "ERR" then
46694799
state.lastError = payload
46704800
debugPrint("ADDON:RX", "ERR", payload or "")
@@ -4677,7 +4807,14 @@ function Comm.HandleAddonMessage(prefix, message, distribution, sender)
46774807

46784808
requestType = requestType and string.upper(trim(requestType)) or nil
46794809
if requestType and isValidStateToken(token) and reason then
4680-
if requestType == "STRATEGY" and state.strategyMutationCommands[token] then
4810+
if requestType == "GROUP_ROLL" and state.groupRollCommands[token] then
4811+
finishGroupRollCommand(token, {
4812+
status = "error",
4813+
matched = 0,
4814+
invoked = 0,
4815+
reason = reason,
4816+
})
4817+
elseif requestType == "STRATEGY" and state.strategyMutationCommands[token] then
46814818
finishStrategyMutationCommand(token, {
46824819
status = "error",
46834820
matched = 0,
@@ -4736,6 +4873,8 @@ function Comm.OnPlayerEnteringWorld()
47364873
state.inventoryCapable = false
47374874
state.inventoryBulkSellCapable = false
47384875
state.inventoryOpenCapable = false
4876+
state.groupRollCapable = false
4877+
state.groupRollCommands = {}
47394878
state.strategyMutationCommands = {}
47404879
state.details = {}
47414880
state.stats = {}

Locales/MultiBotAceLocale-deDE.lua

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -543,10 +543,27 @@ local deDEValues = {
543543
["tips.quests.gobsfound"] = "Gefundene GameObjects",
544544
["tips.quests.gobpromptname"] = "GameObject Name",
545545
["tips.quests.gobnosearchdata"] = "No search data captured.",
546-
["tips.group.group"] = "Gruppenaktionen-Auswahl\n|cffffffffÖffnet ein Untermenü mit den folgenden Gruppenaktionen:\nTrinken, Freilassen, Wiederbeleben.|r\n\n|cffff0000Linksklick zum Erweitern.|r",
546+
["tips.group.group"] = "Gruppenaktionen-Auswahl\n|cffffffffÖffnet ein Untermenü mit den folgenden Gruppenaktionen:\nTrinken, Freilassen, Wiederbeleben, Würfeln.|r\n\n|cffff0000Linksklick zum Erweitern.|r",
547547
["tips.drink.group"] = "Group-Drink\n|cffffffffMit diesem Kommando befiehlt man der Gruppe etwas zu trinken.\nDie Ausführreihenfolge zeigt die Empfänger des Befehls.|r\n\n|cffff0000Linksklicken um Group-Drink auszuführen|r\n|cff999999(Ausführreihenfolge: Raid, Party)|r",
548548
["tips.release.group"] = "Group-Release\n|cffffffffMit diesem Kommando geben die toten Bots ihre Geister auf den nächsten Friedhof frei.\nDie Ausführreihenfolge zeigt die Empfänger des Befehls.|r\n\n|cffff0000Linksklicken um Group-Release auszuführen|r\n|cff999999(Ausführreihenfolge: Raid, Party)|r",
549549
["tips.revive.group"] = "Group-Revive\n|cffffffffMit diesem Kommando werden Geister-Bots auf dem nächsten Friedhof wiederbelebt.\nDie Ausführreihenfolge zeigt die Empfänger des Befehls.|r\n\n|cffff0000Linksklicken um Group-Revive auszuführen|r\n|cff999999(Ausführreihenfolge: Raid, Party)|r",
550+
["tips.roll.group"] = "Gruppenwurf\n|cffffffffÖffnet das Würfelfenster für die aktuelle Gruppe oder den aktuellen Schlachtzug.|r\n\n|cffff0000Linksklick zum Öffnen.|r",
551+
["roll.window.title"] = "Gruppenwurf",
552+
["roll.window.normal"] = "0-100 würfeln",
553+
["roll.window.item_label"] = "Gegenstand",
554+
["roll.window.item_hint"] = "In das Feld klicken und dann Umschalt+Klick auf einen Gegenstand, um den Link einzufügen.",
555+
["roll.window.item_button"] = "Für diesen Gegenstand würfeln",
556+
["roll.status.ready"] = "Bereit.",
557+
["roll.status.sending"] = "Wurfanfrage wird gesendet...",
558+
["roll.status.sent"] = "Wurfanfrage an %d Bot(s) gesendet.",
559+
["roll.status.bridge_unavailable"] = "Bridge-Gruppenwurf ist nicht verfügbar.",
560+
["roll.status.no_group"] = "Du bist in keiner Gruppe.",
561+
["roll.status.no_bots"] = "Keine steuerbaren Bots in deiner Gruppe gefunden.",
562+
["roll.status.forbidden"] = "Kein Bot darf diese Wurfanfrage ausführen.",
563+
["roll.status.rate_limit"] = "Zu viele Wurfanfragen. Bitte kurz warten.",
564+
["roll.status.bad_item"] = "Ungültiger Gegenstandslink.",
565+
["roll.status.timeout"] = "Zeitüberschreitung bei der Wurfanfrage.",
566+
["roll.status.failed"] = "Die Wurfanfrage ist fehlgeschlagen.",
550567
["tips.summon.group"] = "Group-Summon\n|cffffffffMit diesem Kommando ruft man die Gruppe an seine Position.\nDie Ausführreihenfolge zeigt die Empfänger des Befehls.|r\n\n|cffff0000Linksklicken um Group-Summon auszuführen|r\n|cff999999(Ausführreihenfolge: Raid, Party)|r",
551568
["tips.allbots.sellallvendor"] = "Alle verkaufbaren grauen Gegenstände verkaufen (ALLE BOTS)|cffffffff\nAlle deine Bots (die im Einheitenfenster aufgeführt sind) werden alle Gegenstände verkaufen,\ndie sicher an den aktuell anvisierten Händler verkauft werden können.\nGeschützte Gegenstände (Schlüssel, Ruhestein usw.) werden niemals verkauft.|r\n\n|cffff0000Betroffen sind alle Bots, die im Einheitenfenster aufgeführt sind.|r\n|cff999999(Ausgeführt von: jedem Bot)|r",
552569
["tips.allbots.commandsallbots"] = "Ermöglicht dir, Befehle an alle Bots zu senden|cffffffff\nAlle deine Bots (die im Einheitenfenster aufgeführt sind) werden den Befehl ausführen\n\n|cffff0000Betroffen sind alle Bots, die im Einheitenfenster aufgeführt sind.|r\n|cff999999(Ausgeführt von: jedem Bot)|r",

Locales/MultiBotAceLocale-enGB.lua

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -545,10 +545,27 @@ local enGBValues = {
545545
["tips.quests.gobsfound"] = "Game Objects Found",
546546
["tips.quests.gobpromptname"] = "Game Object Name",
547547
["tips.quests.gobnosearchdata"] = "No search data captured.",
548-
["tips.group.group"] = "Group Actions Selector\n|cffffffffThis opens a submenu with the following group actions:\nDrink, Release, Revive.|r\n\n|cffff0000Left-click to expand.|r",
548+
["tips.group.group"] = "Group Actions Selector\n|cffffffffThis opens a submenu with the following group actions:\nDrink, Release, Revive, Roll.|r\n\n|cffff0000Left-click to expand.|r",
549549
["tips.drink.group"] = "Group Drink\n|cffffffffOrders the Group to drink/eat.\n|cffff0000Left-click to activate|r\n|cff999999(Executed by: Raid, Party)|r",
550550
["tips.release.group"] = "Group Release\n|cffffffffReleases the spirits of all dead Bots to the nearest Graveyard.\n|cffff0000Left-click to activate|r\n|cff999999(Executed by: Raid, Party)|r",
551551
["tips.revive.group"] = "Group Revive\n|cffffffffRevives dead Bots at the nearest Graveyard.\n|cffff0000Left-click to activate|r\n|cff999999(Executed by: Raid, Party)|r",
552+
["tips.roll.group"] = "Group Roll\n|cffffffffOpens the roll window for the current party or raid.|r\n\n|cffff0000Left-click to open.|r",
553+
["roll.window.title"] = "Group Roll",
554+
["roll.window.normal"] = "Roll 0-100",
555+
["roll.window.item_label"] = "Item",
556+
["roll.window.item_hint"] = "Click the field, then Shift-click an item to insert its link.",
557+
["roll.window.item_button"] = "Roll for this item",
558+
["roll.status.ready"] = "Ready.",
559+
["roll.status.sending"] = "Sending roll request...",
560+
["roll.status.sent"] = "Roll request sent to %d bot(s).",
561+
["roll.status.bridge_unavailable"] = "Bridge group roll is unavailable.",
562+
["roll.status.no_group"] = "You are not in a group.",
563+
["roll.status.no_bots"] = "No controllable bots were found in your group.",
564+
["roll.status.forbidden"] = "No bot is authorized to execute this roll request.",
565+
["roll.status.rate_limit"] = "Too many roll requests. Please wait a moment.",
566+
["roll.status.bad_item"] = "Invalid item link.",
567+
["roll.status.timeout"] = "The roll request timed out.",
568+
["roll.status.failed"] = "The roll request failed.",
552569
["tips.summon.group"] = "Group Summon\n|cffffffffSummons entire Party or Raid to your location.\n|cffff0000Left-click to activate|r\n|cff999999(Executed by: Raid, Party)|r",
553570
["tips.allbots.sellallvendor"] = "Sell all vendorable Grey items (ALL BOTS)|cffffffff\nAll your bots (those listed in the Units panel) will sell all items\nthat can safely be sold to your current vendor target.\nProtected items (keys, Hearthstone, etc.) are never sold.|r\n\n|cffff0000Affects every bot listed in the Units panel.|r\n|cff999999(Executed by: each Bot)|r",
554571
["tips.allbots.commandsallbots"] = "Allows you to send commands to all Bots|cffffffff\nAll your bots (those listed in the Units panel) will execute the command\n\n|cffff0000Affects every bot listed in the Units panel.|r\n|cff999999(Executed by: each Bot)|r",

Locales/MultiBotAceLocale-enUS.lua

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -545,10 +545,27 @@ local enUSValues = {
545545
["tips.quests.gobsfound"] = "Game Objects Found",
546546
["tips.quests.gobpromptname"] = "Game Object Name",
547547
["tips.quests.gobnosearchdata"] = "No search data captured.",
548-
["tips.group.group"] = "Group Actions Selector\n|cffffffffThis opens a submenu with the following group actions:\nDrink, Release, Revive.|r\n\n|cffff0000Left-click to expand.|r",
548+
["tips.group.group"] = "Group Actions Selector\n|cffffffffThis opens a submenu with the following group actions:\nDrink, Release, Revive, Roll.|r\n\n|cffff0000Left-click to expand.|r",
549549
["tips.drink.group"] = "Group Drink\n|cffffffffOrders the Group to drink/eat.\n|cffff0000Left-click to activate|r\n|cff999999(Executed by: Raid, Party)|r",
550550
["tips.release.group"] = "Group Release\n|cffffffffReleases the spirits of all dead Bots to the nearest Graveyard.\n|cffff0000Left-click to activate|r\n|cff999999(Executed by: Raid, Party)|r",
551551
["tips.revive.group"] = "Group Revive\n|cffffffffRevives dead Bots at the nearest Graveyard.\n|cffff0000Left-click to activate|r\n|cff999999(Executed by: Raid, Party)|r",
552+
["tips.roll.group"] = "Group Roll\n|cffffffffOpens the roll window for the current party or raid.|r\n\n|cffff0000Left-click to open.|r",
553+
["roll.window.title"] = "Group Roll",
554+
["roll.window.normal"] = "Roll 0-100",
555+
["roll.window.item_label"] = "Item",
556+
["roll.window.item_hint"] = "Click the field, then Shift-click an item to insert its link.",
557+
["roll.window.item_button"] = "Roll for this item",
558+
["roll.status.ready"] = "Ready.",
559+
["roll.status.sending"] = "Sending roll request...",
560+
["roll.status.sent"] = "Roll request sent to %d bot(s).",
561+
["roll.status.bridge_unavailable"] = "Bridge group roll is unavailable.",
562+
["roll.status.no_group"] = "You are not in a group.",
563+
["roll.status.no_bots"] = "No controllable bots were found in your group.",
564+
["roll.status.forbidden"] = "No bot is authorized to execute this roll request.",
565+
["roll.status.rate_limit"] = "Too many roll requests. Please wait a moment.",
566+
["roll.status.bad_item"] = "Invalid item link.",
567+
["roll.status.timeout"] = "The roll request timed out.",
568+
["roll.status.failed"] = "The roll request failed.",
552569
["tips.summon.group"] = "Group Summon\n|cffffffffSummons entire Party or Raid to your location.\n|cffff0000Left-click to activate|r\n|cff999999(Executed by: Raid, Party)|r",
553570
["tips.allbots.sellallvendor"] = "Sell all vendorable Grey items (ALL BOTS)|cffffffff\nAll your bots (those listed in the Units panel) will sell all items\nthat can safely be sold to your current vendor target.\nProtected items (keys, Hearthstone, etc.) are never sold.|r\n\n|cffff0000Affects every bot listed in the Units panel.|r\n|cff999999(Executed by: each Bot)|r",
554571
["tips.allbots.commandsallbots"] = "Allows you to send commands to all Bots|cffffffff\nAll your bots (those listed in the Units panel) will execute the command\n\n|cffff0000Affects every bot listed in the Units panel.|r\n|cff999999(Executed by: each Bot)|r",

0 commit comments

Comments
 (0)