Anonymous

Module:Constants: Difference between revisions

From Melvor Idle
Correct RegenerationInterval attributes
(Add many 0.21 modifiers & amend _getModifierText() to support various new substitution options)
(Correct RegenerationInterval attributes)
(44 intermediate revisions by 3 users not shown)
Line 8: Line 8:
--Just hardcoding these because I guess that's where we're at
--Just hardcoding these because I guess that's where we're at
local modifierTypes = {
local modifierTypes = {
  ["MeleeStrengthBonus"] = { text = "{V}% Melee Strength Bonus", skills = {'Combat'} },
["MeleeStrengthBonus"] = { text = "{V}% Melee Strength Bonus from Equipment", skills = {'Combat'} },
  ["DamageToDungeonMonsters"] = { text = "{V}% Damage To Dungeon Monsters", skills = {'Combat'} },
["DamageToDungeonMonsters"] = { text = "{V}% Damage To Dungeon Monsters", skills = {'Combat'} },
  ["GlobalMasteryXP"] = { text = "{V}% Global Mastery XP", skills = {'Woodcutting', 'Fishing', 'Firemaking', 'Cooking', 'Mining', 'Smithing', 'Thieving', 'Farming', 'Fletching', 'Crafting', 'Runecrafting', 'Herblore', 'Agility', 'Summoning'} },
["GlobalMasteryXP"] = { text = "{V}% Global Mastery XP", skills = {'Woodcutting', 'Fishing', 'Firemaking', 'Cooking', 'Mining', 'Smithing', 'Thieving', 'Farming', 'Fletching', 'Crafting', 'Runecrafting', 'Herblore', 'Agility', 'Summoning', 'Astrology'} },
  ["ChanceRandomPotionHerblore"] = { text = "{V}% chance to gain a second potion of a random tier", skills = {'Herblore'} },
["ChanceRandomPotionHerblore"] = { text = "{V}% chance to gain a second potion of a random tier", skills = {'Herblore'} },
  ["FlatPrayerCostReduction"] = { text = "{V} Prayer Point Cost for Prayers", inverseSign = true, skills = {'Prayer'} },
["FlatPrayerCostReduction"] = { text = "{V} Prayer Point Cost for Prayers", inverseSign = true, skills = {'Prayer'} },
  ["MinEarthSpellDmg"] = { text = "{VX} Min Earth Spell Dmg", skills = {'Magic'} },
["MinEarthSpellDmg"] = { text = "{VX} Min Earth Spell Dmg", skills = {'Magic'} },
  ["SlayerTaskLength"] = { text = "{V}% Slayer Task Length/Qty", skills = {'Slayer'} },
["SlayerTaskLength"] = { text = "{V}% Slayer Task Length/Qty", skills = {'Slayer'} },
  ["ChanceToDoubleLootCombat"]
["ChanceToDoubleLootCombat"] = { text = "{V}% Chance To Double Loot in Combat", skills = {'Combat
}
}


--Difficulties are hard coded which is dumb but means hardcoding them here too
--Difficulties are hard coded which is dumb but means hardcoding them here too
local Difficulties = {  
local Difficulties = {  
    [0] = 'Very Easy',
[0] = 'Very Easy',
    [1] = 'Easy',
[1] = 'Easy',
    [2] = 'Medium',
[2] = 'Medium',
    [3] = 'Hard',
[3] = 'Hard',
    [4] = 'Very Hard',
[4] = 'Very Hard',
    [5] = 'Elite',
[5] = 'Elite',
    [6] = 'Insane'}
[6] = 'Insane'
}


--07/03/21: Hardcoding in Combat Triangle Modifiers
function p.getTriangleAttribute(attribute, attackerStyle, targetStyle, mode)
local CombatTriangle = {
if type(attribute) ~= 'string' then
  damageBonus = 1.1,  
error("Parameter 'attribute' must be a string", 2)
  drBonus = 1.25,
elseif type(attackerStyle) ~= 'string' then
  damagePenalty = { Normal = 0.85,
error("Parameter 'attackerStyle' must be a string", 2)
                    Hardcore = 0.75 },
elseif type(targetStyle) ~= 'string' then
  drPenalty = { Melee = { Normal = 0.5,
error("Parameter 'targetStyle' must be a string", 2)
                          Hardcore = 0.25 },
elseif type(mode) ~= 'string' then
                Ranged = { Normal = 0.95,
error("Parameter 'mode' must be a string", 2)
                          Hardcore = 0.75 },
end
                Magic = { Normal = 0.85,
                          Hardcore = 0.75 }},
local modeID = p.getGamemodeID(mode)
  Melee = { bonus = "Ranged", penalty = "Magic" },
if modeID == nil then
  Ranged = { bonus = "Magic", penalty = "Melee" },
error("Invalid gamemode '" .. mode .. "'", 2)
  Magic = { bonus = "Melee", penalty = "Ranged" },
end
}
local attStyle, targStyle = string.lower(attackerStyle), string.lower(targetStyle)
local validStyles = { 'magic', 'melee', 'ranged' }
if not Shared.contains(validStyles, string.lower(attStyle)) then
error("Invalid value for parameter 'attackerStyle'", 2)
elseif not Shared.contains(validStyles, string.lower(targStyle)) then
error("Invalid value for parameter 'targetStyle'", 2)
end
local triangleID = ConstantData.Gamemode.Data[modeID + 1].combatTriangle
local attrData = ConstantData.CombatTriangle[triangleID + 1][attribute]
if attrData == nil then
error("No such attribute: " .. attribute)
else
return attrData[attStyle][targStyle]
end
end


function p.getTriangleDamageModifier(playerStyle, enemyStyle, mode)
function p.getTriangleDamageModifier(attackerStyle, targetStyle, mode)
  if CombatTriangle[playerStyle].bonus == enemyStyle then
return p.getTriangleAttribute('damageModifier', attackerStyle, targetStyle, mode)
    return CombatTriangle.damageBonus
  elseif CombatTriangle[playerStyle].penalty == enemyStyle then
    if mode == 'Hardcore' or mode == 'Adventure' then
      return CombatTriangle.damagePenalty.Hardcore
    else
      return CombatTriangle.damagePenalty.Normal
    end
  else
    return 1
  end
end
end


--Syntax is like p.getTriangleDRModifier('Melee', 'Ranged', 'Normal')
--Syntax is like p.getTriangleDRModifier('Melee', 'Ranged', 'Normal')
--Returns a multiplier that can be multiplied with base DR to get the post-Triangle result
--Returns a multiplier that can be multiplied with base DR to get the post-Triangle result
function p.getTriangleDRModifier(playerStyle, enemyStyle, mode)
function p.getTriangleDRModifier(attackerStyle, targetStyle, mode)
  if CombatTriangle[playerStyle].bonus == enemyStyle then
return p.getTriangleAttribute('reductionModifier', attackerStyle, targetStyle, mode)
    return CombatTriangle.drBonus
  elseif CombatTriangle[playerStyle].penalty == enemyStyle then
    if mode == 'Hardcore' or mode == 'Adventure' then
      return CombatTriangle.drPenalty[playerStyle].Hardcore
    else
      return CombatTriangle.drPenalty[playerStyle].Normal
    end
  else
    return 1
  end
end
end


function p.getDifficultyString(difficulty)
function p.getDifficultyString(difficulty)
  return Difficulties[difficulty]
return Difficulties[difficulty]
end
end


function p.getSkillName(skillID)
function p.getSkillName(skillID)
  for skName, ID in Shared.skpairs(ConstantData.skill) do
return ConstantData.skill[skillID]
    if ID == skillID then
      return skName
    end
  end
  return nil
end
end


function p.getSkillID(skillName)
function p.getSkillID(skillName)
  return ConstantData.skill[skillName]
return ConstantData.skill[skillName]
end
end


function p.getEquipmentSlotName(id)
function p.getEquipmentSlotName(id)
  for slotName, i in Shared.skpairs(ConstantData.equipmentSlot) do
return type(id) == 'number' and ConstantData.equipmentSlot[id] or 'Invalid'
    if i == id then
      return slotName
    end
  end
  return 'Invalid'
end
end


function p.getEquipmentSlotID(name)
function p.getEquipmentSlotID(name)
  return ConstantData.equipmentSlot[name]
return ConstantData.equipmentSlot[name]
end
 
function p.getGamemodeName(id)
return ConstantData.Gamemode.Enum[id]
end
 
function p.getGamemodeID(name)
return ConstantData.Gamemode.Enum[name]
end
end


function p.getCombatStyleName(styleNum)
function p.getCombatStyleName(styleNum)
  for name, num in Shared.skpairs(ConstantData.attackType) do
if type(styleNum) == 'number' then
    if num == styleNum then
local styleName = ConstantData.attackType[styleNum]
      return name
if styleName ~= nil then
    end
return Shared.titleCase(styleName)
  end
end
  return "ERROR: Invalid combat style[[Category:Pages with script errors]]"
elseif type(styleNum) == 'string' and type(ConstantData.attackType[string.lower(styleNum)]) == 'number' then
return Shared.titleCase(styleNum)
end
return "ERROR: Invalid combat style[[Category:Pages with script errors]]"
end
end


function p.getSlayerTierName(tier)
 
  for name, num in Shared.skpairs(ConstantData.slayerTier) do
--- Slayer functions
    if num == tier then
--
      return name
function p.getSlayerTierByID(tierID, slayerLevel) -- returns a full table
    end
if slayerLevel == nil then
  end
slayerLevel = 99 -- this might upgrade to 120 in some update
  return "ERROR: Invalid Slayer tier[[Category:Pages with script errors]]"
end
if type(tierID) ~= 'number' then
return nil
elseif ConstantData.Slayer.Tiers[tierID + 1] == nil then
return nil
else
local result = Shared.clone(ConstantData.Slayer.Tiers[tierID + 1])
result.id = tierID
result.minQuantity = 10*(tierID+1) + 4
result.maxQuantity = 10*(tierID+1) + 4*slayerLevel
return result
end
end
end


function p.getSlayerTierNameByLevel(lvl)
function p.getSlayerTier(name)
  for i, tier in Shared.skpairs(ConstantData.Slayer.Tiers) do
local tierID = ConstantData.slayerTier[name]
    if tier.minLevel <= lvl and (tier.maxLevel >= lvl or tier.maxLevel == -1) then
if tierID == nil then
      return tier.display
return nil
    end
else
  end
return p.getSlayerTierByID(tierID)
  return 'N/A'
end
end
end


function p.getSlayerTier(name)
function p.getSlayerTierByLevel(level) -- returns a full table
  for i, tier in Shared.skpairs(ConstantData.Slayer.Tiers) do
if type(level) ~= 'number' or level < 1 then
    if tier.display == name then
return "ERROR: Invalid Slayer level [[Category:Pages with script errors]]"
      local result = Shared.clone(tier)
end
      result.id = i - 1
      return result
for i, tier in ipairs(ConstantData.Slayer.Tiers) do
    end
if tier.minLevel <= level and (tier.maxLevel == nil or tier.maxLevel >= level) then
  end
return p.getSlayerTierByID(i - 1)
end
end
end
end


function p.getSlayerTierByID(tierID)
--
  if ConstantData.Slayer.Tiers[tierID + 1] == nil then
-- the following functions just return subsets of the slayer functions above
    return nil
--
  end
 
function p.getSlayerTierName(tierID, fallback)
return type(tierID) == 'number' and ConstantData.slayerTier[tierID] or "ERROR: Invalid Slayer tier[[Category:Pages with script errors]]"
end


  local result = Shared.clone(ConstantData.Slayer.Tiers[tierID + 1])
function p.getSlayerTierNameByLevel(lvl, fallback)
  result.id = tierID
local tier = p.getSlayerTierByLevel(lvl)
  return result
if type(tier) == 'table' then
return tier.display
else
return fallback or "ERROR: Invalid Slayer tier[[Category:Pages with script errors]]"
end
end
end
--
--- End of slayer functions


--Turns a modifier name like 'increasedMeleeAccuracyBonus' into several pieces of data:
--Turns a modifier name like 'increasedMeleeAccuracyBonus' into several pieces of data:
Line 431: Line 480:
--ex. "MeleeAccuracyBonus", "+{V}% Melee Accuracy", "+", false
--ex. "MeleeAccuracyBonus", "+{V}% Melee Accuracy", "+", false
function p.getModifierDetails(modifierName)
function p.getModifierDetails(modifierName)
  local baseName = modifierName
local baseName = modifierName
  local isIncrease = true
local isIncrease = true
  local isNegative = false
local isNegative = false
  local valueUnsigned = false
local valueUnsigned = false


  if Shared.startsWith(modifierName, "increased") or Shared.startsWith(modifierName, "decreased") then
if Shared.startsWith(modifierName, "increased") or Shared.startsWith(modifierName, "decreased") then
    baseName = string.sub(modifierName, 10)
baseName = string.sub(modifierName, 10)
    isIncrease = Shared.startsWith(modifierName, "increased")
isIncrease = Shared.startsWith(modifierName, "increased")
  end
end


  local modifier = modifierTypes[baseName]
local modifier = modifierTypes[baseName]
  if modifier == nil then
if modifier == nil then
    return nil
return nil
  end
end


  local isPositive = isIncrease
local isPositive = isIncrease
  if modifier.isIncreaseNegative then
if modifier.isIncreaseNegative then
    isPositive = not isPositive
isPositive = not isPositive
  end
end


  local sign = "+"
local sign = "+"
  if (not isIncrease and not modifier.inverseSign) or (isIncrease and modifier.inverseSign) then
if (not isIncrease and not modifier.inverseSign) or (isIncrease and modifier.inverseSign) then
    sign = "-"
sign = "-"
  end
end


  if type(modifier.unsigned) == 'boolean' then valueUnsigned = modifier.unsigned end
if type(modifier.unsigned) == 'boolean' then valueUnsigned = modifier.unsigned end


  return baseName, modifier.text, sign, not isPositive, valueUnsigned
return baseName, modifier.text, sign, not isPositive, valueUnsigned, modifier
end
end


function p._getModifierText(modifier, value, doColor)
function p._getModifierText(modifier, value, doColor)
  if doColor == nil then doColor = true end
if doColor == nil then doColor = true end
  local modName, modText, sign, isNegative, valueUnsigned = p.getModifierDetails(modifier)
local modName, modText, sign, isNegative, valueUnsigned = p.getModifierDetails(modifier)


  if modName == nil then
if modName == nil then
    return 'ERROR: Invalid modifier type for ' .. modifier .. '[[Category:Pages with script errors]]'
return 'ERROR: Invalid modifier type for ' .. modifier .. '[[Category:Pages with script errors]]'
  end
end
local formatModValue = function(value, rule)
local ruleFunctions = {
['V'] = function(val) return val end,
['VD'] = function(val) return val / 10 end,
['VMS'] = function(val) return val / 1000 end,
['VX'] = function(val) return val * 10 end,
['VX100'] = function(val) return val * 100 end,
['V+100'] = function(val) return val + 100 end,
['VMUL'] = function(val) return 2^val end,
['VITEM'] = function(val)
local item = ItemData.Items[tonumber(val) + 1]
if item ~= nil then
return item.name
end
end
}
local ruleFunc = ruleFunctions[rule] or ruleFunctions['V']
if type(value) == 'table' then
-- If table is a pair of values then format both & add a separator
return ruleFunc(value[1]) .. '-' .. ruleFunc(value[2])
else
return ruleFunc(value)
end
end


  local result = modText
local result = modText


  if type(value) == 'table' then
if type(value) == 'table' then
    if Shared.tableCount(value) > 0 and type(value[1]) == 'table' then
if Shared.tableCount(value) > 0 and type(value[1]) == 'table' then
      --Potentially return multiple rows if necessary
--Potentially return multiple rows if necessary
      local resultArray = {}
local resultArray = {}
      for i, subVal in Shared.skpairs(value) do
for i, subVal in Shared.skpairs(value) do
        table.insert(resultArray, p._getModifierText(modifier, subVal, doColor))
table.insert(resultArray, p._getModifierText(modifier, subVal, doColor))
      end
end
      return table.concat(resultArray, '<br/>')
return table.concat(resultArray, '<br/>')
    else
elseif Shared.contains(modText, '{SV0}') then
      if value[1] ~= nil then
-- If the value is a table and the mod text contains {SV0}, then
        local skillName = p.getSkillName(value[1])
-- the value is a {skillID, val} pair, otherwise it is a range of
        if skillName ~= nil then
-- values {minVal, maxVal}
          result = string.gsub(result, '{SV0}', p.getSkillName(value[1]))
if value[1] ~= nil then
        end
local skillName = p.getSkillName(value[1])
      end
if skillName ~= nil then
      if value[2] ~= nil then value = value[2] end
result = string.gsub(result, '{SV0}', p.getSkillName(value[1]))
    end
end
  end
end
  -- Re-check the type of value, as it may have been modified above even if it was originally a table
if value[2] ~= nil then value = value[2] end
  if type(value) ~= 'table' then
end
    local valSign = (valueUnsigned and '' or sign)
end
    if string.find(result, '{IV}', 1, true) ~= nil and tonumber(value) ~= nil then
      local item = ItemData.Items[tonumber(value) + 1]
local valSign = (valueUnsigned and '' or sign)
      if item ~= nil then
result = string.gsub(result, '{(V[^}]*)}', function(rule) return valSign .. formatModValue(value, rule) end)
        result = string.gsub(result, '{IV}', item.name)
result = string.gsub(result, '{S}', sign)
      end
    end
    result = string.gsub(result, '{V}', valSign..value)
    result = string.gsub(result, '{VD}', valSign..(value / 10))
    result = string.gsub(result, '{VMS}', valSign..(value / 1000))
    result = string.gsub(result, '{VX}', valSign..(value * 10))
    result = string.gsub(result, '{VX100}', valSign..(value * 100))
    result = string.gsub(result, '{V%+100}', valSign..(value + 100))
    result = string.gsub(result, '{VMUL}', 2^value)
    result = string.gsub(result, '{S}', sign)
  end


  if doColor then
if doColor then
    if isNegative ~= nil and isNegative then
if isNegative ~= nil and isNegative then
      result = '<span style="color:red">'..result..'</span>'
result = '<span style="color:red">'..result..'</span>'
    else
else
      result = '<span style="color:green">'..result..'</span>'
result = '<span style="color:green">'..result..'</span>'
    end
end
  end
end


  return result
return result
end
end


function p.getModifierText(frame)
function p.getModifierText(frame)
  local modifier = frame.args ~= nil and frame.args[1] or frame[1]
local modifier = frame.args ~= nil and frame.args[1] or frame[1]
  local value = frame.args ~= nil and frame.args[2] or frame[2]
local value = frame.args ~= nil and frame.args[2] or frame[2]
  local skill = frame.args ~= nil and frame.args.skill or frame.skill
local skill = frame.args ~= nil and frame.args.skill or frame.skill
  local doColor = frame.args ~= nil and frame.args[3] or frame[3]
local doColor = frame.args ~= nil and frame.args[3] or frame[3]


  if doColor ~= nil then
if doColor ~= nil then
    doColor = string.upper(doColor) ~= 'FALSE'
doColor = string.upper(doColor) ~= 'FALSE'
  end
end


  if skill ~= nil and skill ~= '' then
if skill ~= nil and skill ~= '' then
    value = {p.getSkillID(skill), value}
value = {p.getSkillID(skill), value}
  end
end


  return p._getModifierText(modifier, value, doColor)
return p._getModifierText(modifier, value, doColor)
end
end


function p.getModifiersText(modifiers, doColor)
function p.getModifiersText(modifiers, doColor)
  if modifiers == nil or Shared.tableCount(modifiers) == 0 then
if modifiers == nil or Shared.tableCount(modifiers) == 0 then
    return ''
return ''
  end
end


  local modArray = {}
local modArray = {}
  for bonus, value in Shared.skpairs(modifiers) do
for bonus, value in Shared.skpairs(modifiers) do
    table.insert(modArray, p._getModifierText(bonus, value, doColor))
table.insert(modArray, p._getModifierText(bonus, value, doColor))
  end
end
  return table.concat(modArray, "<br/>")
return table.concat(modArray, "<br/>")
end
end


function p.getModifierSkills(modifiers)
function p.getModifierSkills(modifiers)
  local skillArray = {}
local skillArray = {}


  for modifier, value in Shared.skpairs(modifiers) do
for modifier, value in Shared.skpairs(modifiers) do
    if type(value) == 'table' then
if type(value) == 'table' then
      for i, subVal in Shared.skpairs(value) do
for i, subVal in Shared.skpairs(value) do
        local skillName = p.getSkillName(subVal[1])
local skillName = p.getSkillName(subVal[1])
        if not Shared.contains(skillArray, skillName) then
if not Shared.contains(skillArray, skillName) then
          table.insert(skillArray, skillName)
table.insert(skillArray, skillName)
        end
end
      end
end
    end
end


    local baseName = p.getModifierDetails(modifier)
local baseName = p.getModifierDetails(modifier)
    if baseName == nil then
if baseName == nil then
      return { 'ERROR: Modifier '..modifier..' is invalid' }
return { 'ERROR: Modifier '..modifier..' is invalid' }
    end
end


    if modifierTypes[baseName].skills ~= nil then
if modifierTypes[baseName].skills ~= nil then
      for i, skillName in Shared.skpairs(modifierTypes[baseName].skills) do
for i, skillName in Shared.skpairs(modifierTypes[baseName].skills) do
        if not Shared.contains(skillArray, skillName) then
if not Shared.contains(skillArray, skillName) then
          table.insert(skillArray, skillName)
table.insert(skillArray, skillName)
        end
end
      end
end
    end
end
  end
end


  return skillArray
return skillArray
end
end


return p
return p