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
253 changes: 252 additions & 1 deletion Core/MultiBotComm.lua
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ local function ensureBridgeState()
state.questActive = state.questActive or {}
state.gameObjects = state.gameObjects or {}
state.gameObjectSeq = state.gameObjectSeq or 0
state.gameObjectActive = state.gameObjectActive or {}
state.gameObjectActive = state.gameObjectActive or {}
state.talentSpecs = state.talentSpecs or {}
state.talentSpecSeq = state.talentSpecSeq or 0
state.talentSpecActive = state.talentSpecActive or nil
Expand All @@ -115,6 +115,12 @@ local function ensureBridgeState()
state.inventoryActive = state.inventoryActive or nil
state.spellbookSeq = state.spellbookSeq or 0
state.spellbookActive = state.spellbookActive or nil
state.botSkills = state.botSkills or {}
state.botSkillSeq = state.botSkillSeq or 0
state.botSkillActive = state.botSkillActive or nil
state.professionRecipes = state.professionRecipes or {}
state.professionRecipeSeq = state.professionRecipeSeq or 0
state.professionRecipeActive = state.professionRecipeActive or nil
state.outfitSeq = state.outfitSeq or 0
state.outfitActive = state.outfitActive or nil
state.outfitCommands = state.outfitCommands or {}
Expand Down Expand Up @@ -564,6 +570,58 @@ function Comm.RequestSpellbook(name)
return true
end

function Comm.RequestBotSkills(name)
local state = ensureBridgeState()
name = trim(name)
if name == "" or not state.connected then
return false
end

state.botSkillSeq = (tonumber(state.botSkillSeq) or 0) + 1
local token = tostring(math.floor(safeNow() * 1000)) .. "-" .. tostring(state.botSkillSeq)
state.botSkillActive = {
botName = name,
botNameKey = string.lower(name),
token = token,
startedAt = safeNow(),
items = {},
}

if not Comm.Send("GET", "BOT_SKILLS~" .. name .. "~" .. token) then
state.botSkillActive = nil
return false
end

return true
end

function Comm.RequestProfessionRecipes(name, skillId)
local state = ensureBridgeState()
name = trim(name)
skillId = tonumber(skillId or 0) or 0
if name == "" or skillId <= 0 or not state.connected then
return false
end

state.professionRecipeSeq = (tonumber(state.professionRecipeSeq) or 0) + 1
local token = tostring(math.floor(safeNow() * 1000)) .. "-" .. tostring(state.professionRecipeSeq)
state.professionRecipeActive = {
botName = name,
botNameKey = string.lower(name),
skillId = skillId,
token = token,
startedAt = safeNow(),
recipes = {},
}

if not Comm.Send("GET", "PROFESSION_RECIPES~" .. name .. "~" .. skillId .. "~" .. token) then
state.professionRecipeActive = nil
return false
end

return true
end

function Comm.MarkDisconnected(reason)
local state = ensureBridgeState()
state.connected = false
Expand All @@ -572,6 +630,8 @@ function Comm.MarkDisconnected(reason)
state.lastError = reason or nil
state.inventoryActive = nil
state.spellbookActive = nil
state.botSkillActive = nil
state.professionRecipeActive = nil
state.outfitActive = nil
state.outfitCommands = {}
end
Expand Down Expand Up @@ -1533,6 +1593,60 @@ local function getSpellbookFrame()
return MultiBot and MultiBot.spellbook or nil
end

local function getActiveBotSkillRequest(botName, token)
local state = ensureBridgeState()
local active = state.botSkillActive
if type(active) ~= "table" then
return nil
end

if botName and botName ~= "" and string.lower(trim(botName)) ~= trim(active.botNameKey or "") then
return nil
end

if token and token ~= "" and tostring(token) ~= tostring(active.token or "") then
return nil
end

return active
end

local function getActiveProfessionRecipeRequest(botName, token, skillId)
local state = ensureBridgeState()
local active = state.professionRecipeActive
if type(active) ~= "table" then
return nil
end

if botName and botName ~= "" and string.lower(trim(botName)) ~= trim(active.botNameKey or "") then
return nil
end

if token and token ~= "" and tostring(token) ~= tostring(active.token or "") then
return nil
end

if skillId and tonumber(skillId or 0) ~= tonumber(active.skillId or 0) then
return nil
end

return active
end

local function parseRecipeMaterials(raw)
local materials = {}
for token in string.gmatch(raw or "", "([^;]+)") do
local itemId, rest = splitOnce(token, ":")
local required, available = splitOnce(rest or "", ":")
table.insert(materials, {
itemId = tonumber(itemId or "0") or 0,
required = tonumber(required or "0") or 0,
available = tonumber(available or "0") or 0,
})
end
return materials
end

function Comm.HandleAddonMessage(prefix, message, distribution, sender)
if prefix ~= Comm.prefix then
return false
Expand Down Expand Up @@ -1913,6 +2027,139 @@ function Comm.HandleAddonMessage(prefix, message, distribution, sender)
return true
end

if opcode == "BOT_SKILLS_BEGIN" then
local botName, token = splitOnce(payload or "", "~")
botName = trim(urlDecodeField(botName))
token = trim(token)
state.connected = true
state.lastError = nil

local active = getActiveBotSkillRequest(botName, token)
if active then
active.items = {}
end

return true
end

if opcode == "BOT_SKILLS_ITEM" then
local botName, rest = splitOnce(payload or "", "~")
local token, rest2 = splitOnce(rest or "", "~")
local category, rest3 = splitOnce(rest2 or "", "~")
local skillId, rest4 = splitOnce(rest3 or "", "~")
local key, rest5 = splitOnce(rest4 or "", "~")
local skillName, rest6 = splitOnce(rest5 or "", "~")
local value, maxValue = splitOnce(rest6 or "", "~")

botName = trim(urlDecodeField(botName))
token = trim(token)
state.connected = true
state.lastError = nil

local active = getActiveBotSkillRequest(botName, token)
if active then
table.insert(active.items, {
category = trim(urlDecodeField(category)),
skillId = tonumber(skillId or "0") or 0,
key = trim(urlDecodeField(key)),
name = trim(urlDecodeField(skillName)),
value = tonumber(value or "0") or 0,
max = tonumber(maxValue or "0") or 0,
})
end

return true
end

if opcode == "BOT_SKILLS_END" then
local botName, token = splitOnce(payload or "", "~")
botName = trim(urlDecodeField(botName))
token = trim(token)
state.connected = true
state.lastError = nil

local active = getActiveBotSkillRequest(botName, token)
if active then
local key = string.lower(botName)
state.botSkills[key] = active.items or {}
if MultiBot.OnBridgeBotSkills then
MultiBot.OnBridgeBotSkills(botName, state.botSkills[key], token)
end
state.botSkillActive = nil
end

return true
end

if opcode == "PROFESSION_RECIPES_BEGIN" then
local botName, rest = splitOnce(payload or "", "~")
local token, skillId = splitOnce(rest or "", "~")
botName = trim(urlDecodeField(botName))
token = trim(token)
skillId = tonumber(skillId or "0") or 0
state.connected = true
state.lastError = nil

local active = getActiveProfessionRecipeRequest(botName, token, skillId)
if active then
active.recipes = {}
end

return true
end

if opcode == "PROFESSION_RECIPES_ITEM" then
local botName, rest = splitOnce(payload or "", "~")
local token, rest2 = splitOnce(rest or "", "~")
local skillId, rest3 = splitOnce(rest2 or "", "~")
local spellId, rest4 = splitOnce(rest3 or "", "~")
local itemId, rest5 = splitOnce(rest4 or "", "~")
local difficulty, rest6 = splitOnce(rest5 or "", "~")
local craftable, materials = splitOnce(rest6 or "", "~")

botName = trim(urlDecodeField(botName))
token = trim(token)
skillId = tonumber(skillId or "0") or 0
state.connected = true
state.lastError = nil

local active = getActiveProfessionRecipeRequest(botName, token, skillId)
if active then
table.insert(active.recipes, {
skillId = skillId,
spellId = tonumber(spellId or "0") or 0,
itemId = tonumber(itemId or "0") or 0,
difficulty = trim(urlDecodeField(difficulty)),
craftable = tonumber(craftable or "0") or 0,
materials = parseRecipeMaterials(urlDecodeField(materials)),
})
end

return true
end

if opcode == "PROFESSION_RECIPES_END" then
local botName, rest = splitOnce(payload or "", "~")
local token, skillId = splitOnce(rest or "", "~")
botName = trim(urlDecodeField(botName))
token = trim(token)
skillId = tonumber(skillId or "0") or 0
state.connected = true
state.lastError = nil

local active = getActiveProfessionRecipeRequest(botName, token, skillId)
if active then
local key = string.lower(botName) .. ":" .. tostring(skillId)
state.professionRecipes[key] = active.recipes or {}
if MultiBot.OnBridgeProfessionRecipes then
MultiBot.OnBridgeProfessionRecipes(botName, skillId, state.professionRecipes[key], token)
end
state.professionRecipeActive = nil
end

return true
end

if opcode == "RTI_ACK" then
state.connected = true
state.lastError = nil
Expand Down Expand Up @@ -2038,6 +2285,10 @@ function Comm.OnPlayerEnteringWorld()
state.talentSpecActive = nil
state.inventoryActive = nil
state.spellbookActive = nil
state.botSkills = {}
state.botSkillActive = nil
state.professionRecipes = {}
state.professionRecipeActive = nil
state.outfitActive = nil
state.outfitCommands = {}
Comm.MarkDisconnected(nil)
Expand Down
6 changes: 6 additions & 0 deletions Core/MultiBotEvery.lua
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,12 @@ MultiBot.addEvery = function(pFrame, pCombat, pNormal)
unitsBtn.doLeft(unitsBtn, "favorites", unitsBtn.filter)
end
end
},
{ "CharacterInfo", "inv_misc_note_05", MultiBot.L("tips.every.characterinfo", "Infos personnage"), function(b)
if MultiBot.OpenCharacterInfo then
MultiBot.OpenCharacterInfo(b.getName())
end
end
},
{ "Maintenance", "Achievement_Halloween_Smiley_01", MultiBot.L("tips.every.maintenance"), function(b)
SendChatMessage("maintenance", "WHISPER", nil, b.getName())
Expand Down
4 changes: 4 additions & 0 deletions Core/MultiBotInit.lua
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ MultiBot.InitializeIconosFrame()

MultiBot.InitializeSpellBookFrame()

if MultiBot.InitializeCharacterInfoFrame then
MultiBot.InitializeCharacterInfoFrame()
end

if MultiBot.InitializeRewardFrame then
MultiBot.InitializeRewardFrame()
end
Expand Down
24 changes: 24 additions & 0 deletions Locales/MultiBotAceLocale-deDE.lua
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,30 @@ local deDEValues = {
["lootmaster.profession.fishing"] = "Angeln",
["lootmaster.profession.firstaid"] = "Erste Hilfe",
["lootmaster.gear_score"] = "GearScore: %d",
["profession.recipes"] = "Rezepte",
["profession.recipes.count"] = "bekannte(r) Rezept(e)",
["character.info"] = "Charakterinformationen",
["character.skills"] = "Fertigkeiten",
["profession.recipes.loading"] = "Wird geladen...",
["character.skills.count"] = "Fertigkeit(en)",
["character.skills.loading"] = "Wird geladen...",
["character.skills.category.class"] = "Klassenfertigkeiten",
["character.skills.category.profession"] = "Berufe",
["character.skills.category.secondary"] = "Sekundäre Berufe",
["character.skills.category.weapon"] = "Waffenfertigkeiten",
["character.skills.category.armor"] = "Rüstungen",
["lootmaster.profession.alchemy"] = "Alchemie",
["lootmaster.profession.blacksmithing"] = "Schmiedekunst",
["lootmaster.profession.enchanting"] = "Verzauberkunst",
["lootmaster.profession.herbalism"] = "Kräuterkunde",
["lootmaster.profession.inscription"] = "Inschriftenkunde",
["lootmaster.profession.leatherworking"] = "Lederverarbeitung",
["lootmaster.profession.mining"] = "Bergbau",
["lootmaster.profession.skinning"] = "Kürschnerei",
["lootmaster.profession.tailoring"] = "Schneiderei",
["character.skills.skill.arms"] = "Waffen",
["character.skills.skill.fury"] = "Furor",
["character.skills.skill.protection"] = "Schutz",
["tips.units.rti"] = "RTI",
["tips.disperse.main"] = "Disperse",
["tips.disperse.set"] = "Disperse-Distanz setzen",
Expand Down
24 changes: 24 additions & 0 deletions Locales/MultiBotAceLocale-enGB.lua
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,30 @@ local enGBValues = {
["lootmaster.profession.fishing"] = "Fishing",
["lootmaster.profession.firstaid"] = "First Aid",
["lootmaster.gear_score"] = "GearScore: %d",
["profession.recipes"] = "Recipes",
["profession.recipes.count"] = "known recipe(s)",
["character.info"] = "Character Info",
["character.skills"] = "Skills",
["profession.recipes.loading"] = "Loading...",
["character.skills.count"] = "skill(s)",
["character.skills.loading"] = "Loading...",
["character.skills.category.class"] = "Class Skills",
["character.skills.category.profession"] = "Professions",
["character.skills.category.secondary"] = "Secondary Professions",
["character.skills.category.weapon"] = "Weapon Skills",
["character.skills.category.armor"] = "Armor",
["lootmaster.profession.alchemy"] = "Alchemy",
["lootmaster.profession.blacksmithing"] = "Blacksmithing",
["lootmaster.profession.enchanting"] = "Enchanting",
["lootmaster.profession.herbalism"] = "Herbalism",
["lootmaster.profession.inscription"] = "Inscription",
["lootmaster.profession.leatherworking"] = "Leatherworking",
["lootmaster.profession.mining"] = "Mining",
["lootmaster.profession.skinning"] = "Skinning",
["lootmaster.profession.tailoring"] = "Tailoring",
["character.skills.skill.arms"] = "Arms",
["character.skills.skill.fury"] = "Fury",
["character.skills.skill.protection"] = "Protection",
["tips.units.rti"] = "RTI",
["tips.disperse.main"] = "Disperse",
["tips.disperse.set"] = "Set disperse distance",
Expand Down
Loading
Loading