Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 75 additions & 0 deletions Core/MultiBotComm.lua
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ local function ensureBridgeState()
state.glyphActive = state.glyphActive or nil
state.rtiSeq = state.rtiSeq or 0
state.combatSeq = state.combatSeq or 0
state.positionSeq = state.positionSeq or 0
return state
end

Expand All @@ -128,6 +129,27 @@ local function debugPrint(...)
end
end

local function L(key, fallback)
if MultiBot and type(MultiBot.L) == "function" then
return MultiBot.L(key, fallback)
end

return fallback or key
end

local function systemMessage(message)
message = trim(message)
if message == "" then
return
end

if DEFAULT_CHAT_FRAME and DEFAULT_CHAT_FRAME.AddMessage then
DEFAULT_CHAT_FRAME:AddMessage(message)
elseif type(print) == "function" then
print(message)
end
end

local function buildMessage(opcode, payload)
local message = trim(opcode)
if payload ~= nil and payload ~= "" then
Expand Down Expand Up @@ -295,6 +317,31 @@ function Comm.RunCombatCommand(scope, target, command)
return Comm.Send("RUN", "COMBAT~" .. scope .. "~" .. urlEncodeField(target) .. "~" .. token .. "~" .. urlEncodeField(command))
end

function Comm.RunPositionCommand(scope, target, command)
local state = ensureBridgeState()

if not state.connected then
return false
end

command = trim(command or "")
if command == "" then
return false
end

scope = string.upper(trim(scope or "ALL"))
target = trim(target or "")

if scope ~= "ALL" and scope ~= "GROUP" and scope ~= "BOT" then
return false
end

state.positionSeq = (tonumber(state.positionSeq) or 0) + 1
local token = tostring(math.floor(safeNow() * 1000)) .. "-position-" .. tostring(state.positionSeq)

return Comm.Send("RUN", "POSITION~" .. scope .. "~" .. urlEncodeField(target) .. "~" .. token .. "~" .. urlEncodeField(command))
end

function Comm.RequestOutfits(name)
local state = ensureBridgeState()
name = trim(name)
Expand Down Expand Up @@ -1648,6 +1695,34 @@ function Comm.HandleAddonMessage(prefix, message, distribution, sender)
return true
end

if opcode == "POSITION_ACK" then
state.connected = true
state.lastError = nil
debugPrint("ADDON:RX", "POSITION_ACK", payload or "")

local scope, rest = splitOnce(payload or "", "~")
local encodedTarget, rest2 = splitOnce(rest, "~")
local token, rest3 = splitOnce(rest2, "~")
local executedText, encodedCommand = splitOnce(rest3, "~")
local executed = tonumber(executedText) or 0
local command = trim(urlDecodeField(encodedCommand))

if executed > 0 then
local distance = string.match(command, "^disperse set%s+(.+)$")

if distance then
systemMessage(string.format(
L("disperse.confirm.set", "Disperse set to %s yards."),
distance
))
elseif command == "disperse disable" then
systemMessage(L("disperse.confirm.disable", "Disperse disabled."))
end
end

return true
end

if opcode == "ERR" then
state.lastError = payload
debugPrint("ADDON:RX", "ERR", payload or "")
Expand Down
7 changes: 7 additions & 0 deletions Locales/MultiBotAceLocale-deDE.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ end

local deDEValues = {
["tips.units.rti"] = "RTI",
["tips.disperse.main"] = "Disperse",
["tips.disperse.set"] = "Disperse-Distanz setzen",
["tips.disperse.disable"] = "Disperse deaktivieren",
["disperse.bridge.required"] = "Position-Bridge ist nicht verbunden.",
["disperse.invalid_distance"] = "Gib eine Distanz zwischen 1 und 100 Yards ein.",
["disperse.confirm.set"] = "Disperse auf %s Yards gesetzt.",
["disperse.confirm.disable"] = "Disperse deaktiviert.",
["rti.bridge.required"] = "Die RTI-Bridge ist nicht verbunden.",
["info.rti.no_bot_selection"] = "Kein botspezifisches RTI-Symbol ausgewählt.",
["rti.icon.star"] = "Stern",
Expand Down
7 changes: 7 additions & 0 deletions Locales/MultiBotAceLocale-enGB.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ end

local enGBValues = {
["tips.units.rti"] = "RTI",
["tips.disperse.main"] = "Disperse",
["tips.disperse.set"] = "Set disperse distance",
["tips.disperse.disable"] = "Disable disperse",
["disperse.bridge.required"] = "Position bridge is not connected.",
["disperse.invalid_distance"] = "Enter a distance between 1 and 100 yards.",
["disperse.confirm.set"] = "Disperse set to %s yards.",
["disperse.confirm.disable"] = "Disperse disabled.",
["rti.bridge.required"] = "RTI bridge is not connected.",
["info.rti.no_bot_selection"] = "No bot-specific RTI icon selected.",
["rti.icon.star"] = "Star",
Expand Down
7 changes: 7 additions & 0 deletions Locales/MultiBotAceLocale-enUS.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ end

local enUSValues = {
["tips.units.rti"] = "RTI",
["tips.disperse.main"] = "Disperse",
["tips.disperse.set"] = "Set disperse distance",
["tips.disperse.disable"] = "Disable disperse",
["disperse.bridge.required"] = "Position bridge is not connected.",
["disperse.invalid_distance"] = "Enter a distance between 1 and 100 yards.",
["disperse.confirm.set"] = "Disperse set to %s yards.",
["disperse.confirm.disable"] = "Disperse disabled.",
["rti.bridge.required"] = "RTI bridge is not connected.",
["info.rti.no_bot_selection"] = "No bot-specific RTI icon selected.",
["rti.icon.star"] = "Star",
Expand Down
7 changes: 7 additions & 0 deletions Locales/MultiBotAceLocale-esES.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ end

local esESValues = {
["tips.units.rti"] = "RTI",
["tips.disperse.main"] = "Dispersar",
["tips.disperse.set"] = "Definir distancia de dispersión",
["tips.disperse.disable"] = "Desactivar dispersión",
["disperse.bridge.required"] = "El puente de posición no está conectado.",
["disperse.invalid_distance"] = "Introduce una distancia entre 1 y 100 yardas.",
["disperse.confirm.set"] = "Dispersión establecida a %s yardas.",
["disperse.confirm.disable"] = "Dispersión desactivada.",
["rti.bridge.required"] = "El puente RTI no está conectado.",
["info.rti.no_bot_selection"] = "No hay ningún icono RTI específico de bot seleccionado.",
["rti.icon.star"] = "Estrella",
Expand Down
7 changes: 7 additions & 0 deletions Locales/MultiBotAceLocale-frFR.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ end

local frFRValues = {
["tips.units.rti"] = "RTI",
["tips.disperse.main"] = "Disperse",
["tips.disperse.set"] = "Définir la distance de disperse",
["tips.disperse.disable"] = "Désactiver disperse",
["disperse.bridge.required"] = "Le bridge de position n’est pas connecté.",
["disperse.invalid_distance"] = "Entre une distance entre 1 et 100 yards.",
["disperse.confirm.set"] = "Disperse défini à %s yards.",
["disperse.confirm.disable"] = "Disperse désactivé.",
["rti.bridge.required"] = "Le bridge RTI n'est pas connecté.",
["info.rti.no_bot_selection"] = "Aucun bot avec une icône RTI personnelle sélectionnée.",
["rti.icon.star"] = "Étoile",
Expand Down
7 changes: 7 additions & 0 deletions Locales/MultiBotAceLocale-koKR.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ end

local koKRValues = {
["tips.units.rti"] = "RTI",
["tips.disperse.main"] = "분산",
["tips.disperse.set"] = "분산 거리 설정",
["tips.disperse.disable"] = "분산 비활성화",
["disperse.bridge.required"] = "위치 브리지가 연결되어 있지 않습니다.",
["disperse.invalid_distance"] = "1에서 100 야드 사이의 거리를 입력하세요.",
["disperse.confirm.set"] = "분산 거리가 %s 야드로 설정되었습니다.",
["disperse.confirm.disable"] = "분산이 비활성화되었습니다.",
["rti.bridge.required"] = "RTI 브리지가 연결되어 있지 않습니다.",
["info.rti.no_bot_selection"] = "봇 전용 RTI 아이콘이 선택되지 않았습니다.",
["rti.icon.star"] = "별",
Expand Down
7 changes: 7 additions & 0 deletions Locales/MultiBotAceLocale-ruRU.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ end

local ruRUValues = {
["tips.units.rti"] = "RTI",
["tips.disperse.main"] = "Рассредоточение",
["tips.disperse.set"] = "Задать дистанцию рассредоточения",
["tips.disperse.disable"] = "Отключить рассредоточение",
["disperse.bridge.required"] = "Мост позиционирования не подключен.",
["disperse.invalid_distance"] = "Введите дистанцию от 1 до 100 ярдов.",
["disperse.confirm.set"] = "Рассредоточение установлено на %s ярдов.",
["disperse.confirm.disable"] = "Рассредоточение отключено.",
["rti.bridge.required"] = "RTI-мост не подключен.",
["info.rti.no_bot_selection"] = "Не выбрана RTI-иконка для отдельного бота.",
["rti.icon.star"] = "Звезда",
Expand Down
7 changes: 7 additions & 0 deletions Locales/MultiBotAceLocale-zhCN.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ end

local zhCNValues = {
["tips.units.rti"] = "RTI",
["tips.disperse.main"] = "分散",
["tips.disperse.set"] = "设置分散距离",
["tips.disperse.disable"] = "禁用分散",
["disperse.bridge.required"] = "位置桥接未连接。",
["disperse.invalid_distance"] = "请输入 1 到 100 码之间的距离。",
["disperse.confirm.set"] = "分散距离已设置为 %s 码。",
["disperse.confirm.disable"] = "分散已禁用。",
["rti.bridge.required"] = "RTI 桥接未连接。",
["info.rti.no_bot_selection"] = "未选择任何机器人专用 RTI 图标。",
["rti.icon.star"] = "星星",
Expand Down
1 change: 1 addition & 0 deletions MultiBot.toc
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ UI\MultiBotMainUI.lua
UI\MultiBotGmUI.lua
UI\MultiBotRTSCUI.lua
UI\MultiBotRTIUI.lua
UI\MultiBotDisperseUI.lua
Core\MultiBotInit.lua
Data\MultiBotIconos.lua
Data\MultiBotItemus.lua
Expand Down
11 changes: 8 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ GET~GLYPHS
GET~OUTFITS
RUN~RTI
RUN~COMBAT
RUN~POSITION
```

Manual playerbot commands are still intentionally preserved for diagnostics and gameplay actions.
Expand Down Expand Up @@ -171,6 +172,10 @@ The goal is to remove automatic UI-refresh spam.
<td>Combat strategy fine tuning</td>
<td><strong>Bridge-first</strong> avoid AoE, save mana, threat and behind controls</td>
</tr>
<tr>
<td>Disperse controls</td>
<td><strong>Bridge-first</strong> distance set and disable actions through <code>RUN~POSITION</code></td>
</tr>
<tr>
<td>Units / EveryBars</td>
<td><strong>Improved</strong> login, reload and AddClass refresh behavior</td>
Expand Down Expand Up @@ -400,6 +405,7 @@ Implemented bridge-first / chatless areas:
- RTI controls through the bridge.
- Pull Control frame through the bridge.
- Combat strategy fine tuning through the bridge.
- Disperse controls through the bridge with `disperse set <yards>` and `disperse disable`.
- Custom glyph socket mapping and apply order.
- Talent tab navigation stability after switching between tabs.
- Automatic bot reconnect on login/reload for bots already present in the group or raid.
Expand All @@ -416,12 +422,11 @@ Kept intentionally:

# Remaining Work

The Outfits, RTI, Pull Control and Combat Strategy migrations are implemented. The next step is Disperse, followed by final stabilization and cleanup.
The Outfits, RTI, Pull Control, Combat Strategy and Disperse migrations are implemented. The next step is final stabilization and cleanup.

Planned follow-up work:

- Start the Disperse command migration.
- Regression test login, `/reload`, large raid groups, Units, EveryBars, Stats, Inventory, Spellbook, Talents, Glyphs, Outfits, RTI, Pull Control and Combat Strategies.
- Regression test login, `/reload`, large raid groups, Units, EveryBars, Stats, Inventory, Spellbook, Talents, Glyphs, Outfits, RTI, Pull Control, Combat Strategies and Disperse.
- Verify that `MultiBot.allowLegacyChatFallback = false` prevents automatic legacy refresh spam on all migrated UI paths.
- Keep manual diagnostic commands documented and functional.
- Remove obsolete debug prints.
Expand Down
Loading
Loading