|
|
|
|
-- ------------------------------------------------------------------------------ --
|
|
|
|
|
-- TradeSkillMaster --
|
|
|
|
|
-- https://tradeskillmaster.com --
|
|
|
|
|
-- All Rights Reserved - Detailed license information included with addon. --
|
|
|
|
|
-- ------------------------------------------------------------------------------ --
|
|
|
|
|
|
|
|
|
|
local TSM = select(2, ...) ---@type TSM
|
|
|
|
|
local Quality = TSM.Init("Service.ProfessionHelpers.Quality") ---@class Service.ProfessionHelpers.Quality
|
|
|
|
|
local MatString = TSM.Include("Util.MatString")
|
|
|
|
|
local ProfessionInfo = TSM.Include("Data.ProfessionInfo")
|
|
|
|
|
local private = {
|
|
|
|
|
matQualityIterContext = {
|
|
|
|
|
inUse = false,
|
|
|
|
|
isFirst = false,
|
|
|
|
|
result = {},
|
|
|
|
|
qualityMatStrings = {},
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
local NUM_QUALITY_MAT_QUALITIES = 3
|
|
|
|
|
local MAX_QUALITY_MAT_DIFFICULTY_RATIO = 0.25
|
|
|
|
|
local SKILL_PER_TARGET_QUALITY = {
|
|
|
|
|
[3] = {
|
|
|
|
|
0,
|
|
|
|
|
0.5,
|
|
|
|
|
1.0,
|
|
|
|
|
},
|
|
|
|
|
[5] = {
|
|
|
|
|
0,
|
|
|
|
|
0.2,
|
|
|
|
|
0.5,
|
|
|
|
|
0.8,
|
|
|
|
|
1.0,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-- ============================================================================
|
|
|
|
|
-- Module Functions
|
|
|
|
|
-- ============================================================================
|
|
|
|
|
|
|
|
|
|
function Quality.GetNeededSkill(targetQuality, recipeDifficulty, recipeQuality, recipeMaxQuality, hasQualityMats, inspirationAmount)
|
|
|
|
|
if recipeMaxQuality == 1 then
|
|
|
|
|
-- This recipe has quality mats, but doesn't produce a quality item
|
|
|
|
|
return 0, math.huge, 0
|
|
|
|
|
end
|
|
|
|
|
-- Calculate how much skill we need to add in order to craft the target item
|
|
|
|
|
local neededSkill, maxAddedSkill = 0, 0
|
|
|
|
|
local minQuality = floor(recipeQuality)
|
|
|
|
|
local skillPerTargetQuality = SKILL_PER_TARGET_QUALITY[recipeMaxQuality]
|
|
|
|
|
if targetQuality < minQuality then
|
|
|
|
|
-- We can't craft this low of a quality anymore
|
|
|
|
|
return nil, nil
|
|
|
|
|
else
|
|
|
|
|
local currentLowerBound = skillPerTargetQuality[minQuality] * recipeDifficulty
|
|
|
|
|
local currentUpperBound = skillPerTargetQuality[min(ceil(recipeQuality), recipeMaxQuality)] * recipeDifficulty
|
|
|
|
|
local currentQualityRatio = recipeQuality - minQuality
|
|
|
|
|
local currentSkill = currentLowerBound + currentQualityRatio * (currentUpperBound - currentLowerBound)
|
|
|
|
|
local targetLowerBound = skillPerTargetQuality[targetQuality] * recipeDifficulty
|
|
|
|
|
local targetUpperBound = skillPerTargetQuality[min(targetQuality + 1, recipeMaxQuality)] * recipeDifficulty
|
|
|
|
|
neededSkill = max(targetLowerBound - currentSkill, 0)
|
|
|
|
|
maxAddedSkill = targetQuality == recipeMaxQuality and math.huge or (targetUpperBound - currentSkill)
|
|
|
|
|
end
|
|
|
|
|
assert(neededSkill >= 0 and maxAddedSkill > 0)
|
|
|
|
|
local maxQualityMatSkill = hasQualityMats and recipeDifficulty * MAX_QUALITY_MAT_DIFFICULTY_RATIO or 0
|
|
|
|
|
if neededSkill > maxQualityMatSkill + (inspirationAmount or 0) then
|
|
|
|
|
-- We can't get this much skill with just quality reagents and inspiration
|
|
|
|
|
-- TODO: We potentically could with finishing / optional(?) mats
|
|
|
|
|
return nil, nil
|
|
|
|
|
end
|
|
|
|
|
return neededSkill, maxAddedSkill, maxQualityMatSkill
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function Quality.MatCombationIterator(mats)
|
|
|
|
|
local context = private.matQualityIterContext
|
|
|
|
|
assert(not context.inUse)
|
|
|
|
|
context.inUse = true
|
|
|
|
|
context.isFirst = true
|
|
|
|
|
for matString in pairs(mats) do
|
|
|
|
|
if strmatch(matString, "^q:") then
|
|
|
|
|
tinsert(context.qualityMatStrings, matString)
|
|
|
|
|
context.qualityMatStrings[matString] = 1
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
return private.MatCombationIteratorHelper, context
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function Quality.MatQualityItemIterator(qualities)
|
|
|
|
|
return private.MatQualityItemIterator, qualities, nil
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-- ============================================================================
|
|
|
|
|
-- Private Helper Functions
|
|
|
|
|
-- ============================================================================
|
|
|
|
|
|
|
|
|
|
function private.MatCombationIteratorHelper(context)
|
|
|
|
|
if context.isFirst then
|
|
|
|
|
context.isFirst = false
|
|
|
|
|
else
|
|
|
|
|
-- Increment the current value
|
|
|
|
|
local carry = true
|
|
|
|
|
for i = #context.qualityMatStrings, 1, -1 do
|
|
|
|
|
local matString = context.qualityMatStrings[i]
|
|
|
|
|
context.qualityMatStrings[matString] = context.qualityMatStrings[matString] + 1
|
|
|
|
|
if context.qualityMatStrings[matString] > NUM_QUALITY_MAT_QUALITIES then
|
|
|
|
|
context.qualityMatStrings[matString] = 1
|
|
|
|
|
else
|
|
|
|
|
carry = false
|
|
|
|
|
break
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
if carry then
|
|
|
|
|
-- No more values
|
|
|
|
|
wipe(context.result)
|
|
|
|
|
wipe(context.qualityMatStrings)
|
|
|
|
|
context.inUse = false
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
for matString, quality in pairs(context.qualityMatStrings) do
|
|
|
|
|
if type(matString) == "string" then
|
|
|
|
|
context.result[matString] = quality
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
return context.result
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function private.MatQualityItemIterator(tbl, matString)
|
|
|
|
|
matString = next(tbl, matString)
|
|
|
|
|
if not matString then
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
local quality = tbl[matString]
|
|
|
|
|
local matItemString = MatString.GetQualityItem(matString, quality)
|
|
|
|
|
local matWeight = nil
|
|
|
|
|
if quality == 1 then
|
|
|
|
|
matWeight = 0
|
|
|
|
|
else
|
|
|
|
|
matWeight = ProfessionInfo.GetQualityMatWeight(matItemString) * (quality - 1) / (NUM_QUALITY_MAT_QUALITIES - 1)
|
|
|
|
|
end
|
|
|
|
|
return matString, quality, matWeight
|
|
|
|
|
end
|