873 lines
29 KiB
Lua
873 lines
29 KiB
Lua
--[[
|
|
Name: LibCraftingProfessions-1.0
|
|
Developed by: Refaim (rkharito@yandex.ru, https://github.com/refaim/)
|
|
Website: https://github.com/refaim/LibCraftingProfessions-1.0
|
|
Description: A library designed to provide a universal interface for crafting professions.
|
|
Dependencies: LibStub
|
|
Compatibility: World of Warcraft Vanilla (1.12.1), Turtle (1.18.0)
|
|
]]
|
|
|
|
---@type LibStubDef
|
|
local LibStub = getglobal("LibStub")
|
|
assert(LibStub ~= nil)
|
|
|
|
local untyped_lib, _ = LibStub:NewLibrary("LibCraftingProfessions-1.0", 19)
|
|
if not untyped_lib then
|
|
return
|
|
end
|
|
|
|
---@class LibCraftingProfessions
|
|
---@field event_to_handlers table<string, function[]>
|
|
---@field event_frame Frame
|
|
|
|
local lib = --[[---@type LibCraftingProfessions]] untyped_lib
|
|
if lib.event_to_handlers == nil then
|
|
lib.event_to_handlers = {}
|
|
end
|
|
|
|
local IS_TURTLE_WOW = getglobal("TURTLE_WOW_VERSION") ~= nil
|
|
|
|
---@shape LcpProfessionProps
|
|
---@field icon string
|
|
|
|
---@type table<string, LcpProfessionProps>
|
|
local P = {}
|
|
P["Alchemy"] = {icon = [[Interface\Icons\trade_alchemy]]}
|
|
P["Blacksmithing"] = {icon = [[Interface\Icons\trade_blacksmithing]]}
|
|
P["Cooking"] = {icon = [[Interface\Icons\inv_misc_food_15]]}
|
|
P["Enchanting"] = {icon = [[Interface\Icons\trade_engraving]]}
|
|
P["Engineering"] = {icon = [[Interface\Icons\trade_engineering]]}
|
|
P["First Aid"] = {icon = [[Interface\Icons\spell_holy_sealofsacrifice]]}
|
|
P["Leatherworking"] = {icon = [[Interface\Icons\inv_misc_armorkit_17]]}
|
|
P["Mining"] = {icon = [[Interface\Icons\spell_fire_flameblades]]}
|
|
P["Poisons"] = {icon = [[Interface\Icons\trade_brewpoison]]}
|
|
P["Tailoring"] = {icon = [[Interface\Icons\trade_tailoring]]}
|
|
if IS_TURTLE_WOW then
|
|
P["Jewelcrafting"] = {icon = [[Interface\Icons\inv_helmet_44]]}
|
|
P["Survival"] = {icon = [[Interface\Icons\INV_Misc_Rope_01]]}
|
|
end
|
|
local PROFESSION_TO_PROPS = P
|
|
P = {}
|
|
|
|
---@type table<string, string>
|
|
local ENGLISH_TO_LOCALIZED = {}
|
|
---@type table<string, string>
|
|
local LOCALIZED_TO_ENGLISH = {}
|
|
|
|
---@shape LcpProfession
|
|
---@field english_name string
|
|
---@field localized_name string
|
|
---@field icon_texture_path string
|
|
|
|
---@shape LcpKnownProfession: LcpProfession
|
|
---@field cur_rank number
|
|
|
|
---@alias LcpProfessionFrameType "VanillaCraftFrame" | "VanillaTradeSkillFrame" | "TurtleTradeSkillFrame" | "Artisan" | "AdvancedTradeSkillWindow" | "AdvancedTradeSkillWindow2"
|
|
|
|
---@type {FrameType: table<LcpProfessionFrameType, LcpProfessionFrameType>}
|
|
LibCraftingProfessionsConstants = {
|
|
FrameType = {
|
|
VanillaCraftFrame = "VanillaCraftFrame",
|
|
VanillaTradeSkillFrame = "VanillaTradeSkillFrame",
|
|
TurtleTradeSkillFrame = "TurtleTradeSkillFrame",
|
|
Artisan = "Artisan",
|
|
AdvancedTradeSkillWindow = "AdvancedTradeSkillWindow",
|
|
AdvancedTradeSkillWindow2 = "AdvancedTradeSkillWindow2",
|
|
}
|
|
}
|
|
local FrameType = LibCraftingProfessionsConstants.FrameType
|
|
|
|
---@shape LcpProfessionFrame
|
|
---@field frame Frame
|
|
---@field type LcpProfessionFrameType
|
|
|
|
---@alias LcpSkillDifficulty "trivial" | "easy" | "medium" | "optimal" | "difficult"
|
|
|
|
---@shape LcpKnownSkill
|
|
---@field localized_name string
|
|
---@field item_link string
|
|
---@field difficulty LcpSkillDifficulty
|
|
---@field num_available number
|
|
|
|
---@alias LcpScanSkillsHandler fun(profession: LcpKnownProfession, skills: LcpKnownSkill[]):void
|
|
|
|
---@type table<string, LcpKnownSkill[]>
|
|
local skills_by_english_profession_name = {}
|
|
|
|
---@return boolean
|
|
local function ready(value)
|
|
if value == nil then
|
|
return false
|
|
end
|
|
if type(value) == "table" then
|
|
return next(value) ~= nil
|
|
end
|
|
return value ~= "" and value ~= 0
|
|
end
|
|
|
|
---
|
|
--- Retrieves a list of all supported crafting professions in the game.
|
|
---
|
|
---@return LcpProfession[]
|
|
function lib:GetSupportedProfessions()
|
|
---@type LcpProfession[]
|
|
local professions = {}
|
|
for english_name, props in pairs(PROFESSION_TO_PROPS) do
|
|
tinsert(professions, {
|
|
english_name = english_name,
|
|
localized_name = ENGLISH_TO_LOCALIZED[english_name],
|
|
icon_texture_path = props.icon,
|
|
})
|
|
end
|
|
return professions
|
|
end
|
|
|
|
---
|
|
--- Retrieves a list of the player's known crafting professions.
|
|
--- Returns a table of known professions, or nil if game data is not yet available.
|
|
--- Use RegisterEvent("LCP_SKILLS_UPDATE", ...) to ensure data availability.
|
|
---
|
|
---@return LcpKnownProfession[]|nil
|
|
function lib:GetPlayerProfessions()
|
|
local num_of_professions = GetNumSkillLines()
|
|
if not ready(num_of_professions) then
|
|
return nil
|
|
end
|
|
|
|
---@type LcpKnownProfession[]
|
|
local professions = {}
|
|
for i = 1, num_of_professions do
|
|
local localized_name, is_header, _, rank, _, _, _, _, _, _, _, _, _ = GetSkillLineInfo(i)
|
|
if not is_header then
|
|
if not ready(localized_name) then
|
|
return nil
|
|
end
|
|
|
|
local english_name = LOCALIZED_TO_ENGLISH[localized_name]
|
|
local crafting_props = PROFESSION_TO_PROPS[english_name]
|
|
if crafting_props ~= nil then
|
|
if not ready(rank) then
|
|
return nil
|
|
end
|
|
tinsert(professions, {
|
|
english_name = english_name,
|
|
localized_name = localized_name,
|
|
icon_texture_path = crafting_props.icon,
|
|
cur_rank = rank,
|
|
})
|
|
end
|
|
end
|
|
end
|
|
|
|
return professions
|
|
end
|
|
|
|
---
|
|
--- Retrieves a list of the player's skills for a specific profession.
|
|
--- Returns a table of known skills for the specified profession, or nil if game data is not yet available
|
|
--- Use RegisterEvent("LCP_SKILLS_UPDATE", ...) to ensure data availability.
|
|
---
|
|
--- @param profession_name string
|
|
--- @return LcpKnownSkill[]|nil
|
|
function lib:GetPlayerProfessionSkills(profession_name)
|
|
return skills_by_english_profession_name[profession_name] or skills_by_english_profession_name[LOCALIZED_TO_ENGLISH[profession_name]]
|
|
end
|
|
|
|
---
|
|
--- Registers a handler for the specific library event.
|
|
--- LCP_SKILLS_UPDATE is fired when skill data is updated and ready for retrieval.
|
|
--- LCP_FRAME_SHOW is fired when a crafting profession frame is shown.
|
|
--- LCP_FRAME_CLOSE is fired when a crafting profession frame is closed.
|
|
---@param event string
|
|
---@param handler function
|
|
---@overload fun(event: "LCP_SKILLS_UPDATE", handler: fun(profession: LcpKnownProfession, skills: LcpKnownSkill[]):void)
|
|
---@overload fun(event: "LCP_FRAME_SHOW", handler: fun(profession: LcpKnownProfession, frame: Frame, frame_type: LcpProfessionFrameType):void)
|
|
---@overload fun(event: "LCP_FRAME_CLOSE", handler: fun(frame: Frame, frame_type: LcpProfessionFrameType):void)
|
|
function lib:RegisterEvent(event, handler)
|
|
if lib.event_to_handlers[event] == nil then
|
|
lib.event_to_handlers[event] = {}
|
|
end
|
|
tinsert(lib.event_to_handlers[event], --[[---@type function]] handler)
|
|
end
|
|
|
|
---@shape _LcpFilterOption
|
|
---@field name string
|
|
---@field type string
|
|
|
|
---@shape _LcpProfessionAdapter
|
|
---@field GetProfessionInfo fun():string|nil, string|nil, number|nil, number|nil
|
|
---@field GetNumSkills fun():number|nil
|
|
---@field GetSkillInfo fun(index:number):string|nil, string|nil, number|nil, wowboolean
|
|
---@field GetSkillItemLink fun(index:number):string|nil
|
|
---@field ExpandHeader fun(index:number):void
|
|
---@field CollapseHeader fun(index:number):void
|
|
---@field DisableFilters fun():_LcpFilterOption[]
|
|
---@field EnableFilters fun(options:_LcpFilterOption[]):void
|
|
|
|
---@param adapter _LcpProfessionAdapter
|
|
---@return LcpKnownSkill[]|nil
|
|
local function scan_skills(adapter)
|
|
local localized_profession, english_profession, cur_rank, max_rank = adapter.GetProfessionInfo()
|
|
if not ready(localized_profession) or not ready(english_profession) or not ready(cur_rank) or not ready(max_rank) then
|
|
return nil
|
|
end
|
|
|
|
local disabled_filters = adapter.DisableFilters()
|
|
|
|
local num_of_skills_before_expansion = adapter.GetNumSkills()
|
|
if not ready(num_of_skills_before_expansion) then
|
|
return nil
|
|
end
|
|
|
|
---@type table<string, true>
|
|
local set_of_headers_to_collapse = {}
|
|
for i = 1, num_of_skills_before_expansion do
|
|
local skill_name, skill_type_or_difficulty, _, is_expanded = adapter.GetSkillInfo(i)
|
|
if not ready(skill_name) or not ready(skill_type_or_difficulty) then
|
|
return nil
|
|
end
|
|
if skill_type_or_difficulty == "header" and is_expanded == nil then
|
|
set_of_headers_to_collapse[ --[[---@not nil]] skill_name] = true
|
|
end
|
|
end
|
|
adapter.ExpandHeader(0)
|
|
|
|
local num_of_skills_after_expansion = adapter.GetNumSkills()
|
|
if not ready(num_of_skills_after_expansion) then
|
|
return nil
|
|
end
|
|
|
|
---@type LcpKnownSkill[]
|
|
local skills = {}
|
|
for i = 1, num_of_skills_after_expansion do
|
|
local skill_name, skill_type_or_difficulty, num_available, _ = adapter.GetSkillInfo(i)
|
|
if not ready(skill_name) or not ready(skill_type_or_difficulty) then
|
|
return nil
|
|
end
|
|
if skill_type_or_difficulty ~= "header" then
|
|
local item_link = adapter.GetSkillItemLink(i)
|
|
if num_available == nil or not ready(item_link) then
|
|
return nil
|
|
end
|
|
|
|
---@type LcpKnownSkill
|
|
local skill = {
|
|
localized_name = --[[---@not nil]] skill_name,
|
|
item_link = --[[---@not nil]] item_link,
|
|
difficulty = --[[---@type LcpSkillDifficulty]] skill_type_or_difficulty,
|
|
num_available = --[[---@not nil]] num_available,
|
|
}
|
|
tinsert(skills, skill)
|
|
end
|
|
end
|
|
|
|
for i = adapter.GetNumSkills(), 1, -1 do
|
|
local skill_name, skill_type_or_difficulty, _, _ = adapter.GetSkillInfo(i)
|
|
if skill_type_or_difficulty == "header" and set_of_headers_to_collapse[ --[[---@not nil]] skill_name] ~= nil then
|
|
adapter.CollapseHeader(i)
|
|
end
|
|
end
|
|
|
|
adapter.EnableFilters(disabled_filters)
|
|
|
|
return skills
|
|
end
|
|
|
|
---@param known_professions LcpKnownProfession[]|nil
|
|
local function forget_obsolete_professions(known_professions)
|
|
if known_professions == nil then
|
|
return
|
|
end
|
|
|
|
---@type table<string, boolean>
|
|
local known_profession_names_set = {}
|
|
for _, profession in ipairs(--[[---@not nil]] known_professions) do
|
|
known_profession_names_set[profession.english_name] = true
|
|
end
|
|
|
|
for english_name, _ in pairs(skills_by_english_profession_name) do
|
|
if known_profession_names_set[english_name] == nil then
|
|
skills_by_english_profession_name[english_name] = nil
|
|
end
|
|
end
|
|
end
|
|
|
|
---@param known_professions LcpKnownProfession[]|nil
|
|
---@param name string
|
|
---@return LcpKnownProfession|nil
|
|
local function find_known_profession(known_professions, name)
|
|
local profession
|
|
for _, candidate in ipairs(known_professions or {}) do
|
|
if candidate.localized_name == name or candidate.english_name == name then
|
|
profession = candidate
|
|
break
|
|
end
|
|
end
|
|
return profession
|
|
end
|
|
|
|
---@param english_name string
|
|
---@param skills LcpKnownSkill[]
|
|
local function save_skills(english_name, skills)
|
|
skills_by_english_profession_name[english_name] = skills
|
|
|
|
local known_professions = lib:GetPlayerProfessions()
|
|
forget_obsolete_professions(known_professions)
|
|
|
|
local profession = find_known_profession(known_professions, english_name)
|
|
if profession == nil then
|
|
return
|
|
end
|
|
|
|
for _, handler in ipairs(lib.event_to_handlers["LCP_SKILLS_UPDATE"] or {}) do
|
|
handler(profession, skills)
|
|
end
|
|
end
|
|
|
|
---@shape LcpThirdPartyProfessionFrameAddon
|
|
---@field name string
|
|
---@field frame_name string
|
|
---@field opens_and_closes_vanilla_profession_frames boolean
|
|
|
|
---@type LcpThirdPartyProfessionFrameAddon
|
|
local artisan = {name = "Artisan", frame_name = "ArtisanFrame", opens_and_closes_vanilla_profession_frames = true}
|
|
---@type LcpThirdPartyProfessionFrameAddon
|
|
local atsw = {name = "AdvancedTradeSkillWindow", frame_name = "ATSWFrame", opens_and_closes_vanilla_profession_frames = false}
|
|
---@type LcpThirdPartyProfessionFrameAddon
|
|
local atsw2 = {name = "AdvancedTradeSkillWindow2", frame_name = "ATSWFrame", opens_and_closes_vanilla_profession_frames = true}
|
|
|
|
local SUPPORTED_THIRD_PARTY_ADDONS = {artisan, atsw, atsw2}
|
|
|
|
---@param addon LcpThirdPartyProfessionFrameAddon
|
|
local function is_third_party_loaded(addon)
|
|
return IsAddOnLoaded(addon.name) == 1 and getglobal(addon.frame_name) ~= nil
|
|
end
|
|
|
|
---@return LcpProfessionFrame
|
|
local function detect_profession_frame(professionFrame)
|
|
---@type Frame
|
|
local atsw1_or_atsw2_frame = getglobal(atsw2.frame_name)
|
|
if atsw1_or_atsw2_frame ~= nil then
|
|
---@type LcpProfessionFrameType
|
|
local frame_type = FrameType.AdvancedTradeSkillWindow
|
|
if is_third_party_loaded(atsw2) then
|
|
frame_type = FrameType.AdvancedTradeSkillWindow2
|
|
end
|
|
return {frame = atsw1_or_atsw2_frame, type = frame_type}
|
|
end
|
|
|
|
if is_third_party_loaded(artisan) then
|
|
return {frame = getglobal(artisan.frame_name), type = FrameType.Artisan}
|
|
end
|
|
|
|
if professionFrame == TradeSkillFrame then
|
|
local frame_type = IS_TURTLE_WOW and FrameType.TurtleTradeSkillFrame or FrameType.VanillaTradeSkillFrame
|
|
return {frame = professionFrame, type = frame_type}
|
|
end
|
|
|
|
return {frame = professionFrame, type = FrameType.VanillaCraftFrame}
|
|
end
|
|
|
|
---@param english_name string
|
|
---@param localized_name string
|
|
---@param cur_rank number
|
|
---@param frame Frame
|
|
local function send_frame_show_event(english_name, localized_name, cur_rank, frame)
|
|
local profession = {
|
|
english_name = english_name,
|
|
localized_name = localized_name,
|
|
cur_rank = cur_rank,
|
|
}
|
|
local real_frame = detect_profession_frame(frame)
|
|
for _, handler in ipairs(lib.event_to_handlers["LCP_FRAME_SHOW"] or {}) do
|
|
handler(profession, real_frame.frame, real_frame.type)
|
|
end
|
|
end
|
|
|
|
---@param frame Frame
|
|
local function send_frame_close_event(frame)
|
|
local real_frame = detect_profession_frame(frame)
|
|
for _, handler in ipairs(lib.event_to_handlers["LCP_FRAME_CLOSE"] or {}) do
|
|
handler(real_frame.frame, real_frame.type)
|
|
end
|
|
end
|
|
|
|
---@return CraftFrame
|
|
local function get_craft_frame()
|
|
if CraftFrame == nil then
|
|
LoadAddOn("Blizzard_CraftUI")
|
|
end
|
|
return CraftFrame
|
|
end
|
|
|
|
---@type _LcpProfessionAdapter
|
|
local craft_adapter = {
|
|
GetProfessionInfo = function()
|
|
local name, cur_rank, max_rank = GetCraftDisplaySkillLine()
|
|
if name == nil then -- GetCraftDisplaySkillLine() returns nil for the "Beast Training" frame
|
|
name = GetCraftName()
|
|
end
|
|
return name, LOCALIZED_TO_ENGLISH[--[[---@type string]] name], cur_rank, max_rank
|
|
end,
|
|
GetNumSkills = GetNumCrafts,
|
|
GetSkillInfo = function(i)
|
|
local name, _, type, num_available, is_expanded = GetCraftInfo(i)
|
|
return name, type, num_available, is_expanded
|
|
end,
|
|
GetSkillItemLink = GetCraftItemLink,
|
|
ExpandHeader = ExpandCraftSkillLine,
|
|
CollapseHeader = CollapseCraftSkillLine,
|
|
DisableFilters = function() return {} end,
|
|
EnableFilters = function(options) end,
|
|
}
|
|
|
|
local function try_send_craft_frame_show_event()
|
|
local localized_name, english_name, cur_rank, _ = craft_adapter.GetProfessionInfo()
|
|
if not ready(localized_name) or not ready(english_name) or not ready(cur_rank) then
|
|
return
|
|
end
|
|
send_frame_show_event(--[[---@not nil]] english_name, --[[---@not nil]] localized_name, --[[---@not nil]] cur_rank, get_craft_frame())
|
|
end
|
|
|
|
local craft_scan_in_progress = false
|
|
|
|
local function scan_craft_frame()
|
|
craft_scan_in_progress = true
|
|
|
|
local localized_name, english_name, _, _ = craft_adapter.GetProfessionInfo()
|
|
if not ready(localized_name) or not ready(english_name) then
|
|
craft_scan_in_progress = false
|
|
return
|
|
end
|
|
|
|
local skills = scan_skills(craft_adapter)
|
|
if not ready(skills) then
|
|
craft_scan_in_progress = false
|
|
return
|
|
end
|
|
|
|
save_skills(--[[---@not nil]] english_name, --[[---@not nil]] skills)
|
|
craft_scan_in_progress = false
|
|
end
|
|
|
|
---@shape _LcpSkillFilterAdapter
|
|
---@field GetType fun(): "inv_slot" | "subclass"
|
|
---@field GetOptions fun(): string...
|
|
---@field GetOptionState fun(index:number): wowboolean
|
|
---@field SetOptionState fun(index:number, enable:wowboolean, exclusive:wowboolean): void
|
|
|
|
---@param adapter _LcpSkillFilterAdapter
|
|
---@return _LcpFilterOption[]
|
|
local function disable_trade_skill_filters(adapter)
|
|
if adapter.GetOptionState(0) == 1 then
|
|
return {}
|
|
end
|
|
|
|
---@type _LcpFilterOption[]
|
|
local selected_options = {}
|
|
for i, option in ipairs({adapter.GetOptions()}) do
|
|
if adapter.GetOptionState(i) == 1 then
|
|
tinsert(selected_options, {name = option, type = adapter.GetType()})
|
|
end
|
|
end
|
|
|
|
adapter.SetOptionState(0, 1, 1)
|
|
|
|
return selected_options
|
|
end
|
|
|
|
---@param adapter _LcpSkillFilterAdapter
|
|
---@param options _LcpFilterOption[]
|
|
local function enable_trade_skill_filters(adapter, options)
|
|
---@type table<string, boolean>
|
|
local options_set = {}
|
|
for _, option in ipairs(options) do
|
|
if option.type == adapter.GetType() then
|
|
options_set[option.name] = true
|
|
end
|
|
end
|
|
|
|
for i, option in ipairs({adapter.GetOptions()}) do
|
|
if options_set[option] then
|
|
adapter.SetOptionState(i, 1, 1)
|
|
end
|
|
end
|
|
end
|
|
|
|
local function get_trade_skill_frame()
|
|
if TradeSkillFrame == nil then
|
|
LoadAddOn("Blizzard_TradeSkillUI")
|
|
end
|
|
return TradeSkillFrame
|
|
end
|
|
|
|
---@type _LcpSkillFilterAdapter
|
|
local inv_slot_filter_adapter = {
|
|
GetType = function() return "inv_slot" end,
|
|
GetOptions = GetTradeSkillInvSlots,
|
|
GetOptionState = GetTradeSkillInvSlotFilter,
|
|
SetOptionState = SetTradeSkillInvSlotFilter,
|
|
}
|
|
|
|
---@type _LcpSkillFilterAdapter
|
|
local subclass_filter_adapter = {
|
|
GetType = function() return "subclass" end,
|
|
GetOptions = GetTradeSkillSubClasses,
|
|
GetOptionState = GetTradeSkillSubClassFilter,
|
|
SetOptionState = SetTradeSkillSubClassFilter,
|
|
}
|
|
|
|
---@type _LcpProfessionAdapter
|
|
local trade_skill_adapter = {
|
|
GetProfessionInfo = function()
|
|
local name, cur_rank, max_rank = GetTradeSkillLine()
|
|
return name, LOCALIZED_TO_ENGLISH[--[[---@type string]] name], cur_rank, max_rank
|
|
end,
|
|
GetNumSkills = GetNumTradeSkills,
|
|
GetSkillInfo = GetTradeSkillInfo,
|
|
GetSkillItemLink = GetTradeSkillItemLink,
|
|
ExpandHeader = ExpandTradeSkillSubClass,
|
|
CollapseHeader = CollapseTradeSkillSubClass,
|
|
DisableFilters = function()
|
|
local result = {}
|
|
for _, adapter in ipairs({inv_slot_filter_adapter, subclass_filter_adapter}) do
|
|
for _, option in ipairs(disable_trade_skill_filters(adapter)) do
|
|
tinsert(result, option)
|
|
end
|
|
end
|
|
return result
|
|
end,
|
|
EnableFilters = function(options)
|
|
for _, adapter in ipairs({inv_slot_filter_adapter, subclass_filter_adapter}) do
|
|
enable_trade_skill_filters(adapter, options)
|
|
end
|
|
end,
|
|
}
|
|
|
|
local function try_send_trade_skill_frame_show_event()
|
|
local localized_name, english_name, cur_rank, _ = trade_skill_adapter.GetProfessionInfo()
|
|
if not ready(localized_name) or not ready(english_name) or not ready(cur_rank) then
|
|
return false
|
|
end
|
|
send_frame_show_event(--[[---@not nil]] english_name, --[[---@not nil]] localized_name, --[[---@not nil]] cur_rank, get_trade_skill_frame())
|
|
end
|
|
|
|
local trade_skill_scan_in_progress = false
|
|
|
|
---@return boolean
|
|
local function scan_trade_skill_frame()
|
|
trade_skill_scan_in_progress = true
|
|
|
|
local localized_name, english_name, _, _ = trade_skill_adapter.GetProfessionInfo()
|
|
if not ready(localized_name) or not ready(english_name) then
|
|
trade_skill_scan_in_progress = false
|
|
return false
|
|
end
|
|
|
|
local skills = scan_skills(trade_skill_adapter)
|
|
if not ready(skills) then
|
|
trade_skill_scan_in_progress = false
|
|
return false
|
|
end
|
|
|
|
save_skills(--[[---@not nil]] english_name, --[[---@not nil]] skills)
|
|
|
|
trade_skill_scan_in_progress = false
|
|
return true
|
|
end
|
|
|
|
local L = ENGLISH_TO_LOCALIZED
|
|
|
|
local game_locale = GetLocale()
|
|
if game_locale == "enUS" or game_locale == "enGB" then
|
|
L["Alchemy"] = "Alchemy"
|
|
L["Blacksmithing"] = "Blacksmithing"
|
|
L["Cooking"] = "Cooking"
|
|
L["Enchanting"] = "Enchanting"
|
|
L["Engineering"] = "Engineering"
|
|
L["First Aid"] = "First Aid"
|
|
L["Leatherworking"] = "Leatherworking"
|
|
L["Mining"] = "Mining"
|
|
L["Poisons"] = "Poisons"
|
|
L["Tailoring"] = "Tailoring"
|
|
if IS_TURTLE_WOW then
|
|
L["Jewelcrafting"] = "Jewelcrafting"
|
|
L["Survival"] = "Survival"
|
|
end
|
|
elseif game_locale == "deDE" then
|
|
L["Alchemy"] = "Alchimie"
|
|
L["Blacksmithing"] = "Schmiedekunst"
|
|
L["Cooking"] = "Kochkunst"
|
|
L["Enchanting"] = "Verzauberkunst"
|
|
L["Engineering"] = "Ingenieurskunst"
|
|
L["First Aid"] = "Erste Hilfe"
|
|
L["Leatherworking"] = "Lederverarbeitung"
|
|
L["Mining"] = "Bergbau"
|
|
L["Poisons"] = "Gifte"
|
|
L["Tailoring"] = "Schneiderei"
|
|
if IS_TURTLE_WOW then
|
|
L["Jewelcrafting"] = "Juwelenschleifen"
|
|
L["Survival"] = "Survival"
|
|
end
|
|
elseif game_locale == "esES" then
|
|
L["Alchemy"] = "Alquimia"
|
|
L["Blacksmithing"] = "Herrería"
|
|
L["Cooking"] = "Cocina"
|
|
L["Enchanting"] = "Encantamiento"
|
|
L["Engineering"] = "Ingeniería"
|
|
L["First Aid"] = "Primeros auxilios"
|
|
L["Leatherworking"] = "Peletería"
|
|
L["Mining"] = "Minería"
|
|
L["Poisons"] = "Venenos"
|
|
L["Tailoring"] = "Sastrería"
|
|
if IS_TURTLE_WOW then
|
|
L["Blacksmithing"] = "Ferraria"
|
|
L["Cooking"] = "Culinária"
|
|
L["Enchanting"] = "Encantamento"
|
|
L["Engineering"] = "Engenharia"
|
|
L["First Aid"] = "Primeiros Socorros"
|
|
L["Jewelcrafting"] = "Joalheria"
|
|
L["Survival"] = "Survival"
|
|
L["Leatherworking"] = "Couraria"
|
|
L["Mining"] = "Mineração"
|
|
L["Tailoring"] = "Alfaiataria"
|
|
end
|
|
elseif game_locale == "esMX" then
|
|
L["Alchemy"] = "Alquimia"
|
|
L["Blacksmithing"] = "Herrería"
|
|
L["Cooking"] = "Cocina"
|
|
L["Enchanting"] = "Encantamiento"
|
|
L["Engineering"] = "Ingeniería"
|
|
L["First Aid"] = "Primeros auxilios"
|
|
L["Leatherworking"] = "Peletería"
|
|
L["Mining"] = "Minería"
|
|
L["Poisons"] = "Venenos"
|
|
L["Tailoring"] = "Sastrería"
|
|
if IS_TURTLE_WOW then
|
|
L["Jewelcrafting"] = "Joyería"
|
|
L["Survival"] = "Survival"
|
|
end
|
|
elseif game_locale == "frFR" then
|
|
L["Alchemy"] = "Alchimie"
|
|
L["Blacksmithing"] = "Forge"
|
|
L["Cooking"] = "Cuisine"
|
|
L["Enchanting"] = "Enchantement"
|
|
L["Engineering"] = "Ingénieur"
|
|
L["First Aid"] = "Premiers soins"
|
|
L["Leatherworking"] = "Travail du cuir"
|
|
L["Mining"] = "Minage"
|
|
L["Poisons"] = "Poisons"
|
|
L["Tailoring"] = "Couture"
|
|
if IS_TURTLE_WOW then
|
|
L["Jewelcrafting"] = "Joaillerie"
|
|
L["Survival"] = "Survival"
|
|
end
|
|
elseif game_locale == "koKR" then
|
|
L["Alchemy"] = "연금술"
|
|
L["Blacksmithing"] = "대장기술"
|
|
L["Cooking"] = "요리"
|
|
L["Enchanting"] = "마법부여"
|
|
L["Engineering"] = "기계공학"
|
|
L["First Aid"] = "응급치료"
|
|
L["Leatherworking"] = "가죽세공"
|
|
L["Mining"] = "채광"
|
|
L["Poisons"] = "독 조제"
|
|
L["Tailoring"] = "재봉술"
|
|
if IS_TURTLE_WOW then
|
|
L["Jewelcrafting"] = "보석세공"
|
|
L["Survival"] = "Survival"
|
|
end
|
|
elseif game_locale == "ptBR" then
|
|
L["Alchemy"] = "Alquimia"
|
|
L["Blacksmithing"] = "Ferraria"
|
|
L["Cooking"] = "Culinária"
|
|
L["Enchanting"] = "Encantamento"
|
|
L["Engineering"] = "Engenharia"
|
|
L["First Aid"] = "Primeiros Socorros"
|
|
L["Leatherworking"] = "Couraria"
|
|
L["Mining"] = "Mineração"
|
|
L["Poisons"] = "Venenos"
|
|
L["Tailoring"] = "Alfaiataria"
|
|
if IS_TURTLE_WOW then
|
|
L["Jewelcrafting"] = "Joalheria"
|
|
L["Survival"] = "Survival"
|
|
end
|
|
elseif game_locale == "ruRU" then
|
|
L["Alchemy"] = "Алхимия"
|
|
L["Blacksmithing"] = "Кузнечное дело"
|
|
L["Cooking"] = "Кулинария"
|
|
L["Enchanting"] = "Наложение чар"
|
|
L["Engineering"] = "Инженерное дело"
|
|
L["First Aid"] = "Первая помощь"
|
|
L["Leatherworking"] = "Кожевничество"
|
|
L["Mining"] = "Горное дело"
|
|
L["Poisons"] = "Яды"
|
|
L["Tailoring"] = "Портняжное дело"
|
|
if IS_TURTLE_WOW then
|
|
L["Jewelcrafting"] = "Ювелирное дело"
|
|
L["Survival"] = "Survival"
|
|
end
|
|
elseif game_locale == "zhCN" then
|
|
L["Alchemy"] = "炼金术"
|
|
L["Blacksmithing"] = "锻造"
|
|
L["Cooking"] = "烹饪"
|
|
L["Enchanting"] = "附魔"
|
|
L["Engineering"] = "工程学"
|
|
L["First Aid"] = "急救"
|
|
L["Leatherworking"] = "制皮"
|
|
L["Mining"] = "采矿"
|
|
L["Poisons"] = "毒药"
|
|
L["Tailoring"] = "裁缝"
|
|
if IS_TURTLE_WOW then
|
|
L["Jewelcrafting"] = "珠宝加工"
|
|
L["Survival"] = "Survival"
|
|
end
|
|
elseif game_locale == "zhTW" then
|
|
L["Alchemy"] = "煉金術"
|
|
L["Blacksmithing"] = "鍛造"
|
|
L["Cooking"] = "烹飪"
|
|
L["Enchanting"] = "附魔"
|
|
L["Engineering"] = "工程學"
|
|
L["First Aid"] = "急救"
|
|
L["Leatherworking"] = "製皮"
|
|
L["Mining"] = "採礦"
|
|
L["Poisons"] = "毒藥"
|
|
L["Tailoring"] = "裁縫"
|
|
if IS_TURTLE_WOW then
|
|
L["Jewelcrafting"] = "珠寶設計"
|
|
L["Survival"] = "Survival"
|
|
end
|
|
end
|
|
|
|
for english_name, localized_name in pairs(ENGLISH_TO_LOCALIZED) do
|
|
LOCALIZED_TO_ENGLISH[localized_name] = english_name
|
|
end
|
|
|
|
---@param frame Frame
|
|
---@return table
|
|
local function as_table(frame)
|
|
return --[[---@type table]] frame
|
|
end
|
|
|
|
local was_third_party_on_hide_hooked = false
|
|
|
|
---@param addon LcpThirdPartyProfessionFrameAddon
|
|
local function hook_third_party_on_hide(addon)
|
|
if not is_third_party_loaded(addon) then
|
|
return
|
|
end
|
|
|
|
---@type Frame
|
|
local frame = getglobal(addon.frame_name)
|
|
if frame == nil then
|
|
return
|
|
end
|
|
if as_table(frame).is_hooked_by_lcp == true then
|
|
was_third_party_on_hide_hooked = true
|
|
return
|
|
end
|
|
|
|
local on_hide = frame:GetScript("OnHide")
|
|
frame:SetScript("OnHide", function()
|
|
if on_hide ~= nil then
|
|
(--[[---@not nil]] on_hide)()
|
|
end
|
|
send_frame_close_event(frame)
|
|
end)
|
|
|
|
as_table(frame).is_hooked_by_lcp = true
|
|
was_third_party_on_hide_hooked = true
|
|
end
|
|
|
|
if lib.event_frame ~= nil then
|
|
lib.event_frame:UnregisterAllEvents()
|
|
lib.event_frame:SetScript("OnUpdate", nil)
|
|
lib.event_frame:SetScript("OnEvent", nil)
|
|
end
|
|
|
|
local render_pseudo_time = 0
|
|
local craft_frame_successfully_scanned_at = 0
|
|
local trade_skill_frame_successfully_scanned_at = 0
|
|
|
|
lib.event_frame = CreateFrame("Frame")
|
|
|
|
lib.event_frame:SetScript("OnUpdate", function ()
|
|
-- Third-party addons can trigger multiple UPDATE events
|
|
-- so we count rendered frames to not scan skills more than once per frame
|
|
render_pseudo_time = render_pseudo_time + 1
|
|
if render_pseudo_time >= 100 then
|
|
render_pseudo_time = 1
|
|
end
|
|
end)
|
|
|
|
lib.event_frame:SetScript("OnEvent", function()
|
|
local do_craft_scan = false
|
|
local do_trade_skill_scan = false
|
|
|
|
if event == "ADDON_LOADED" then
|
|
for _, addon in ipairs(SUPPORTED_THIRD_PARTY_ADDONS) do
|
|
if addon.name == arg1 and addon.opens_and_closes_vanilla_profession_frames then
|
|
hook_third_party_on_hide(addon)
|
|
end
|
|
end
|
|
elseif event == "CRAFT_SHOW" then
|
|
try_send_craft_frame_show_event()
|
|
do_craft_scan = true
|
|
elseif event == "CRAFT_UPDATE" then
|
|
if not craft_scan_in_progress then
|
|
-- Learned new skill AND craft frame is opened
|
|
do_craft_scan = true
|
|
end
|
|
elseif event == "CRAFT_CLOSE" then
|
|
if not was_third_party_on_hide_hooked then
|
|
send_frame_close_event(get_craft_frame())
|
|
end
|
|
elseif event == "TRADE_SKILL_SHOW" then
|
|
try_send_trade_skill_frame_show_event()
|
|
do_trade_skill_scan = true
|
|
elseif event == "TRADE_SKILL_UPDATE" then
|
|
if not trade_skill_scan_in_progress then
|
|
-- Learned new skill AND trade skill frame is opened
|
|
do_trade_skill_scan = true
|
|
end
|
|
elseif event == "TRADE_SKILL_CLOSE" then
|
|
if not was_third_party_on_hide_hooked then
|
|
send_frame_close_event(get_trade_skill_frame())
|
|
end
|
|
elseif event == "CHARACTER_POINTS_CHANGED" then
|
|
-- Learned or unlearned profession/specialization
|
|
forget_obsolete_professions(lib:GetPlayerProfessions())
|
|
elseif event == "SKILL_LINES_CHANGED" then
|
|
-- Raised the profession skill level OR learned/unlearned profession/specialization
|
|
do_craft_scan = true
|
|
do_trade_skill_scan = true
|
|
end
|
|
|
|
if do_craft_scan and craft_frame_successfully_scanned_at ~= render_pseudo_time then
|
|
if scan_craft_frame() then
|
|
craft_frame_successfully_scanned_at = render_pseudo_time
|
|
end
|
|
end
|
|
|
|
if do_trade_skill_scan and trade_skill_frame_successfully_scanned_at ~= render_pseudo_time then
|
|
if scan_trade_skill_frame() then
|
|
trade_skill_frame_successfully_scanned_at = render_pseudo_time
|
|
end
|
|
end
|
|
end)
|
|
lib.event_frame:RegisterEvent("ADDON_LOADED")
|
|
lib.event_frame:RegisterEvent("CRAFT_SHOW")
|
|
lib.event_frame:RegisterEvent("CRAFT_UPDATE")
|
|
lib.event_frame:RegisterEvent("CRAFT_CLOSE")
|
|
lib.event_frame:RegisterEvent("TRADE_SKILL_SHOW")
|
|
lib.event_frame:RegisterEvent("TRADE_SKILL_UPDATE")
|
|
lib.event_frame:RegisterEvent("TRADE_SKILL_CLOSE")
|
|
lib.event_frame:RegisterEvent("CHARACTER_POINTS_CHANGED")
|
|
lib.event_frame:RegisterEvent("SKILL_LINES_CHANGED")
|
|
|
|
for _, addon in ipairs(SUPPORTED_THIRD_PARTY_ADDONS) do
|
|
if is_third_party_loaded(addon) and addon.opens_and_closes_vanilla_profession_frames then
|
|
hook_third_party_on_hide(addon)
|
|
end
|
|
end
|