Module:Constants: Difference between revisions

From Melvor Idle
(Added Combat Triangle numbers and getTriangleDamageModifier and getTriangleDRModifier for use in building various other functions in other modules eventually)
(Updated Arch Tool Level display, Fixed error on nil modifiers in getModifiersDifference)
 
(121 intermediate revisions by 7 users not shown)
Line 1: Line 1:
local p = {}
local p = {}
local ConstantData = mw.loadData('Module:Constants/data')
local ItemData = mw.loadData('Module:Items/data')


local Shared = require('Module:Shared')
local Shared = require('Module:Shared')
local GameData = require('Module:GameData')


--Just hardcoding these because I guess that's where we're at
--Just hardcoding these because I guess that's where we're at
--getModifierSkills still needs skills, otherwise this can be removed
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'
["GlobalMasteryXP"] = { text = "{V}% Global Mastery XP", skills = {'Woodcutting', 'Fishing', 'Firemaking', 'Cooking', 'Mining', 'Smithing', 'Thieving', 'Farming', 'Fletching', 'Crafting', 'Runecrafting', 'Herblore', 'Agility', 'Summoning', 'Astrology', 'Archaeology'} },
["ChanceRandomPotionHerblore"] = { text = "{V}% chance to gain a second potion of a random tier", skills = {'Herblore'} },
["FlatPrayerCostReduction"] = { text = "{V} Prayer Point Cost for Prayers (Prayer Point cost cannot go below 1)", inverseSign = true, skills = {'Prayer'} },
["MinEarthSpellDmg"] = { text = "{VX} Min Earth Spell Dmg", skills = {'Magic'} },
["SlayerTaskLength"] = { text = "{V}% Slayer Task Length/Qty", skills = {'Slayer'} },
["ChanceToDoubleLootCombat"] = { text = "{V}% Chance To Double Loot in Combat", skills = {'Combat'} },
["GPFromAgility"] = { text = "{V}% GP From Agility", skills = {'Agility'} },
["SkillXP"] = { text = "{V}% {SV0} Skill XP" },
["MiningNodeHP"] = { text = "{V} Mining Node HP", skills = {'Mining'} },
["FarmingYield"] = { text = "{V}% Farming Yield", skills = {'Farming'} },
["GPFromMonstersFlat"] = { text = "{V} GP From Monsters", skills = {'Combat'} },
["GlobalPreservationChance"] = { text = "{V}% Chance to Preserve Resources in Skills" },
["RunePreservation"] = { text = "{V}% Rune Preservation", skills = {'Magic'} },
["MaxHitpoints"] = { text = "{VX} Maximum Hitpoints", skills = {'Combat', 'Hitpoints'} },
["ChanceToDoubleItemsSkill"] = { text = "{V}% Chance to Double Items in {SV0}" },
["autoSlayerUnlocked"] = { text = "{V} Auto Slayer Unlocked", skills = {'Slayer'} },
["HitpointRegeneration"] = { text = "{V}% Hitpoint Regeneration", skills = {'Combat', 'Hitpoints'} },
["PotionChargesFlat"] = { text = "{V} Charges per Potion" },
["SkillInterval"] = { text = "{VMS}s {SV0} Interval", isIncreaseNegative = true, isSkill = true },
["BankSpace"] = { text = "{V} Bank Space" },
["MinHitBasedOnMaxHit"] = { text = "{V}% of Maximum Hit added to Minimum Hit", skills = {'Combat'} },
["
}
}


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


--07/03/21: Hardcoding in Combat Triangle Modifiers
function p.getTriangleAttribute(attribute, attackerStyle, targetStyle, modeName)
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(modeName) ~= 'string' then
                Ranged = { Normal = 0.95,
error("Parameter 'modeName' must be a string", 2)
                          Hardcore = 0.75 },
end
                Magic = { Normal = 0.85,
                          Hardcore = 0.75 }},
local mode = GameData.getEntityByName('gamemodes', modeName)
  Melee = { bonus = "Ranged", penalty = "Magic" },
if mode == nil then
  Ranged = { bonus = "Magic", penalty = "Melee" },
error("Invalid gamemode '" .. modeName .. "'", 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 combatTriangle = GameData.getEntityByID('combatTriangles', mode.combatTriangle)
if combatTriangle == nil then
error("No such combat triangle: " .. mode.combatTriangle)
end
local attrData = combatTriangle[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 GameData.rawData.combatAreaDifficulties[difficulty + 1]
end
end


function p.getSkillName(skillID)
function p.getSkillName(skillID)
  for skName, ID in Shared.skpairs(ConstantData.skill) do
local skill = GameData.getSkillData(skillID)
    if ID == skillID then
if skill ~= nil then
      return skName
return skill.name
    end
end
  end
  return nil
end
end


function p.getSkillID(skillName)
function p.getSkillID(skillName)
  return ConstantData.skill[skillName]
for i, skillData in ipairs(GameData.rawData.skillData) do
if skillData.data.name == skillName then
return skillData.skillID
end
end
end
end


function p.getEquipmentSlotName(id)
function p.getEquipmentSlotName(id)
  for slotName, i in Shared.skpairs(ConstantData.equipmentSlot) do
local slotData = GameData.getEntityByID('equipmentSlots', id)
    if i == id then
if slotData ~= nil then
      return slotName
return slotData.name
    end
end
  end
  return 'Invalid'
end
end


function p.getEquipmentSlotID(name)
function p.getEquipmentSlotID(name)
  return ConstantData.equipmentSlot[name]
local slotData = GameData.getEntityByName('equipmentSlots', name)
if slotData ~= nil then
return slotData.id
end
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 = GameData.rawData.attackTypes[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(GameData.rawData.attackTypes[string.lower(styleNum)]) == 'number' then
return Shared.titleCase(styleNum)
end
return Shared.printError('Invalid combat style')
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)
    end
if type(tierID) ~= 'number' then
  end
return nil
  return "ERROR: Invalid Slayer tier[[Category:Pages with script errors]]"
else
return GameData.rawData.slayerTiers[tierID + 1]
end
end
end


function p.getSlayerTierNameByLevel(lvl)
function p.getSlayerTier(name)
  for i, tier in Shared.skpairs(ConstantData.Slayer.Tiers) do
return GameData.getEntityByProperty('slayerTiers', 'display', name)
    if tier.minLevel <= lvl and (tier.maxLevel >= lvl or tier.maxLevel == -1) then
      return tier.display
    end
  end
  return 'N/A'
end
end


function p.getSlayerTier(name)
function p.getSlayerTierByLevel(level)
  for i, tier in Shared.skpairs(ConstantData.Slayer.Tiers) do
if type(level) ~= 'number' or level < 1 then
    if tier.display == name then
return Shared.printError('Invalid Slayer level')
      local result = Shared.clone(tier)
end
      result.id = i - 1
      return result
for i, tier in ipairs(GameData.rawData.slayerTiers) do
    end
if tier.minLevel <= level and (tier.maxLevel == nil or tier.maxLevel >= level) then
  end
return tier
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


  local result = Shared.clone(ConstantData.Slayer.Tiers[tierID + 1])
function p.getSlayerTierName(tierID)
  result.id = tierID
if type(tierID) == 'number' then
  return result
local tier = p.getSlayerTierByID(tierID)
if tier ~= nil then
return tier.display
end
end
return Shared.printError('Invalid Slayer tier')
end
end


--Turns a modifier name like 'increasedMeleeAccuracyBonus' into several pieces of data:
function p.getSlayerTierNameByLevel(lvl)
--Base Name, Text, Sign, and IsNegative
local tier = p.getSlayerTierByLevel(lvl)
--ex. "MeleeAccuracyBonus", "+{V}% Melee Accuracy", "+", false
if type(tier) == 'table' then
function p.getModifierDetails(modifierName)
return tier.display
  local baseName = modifierName
else
  local isIncrease = true
return Shared.printError('Invalid Slayer tier')
  local isNegative = false
end
end


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


  local modifier = modifierTypes[baseName]
--Turns a modifier name like 'increasedHPRegenFlat' into several pieces of data:
  if modifier == nil then
--Base Name, Description, IsNegative, and modifyValue
    mw.log(baseName)
--ex. "HPRegenFlat", "+${value} Flat Hitpoints Regeneration", false, "multiplyByNumberMultiplier"
    return nil
function p.getModifierDetails(modifierName)
  end
local baseName = modifierName
local modifier = GameData.rawData.modifierData[modifierName]


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


  local sign = "+"
if Shared.startsWith(modifierName, "increased") or Shared.startsWith(modifierName, "decreased") then
  if (not isIncrease and not modifier.inverseSign) or (isIncrease and modifier.inverseSign) then
baseName = string.sub(modifierName, 10)
    sign = "-"
end
  end


  return baseName, modifier.text, sign, not isPositive
return baseName, modifier.description, modifier.isNegative, modifier.modifyValue
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 = p.getModifierDetails(modifier)
local modName, modText, isNegative, modifyValue = p.getModifierDetails(modifier)
 
if modName == nil then
return Shared.printError('Invalid modifier type for "' .. modifier .. '"')
end
 
if modifyValue ~= nil and string.match(modifyValue, 'ToolLevels') then
modifyValue = 'ArchaeologyToolLevels'
end
 
local formatModValue = function(value, rule)
local ruleFunctions = {
['value'] = function(val) return val end,
['multiplyByNumberMultiplier'] = function(val) return val * 10 end,
['divideByNumberMultiplier'] = function(val) return val / 10 end,
['milliToSeconds'] = function(val) return val / 1000 end,
['(value)=>value*100'] = function(val) return val * 100 end,
['(value)=>100+value'] = function(val) return val + 100 end,
['(value)=>value+1'] = function(val) return val + 1 end,
['(value)=>Math.pow(2,value)'] = function(val) return 2^val end,
["(value)=>{if(value>=2){return getLangString('ALLOW_UNHOLY_PRAYERS');}\nelse if(value>=1){return getLangString('ALLOW_UNHOLY_PRAYERS_WITH_EQUIPMENT');}\nelse{return 'Invalid modifier value.';}}"] = function(val) return 'Allows for Unholy Prayers to be used' end,
['ArchaeologyToolLevels'] = function(val)
local toolLevel = '+' .. val
if string.match(modName, 'Sieve') then
toolLevel = toolLevel ..  ' level of the Sieve Tool in Archaeology'
elseif string.match(modName, 'Trowel') then
toolLevel = toolLevel ..  ' level of the Trowel Tool in Archaeology'
elseif string.match(modName, 'Brush') then
toolLevel = toolLevel ..  ' level of the Brush Tool in Archaeology'
elseif string.match(modName, 'Shovel') then
toolLevel = toolLevel ..  ' level of the Shovel Tool in Archaeology'
end
if val > 1 then
return string.gsub(toolLevel, 'level', 'levels')
else
return toolLevel
end
end,
['(value)=>game.golbinRaid.startingWeapons[value].name'] = function(val)
-- For golbin raid starting weapons
local startingWeapons = { 'melvorD:Bronze_Scimitar', 'melvorD:Adamant_Scimitar' }
local itemID = startingWeapons[val + 1]
local item = GameData.getEntityByID('items', itemID)
if item ~= nil then
return item.name
else
return 'Unknown'
end
end
}
local ruleFunc = ruleFunctions[modifyValue] or ruleFunctions['value']


  if modName == nil then
if type(value) == 'table' then
    return 'ERROR: Invalid modifier type [[Category:Pages with script errors]]'
-- If table is a pair of values then format both & add a separator
  end
return ruleFunc(value[1]) .. '-' .. ruleFunc(value[2])
else
return ruleFunc(value)
end
end


  local result = modText
local valueArray, resultArray = nil, {}
if type(value) ~= 'table' then
valueArray = {value}
else
valueArray = value
end


  if type(value) == 'table' then
for i, subVal in ipairs(valueArray) do
    if Shared.tableCount(value) > 0 and type(value[1]) == 'table' then
local resultText = modText
      --Potentially return multiple rows if necessary
-- A few modifiers don't have official descriptions; Fallback to manual ones instead
      local resultArray = {}
if string.match(resultText, 'UNDEFINED TRANSLATION') then
      for i, subVal in Shared.skpairs(value) do
resultText = modifierTypes[modName].text
        table.insert(resultArray, p._getModifierText(modifier, subVal, doColor))
end
      end
local modMagnitude = nil
      return table.concat(resultArray, '<br/>')
if type(subVal) == 'table' and subVal.skillID ~= nil then
    else
-- Modifier value is skill specific
      if value[1] ~= nil then
modMagnitude = subVal.value
        local skillName = p.getSkillName(value[1])
local skillName = p.getSkillName(subVal.skillID)
        if skillName ~= nil then
if skillName ~= nil then
          result = string.gsub(result, '{SV0}', p.getSkillName(value[1]))
resultText = string.gsub(resultText, '${skillName}', skillName)
        end
end
      end
else
      if value[2] ~= nil then
-- Modifier value is the magnitude only
        result = string.gsub(result, '{V1}', sign..value[2])
modMagnitude = subVal
        result = string.gsub(result, '{VMS1}', sign..(value[2] / 1000))
end
      end
    end
  else
    if string.find(result, '{IV}', 1, true) ~= nil and tonumber(value) ~= nil then
      local item = ItemData.Items[tonumber(value) + 1]
      if item ~= nil then
        result = string.gsub(result, '{IV}', item.name)
      end
    end
    result = string.gsub(result, '{V}', sign..value)
    result = string.gsub(result, '{VMS}', sign..(value / 1000))
    result = string.gsub(result, '{VX}', sign..(value * 10))
  end


  if doColor then
resultText = string.gsub(resultText, '${value}', function(rule) return (formatModValue(modMagnitude, rule) or '') end)
    if isNegative ~= nil and isNegative then
      result = '<span style="color:red">'..result..'</span>'
    else
      result = '<span style="color:green">'..result..'</span>'
    end
  end


  return result
if doColor then
local colorCode = (isNegative ~= nil and isNegative and 'color:red' or 'color:green')
resultText = '<span style="' .. colorCode .. '">' .. resultText .. '</span>'
end
table.insert(resultArray, resultText)
end
 
return table.concat(resultArray, '<br/>')
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 = { { ["skillID"] = p.getSkillID(skill), ["value"] = 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, inline, maxVisible)
  if modifiers == nil or Shared.tableCount(modifiers) == 0 then
if inline == nil then inline = false end
    return ''
if type(maxVisible) ~= 'number' then maxVisible = nil end
  end
if modifiers == nil or Shared.tableIsEmpty(modifiers) then
return ''
end


  local modArray = {}
local modArray = { ["visible"] = {}, ["overflow"] = {} }
  for bonus, value in Shared.skpairs(modifiers) do
local modCount = { ["visible"] = 0, ["overflow"] = 0 }
    table.insert(modArray, p._getModifierText(bonus, value, doColor))
local insertKey = 'visible'
  end
for bonus, value in pairs(modifiers) do
  return table.concat(modArray, "<br/>")
-- If there is a single by skill modifier with multiple values, this will
-- appear as multiple rows. Split these so the number of visible lines is
-- always accurate
local valueArray = nil
if type(value) == 'table' then
valueArray = value
else
valueArray = {value}
end
for i, subVal in ipairs(valueArray) do
if type(subVal) == 'table' and subVal.skillID ~= nil then
subVal = {subVal}
end
if maxVisible ~= nil and not inline and insertKey == 'visible' and modCount[insertKey] >= maxVisible then
insertKey = 'overflow'
end
table.insert(modArray[insertKey], p._getModifierText(bonus, subVal, doColor))
modCount[insertKey] = modCount[insertKey] + 1
end
end
if inline then
return table.concat(modArray['visible'], ' and ')
else
if modCount['overflow'] == 1 then
table.insert(modArray['visible'], modArray['overflow'][1])
end
local overflowText = ''
if modCount['overflow'] > 1 then
-- Number of other modifiers has exceeded the specified maximum
overflowText = table.concat({
'<br/><span class="mw-collapsible mw-collapsed" ',
'data-expandtext="Show ' .. Shared.formatnum(modCount['overflow']) .. ' more modifiers" ',
'data-collapsetext="Hide">',
table.concat(modArray['overflow'], '<br/>'),
'</span>'
})
end
return table.concat(modArray['visible'], '<br/>') .. overflowText
end
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 pairs(modifiers) do
    if type(value) == 'table' then
if type(value) == 'table' then
      for i, subVal in Shared.skpairs(value) do
for i, subVal in ipairs(value) do
        local skillName = p.getSkillName(subVal[1])
if type(subVal) == 'table' and subVal.skillID ~= nil then
        if not Shared.contains(skillArray, skillName) then
local skillName = p.getSkillName(subVal.skillID)
          table.insert(skillArray, skillName)
if not Shared.contains(skillArray, skillName) then
        end
table.insert(skillArray, skillName)
      end
end
    end
end
end
end


    local baseName = p.getModifierDetails(modifier)
local baseName = p.getModifierDetails(modifier)
    if modifierTypes[baseName].skills ~= nil then
if baseName == nil then
      for i, skillName in Shared.skpairs(modifierTypes[baseName].skills) do
return { Shared.printError('Modifier "' .. modifier .. '" is invalid') }
        if not Shared.contains(skillArray, skillName) then
end
          table.insert(skillArray, skillName)
 
        end
if modifierTypes[baseName].skills ~= nil then
      end
for i, skillName in Shared.skpairs(modifierTypes[baseName].skills) do
    end
if not Shared.contains(skillArray, skillName) then
  end
table.insert(skillArray, skillName)
end
end
end
end
 
return skillArray
end
 
-- Returns a modifiers table indicating modifiersNew less modifiersOld
-- The returned table can be passed to getModifiersText to obtain the
-- result in a human readable format
function p.getModifiersDifference(modifiersOld, modifiersNew)
local modHasPrefix = {}
local modDiff, modDiffBase = {}, {}
local allMods = {
{ ["mods"] = (modifiersNew or {}), ["mult"] = 1 },
{ ["mods"] = (modifiersOld or {}), ["mult"] = -1 }
}
 
-- Generate modifiers table containing only variances
-- Create modDiffBase with mod base names (less 'increased'/'decreased' prefixes),
for i, modDef in ipairs(allMods) do
for modName, value in pairs(modDef.mods) do
local modBaseName, modIsIncrease = modName, true
if Shared.startsWith(modName, "increased") or Shared.startsWith(modName, "decreased") then
modBaseName = string.sub(modName, 10)
modIsIncrease = Shared.startsWith(modName, "increased")
modHasPrefix[modBaseName] = true
end
local modMult = (modIsIncrease and 1 or -1) * modDef.mult
 
if type(value) == 'table' then
-- Skill specific modifier
if modDiffBase[modBaseName] == nil then
modDiffBase[modBaseName] = {}
end
for j, subVal in ipairs(value) do
if type(subVal) == 'table' and subVal.skillID ~= nil then
modDiffBase[modBaseName][subVal.skillID] = (modDiffBase[modBaseName][subVal.skillID] or 0) + subVal.value * modMult
end
end
else
modDiffBase[modBaseName] = (modDiffBase[modBaseName] or 0) + value * modMult
end
end
end
 
-- Transform modDiffBase into modDiff with the appropriate mod name within the return value
for modBaseName, value in pairs(modDiffBase) do
if type(value) == 'table' then
-- Skill specific modifier
for skillID, subVal in pairs(value) do
if subVal ~= 0 then
local modName = nil
if modHasPrefix[modBaseName] then
modName = (subVal < 0 and 'decreased' or 'increased') .. modBaseName
else
modName = modBaseName
end
if modDiff[modName] == nil then
modDiff[modName] = {}
end
table.insert(modDiff[modName], { ["skillID"] = skillID, ["value"] = math.abs(subVal) })
end
end
elseif value ~= 0 then
local modName = nil
if modHasPrefix[modBaseName] then
modName = (value < 0 and 'decreased' or 'increased') .. modBaseName
else
modName = modBaseName
end
modDiff[modName] = (modDiff[modName] or 0) + math.abs(value)
if GameData.rawData.modifierData[modName] == nil then
modDiff[modName] = nil
end
end
end
 
return modDiff
end


  return skillArray
-- From game version 1.1 onwards, some entities have custom descriptions, while
-- many are generated based on the modifiers associated to that entity. This
-- function handles that logic given a custom description (may be nil) and
-- a modifiers object
function p.getDescription(customDescription, modifiers)
if customDescription ~= nil then
return customDescription
else
return p.getModifiersText(modifiers, false)
end
end
end


return p
return p

Latest revision as of 22:12, 16 January 2024

Documentation for this module may be created at Module:Constants/doc

local p = {}

local Shared = require('Module:Shared')
local GameData = require('Module:GameData')

--Just hardcoding these because I guess that's where we're at
--getModifierSkills still needs skills, otherwise this can be removed
local modifierTypes = {
	["MeleeStrengthBonus"] = { text = "{V}% Melee Strength Bonus from Equipment", 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', 'Astrology', 'Archaeology'} },
	["ChanceRandomPotionHerblore"] = { text = "{V}% chance to gain a second potion of a random tier", skills = {'Herblore'} },
	["FlatPrayerCostReduction"] = { text = "{V} Prayer Point Cost for Prayers (Prayer Point cost cannot go below 1)", inverseSign = true, skills = {'Prayer'} },
	["MinEarthSpellDmg"] = { text = "{VX} Min Earth Spell Dmg", skills = {'Magic'} },
	["SlayerTaskLength"] = { text = "{V}% Slayer Task Length/Qty", skills = {'Slayer'} },
	["ChanceToDoubleLootCombat"] = { text = "{V}% Chance To Double Loot in Combat", skills = {'Combat'} },
	["GPFromAgility"] = { text = "{V}% GP From Agility", skills = {'Agility'} },
	["SkillXP"] = { text = "{V}% {SV0} Skill XP" },
	["MiningNodeHP"] = { text = "{V} Mining Node HP", skills = {'Mining'} },
	["FarmingYield"] = { text = "{V}% Farming Yield", skills = {'Farming'} },
	["GPFromMonstersFlat"] = { text = "{V} GP From Monsters", skills = {'Combat'} },
	["GlobalPreservationChance"] = { text = "{V}% Chance to Preserve Resources in Skills" },
	["RunePreservation"] = { text = "{V}% Rune Preservation", skills = {'Magic'} },
	["MaxHitpoints"] = { text = "{VX} Maximum Hitpoints", skills = {'Combat', 'Hitpoints'} },
	["ChanceToDoubleItemsSkill"] = { text = "{V}% Chance to Double Items in {SV0}" },
	["autoSlayerUnlocked"] = { text = "{V} Auto Slayer Unlocked", skills = {'Slayer'} },
	["HitpointRegeneration"] = { text = "{V}% Hitpoint Regeneration", skills = {'Combat', 'Hitpoints'} },
	["PotionChargesFlat"] = { text = "{V} Charges per Potion" },
	["SkillInterval"] = { text = "{VMS}s {SV0} Interval", isIncreaseNegative = true, isSkill = true },
	["BankSpace"] = { text = "{V} Bank Space" },
	["MinHitBasedOnMaxHit"] = { text = "{V}% of Maximum Hit added to Minimum Hit", skills = {'Combat'} },
	["DamageToSlayerTasks"] = { text = "{V}% Damage To Slayer Tasks", skills = {'Combat'} },
	["Lifesteal"] = { text = "{V}% Lifesteal", skills = {'Combat'} },
	["HPRegenFlat"] = { text = "{VX} Flat HP Regen", skills = {'Combat', 'Hitpoints'} },
	["ChanceToDoubleOres"] = { text = "{V}% Chance to Double Ores in Mining", skills = {'Mining'} },
	["MonsterRespawnTimer"] = { text = "{VMS}s Monster Respawn Timer", isIncreaseNegative = true, skills = {'Combat'} },
	["SkillPreservationChance"] = { text = "{V}% Chance to Preserve Resources in {SV0}" },
	["DamageToCombatAreaMonsters"] = { text = "{V}% Damage To Combat Area Monsters", skills = {'Combat'} },
	["TreeCutLimit"] = { text = "{V} Tree Cut Limit", skills = {'Woodcutting'} },
	["EquipmentSets"] = { text = "{V} Equipment Sets" },
	["HiddenSkillLevel"] = { text = "{V} Hidden {SV0} Level" },
	["ChanceToPreservePrayerPoints"] = { text = "{V}% Chance To Preserve Prayer Points", skills = {'Prayer'} },
	["ReflectDamage"] = { text = "{V}% Reflect Damage", skills = {'Combat'} },
	["MeleeEvasion"] = { text = "{V}% Melee Evasion", skills = {'Combat'} },
	["DamageToSlayerAreaMonsters"] = { text = "{V}% Damage To Slayer Area Monsters", skills = {'Combat'} },
	["GPFromMonsters"] = { text = "{V}% GP From Monsters", skills = {'Combat'} },
	["MagicEvasion"] = { text = "{V}% Magic Evasion", skills = {'Combat'} },
	["DamageReduction"] = { text = "{V}% Damage Reduction", skills = {'Combat'} },
	["MinWaterSpellDmg"] = { text = "{VX} Min Water Spell Dmg", skills = {'Magic'} },
	["DamageToAllMonsters"] = { text = "{V}% Damage To All Monsters", skills = {'Combat'} },
	["golbinRaidIncreasedStartingRuneCount"] = { text = "{V} to starting Elemental Rune count" },
	["FoodHealingValue"] = { text = "{V}% Food Healing Value", skills = {'Combat'} },
	["MinFireSpellDmg"] = { text = "{VX} Min Fire Spell Dmg", skills = {'Magic'} },
	["SlayerCoins"] = { text = "{V}% Slayer Coins", skills = {'Slayer'} },
	["GPFromThievingFlat"] = { text = "{V} GP From Thieving", skills = {'Thieving'} },
	["GlobalAccuracy"] = { text = "{V}% Global Accuracy", skills = {'Combat'} },
	["SlayerAreaEffectNegationFlat"] = { text = "{V}% Flat Slayer Area Effect Negation", skills = {'Combat'} },
	["MagicAccuracyBonus"] = { text = "{V}% Magic Accuracy Bonus", skills = {'Combat'} },
	["SkillIntervalPercent"] = { text = "{V}% {SV0} Interval", isIncreaseNegative = true, isSkill = true },
	["GlobalSkillXP"] = { text = "{V}% Global Skill XP" },
	["MeleeAccuracyBonus"] = { text = "{V}% Melee Accuracy Bonus", skills = {'Combat'} },
	["DamageToBosses"] = { text = "{V}% Damage To Bosses", skills = {'Combat'} },
	["ChanceToPreservePotionCharge"] = { text = "{V}% Chance To Preserve Potion Charge" },
	["MaxHitPercent"] = { text = "{V}% Max Hit", skills = {'Combat'} },
	["AltMagicSkillXP"] = { text = "{V}% Alt. Magic Skill XP", skills = {'Magic'} },
	["MinAirSpellDmg"] = { text = "{VX} Min Air Spell Dmg", skills = {'Magic'} },
	["AutoEatEfficiency"] = { text = "{V}% Auto Eat Efficiency", skills = {'Combat'} },
	["GPFromThieving"] = { text = "{V}% GP From Thieving", skills = {'Thieving'} },
	["ChanceToDoubleItemsGlobal"] = { text = "{V}% Chance to Double Items Globally" },
	["GPGlobal"] = { text = "{V}% GP from all sources (Except Item Selling)", skills = {'Combat', 'Thieving', 'Agility'} },
	["RangedAccuracyBonus"] = { text = "{V}% Ranged Accuracy Bonus", skills = {'Combat'} },
	["AutoEatThreshold"] = { text = "{V}% Auto Eat Threshold", skills = {'Combat'} },
	["freeBonfires"] = { text = "Bonfires in Firemaking require no logs to light. Automatically relights Bonfires when depleted", unsigned = true, skills = {'Firemaking'} },
	["AutoEatHPLimit"] = { text = "{V}% Auto Eat HP Limit", skills = {'Combat'} },
	["BankSpaceShop"] = { text = "{V} Bank Space from Shop" },
	["BirdNestDropRate"] = { text = "{V}% Bird Nest drop rate", skills = {'Woodcutting'} },
	["RangedEvasion"] = { text = "{V}% Ranged Evasion", skills = {'Combat'} },
	["ChanceDoubleHarvest"] = { text = "{V}% chance for double harvest", skills = {'Farming'} },
	["golbinRaidStartingWeapon"] = { text = "Start the Golbin Raid with an {VITEM}", unsigned = true },
	["AttackRolls"] = { text =  "Your Attacks now roll twice (Select highest chance)", unsigned = true, skills = {'Combat'} },
	["AmmoPreservation"] = { text = "{V}% Ammo Preservation", skills = {'Ranged'} },
	["RangedStrengthBonus"] = { text = "{V}% Ranged Strength Bonus from Equipment", skills = {'Combat'} },
	["MagicDamageBonus"] = { text = "{V}% Magic Damage Bonus from Equipment", skills = {'Combat'} },
	["MasteryXP"] = { text = "{V}% {SV0} Mastery XP" },
	["dungeonEquipmentSwapping"] = { text = "{V} Dungeon Equipment Swapping", skills = {'Combat'} },
	["SeeingGoldChance"] = { text = "{V}% chance for Silver Ore to also produce a Gold Bar when smithed", skills = {'Smithing'} },
	["ElementalRuneGain"] = { text = "{V} runes received when generating random elemental runes", skills = {'Runecrafting'} },
	["GPFromSales"] = { text = "{V}% GP From Sales" },
	["MaxHitFlat"] = { text = "{VX} Max Hit", skills = {'Combat'} },
	["ChanceNoDamageMining"] = { text = "{V}% chance to do zero damage to Ores and Rune Essence", skills = {'Mining'} },
	["ChanceForElementalRune"] = { text = "{V}% chance to receive random elemental runes per Runecraft", skills = {'Runecrafting'} },
	["ChanceToApplyBurn"] = { text = "{V}% Chance to apply Burn to Enemy in Combat", skills = {'Combat'} },
	["SummoningShardCost"] = { text = "{V} Shard Cost when creating Familiars in Summoning", skills = {'Summoning'}, isIncreaseNegative = true },
	["SummoningCreationCharges"] = { text = "{V} Base Quantity for Summoning Tablet Creation", skills = {'Summoning'} },
	["SummoningChargePreservation"] = { text = "{V}% Chance to preserve Summoning Charges", skills = {'Summoning'} },
	["GPOnEnemyHit"] = { text = "{V} GP Gained on successful Enemy Hit", skills = {'Combat'} },
	["AdditionalRunecraftCountRunes"] = { text = "{V} Additional Runes of the same type in Runecrafting", skills = {'Runecrafting'} },
	["ChanceAdditionalSkillResource"] = { text = "{V}% Chance to gain +1 additional resource in {SV0}. Cannot be doubled" },
	["AttackIntervalPercent"] = { text = "{V}% Attack Interval", isIncreaseNegative = true, skills = {'Combat'} },
	["summoningSynergy_0_1"] = {text = "Upon killing an Enemy, grants GP equal to {V}% of their highest base Evasion Rating.", skills = {"Combat",}},
	["summoningSynergy_0_6"] = {text = "Grants GP equal to {V}% of your MELEE damage dealt.", skills = {"Combat"}},
	["summoningSynergy_0_7"] = {text = "Grants GP equal to {V}% of your RANGED damage dealt.", skills = {"Combat"}},
	["summoningSynergy_0_8"] = {text = "Grants GP equal to {V}% of your MAGIC damage dealt.", skills = {"Combat"}},
	["summoningSynergy_0_12"] = {text = "Upon killing a Slayer Task Enemy, grants {V}% GP.", skills = {"Combat"}},
	["summoningSynergy_0_13"] = {text = "Upon being hit by an Enemy, grants GP equal to ({V} * Your Damage Reduction). This can only proc once every Enemy Attack Turn.", skills = {"Combat"}},
	["summoningSynergy_0_14"] = {text = "{VX100}% of regenerated health gained as GP", skills = {"Combat"}},
	["summoningSynergy_0_15"] = {text = "Upon killing an Enemy that is BURNING, grants {V}% GP.", skills = {"Combat"}},
	["summoningSynergy_1_2"] = {text = "When player has full HP, effects from the Occultist Familiar are tripled.", skills = {"Combat"}},
	["summoningSynergy_1_8"] = {text = "{V} Magic Defence Bonus.", skills = {"Combat"}},
	["summoningSynergy_1_12"] = {text = "If the Enemy is your current Slayer Task, {V}% Enemy Accuracy Rating.", skills = {"Combat"}, inverseSign = true},
	["summoningSynergy_1_13"] = {text = "Grants flat Melee & Ranged Defence Bonus equal to your Damage Reduction", skills = {"Combat"}},
	["summoningSynergy_1_14"] = {text = "If the Enemy has more combined Evasion Ratings than the Player, grants {V}% Hitpoint Regeneration.", skills = {"Combat", "Hitpoints"}},
	["summoningSynergy_1_15"] = {text = "If the Player is BURNING, grants {V} Melee, Ranged and Magic Defence Bonus.", skills = {"Combat"}},
	["summoningSynergy_2_12"] = {text = "Grants Slayer Coins equal to {V}% of HP leeched from Lifesteal.", skills = {"Slayer"}},
	["summoningSynergy_2_13"] = {text = "Upon attacking an Enemy, heals you for {V}% of your Damage Reduction. This can only proc once every 2 seconds.", skills = {"Combat"}},
	["summoningSynergy_2_15"] = {text = "Heals you for all damage dealt by the Wolf & Dragon Familiars.", skills = {"Combat"}},
	["summoningSynergy_3_4"] = {text = "{V}% chance per action in Woodcutting to gain a random Gem.", skills = {'Woodcutting'}},
	["summoningSynergy_3_5"] = {text = "{V}% Increased Special Item chance in Fishing. {V}% Increased chance to obtain a Bird Nests in Woodcutting.", skills = {'Fishing', 'Woodcutting'}},
	["summoningSynergy_3_9"] = {text = "{V}% chance to receive +1 Cooked Food in Cooking. Cannot be doubled.", skills = {'Cooking'}},
	["summoningSynergy_3_10"] = {text = "{V}% Runecrafting Preservation Chance when creating Staves.", skills = {'Runecrafting'}},
	["summoningSynergy_3_11"] = {text = "When successfully pickpocketing the Lumberjack in Thieving, grants {V} Bird Nest instead of GP.", skills = {'Thieving'}},
	["summoningSynergy_3_16"] = {text = "In Woodcutting, {V}% chance for a random Silver or Gold Jewelry to drop instead of a Bird Nest.", skills = {'Woodcutting'}},
	["summoningSynergy_3_17"] = {text = "{V}% chance to gain +1 Base Logs from Woodcutting, or produced Items from Smithing.", skills = {'Woodcutting', 'Smithing'}},
	["summoningSynergy_3_18"] = {text = "While the Bird Nest Potion is active in Woodcutting, grants {V} minimum Bird Nest.", skills = {'Woodcutting'}},
	["summoningSynergy_3_19"] = {text = "{V}% of Woodcutting Skill XP is earned as Firemaking Skill XP. Chance to double Logs is halved.", skills = {'Woodcutting', 'Firemaking'}},
	["summoningSynergy_4_5"] = {text = "When receiving a Gem from Mining or Fishing, there is a {V}% chance to get another random Gem.", skills = {'Fishing', 'Mining'}},
	["summoningSynergy_4_9"] = {text = "{V}% base burn chance in Cooking. Grants 100 Coal Ore when burning Food.", skills = {'Cooking'}},
	["summoningSynergy_4_10"] = {text = "Base quantity for Rune Essence in Mining is doubled.", skills = {'Mining'}},
	["summoningSynergy_4_11"] = {text = "When successfully pickpocketing the Miner in Thieving, {V}% chance to get a random Gem.", skills = {'Thieving'}},
	["summoningSynergy_4_16"] = {text = "Base quantity for Silver Ore & Gold Ore is doubled in Mining.", skills = {'Mining'}},
	["summoningSynergy_4_17"] = {text = "{V}% chance to receive a smithed verion of the Ore you are Mining.", skills = {'Mining'}},
	["summoningSynergy_4_18"] = {text = "While the Perfect Swing Potion is active in Mining, all Mining Nodes have {V} Max HP.", skills = {'Mining'}},
	["summoningSynergy_4_19"] = {text = "{V}% chance to receive a Diamond per action in Firemaking.", skills = {'Firemaking'}},
	["summoningSynergy_5_9"] = {text = "{V}% chance to receive an extra Fish as a Cooked version while Fishing.", skills = {'Fishing'}},
	["summoningSynergy_5_10"] = {text = "In Runecrafting, when creating a Combination Rune that requires Water Runes as an ingredient, produce {V} extra Combination Runes.", skills = {'Runecrafting'}},
	["summoningSynergy_5_11"] = {text = "-50% Thieving Skill Interval for Fisherman only. Also grants +2 Base Thieving Item Qty from Fisherman only.", skills = {'Thieving'}},
	["summoningSynergy_5_16"] = {text = "33% chance to gain a random Gem while creating Jewelry in Crafting.", skills = {'Crafting'}},
	["summoningSynergy_5_17"] = {text = "While creating Dragon Gear in Smithing, grants {V}% Smithing Preservation chance.", skills = {'Smithing'}},
	["summoningSynergy_5_18"] = {text = "{V}% charges when using the Fishermans Potion. Bonus is applied when new Potion is activated. Charges are used each Fishing action.", skills = {'Fishing'}},
	["summoningSynergy_6_7"] = {text = "While fighting a Ranged Enemy, grants {V} Melee Accuracy Bonus and {V} Melee Strength Bonus.", skills = {"Combat", 'Melee'}},
	["summoningSynergy_6_8"] = {text = "While fighting your current Slayer Task, grants {V}% of your Magic Max Hit as Minimum Damage.", skills = {"Combat", 'Magic'}},
	["summoningSynergy_6_12"] = {text = "While fighting your current Slayer Task, grants {V}% of your Melee Max Hit as Minimum Damage.", skills = {"Combat", 'Melee'}},
	["summoningSynergy_6_13"] = {text = "While fighting a Ranged Enemy, grants {V}% Damage Reduction.", skills = {"Combat"}},
	["summoningSynergy_6_14"] = {text = "While using a Melee Weapon, grants {V}% of your Melee Max Hit as Flat HP Regen.", skills = {"Combat", 'Melee', 'Hitpoints'}},
	["summoningSynergy_6_15"] = {text = "If the Enemy is BURNING, effects from the Minotaur Familiar are tripled.", skills = {"Combat", 'Melee'}},
	["summoningSynergy_7_8"] = {text = "While fighting a Magic Enemy, grants {V} Ranged Accuracy Bonus and {V} Ranged Strength Bonus.", skills = {"Combat", 'Ranged'}},
	["summoningSynergy_7_12"] = {text = "While fighting your current Slayer Task, grants {V}% of your Ranged Max Hit as Minimum Damage.", skills = {"Combat", 'Ranged'}},
	["summoningSynergy_7_13"] = {text = "While fighting a Magic Enemy, grants {V}% Damage Reduction.", skills = {"Combat"}},
	["summoningSynergy_7_14"] = {text = "While using a Ranged Weapon, grants {V}% of your Ranged Max Hit as HP Regeneration.", skills = {"Combat", 'Ranged', 'Hitpoints'}},
	["summoningSynergy_7_15"] = {text = "Your Ranged Attacks now have {V}% to inflict BURNING on the Enemy.", skills = {"Combat", 'Ranged'}},
	["summoningSynergy_8_12"] = {text = "Grants Slayer Coins equal to {V}% of your Magic Damage while on Slayer Task.", skills = {'Slayer'}},
	["summoningSynergy_8_13"] = {text = "While fighting a Melee Enemy, grants {V}% Damage Reduction.", skills = {"Combat"}},
	["summoningSynergy_8_14"] = {text = "Grants {V}% of your Max Hit as HP Regeneration if using a Magic Attack Style.", skills = {"Combat", 'Magic', 'Hitpoints'}},
	["summoningSynergy_9_11"] = {text = "The Chef in Thieving now deals no damage to you.", skills = {'Thieving'}},
	["summoningSynergy_9_16"] = {text = "Crafting Recipes that require Dragonhide now use {V} quantity to create. Recipe cost cannot go below 1.", skills = {'Crafting'}, inverseSign = true},
	["summoningSynergy_9_17"] = {text = "{VMS}s Skill Interval for Cooking & Smithing.", inverseSign = true, skills = {'Cooking', 'Smithing'}},
	["summoningSynergy_9_18"] = {text = "Generous Cook Potions now provide {V}% charges. This bonus is applied when a new potion is activated.", skills = {'Cooking'}},
	["summoningSynergy_10_11"] = {text = "Successfully pickpocketting the Miner in Thieving will now grant {V} Rune Essence.", skills = {'Thieving'}},
	["summoningSynergy_10_16"] = {text = "{V}% chance to double when creating Leather, Hard Leather or Dragonhide Armour in Crafting.", skills = {'Crafting'}},
	["summoningSynergy_10_17"] = {text = "{V}% Smithing & Runecrafting Preservation Chance.", skills = {'Smithing', 'Runecrafting'}},
	["summoningSynergy_10_18"] = {text = "While the Elemental Potion is active in Runecrafting, grants a chance to get random Combination Runes. The chance and quantity is equal to that of the Elemental Potion.", skills = {'Runecrafting'}},
	["summoningSynergy_10_19"] = {text = "Grants {V} Fire Runes while creating Elemental Runes.", skills = {'Runecrafting'}},
	["summoningSynergy_11_16"] = {text = "Upon receiving an item in Thieving, grants GP equal to {VX100}% of its sale price.", skills = {'Thieving'}},
	["summoningSynergy_11_17"] = {text = "Upon successfully pickpocketting an item from the Miner in Thieving, {V}% chance to receive a random Bar.", skills = {'Thieving'}},
	["summoningSynergy_11_18"] = {text = "{V}% chance to obtain a single Herb Sack while Thieving the Farmer, on top of the original item obtained.", skills = {'Thieving'}},
	["summoningSynergy_11_19"] = {text = "While Thieving any NPC, 50% chance to grant +100% GP, 35% chance to grant 4x Items, or 15% chance to receive no items or GP at all.", skills = {'Thieving'}},
	["summoningSynergy_12_13"] = {text = "While fighting your current Slayer Task, {V}% Damage Reduction.", skills = {"Combat"}},
	["summoningSynergy_12_14"] = {text = "While fighting your current Slayer Task, {V}% Hitpoints Regeneration.", skills = {"Combat", "Hitpoints"}},
	["summoningSynergy_13_14"] = {text = "{V}% Hitpoints Regeneration if you have less than 75% Current HP.", skills = {"Combat", "Hitpoints"}},
	["summoningSynergy_16_17"] = {text = "{V}% chance to preserve resources in Crafting when creating Rings or Amulets only.", skills = {'Crafting'}},
	["summoningSynergy_16_18"] = {text = "Crafting Potions now last twice as long. Bonus is applied when a new potion is activated. Charges are used per Crafting action.", skills = {'Crafting'}},
	["summoningSynergy_16_19"] = {text = "Burning Logs in Firemaking grants GP equal to {V+100}% of its base sale price.", skills = {'Firemaking'}},
	["summoningSynergy_17_18"] = {text = "While using the Seeing Gold Potion in Smithing, double Silver & Gold Bar output.", skills = {'Smithing'}},
	["summoningSynergy_17_19"] = {text = "{V} Coal required for Smithing Item production.", skills = {'Smithing'}, inverseSign = true},
	["summoningSynergy_18_19"] = {text = "While using the Controlled Heat Potions, +5% Firemaking Skill XP and Bonfire duration is doubled. Charges are used per Firemaking action.", skills = {'Firemaking'}},
	-- New 0.21 modifiers
	["AgilityObstacleCost"] = { text = "{V}% Agility Obstacle Build Costs", skills = {'Agility'}, isIncreaseNegative = true },
	["allowAttackAugmentingMagic"] = { text = "Magic Curses and Auroras can be used without a magic weapon", skills = {'Combat'} },
	["allowSignetDrops"] = { text = "Something else drops instead of Gold Topaz Ring" },
	["aprilFoolsDecreasedCarrotGang"] = { text = "{V} Carrot Gang reputation points", isIncreaseNegative = true, inverseSign = true, skills = {'Combat'} },
	["aprilFoolsDecreasedLemonGang"] = { text = "{V} Lemon Gang reputation points", isIncreaseNegative = true, inverseSign = true, skills = {'Combat'} },
	["aprilFoolsDecreasedMovementSpeed"] = { text = "{V} Movement Speed", isIncreaseNegative = true, inverseSign = true },
	["aprilFoolsDecreasedTeleportCost"] = { text = "{V}% Rune cost for Teleportation Spells", inverseSign = true },
	["aprilFoolsDecreasedUpdateDelay"] = { text = "{V} days next Major Update has been delayed", inverseSign = true },
	["aprilFoolsIncreasedCarrotGang"] = { text = "{V} Carrot Gang reputation points", skills = {'Combat'} },
	["aprilFoolsIncreasedLemonGang"] = { text = "{V} Lemon Gang reputation points", skills = {'Combat'} },
	["aprilFoolsIncreasedMovementSpeed"] = { text = "{V} Movement Speed" },
	["aprilFoolsIncreasedTeleportCost"] = { text = "{V}% Rune cost for Teleportation Spells", isIncreaseNegative = true },
	["aprilFoolsIncreasedUpdateDelay"] = { text = "{V} days next Major Update has been delayed", isIncreaseNegative = true },
	["AttackInterval"] = { text = "{VMS}s Attack Interval", isIncreaseNegative = true, skills = {'Combat'} },
	["autoBurying"] = { text = "Bones are automatically buried for {V+100}% of their prayer point value", unsigned = true, skills = {'Prayer'} },
	["autoLooting"] = { text = "Combat loot is automatically collected", skills = {'Combat'} },
	["bleedImmunity"] = { text = "{V}% chance to ignore bleed", skills = {'Combat'} },
	["BleedLifesteal"] = { text = "{V}% Bleed lifesteal", skills = {'Combat'} },
	["BonusCoalMining"] = { text = "{V} Coal Ore per Ore Mined. (Item doubling does not apply)", skills = {'Mining'} },
	["bonusCoalOnDungeonCompletion"] = { text = "1% chance to receive {V} Coal when completing a dungeon", skills = {'Combat'} },
	["burnImmunity"] = { text = "{V}% chance to ignore burn", skills = {'Combat'} },
	["BurnLifesteal"] = { text = "{V}% Burn lifesteal", skills = {'Combat'} },
	["bypassSlayerItems"] = { text = "Bypass Slayer Area item requirements", skills = {'Slayer'} },
	["ChanceToConvertSeedDrops"] = { text = "{V}% chance to convert combat seed drops to herbs", skills = {'Combat'} },
	["CompostPreservationChance"] = { text = "{V}% Chance to preserve Compost or Weird Gloop applied to Farming Plots when harvesting", skills = {'Farming'} },
	["Confusion"] = { text = "{V}% of remaining Hitpoints taken as damage on a successful attack (once per turn)", isIncreaseNegative = true, skills = {'Combat'} },
	["curseImmunity"] = { text = "Immune to curses", skills = {'Combat'} },
	["DamageReductionPercent"] = { text = "{V}% Damage Reduction", skills = {'Combat'} },
	["DamageTaken"] = { text = "{V}% more Damage taken", isIncreaseNegative = true, skills = {'Combat'} },
	["debuffImmunity"] = { text = "Immune to debuffs", skills = {'Combat'} },
	["Decay"] = { text = "{V}% of Maximum Hitpoints taken as damage on a successful attack (once per turn)", isIncreaseNegative = true, skills = {'Combat'} },
	["doubleItemsSkill"] = { text = "x{VMUL} Items received from {SV0}", unsigned = true },
	["doubleOresMining"] = { text = "x2 Ores received from Mining", unsigned = true, skills = {'Mining'} },
	["DragonBreathDamage"] = { text = "{V}% damage taken from dragonbreath", isIncreaseNegative = true, skills = {'Combat'} },
	["FiremakingCoalChance"] = { text = "{V}% chance to receive coal when burning logs in Firemaking", skills = {'Firemaking'} },
	["FlatMaxHitpoints"] = { text = "{VX} Maximum Hitpoints", skills = {'Hitpoints'} },
	["FlatMinHit"] = { text = "{VX} Minimum Hit", skills = {'Combat'} },
	["FlatReflectDamage"] = { text = "{VX} Reflect Damage", skills = {'Combat'} },
	["freeCompost"] = { text = "Composting crops in Farming is free", skills = {'Farming'} },
	["GlobalEvasion"] = { text = "{V}% Global Evasion", skills = {'Combat'} },
	["golbinRaidIncreasedMaximumAmmo"] = { text = "{V}% Maximum Ammo in Golbin Raid", skills = {'Combat'} },
	["golbinRaidIncreasedMaximumRunes"] = { text = "{V}% Maximum Runes in Golbin Raid", skills = {'Combat'} },
	["golbinRaidIncreasedMinimumFood"] = { text = "{V} Minimum Food in Golbin Raid", skills = {'Combat'} },
	["golbinRaidIncreasedPrayerLevel"] = { text = "{V} Prayer Levels in Golbin Raid", skills = {'Prayer'} },
	["golbinRaidIncreasedPrayerPointsStart"] = { text = "{V} Starting Prayer Points in Golbin Raid", skills = {'Prayer'} },
	["golbinRaidIncreasedPrayerPointsWave"] = { text = "{V} Prayer Points per Wave in Golbin Raid", skills = {'Prayer'} },
	["golbinRaidPassiveSlotUnlocked"] = { text = "Unlocked Passive Slot in Golbin Raid", skills = {'Combat'} },
	["golbinRaidPrayerUnlocked"] = { text = "Unlocked Prayer in Golbin Raid", skills = {'Prayer'} },
	["golbinRaidWaveSkipCostReduction"] = { text = "{V}% Golbin Raid wave Skip Cost", inverseSign = true, skills = {'Combat'} },
	["GPMultiplierCap"] = { text = "{VD}% maximum gp per damage dealt", skills = {'Combat'} },
	["GPMultiplierMin"] = { text = "{VD}% minimum gp per damage dealt", skills = {'Combat'} },
	["GPMultiplierPer1MGP"] = { text = "{VD}% GP per damage dealt for every 1M GP owned", skills = {'Combat'} },
	["itemProtection"] = { text = "Items are not lost on death", skills = {'Combat'} },
	["MagicCritChance"] = { text = "{V}% Magic critical hit chance", skills = {'Magic'} },
	["MagicLifesteal"] = { text = "{V}% Magic lifesteal", skills = {'Magic'} },
	["MagicMaxHit"] = { text = "{V}% Magic Max Hit", skills = {'Magic'} },
	["magicProtection"] = { text = "You have a set {V}% chance to dodge Magic attacks", skills = {'Magic'} },
	["MasteryPoolProgress"] = { text = "{V}% to effective Mastery Pool progress" },
	["MaxAirSpellDmg"] = { text = "{VX} Max Air Spell Dmg", skills = {'Magic'} },
	["MaxEarthSpellDmg"] = { text = "{VX} Max Earth Spell Dmg", skills = {'Magic'} },
	["MaxFireSpellDmg"] = { text = "{VX} Max Fire Spell Dmg", skills = {'Magic'} },
	["MaxWaterSpellDmg"] = { text = "{VX} Max Water Spell Dmg", skills = {'Magic'} },
	["MeleeCritChance"] = { text = "{V}% Melee critical hit chance", skills = {'Combat'} },
	["MeleeLifesteal"] = { text = "{V}% Melee Lifesteal", skills = {'Combat'} },
	["MeleeMaxHit"] = { text = "{V}% Melee Max Hit", skills = {'Combat'} },
	["meleeProtection"] = { text = "You have a set {V}% chance to dodge Melee attacks", skills = {'Combat'} },
	["MeleeStunThreshold"] = { text = "Melee attacks stun the target when they deal {V}% of max hit", skills = {'Combat'} },
	["MiningGemChance"] = { text = "{V}% Chance to receive gems from Mining (Does not work for Rune Essence)", skills = {'Combat'} },
	["OffItemChance"] = { text = "{V}% increased chance to receive an off-item (An item from a skill that is not the main resource you are gathering)" },
	["poisonImmunity"] = { text = "{V}% chance to ignore poison", skills = {'Combat'} },
	["PoisonLifesteal"] = { text = "{V}% Poison lifesteal", skills = {'Combat'} },
	["PrayerCost"] = { text = "{V}% Prayer Point Cost for Prayers (Prayer Point cost cannot go below 1)", isIncreaseNegative = true, skills = {'Prayer'} },
	["RangedCritChance"] = { text = "{V}% Ranged critical hit chance", skills = {'Ranged'} },
	["RangedLifesteal"] = { text = "{V}% Ranged Lifesteal", skills = {'Ranged'} },
	["RangedMaxHit"] = { text = "{V}% Ranged Max Hit", skills = {'Ranged'} },
	["rangedProtection"] = { text = "You have a set {V}% chance to dodge Ranged attacks", skills = {'Ranged'} },
	["RebirthChance"] = { text = "{V}% chance to respawn with full hitpoints upon reaching 0 hitpoints", skills = {'Combat'} },
	["RedemptionPercent"] = { text = "{V}% of max hitpoints healed on redemption", skills = {'Combat'} },
	["RedemptionThreshold"] = { text = "{V}% redemption threshold", skills = {'Combat'} },
	["RolledReflectDamage"] = { text = "{S}0-{VX} Reflect Damage", unsigned = true, skills = {'Combat'} },
	["RuneProvision"] = { text = "Rune providing items provide {VMUL}x as many runes", unsigned = true, skills = {'Combat'} },
	["SecondaryFoodBurnChance"] = { text = "{V}% Secondary Chance to burn food when Cooking", isIncreaseNegative = true, skills = {'Cooking'} },
	["sleepImmunity"] = { text = "Immune to Sleep", skills = {'Combat'} },
	["SmithingCoalCost"] = { text = "{V}% Coal Costs for Smithing", skills = {'Smithing'}, isIncreaseNegative = true },
	["stunImmunity"] = { text = "{V}% chance to ignore Stuns and Freezes", skills = {'Combat'} },
	["summoningSynergy_9_19"] = { text = "" },
	-- 0.22 Modifiers
	["AllotmentSeedCost"] = { text = "{V} seed cost to plant Allotments in Farming", isIncreaseNegative = true, skills = {'Farming'} },
	["AltMagicRunePreservation"] = { text = "{V}% Rune Preservation for Alt. Magic Spells", skills = {'Magic'} },
	["autoEquipFoodUnlocked"] = { text = "Auto Equip Food Unlocked", skills = {'Combat', 'Cooking'} },
	["autoSwapFoodUnlocked"] = { text = "Auto Swap Food Unlocked", skills = {'Combat'} },
	["ChancePerfectCookFire"] = { text = "{V}% Perfect Cook chance for items cooked on Cooking Fire", skills = {'Cooking'} },
	["ChancePerfectCookFurnace"] = { text = "{V}% Perfect Cook chance for items cooked in Furnace", skills = {'Cooking'} },
	["ChancePerfectCookGlobal"] = { text = "{V}% Global Perfect Cook chance.", skills = {'Cooking'} },
	["ChancePerfectCookPot"] = { text = "{V}% Perfect Cook chance for items cooked in Pot", skills = {'Cooking'} },
	["ChanceSuccessfulCook"] = { text = "{V}% chance to successfully Cook an item.", skills = {'Cooking'} },
	["FishingSpecialChance"] = { text = "{V}% chance to receive Special Items from Fishing", skills = {'Fishing'} },
	["Frostburn"] = { text = "{V}% of Current HP taken as damage per Attack", isIncreaseNegative = true, skills = {'Combat'} },
	["masteryToken"] = { text = "Grants Mastery Pool XP equal to {V}% of the maximum Mastery Pool XP for the respective skill",
							 skills = {'Woodcutting', 'Fishing', 'Firemaking', 'Cooking', 'Mining', 'Smithing', 'Thieving', 'Farming',
							 					 'Fletching', 'Crafting', 'Runecrafting', 'Herblore', 'Agility', 'Summoning', 'Astrology'} },
	["MinThievingGP"] = { text = "{V}% minimum GP from Thieving", skills = {'Thieving'} },
	["RunecraftingEssencePreservation"] = { text = "{V}% chance to preserve resources when Runecrafting runes", skills = {'Runecrafting'} },
	["SummoningMaxHit"] = { text = "{V}% Summoning Max Hit", skills = {'Combat'} },
	["ThievingStealth"] = { text = "{V} Stealth while Thieving", skills = {'Thieving'} },
	-- 1.0 Modifiers
	["AfflictionChance"] = { text = "{V}% chance to apply affliction when attacking", skills = {'Combat'} },
	["allowLootContainerStacking"] = { text = "Items other than bones stack within the loot container", skills = {'Combat'} },
	["BaseStardustDropQty"] = { text = "{V} to base drop quantity of Stardust and Golden Stardust from Astrology", skills = {'Astrology'} },
	["BleedReflectChance"] = { text = "{V}% chance to inflict a bleed that does 100% of the attack's damage to attackers when hit", skills = {'Combat'} },
	["ChanceForDiamondFiremaking"] = { text = "{V}% chance to receive a Diamond per action in Firemaking (Cannot be doubled)", skills = {'Firemaking'} },
	["ChanceToApplyFrostburn"] = { text = "{V}% chance to apply Frostburn when attacking", skills = {'Combat'} },
	["ChanceToApplyPoison"] = { text = "{V}% chance to apply Poison when hitting with an attack", skills = {'Combat'} },
	["ChanceToIncreaseStunDuration"] = { text = "{V}% chance to increase the length of stuns inflicted by 1 turn", skills = {'Combat'} },
	["ChanceToPreserveFood"] = { text = "{V}% chance to Preserve Food when eaten", skills = {'Combat'} },
	["ElementalEffectChance"] = { text = "{V}% chance to apply Burn, Frostburn or Freeze when hitting with a Magic attack (once per turn)", skills = {'Combat'} },
	["EndOfTurnHealing2"] = { text = "{V}% of current hitpoints every 2 turns", skills = {'Combat', 'Hitpoints'} },
	["EndOfTurnHealing3"] = { text = "{V}% of current hitpoints every 3 turns", skills = {'Combat', 'Hitpoints'} },
	["EndOfTurnHealing5"] = { text = "{V}% of current hitpoints every 5 turns", skills = {'Combat', 'Hitpoints'} },
	["freeProtectItem"] = { text = "The Protect Item Prayer costs nothing", skills = {'Prayer'} },
	["frostBurnImmunity"] = { text = "{V}% chance to ignore Frostburn", skills = {'Combat'} },
	["globalEvasionHPScaling"] = { text = "Evasion Ratings are multiplied by {V} times current Hitpoints percent", skills = {'Combat'} },
	["GPFromFiremaking"] = { text = "{V}% GP from Firemaking.", skills = {'Firemaking'} },
	["infiniteLootContainer"] = { text = "The loot container has an infinite amount of slots", skills = {'Combat'} },
	["magicImmunity"] = { text = "Immune to Magic attacks", skills = {'Combat'} },
	["meleeImmunity"] = { text = "Immune to Melee attacks", skills = {'Combat'} },
	["MeleeStunChance"] = { text = "{V}% chance to stun when hitting with a Melee attack (once per turn)", skills = {'Combat'} },
	["MinNatureSpellDamageBasedOnMaxHit"] = { text = "{V}% of Maximum Hit added to Minimum Hit when using Nature spells", skills = {'Combat'} },
	["NonMagicPoisonChance"] = { text = "{V}% chance to apply poison when hitting with a Melee or Ranged attack", skills = {'Combat'} },
	["OnHitSlowMagnitude"] = { text = "Inflict a slow that increases the target's attack interval by {V}% when hitting with an attack", skills = {'Combat'} },
	["otherStyleImmunity"] = { text = "Immune to all attack types other than their own", skills = {'Combat'} },
	["PoisonReflectChance"] = { text = "{V}% chance to poison attackers when hit", skills = {'Combat'} },
	["rangedImmunity"] = { text = "Immune to Ranged attacks", skills = {'Combat'} },
	["RegenerationInterval"] = { text = "{VMS}s Hitpoint Regeneration interval", isIncreaseNegative = true, skills = {'Combat', 'Hitpoints'} },
	["slowImmunity"] = { text = "{V}% chance to ignore Slow effects", skills = {'Combat'} },
	["SurgeSpellAccuracy"] = { text = "{V}% Accuracy Rating when using Surge spells", skills = {'Combat'} },
	["SurgeSpellMaxHit"] = { text = "{V}% Max Hit when using Surge spells", skills = {'Combat'} },
	["TotalBleedDamage"] = { text = "{VX} total damage to bleeds inflicted", skills = {'Combat'} },
	-- The below are not present in 1.0 but are left here for now until everything is fully-migrated to 1.0
	["CombatStoppingThreshold"] = { text = "{V}% automatic combat stopping threshold", skills = {'Combat'} },
	["MagicCritMult"] = { text = "{V}% Magic critical hit multiplier", skills = {'Magic'} },
	["MeleeCritMult"] = { text = "{V}% Melee critical hit multiplier", skills = {'Combat'} },
	["RangedCritMult"] = { text = "{V}% Ranged critical hit multiplier", skills = {'Ranged'} },
	-- New 1.1 modifiers
	["15SlowStunChance2Turns"] = { text = "{V}% chance to apply a 15% Slow for 2 Attack Turns when hitting with any attack (once per turn)", skills = {'Combat'} },
	["30Slow5TurnsChance"] = { text = "{V}% chance to inflict a Slow that increases the target's attack interval by 30% for 5 target turns when hitting with an attack", skills = {'Combat'} },
	["5DROnBeingHit"] = { text = "When hit by an Enemy, gain +5% Damage Reduction for 1 Enemy Turn (Does not Stack)", skills = {'Combat'} },
	["AbsorbingSkin"] = { text = "Target gains +3% Damage Reduction for every successful hit by the Attacker (Stacks up to 10 times)", skills = {'Combat'} },
	["AdditionalAshInFiremaking"] = { text = "{V} Ash per burn in Firemaking (Cannot be doubled)", isIncreaseNegative = true, skills = {'Firemaking'} },
	["AgilityPillarCost"] = { text = "{V}% Agility Pillar build costs", isIncreaseNegative = true, skills = {'Agility'} },
	["allowNonMagicCurses"] = { text = "Magic Curses can be used without a Magic weapon", skills = {'Combat'} },
	["applyDespairCurseOnSpawn"] = { text = "Apply Despair Curse to the Target on spawn or revive", skills = {'Combat'} },
	["applyMadnessCurseOnSpawn"] = { text = "Apply Madness Curse to the Target on spawn or revive", skills = {'Combat'} },
	["applyRandomCurseOnSpawn"] = { text = "Apply a random Curse to the Target on spawn or revive", skills = {'Combat'} },
	["applyTormentCurseOnSpawn"] = { text = "Apply Torment Curse to the Target on spawn or revive", skills = {'Combat'} },
	["Assassin"] = { text = "When Target is hit, Attacker gains a stack of Assassin: +30% Global Accuracy (Stacks up to 5 times and resets after 5 Attack Turns)", skills = {'Combat'} },
	["bigRon"] = { text = "Big Ol Ron is active", skills = {'Combat'} },
	["BleedDOTDamage"] = { text = "{V}% Damage taken from Bleeds", skills = {'Combat'} },
	["BoltProduction"] = { text = "{V} Bolts produced per action in Fletching", skills = {'Fletching'} },
	["BonusFishingSpecialChance"] = { text = "{V}% Special Item chance in Fishing", skills = {'Fishing'} },
	["BurnDOTDamage"] = { text = "{V}% Damage taken from Burns", skills = {'Combat'} },
	["bypassAllSlayerItems"] = { text = "Bypass All Slayer Area item requirements", skills = {'Combat'} },
	["ChanceAdditionalBarSmithing"] = { text = "{V}% Chance to gain +1 additional bar in Smithing (Cannot be doubled)", skills = {'Smithing'} },
	["ChanceAdditionalPerfectItem"] = { text = "{V}% chance to receive an additional Perfect Item from Cooking (Cannot be doubled)", skills = {'Cooking'} },
	["ChanceDarkBlade"] = { text = "{V}% chance to apply Dark Blade Effect (+1% Max Hit) to the Attacker per successful hit (Stacks up to 30 times)", skills = {'Combat'} },
	["ChanceDoubleSlayerTaskKill"] = { text = "{V}% chance for a Slayer Task kill to count as 2 kills (Rewards Slayer Coins for 2nd kill, but not Slayer XP)", skills = {'Combat'} },
	["ChanceExtraArrows"] = { text = "{V}% chance for +5 Arrows produced per action in Fletching (Cannot be doubled)", skills = {'Fletching'} },
	["ChanceExtraCrossbows"] = { text = "{V}% chance for +1 Crossbow produced per action in Fletching (Cannot be doubled)", skills = {'Fletching'} },
	["ChanceExtraJavelins"] = { text = "{V}% chance for +3 Javelins produced per action in Fletching (Cannot be doubled)", skills = {'Fletching'} },
	["ChanceExtraMeteoriteOre"] = { text = "{V}% chance for +1 Meteorite Ore in Mining (Cannot be doubled)", skills = {'Mining'} },
	["ChanceExtraUnstrungBows"] = { text = "{V}% chance for +2 Unstrung Bows produced per action in Fletching (Cannot be doubled)", skills = {'Fletching'} },
	["ChanceForArrowShaftsWoodcutting"] = { text = "{V}% chance to gain Arrow Shafts when cutting Trees (Cannot be Doubled)", skills = {'Fletching', 'Woodcutting'} },
	["ChanceForAshInFiremaking"] = { text = "{V}% chance to receive Ash per burn in Firemaking", skills = {'Firemaking'} },
	["ChanceForAshInWoodcutting"] = { text = "{V}% chance to receive an Ash drop while Woodcutting", skills = {'Woodcutting'} },
	["ChanceForCharcoalInFiremaking"] = { text = "{V}% chance to receive Charcoal per burn in Firemaking", skills = {'Firemaking'} },
	["ChanceForOneExtraFish"] = { text = "{V}% chance to receive +1 Fish in Fishing (Cannot be doubled)", skills = {'Fishing'} },
	["ChanceForOneExtraOre"] = { text = "{V}% chance to receive +1 Ore in Mining (Cannot be doubled)", skills = {'Mining'} },
	["ChanceForQualitySuperiorGem"] = { text = "{V}% chance to receive a Quality Superior Gem while Mining Gem Veins or Meteorite Ore", skills = {'Mining'} },
	["ChanceForStardustInFiremaking"] = { text = "{V}% chance to receive Stardust when burning Magic Logs in Firemaking", skills = {'Firemaking'} },
	["ChanceGoldenStardust"] = { text = "{V}% chance to locate Golden Stardust in Astrology", skills = {'Astrology'} },
	["ChanceItemToGoldFletching"] = { text = "{V}% chance for Items produced in Fletching to be converted to GP equal to 150% Base Sale price", skills = {'Fletching'} },
	["ChanceStardust"] = { text = "{V}% chance to locate Stardust in Astrology", skills = {'Astrology'} },
	["ChanceStardustCuttingMagicLogs"] = { text = "{V}% chance to receive Stardust when cutting Magic Logs in Woodcutting (Quantity equal to Logs received)", skills = {'Woodcutting'} },
	["ChanceToApplyBurnWithRanged"] = { text = "{V}% chance to apply burn when attacking with Ranged", skills = {'Combat'} },
	["ChanceToApplyDeadlyPoison"] = { text = "{V}% chance to apply Deadly Poison to the Target", skills = {'Combat'} },
	["ChanceToApplyDeadlyPoisonWhenPoisoned"] = { text = "If target is poisoned, {V}% chance to apply deadly poison when hitting with an attack", skills = {'Combat'} },
	["ChanceToApplyDecayCurse"] = { text = "{V}% to apply Decay Curse to the Target per hit", skills = {'Combat'} },
	["ChanceToApplyShock"] = { text = "{V}% chance to reduce Target Damage Reduction by 1% per successful hit. Stacks up to 20 times", skills = {'Combat'} },
	["ChanceToApplySleepToTargetWhenHit"] = { text = "When hit, {V}% chance to apply Sleep to the Target for 1 turn", skills = {'Combat'} },
	["ChanceToAvoidCurses"] = { text = "{V}% chance to avoid Curses", skills = {'Combat'} },
	["ChanceToAvoidSleep"] = { text = "{V}% chance to avoid Sleep", skills = {'Combat'} },
	["ChanceToAvoidStun"] = { text = "{V}% chance to avoid being Stunned", skills = {'Combat'} },
	["ChanceToAvoidThievingStuns"] = { text = "{V}% chance to avoid the stun interval and stun damage in Thieving when pickpocket attempt fails", skills = {'Thieving'} },
	["ChanceToDoubleLeatherDragonhideCrafting"] = { text = "{V}% chance to double items in Crafting when making Leather or Dragonhide armour", skills = {'Crafting'} },
	["ChanceToFindLostChest"] = { text = "{V}% chance to find a Lost Chest while Fishing (This is separate to the Special Fishing Chance)", skills = {'Fishing'} },
	["ChanceToFindMeteorite"] = { text = "{V}% chance to locate a Meteorite in Astrology", skills = {'Astrology'} },
	["ChanceToFindMushroomWoodcutting"] = { text = "{V}% chance to find a Mushroom in Woodcutting (Cannot be doubled)", skills = {'Woodcutting'} },
	["ChanceToIncreaseSleepDuration"] = { text = "{V}% chance for Sleep applied to the Enemy to last an extra 1 Attack Turn", skills = {'Combat'} },
	["ChanceToPreserveConsumable"] = { text = "{V}% chance to preserve Consumable Slot charges" },
	["coalGainedOnCookingFailure"] = { text = "{V} Coal Ore when failing to Cook Food", skills = {'Cooking'} },
	["CookingSuccessCap"] = { text = "{V}% Cooking success chance cap", skills = {'Cooking'} },
	["CraftingJewelryPreservation"] = { text = "{V}% chance to preserve resources in Crafting when making jewelry", skills = {'Crafting'} },
	["CraftingJewelryRandomGemChance"] = { text = "{V}% chance to gain a random gem when creating jewelry in Crafting", skills = {'Crafting'} },
	["CraftingPotionCharges"] = { text = "{V}% Crafting Potion charges", skills = {'Crafting'} },
	["CurseLifesteal"] = { text = "{V}% Lifesteal if target is Cursed", skills = {'Combat'} },
	["CyclopsCreationCharges"] = { text = "{V} Base Quantity for Cyclops Tablet Creation in Summoning", skills = {'Summoning'} },
	["DamageDealtIfPoisoned"] = { text = "{V}% damage dealt if target is poisoned", isIncreaseNegative = true, skills = {'Combat'} },
	["DamageReductionAgainstBosses"] = { text = "{V}% Damage Reduction when fighting a Dungeon Boss", skills = {'Combat'} },
	["DamageReductionAgainstMagic"] = { text = "{V}% Damage Reduction when fighting a Magic Enemy", skills = {'Combat'} },
	["DamageReductionAgainstMelee"] = { text = "{V}% Damage Reduction when fighting a Melee Enemy", skills = {'Combat'} },
	["DamageReductionAgainstRanged"] = { text = "{V}% Damage Reduction when fighting a Ranged Enemy", skills = {'Combat'} },
	["DamageReductionAgainstSlayerTasks"] = { text = "{V}% Damage Reduction when fighting a Slayer Task monster", skills = {'Combat'} },
	["DamageReductionWithMagic2HWeapon"] = { text = "{V}% Damage Reduction when using a Magic 2-Handed Weapon", skills = {'Combat'} },
	["DamageTakenAddedAsPrayerPoints"] = { text = "{VD}% of all damage taken is added as Prayer Points (Rounded down)", skills = {'Combat'} },
	["DamageTakenPerAttack"] = { text = "{V}% of Current HP taken as damage per Attack", isIncreaseNegative = true, skills = {'Combat'} },
	["DamageTakenWhenAsleep"] = { text = "{V}% damage taken when asleep", isIncreaseNegative = true, skills = {'Combat'} },
	["DamageTakenWhenStunned"] = { text = "{V}% damage taken when stunned", isIncreaseNegative = true, skills = {'Combat'} },
	["DeadlyPoisonDOTDamage"] = { text = "{V}% Damage taken from Deadly Poison", skills = {'Combat'} },
	["DeadlyToxinsFromHerblore"] = { text = "When creating Lethal Toxins Potions in Herblore, gain +${value} Deadly Toxins Potion(s) as an additional Potion (Cannot be doubled)", skills = {'Herblore'} },
	["decreaseEnemyEvasionOnSleep"] = { text = "When a Sleep is applied to the Target, -10% Global Evasion Rating for the remainder of the fight (Stacks up to 3 times)", skills = {'Combat'} },
	["decreaseEnemyEvasionOnStun"] = { text = "When a Stun is applied to the Target, -10% Global Evasion Rating for the remainder of the fight (Stacks up to 3 times)", skills = {'Combat'} },
	["disableGoldenStardustDrops"] = { text = "No longer receive Golden Stardust from Astrology", isIncreaseNegative = true, skills = {'Astrology'} },
	["disableHPRegeneration"] = { text = "Passive Hitpoint Regeneration is disabled", isIncreaseNegative = true, skills = {'Combat', 'Hitpoints'} },
	["disableLifesteal"] = { text = "Disables all sources of Lifesteal", isIncreaseNegative = true, skills = {'Combat'} },
	["disableSalamanderItemReduction"] = { text = "Item Cost reduction is disabled when making Salamander Tablets in Summoning (Excludes Shard Cost)", isIncreaseNegative = true, skills = {'Summoning'} },
	["doubleBoneDrops"] = { text = "All Bone drops from Combat are doubled", skills = {'Combat'} },
	["doubleLifesteal"] = { text = "Doubles the Attacker Lifesteal percent", skills = {'Combat'} },
	["doubleLogProduction"] = { text = "Quantity of logs produced by Woodcutting is doubled", skills = {'Woodcutting'} },
	["doubleRuneEssenceMining"] = { text = "x{VMUL} Rune Essence received from Mining", unsigned=true, skills = {'Mining'} },
	["doubleSilverGoldMining"] = { text = "x{VMUL} Gold and Silver Ore recieved from Mining", unsigned=true, skills = {'Mining'} },
	["doubleSilverGoldSmithingWithSeeingGold"] = { text = "x2 Silver and Gold bars recieved from Smithing when using Seeing Gold Potions", skills = {'Smithing'} },
	["Duality"] = { text = "For each Target Attack Turn: 50% chance for the Target to apply -50% Attack Interval to itself for 2 turns", skills = {'Combat'} },
	["EndOfTurnEvasion2"] = { text = "Gains up to {V}% Global Evasion Rating every 2 turns (Lasts 2 turns)", skills = {'Combat'} },
	["EndOfTurnMaxHealing2"] = { text = "Heal {V}% of max hitpoints every 2 turns", skills = {'Combat', 'Hitpoints'} },
	["EnemyDamageReduction"] = { text = "Enemy Damage Reduction is decreased by flat {V}%", isIncreaseNegative = true, skills = {'Combat'} },
	["EvasionAgainstMagic"] = { text = "{V}% Global Evasion against Magic targets", skills = {'Combat'} },
	["EvasionAgainstMelee"] = { text = "{V}% Global Evasion against Melee targets", skills = {'Combat'} },
	["EvasionAgainstRanged"] = { text = "{V}% Global Evasion against Ranged targets", skills = {'Combat'} },
	["EvasionBasedOnDR"] = { text = "{V}% Global Evasion Rating for every 2% base Damage Reduction", skills = {'Combat'} },
	["FiremakingLogGP"] = { text = "{V}% of Log base sale price granted as GP when Burnt in Firemaking", skills = {'Firemaking'} },
	["FireRunesWhenMakingElementalRunes"] = { text = "{V} Fire Runes gained when Runecrafting elemental runes", skills = {'Runecrafting'} },
	["FishermansPotionCharges"] = { text = "{V}% Fisherman's Potion charges", skills = {'Fishing'} },
	["FishingCookedChance"] = { text = "{V}% chance to gain 1 cooked version of a fish when Fishing", skills = {'Fishing'} },
	["FlatBlockAttackBonus"] = { text = "{V} Block Attack Bonus", skills = {'Combat'} },
	["FlatCraftingDragonhideCost"] = { text = "{V} Dragonhide costs when Crafting (Cannot be reduced below 1)", isIncreaseNegative = true, skills = {'Crafting'} },
	["FlatFarmingYield"] = { text = "{V} harvest quantity from Farming (Cannot be doubled or multiplied)", skills = {'Farming'} },
	["FlatHPRegenBasedOnMagicMaxHit"] = { text = "{V}% of Magic max hit as flat hitpoints regeneration", skills = {'Combat', 'Hitpoints'} },
	["FlatHPRegenBasedOnMeleeMaxHit"] = { text = "{V}% of Melee max hit as flat hitpoint regeneration", skills = {'Combat', 'Hitpoints'} },
	["FlatHPRegenBasedOnRangedMaxHit"] = { text = "{V}% of Ranged max hit as flat hitpoints regeneration", skills = {'Combat', 'Hitpoints'} },
	["FlatMagicAccuracyBonusPerAttackInterval"] = { text = "{V} Flat Magic Accuracy Bonus per 0.1s Attack Interval. This is doubled if a 2-Handed Weapon is currently equipped", skills = {'Combat'} },
	["FlatMagicAttackBonus"] = { text = "{V} Magic Attack Bonus", skills = {'Combat'} },
	["FlatMagicDefenceBonus"] = { text = "{V} Magic Defence Bonus", skills = {'Combat'} },
	["FlatMeleeAccuracyBonusPerAttackInterval"] = { text = "{V} Flat Melee Accuracy Bonus per 0.1s Attack Interval. This is doubled if a 2-Handed Weapon is currently equipped", skills = {'Combat'} },
	["FlatMeleeDefenceBonus"] = { text = "{V} Melee Defence Bonus", skills = {'Combat'} },
	["FlatMeleeStrengthBonus"] = { text = "{V} Melee Strength Bonus", skills = {'Combat'} },
	["FlatMeleeStrengthBonusPerAttackInterval"] = { text = "{V} Flat Melee Strength Bonus per 0.1s Attack Interval. This is doubled if a 2-Handed Weapon is currently equipped", skills = {'Combat'} },
	["FlatRangedAccuracyBonusPerAttackInterval"] = { text = "{V} Flat Ranged Accuracy Bonus per 0.1s Attack Interval. This is doubled if a 2-Handed Weapon is currently equipped", skills = {'Combat'} },
	["FlatRangedAttackBonus"] = { text = "{V} Ranged Attack Bonus", skills = {'Combat'} },
	["FlatRangedDefenceBonus"] = { text = "{V} Ranged Defence Bonus", skills = {'Combat'} },
	["FlatRangedStrengthBonus"] = { text = "{V} Ranged Strength Bonus", skills = {'Combat'} },
	["FlatRangedStrengthBonusPerAttackInterval"] = { text = "{V} Flat Ranged Strength Bonus per 0.1s Attack Interval. This is doubled if a 2-Handed Weapon is currently equipped", skills = {'Combat'} },
	["FlatSlashAttackBonus"] = { text = "{V} Slash Attack Bonus", skills = {'Combat'} },
	["FlatSmithingCoalCost"] = { text = "{V} Coal Ore Cost when Smithing", isIncreaseNegative = true, skills = {'Smithing'} },
	["FlatStabAttackBonus"] = { text = "{V} Stab Attack Bonus", skills = {'Combat'} },
	["FletchingBoltQuantity"] = { text = "{V} Base Quantity when creating Bolts in Fletching", skills = {'Fletching'} },
	["FletchingIntervalWithArrows"] = { text = "{VMS}s Fletching Interval when making Arrows", isIncreaseNegative = true, skills = {'Fletching'} },
	["freezeImmunity"] = { text = "{V}% chance to ignore Freezes only", inverseSign = true, skills = {'Combat'} },
	["gainSlayerCoinsBasedOnEnemyCombatLevelMagic"] = { text = "Killing a Magic Slayer Task Enemy grants Slayer Coins equal to Enemy Combat Level", skills = {'Combat'} },
	["gainSlayerCoinsBasedOnEnemyCombatLevelMelee"] = { text = "Killing a Melee Slayer Task Enemy grants Slayer Coins equal to Enemy Combat Level", skills = {'Combat'} },
	["gainSlayerCoinsBasedOnEnemyCombatLevelRanged"] = { text = "Killing a Ranged Slayer Task Enemy grants Slayer Coins equal to Enemy Combat Level", skills = {'Combat'} },
	["GemVeinChance"] = { text = "{V}% Chance to find gem veins when Mining", skills = {'Mining'} },
	["GenerousCookPotionCharges"] = { text = "{V}% Generous Cook Potion charges", skills = {'Cooking'} },
	["giveRandomComboRunesRunecrafting"] = { text = "Gain a chance to receive random combination runes when recieving random elemental runes equal to the chance to receive random elemental runes from Runecrafting", skills = {'Runecrafting'} },
	["globalAccuracyHPScaling"] = { text = "Accuracy Ratings are multiplied by {V} times current Hitpoints percent", unsigned = true, skills = {'Combat'} },
	["GlobalSkillIntervalPercent"] = { text = "{V}% Interval for all Non-Combat Skills", isIncreaseNegative = true },
	["GlobalSleepChance"] = { text = "{V}% chance to apply Sleep when hitting with any attack (once per turn)", skills = {'Combat'} },
	["GlobalStunChance"] = { text = "{V}% chance to apply a Stun for 1 Attack Turn when hitting with any attack (once per turn)", skills = {'Combat'} },
	["GPBasedOnEnemyCombatLevel"] = { text = "{V}% GP gained per Attack Turn equal to the Enemy Combat Level", skills = {'Combat'} },
	["GPBasedOnSummonDamage"] = { text = "{V}% of damage dealt by Summoning Familiars gained as GP", skills = {'Combat'} },
	["GPFromAgilityPerActiveObstacle"] = { text = "{V}% GP from Agility per active Obstacle", skills = {'Agility'} },
	["GPFromBurningMonsters"] = { text = "{V}% GP from burning Monsters", skills = {'Combat'} },
	["GPFromItemAlchemy"] = { text = "{VX100}% Item Alchemy Item sale price conversion" },
	["GPFromMonstersFlatBasedOnEvasion"] = { text = "{V}% of enemy's highest evasion rating as GP on kill", skills = {'Combat'} },
	["GPFromNegativeObstacles"] = { text = "{V}% GP from Agility Obstacles that contain a negative modifier", skills = {'Agility'} },
	["GPFromSlayerTaskMonsters"] = { text = "{V}% GP from Slayer Task monsters", skills = {'Combat'} },
	["GPOnRegenBasedOnHPGain"] = { text = "{VD}% of passively regenerated health gained as GP", skills = {'Combat'} },
	["GPPerDamage"] = { text = "{VD}% of damage dealt gained as GP", skills = {'Combat'} },
	["GPPerMagicDamage"] = { text = "{VD}% of magic damage dealt gained as GP", skills = {'Combat'} },
	["GPPerMeleeDamage"] = { text = "{VD}% of melee damage dealt gained as GP", skills = {'Combat'} },
	["GPPerRangedDamage"] = { text = "{VD}% of ranged damage dealt gained as GP", skills = {'Combat'} },
	["GPWhenHitBasedOnDR"] = { text = "{V} GP gained per your damage reduction when hit by an enemy (Procs once per Enemy Attack Turn)", skills = {'Combat'} },
	["growingMadnessPassive"] = { text = "For every Enemy Attack Turn, the Enemy gains -2% Attack Interval, +2% Maximum Hit (Stacks 25 times)", isIncreaseNegative = true, skills = {'Combat'} },
	["halveDamageReduction"] = { text = "Damage Reduction is halved (Floored)", isIncreaseNegative = true, skills = {'Combat'} },
	["halvedWoodcuttingDoubleChance"] = { text = "Chance to double Logs while Woodcutting is halved", isIncreaseNegative = true , skills = {'Woodcutting'}},
	["HealingOnAttackBasedOnDR"] = { text = "Heal for {VX}% of your damage reduction on attacking an enemy (once per turn)", skills = {'Combat', 'Hitpoints'} },
	["healOnHitBasedOnTargetDR"] = { text = "Heal for {VX}% of the Target's base Damage Reduction on a successful attack (once per turn)", skills = {'Combat', 'Hitpoints'} },
	["HealWhenSleep"] = { text = "When Sleep is applied to you, heal for {V}% of your Max HP", skills = {'Combat', 'Hitpoints'} },
	["HealWhenStunned"] = { text = "When a stun is applied to you, heal for {V}% of your Max HP", skills = {'Combat', 'Hitpoints'} },
	["HerbSackChanceThievingFarmer"] = { text = "{V}% chance to receive a Herb Sack when gaining a Common Drop from Thieving the Farmer", skills = {'Thieving'} },
	["HitpointRegenerationAgainstSlayerTasks"] = { text = "{V}% Hitpoint Regeneration when fighting Slayer Task monsters", skills = {'Combat', 'Hitpoints'} },
	["HPRegenWhenEnemyHasMoreEvasion"] = { text = "{V}% hitpoint regeneration when the enemy has more combined evasion ratings than the player", skills = {'Combat', 'Hitpoints'} },
	["InfernalSpellAccuracy"] = { text = "{V}% Accuracy Rating when using Archaic Spells that use Infernal Runes", skills = {'Combat', 'Magic'} },
	["JavelinProduction"] = { text = "{V} base Javelins produced per action in Fletching", skills = {'Fletching'} },
	["JavelinResourceCost"] = { text = "{V}% Resource Cost for Javelins in Fletching", isIncreaseNegative = true, skills = {'Fletching'} },
	["LeprechaunCreationCharges"] = { text = "{V} Base Quantity for Leprechaun Tablet Creation in Summoning", skills = {'Summoning'} },
	["Leviathan"] = { text = "When hit, gain a stack of Leviathan: +5% Reflect Damage and +1% Damage Reduction (Stacks up to 5 times)", skills = {'Combat'} },
	["LifestealBasedOnHPRegenEffectiveness"] = { text = "Increased Lifesteal based on {V}% * Current HP Regen Effectiveness (Eg. 5% * 300 = +15% Lifesteal)", skills = {'Combat'} },
	["LightningSpellAccuracy"] = { text = "{V}% Accuracy Rating when using Archaic Spells that use Lightning Runes", skills = {'Combat', 'Magic'} },
	["MagicMaxHitBonusAgainstMelee"] = { text = "{V}% Magic Max Hit. This value is tripled if fighting a Melee Enemy", skills = {'Combat'} },
	["MagicMaxHitFlat"] = { text = "{V} Flat Magic Maximum Hit", skills = {'Combat', 'Strength'} },
	["MagicMinHitBasedOnMaxHitSlayerTask"] = { text = "{V}% of Magic Maximum Hit added to Minimum Hit when fighting Slayer Task monsters", skills = {'Combat'} },
	["MasteryPoolCap"] = { text = "{V}% Mastery Pool XP Cap" },
	["MasteryXPFromNegativeObstacles"] = { text = "{V}% Agility Mastery XP from Obstacles that contain a negative modifier", skills = {'Agility'} },
	["MaxHitPercentBasedOnDamageReduction"] = { text = "{V}% Max Hit for each 1% of Damage Reduction", skills = {'Combat'} },
	["MaxHitPercentBasedOnEnemyDamageReduction"] = { text = "{V}% Max Hit for each 1% of Damage Reduction the Enemy has", skills = {'Combat'} },
	["MaxHPBurnDamage"] = { text = "Burns to the Target deal {V}% Max HP as extra damage", skills = {'Combat'} },
	["MeleeMaxHitBasedOnMaxHitSlayerTask"] = { text = "{V}% of Melee Maximum Hit added to Minimum Hit when fighting Slayer Task monsters", skills = {'Combat'} },
	["MeleeMaxHitBonusAgainstRanged"] = { text = "{V}% Melee Max Hit. This value is tripled if fighting a Ranged Enemy", skills = {'Combat'} },
	["MeleeMaxHitFlat"] = { text = "{V} Flat Melee Maximum Hit", skills = {'Combat', 'Strength'} },
	["MeleeRangedDefenceBonusBasedOnDR"] = { text = "Gain Melee and Ranged Defence Bonus equal to damage reduction. (e.g. 50% damage reduction grants +50 melee and ranged defence bonus)", skills = {'Combat'} },
	["MeteoriteOre"] = { text = "{V} Meteorite Ore gained when Mining Meteorite Veins", skills = {'Mining'} },
	["MinBirdNestQuantity"] = { text = "{V} minimum Bird Nest's recieved from Woodcutting", skills = {'Woodcutting'} },
	["MinimumBirdNestsWhenPotionActive"] = { text = "{V} minimum Bird Nests recieved from Woodcutting when the Bird Nest Potion is active", skills = {'Woodcutting'} },
	["MinInfernalArchaicDmg"] = { text = "{V} Minimum Damage for Archaic Spells that use Infernal Runes", skills = {'Combat', 'Magic'} },
	["MiningBarChance"] = { text = "{V}% chance to recieve the bar version of an ore when Mining", skills = {'Mining'} },
	["MiningNodeHPWithPerfectSwing"] = { text = "{V} Mining node HP when using Perfect Swing Potions", skills = {'Mining'} },
	["MinLightningArchaicDmg"] = { text = "{V} Minimum Damage for Archaic Spells that use Lightning Runes", skills = {'Combat', 'Magic'} },
	["MinMeteorShowerSpellDamage"] = { text = "{V} minimum Spell damage when using the Meteor Shower Archaic Spell", skills = {'Combat'} },
	["MinPoisonArchaicDmg"] = { text = "{V} Minimum Damage for Archaic Spells that use Poison Runes", skills = {'Combat', 'Magic'} },
	["momentInTimePassive"] = { text = "For every Enemy Attack Turn, the Enemy gains -2% Attack Interval, +2% Maximum Hit, +2% Global Accuracy (Stacks 25 times)", isIncreaseNegative = true, skills = {'Combat'} },
	["NonCombatSkillXP"] = { text = "{V}% Non-Combat Skill XP" },
	["NonShardCostForEquippedTablets"] = { text = "{V}% Item creation cost for equipped Summoning Tablets (Excludes Shard Cost)", isIncreaseNegative = true, skills = {'Summoning'} },
	["PassiveCookInterval"] = { text = "{V}% Passive Cook Interval", isIncreaseNegative = true, skills = {'Cooking'} },
	["PlayerDamageReduction"] = { text = "Reduce Player damage reduction by {V}%", isIncreaseNegative = true, skills = {'Combat'} },
	["PlayerRage"] = { text = "When hit, gain a stack of Rage: +2% Max Hit and -2% Attack Interval (Stacks up to 10 times)", skills = {'Combat'} },
	["PoisonDOTDamage"] = { text = "{V}% Damage taken from Poison", skills = {'Combat'} },
	["PoisonSpellAccuracy"] = { text = "{V}% Accuracy Rating when using Archaic Spells that use Poison Runes", skills = {'Combat', 'Magic'} },
	["PrayerPointsWhenHit"] = { text = "Gain {V} Prayer Points for each successful Enemy hit on you", skills = {'Combat'} },
	["Rage"] = { text = "When Target is hit, Attacker gains a stack of Rage: +2% Max Hit and -2% Attack Interval (Stacks up to 10 times)" },
	["RandomBarChanceThievingMiner"] = { text = "{V}% chance to receive a random bar when gaining a Common Drop from Thieving the Miner", skills = {'Thieving'} },
	["RangedMaxHitBasedOnMaxHitSlayerTask"] = { text = "{V}% of Ranged Maximum Hit added to Minimum Hit when fighting Slayer Task monsters", skills = {'Combat'} },
	["RangedMaxHitBonusAgainstMagic"] = { text = "{V}% Ranged Max Hit. This value is tripled if fighting a Magic Enemy", skills = {'Combat'} },
	["RangedMaxHitFlat"] = { text = "{V} Flat Ranged Maximum Hit", skills = {'Combat', 'Strength'} },
	["reducedTargetDamageRedcutionIfBleeding"] = { text = "While Target is Bleeding, reduce their Damage Reduction by {V}%", skills = {'Combat'} },
	["reignOverTimePassive"] = { text = "For every Enemy Attack Turn, Enemy gains -2% Attack Interval, +2% Maximum Hit, +2% Global Accuracy, +2% Global Evasion Rating (Stacks 25 times)", isIncreaseNegative = true, skills = {'Combat'} },
	["RunecraftingStavePreservation"] = { text = "{V}% chance to preserve resources in Runecrafting when making staves", skills = {'Runecrafting'} },
	["RunecraftingWaterComboRunes"] = { text = "{V} base quantity when creating Combination runes that require Water Runes in Runecrafting", skills = {'Runecrafting'} },
	["RuneEssenceThievingMiner"] = { text = "{V} Rune Essence gained when Thieving the Miner", skills = {'Thieving'} },
	["SalamanderCreationCharges"] = { text = "{V}% Salamander Tablets made in Summoning", skills = {'Summoning'} },
	["SCfromLifesteal"] = { text = "{VD}% of lifesteal healing gained as Slayer Coins", skills = {'Combat'} },
	["shadowCloak"] = { text = "", skills = {'Combat'} },
	["SkillMasteryXPPerAmeria"] = { text = "{V}% {SV0} Mastery XP per maxed Star in Ameria constellation in Astrology", isSkill = true },
	["SkillMasteryXPPerArachi"] = { text = "{V}% {SV0} Mastery XP per maxed Star in Arachi constellation in Astrology", isSkill = true },
	["SkillMasteryXPPerDeedree"] = { text = "{V}% {SV0} Mastery XP per maxed Star in Deedree constellation in Astrology", isSkill = true },
	["SkillMasteryXPPerHyden"] = { text = "{V}% {SV0} Mastery XP per maxed Star in Hyden constellation in Astrology", isSkill = true },
	["SkillMasteryXPPerIridan"] = { text = "{V}% {SV0} Mastery XP per maxed Star in Iridan constellation in Astrology", isSkill = true },
	["SkillMasteryXPPerKo"] = { text = "{V}% {SV0} Mastery XP per maxed Star in Ko constellation in Astrology", isSkill = true },
	["SkillMasteryXPPerQimican"] = { text = "{V}% {SV0} Mastery XP per maxed Star in Qimican constellation in Astrology", isSkill = true },
	["SkillMasteryXPPerSyllia"] = { text = "{V}% {SV0} Mastery XP per maxed Star in Syllia constellation in Astrology", isSkill = true },
	["SkillMasteryXPPerVale"] = { text = "{V}% {SV0} Mastery XP per maxed Star in Vale constellation in Astrology", isSkill = true },
	["SkillPreservationCap"] = { text = "{V}% Resource Preservation cap in {SV0}", isSkill = true },
	["SlayerCoinsBasedOnTargetDR"] = { text = "Gain Slayer Coins equal to {V}% of the Target Damage Reduction", skills = {'Combat'} },
	["SlayerCoinsPerDamage"] = { text = "{V}% Damage Dealt gained as Slayer Coins", skills = {'Combat'} },
	["SlayerCoinsPerMagicDamageSlayerTask"] = { text = "{VD}% of Magic Damage Dealt against Slayer Task monsters gained as Slayer Coins", skills = {'Combat'} },
	["SlayerCoinsPerPoisonDamage"] = { text = "{VD}% of Poison damage dealt is gained as Slayer Coins", skills = {'Combat'} },
	["SlayerTaskMonsterAccuracy"] = { text = "{V}% Slayer Task monster Accuracy Rating", skills = {'Combat'} },
	["SmithingDragonGearPreservation"] = { text = "{V}% chance to preserve resources in Smithing when making Dragon Gear", skills = {'Smithing'} },
	["SummoningAttackLifesteal"] = { text = "{V}% Lifesteal for Summoning attacks", skills = {'Combat'} },
	["SummoningCreationChargesForEquippedTablets"] = { text = "{V} Base Quantity when creating equipped Summoning Tablets", skills = {'Combat', 'Magic'} },
	["SummoningIntervalForOctopus"] = { text = "{V}% Summoning Interval when making Octopus Tablets", isIncreaseNegative = true, skills = {'Summoning'} },
	["SummoningIntervalPercentForEquippedTablets"] = { text = "{V}% Summoning Interval for equipped Summoning Tablets", isIncreaseNegative = true, skills = {'Combat', 'Magic'} },
	["summoningSynergy_Bear_Devil"] = { text = "{V}% Firemaking XP and +100% bonfire duration when using Controlled Heat Potions", inverseSign = true, skills = {'Firemaking'} },
	["summoningSynergy_Devil_Eagle"] = { text = "While Thieving - 50% chance for +10% base Skill XP, 40% chance for 2.5x GP, and 10% chance to gain no Items or GP", skills = {'Thieving'} },
	["summoningSynergy_Ent_Leprechaun"] = { text = "{V} Bird Nest when thieving the lumberjack, but gain no GP", inverseSign = true, skills = {'Woodcutting', 'Thieving'} },
	["summoningSynergy_Leprechaun_Devil"] = { text = "+50% chance to gain 100% GP, +35% chance to gain 4x items and +15% chance to gain no items or gp from Thieving", skills = {'Thieving'} },
	["summoningSynergy_Mole_Leprechaun"] = { text = "{V}% chance to receive a gem while thieving the Miner", inverseSign = true, skills = {'Thieving'} },
	["summoningSynergy_Octopus_Leprechaun"] = { text = "+50% Thieving Interval and +2 base item quantity when thieving the Fisherman", skills = {'Thieving'} },
	["ThievingAreaUniqueChance"] = { text = "{V}% chance to receive Thieving Area Unique Item", skills = {'Thieving'} },
	["ThievingAutoSellPrice"] = { text = "Automatically sell Common Drops from Thieving for {V}x their base sale price", skills = {'Thieving'} },
	["thievingChefNoDamage"] = { text = "Take no damage when stunned by the Chef in Thieving", skills = {'Thieving'} },
	["ThievingStunIntervalPercent"] = { text = "{V}% Thieving Stun Interval", isIncreaseNegative = true, skills = {'Thieving'} },
	["TownshipAridPlainsProduction"] = { text = "{V}% Township Building Production in Arid Plains Biome", skills = {'Township'} },
	["TownshipBarProduction"] = { text = "{V}% Township Bar Production", skills = {'Township'} },
	["TownshipBlacksmithProduction"] = { text = "{V}% Township Production for Blacksmith buildings", skills = {'Township'} },
	["TownshipBuildingCost"] = { text = "{V}% Township Building Cost", isIncreaseNegative = true, skills = {'Township'} },
	["TownshipBuildingHappinessPenalties"] = { text = "{V}% Township Building Happiness Penalties", isIncreaseNegative = true, skills = {'Township'} },
	["TownshipClothingProduction"] = { text = "{V}% Township Clothing Production", skills = {'Township'} },
	["TownshipCoalProduction"] = { text = "{V}% Township Coal Production", skills = {'Township'} },
	["TownshipCoalUsage"] = { text = "{V}% Township Coal Usage", isIncreaseNegative = true, skills = {'Township'} },
	["TownshipDeadStorage"] = { text = "{V}% Township Dead Storage", skills = {'Township'} },
	["TownshipDesertProduction"] = { text = "{V}% Township Building Production in Desert Biome", skills = {'Township'} },
	["townshipDisableHunting"] = { text = "Hunting is forbidden in Township", isIncreaseNegative = true, skills = {'Township'} },
	["TownshipEducation"] = { text = "{V}% Township Education", skills = {'Township'} },
	["TownshipFarmProduction"] = { text = "{V}% Township Production for Farm buildings", skills = {'Township'} },
	["TownshipFishingDockProduction"] = { text = "{V}% Township Production for Fishing Dock buildings", skills = {'Township'} },
	["TownshipFoodProduction"] = { text = "{V}% Township Food Production", skills = {'Township'} },
	["TownshipFoodUsage"] = { text = "{V}% Township Citizen Food Usage", isIncreaseNegative = true, skills = {'Township'} },
	["TownshipForestProduction"] = { text = "{V}% Township Building Production in Forest Biome", skills = {'Township'} },
	["TownshipGPProduction"] = { text = "{V}% Township GP Production", skills = {'Township'} },
	["TownshipGrasslandsProduction"] = { text = "{V}% Township Building Production in Grasslands Biome", skills = {'Township'} },
	["TownshipHappiness"] = { text = "{V}% Township Happiness", skills = {'Township'} },
	["TownshipHealth"] = { text = "{V}% Township Health", skills = {'Township'} },
	["TownshipHerbProduction"] = { text = "{V}% Township Herb Production", skills = {'Township'} },
	["TownshipJungleProduction"] = { text = "{V}% Township Building Production in Jungle Biome", skills = {'Township'} },
	["TownshipLeatherProduction"] = { text = "{V}% Township Leather Production", skills = {'Township'} },
	["TownshipMagicEmporiumProduction"] = { text = "{V}% Township Production for Magic Emporium buildings", skills = {'Township'} },
	["TownshipMaxStorage"] = { text = "{V}% Township Max Storage", skills = {'Township'} },
	["TownshipMountainsProduction"] = { text = "{V}% Township Building Production in Mountains Biome", skills = {'Township'} },
	["TownshipOrchardProduction"] = { text = "{V}% Township Production for Orchard buildings", skills = {'Township'} },
	["TownshipOreProduction"] = { text = "{V}% Township Ore Production", skills = {'Township'} },
	["TownshipPlankProduction"] = { text = "{V}% Township Plank Production", skills = {'Township'} },
	["TownshipPopulationCap"] = { text = "{V} Township Population Cap", skills = {'Township'} },
	["TownshipPotionProduction"] = { text = "{V}% Township Potion Production", skills = {'Township'} },
	["TownshipResourceProduction"] = { text = "{V}% Township Resource Generation", skills = {'Township'} },
	["TownshipRuneEssenceProduction"] = { text = "{V}% Township Rune Essence Production", skills = {'Township'} },
	["TownshipSnowlandsProduction"] = { text = "{V}% Township Building Production in Snowlands Biome", skills = {'Township'} },
	["TownshipStoneProduction"] = { text = "{V}% Township Stone Production", skills = {'Township'} },
	["TownshipSwampProduction"] = { text = "{V}% Township Building Production in Swamp Biome", skills = {'Township'} },
	["TownshipTaxPerCitizen"] = { text = "{V}% GP gained from Township Citizen Tax", skills = {'Township'} },
	["TownshipTraderStock"] = { text = "{V} Township Trader GP Limit per visit", skills = {'Township'} },
	["TownshipValleyProduction"] = { text = "{V}% Township Building Production in Valley Biome", skills = {'Township'} },
	["TownshipWaterProduction"] = { text = "{V}% Township Building Production in Water Biome", skills = {'Township'} },
	["TownshipWoodcuttingProduction"] = { text = "{V}% Township Production for Woodcutting buildings", skills = {'Township'} },
	["TownshipWoodProduction"] = { text = "{V}% Township Wood Production", skills = {'Township'} },
	["WoodcuttingGemChance"] = { text = "{V}% chance to receive a gem per Woodcutting action", skills = {'Woodcutting'} },
	["WoodcuttingJewelryChance"] = { text = "{V}% chance for Silver or Gold Jewelry to drop instead of a Bird's Nest from Woodcutting", skills = {'Woodcutting'} },
	["WoodcuttingXPAddedAsFiremakingXP"] = { text = "{V}% Woodcutting XP added as Firemaking XP", skills = {'Woodcutting', 'Firemaking'} },
	["XPFromNegativeObstacles"] = { text = "{V}% Agility Skill XP from Obstacles that contain a negative modifier", skills = {'Agility'} },
	-- New 1.1.2 modifiers
	["enableNightfallSeason"] = { text = "There is a 20% chance of a Nightfall Season occurring in Township", skills = {'Township'} },
	["enableSolarEclipseSeason"] = { text = "There is a 20% chance of a Solar Eclipse Season occurring in Township", skills = {'Township'} },
	["EssenceFromMining"] = { text = "{V} base quantity received from Essence nodes in Mining", skills = {'Mining'} },
	["MasteryTokens"] = { text = "{V} Mastery Tokens received", skills = {'Woodcutting', 'Fishing', 'Firemaking', 'Cooking', 'Mining', 'Smithing', 'Thieving', 'Farming', 'Fletching', 'Crafting', 'Runecrafting', 'Herblore', 'Agility', 'Summoning', 'Astrology'} },
	["TownshipRepairCost"] = { text = "{V}% Township repair costs", isIncreaseNegative = true, skills = {'Township'} },
	["TownshipTraderCost"] = { text = "{V}% Township Trader costs", isIncreaseNegative = true, skills = {'Township'} },
	-- New 1.2 modifiers
	["AccuracyIfCursed"] = { text = "{V}% Global Accuracy when Cursed", isIncreaseNegative = true, skills = {'Combat'} },
	["agilityItemCostReductionCanReach100"] = { text = "Item cost reduction in Agility can now reach 100%", skills = {'Agility'} },
	["AgilityObstacleItemCost"] = { text = "{V}% Agility Obstacle Item Costs", skills = {'Agility'}, isIncreaseNegative = true },
	["allowUnholyPrayerUse"] = { text = "Allow Unholy Prayer Use", unsigned = true, skills = {'Combat', 'Prayer'} },
	["AmmoPreservationBypass"] = { text = "{V}% Ammo Preservation (Bypass Gamemode Limitation)", skills = {'Combat', 'Ranged'} },
	["applyAttackMasterRelicEffect"] = { text = "Apply -1% Melee Evasion to the Target per hit, stacking up to 30 times and lasts until the end of the fight", skills = {'Combat'} },
	["applyMagicMasterRelicEffect"] = { text = "Start the fight with 100% Magic Critical Hit chance, which decreases by 20% per Attack Turn", skills = {'Combat'} },
	["applyStrengthMasterRelicEffect"] = { text = "Apply 1 stack of Rage to self per Attack Turn, stacking up to 10 times and resetting at max stacks", skills = {'Combat'} },
	["ArchaeologyCommonItemSkillXP"] = { text = "{V}% Archaeology Skill XP when locating a Common Artefact", skills = {'Archaeology'} },
	["archaeologyVeryRareMapPreservation"] = { text = "Finding a Very Rare or Super Rare item in Archaeology will use no Dig Site Map excavation charges", skills = {'Archaeology'} },
	["ArrowProduction"] = { text = "{V} Arrows produced per action in Fletching" },
	["BarrierSummonDamage"] = { text = "{V}% Summoning Familiar damage added as extra damage to Barrier", skills = {'Combat'} },
	["BarrierSummonDamageIfSlayerTask"] = { text = "{V}% Barrier damage added to Summon Familiar if target is current Slayer Task", skills = {'Combat'} },
	["BaseCraftingConsumableProduction"] = { text = "{V} base quantity of Consumables produced per action in Crafting" },
	["BoltSpellMaxHitFlat"] = { text = "{VX} Max Hit when using Bolt spells", skills = {'Combat'} },
	["BrushToolLevel"] = { text = "{V} Brush tool level", skills = {'Archaeology'} },
	["BurnReflectChance"] = { text = "{V}% chance to inflict a Burn to the Attacker when hit", skills = {'Combat'} },
	["ChanceAdditionalSoup"] = { text = "{V} chance to receive an additional Soup from Cooking (Cannot be doubled)", skills = {'Cooking'} },
	["ChanceBarrierBleed"] = { text = "{V}% chance for Summon to apply a Barrier Bleed to the enemy that deals damage equal to 200% Summon Max Hit over 10s", skills = {'Combat'} },
	["ChanceBarrierBurn"] = { text = "{V}% chance for Summon to apply a Barrier Burn to the enemy", skills = {'Combat'} },
	["ChanceCrystallization"] = { text = "{V}% chance to apply Crystallization (Target is stunned and takes +50% Damage during effect)", skills = {'Combat'} },
	["ChanceCrystalSanction"] = { text = "{V}% chance to apply Crystal Sanction to the Target (Next Attack Turn from Target deals no Damage)", skills = {'Combat'} },
	["ChanceForChestOfGemsInWoodcutting"] = { text = "{V}% chance to obtain a Chest of Gems per Woodcutting action", skills = {'Woodcutting'} },
	["ChanceForEnchantedUrnInCrafting"] = { text = "{V}% chance for Urns produced in Crafting to be Enchanted", skills = {'Crafting'} },
	["ChanceForGoldFromCrafting30"] = { text = "{V}% chance to to gain GP equal to 30% of the base sale price of the Item crafted in Crafting", skills = {'Skilling', 'Fishing'} },
	["ChanceForGPFromFishing"] = { text = "{V}% chance to gain GP equal to base fish sale price while Fishing", skills = {'Fishing'} },
	["ChanceToApply5Slow"] = { text = "{V}% chance to apply a Slow to the Target that increases its Attack Interval by +5% for 3 Turns.", skills = {'Combat'} },
	["ChanceToApplyBlind"] = { text = "{V}% chance to apply -20% Global Accuracy to the Target when hit", skills = {'Combat'} },
	["ChanceToApplyConfusionCurse"] = { text = "{V}% chance to apply Confusion Curse to the Target per hit", skills = {'Combat'} },
	["ChanceToCatchExtraSameAreaFish"] = { text = "{V}% chance to catch +1 random Fish from the same Fishing Area (Cannot be doubled)", skills = {'Skilling', 'Fishing'} },
	["ChanceToCleanse"] = { text = "{V}% to apply Cleanse to self for 2 turns (Immune to all debuffs and damage over time effects)", skills = {'Combat'} },
	["ChanceToDodge"] = { text = "{V}% chance to convert a successful hit from the Target into a miss", skills = {'Combat'} },
	["ChanceToDodgeCrystallization"] = { text = "{V}% chance to dodge Crystallization from being applied", skills = {'Combat'} },
	["ChanceToDodgeCrystalSanction"] = { text = "{V}% chance to dodge Crystal Sanction from being applied", skills = {'Combat'} },
	["ChanceToLocateAncientRelic"] = { text = "{V}% increased chance to locate Ancient Relics" },
	["ChanceToLocateSkillPet"] = { text = "{V}% increased chance to locate a Skill Pet" },
	["ChanceToNull"] = { text = "{V}% chance to apply Null to the Target for 2 Turns (Prevents the Target from applying buffs or modifier effects to themself).", skills = {'Combat'} },
	["ChanceToPreserveMapCharges"] = { text = "{V}% chance to preserve dig site map excavation actions", skills = {'Cartography'} },
	["ChanceToPreservePrayerPointsPerPoint"] = { text = "{V}% chance to preserve Prayer Points per Prayer Point cost of active Prayers", skills = {'Combat'} },
	["ChanceToPreserveUnholyPrayerPoints"] = { text = "{V}% chance to preserve Prayer Points for Unholy Prayers", skills = {'Combat', 'Prayer'} },
	["ChanceToReceiveNoCombatDrops"] = { text = "{V}% chance to receive no Combat drops from Monsters or Dungeons", isIncreaseNegative = true, skills = {'Combat'} },
	["ChanceWeakeningTouch"] = { text = "{V}% chance to apply Weakening Touch to the Target", skills = {'Combat'} },
	["cleansed"] = { text = "Immune to all debuffs and damage over time effects", skills = {'Combat'} },
	["CombinationRuneProduction"] = { text = "{V} Combination Runes produced per action in Runecrafting", skills = {'Runecrafting'} },
	["convertBoneDropsIntoCake"] = { text = "Converts all Bone drops from Combat into Birthday Cake Slice drops", skills = {'Comabt'} },
	["CookingIntervalForBasicSoup"] = { text = "{V}% Cooking Interval when making Basic Soup", isIncreaseNegative = true, skills = {'Cooking'} },
	["crystallized"] = { text = "Modifier to determined status of crystallized effect", skills = {'Combat'} },
	["CurseOnHitWithUnholyMark"] = { text = "{V}% chance to apply a random Curse when hitting with an attack if the target has Unholy Mark", skills = {'Combat'} },
	["DamageBasedOnCurrentHitpoints"] = { text = "{V}% of target's current hitpoints dealt as damage when hitting with an attack", skills = {'Combat'} },
	["DamageBasedOnMaxHitpoints"] = { text = "{V}% of target's max hitpoints dealt as damage when hitting with an attack", skills = {'Combat'} },
	["DamageDealtPerEffect"] = { text = "{V}% damage dealt per effect affected by", skills = {'Combat'} },
	["DamageDealtWith2Effects"] = { text = "{V}% damage dealt if affected by 2 or more effects", skills = {'Combat'} },
	["DamageReductionIfCursed"] = { text = "{V}% Damage Reduction when Cursed", isIncreaseNegative = true, skills = {'Combat'} },
	["DamageReductionPer30Defence"] = { text = "{V}% Damage Reduction per 30 Defence Skill Levels", skills = {'Combat'} },
	["DamageReductionWithActivePrayer"] = { text = "{V}% Damage Reduction when at least one Prayer is active", skills = {'Combat'} },
	["DamageTakenBasedOnHP"] = { text = "{V}% damage taken per percent of hitpoints missing", isIncreaseNegative = true, skills = {'Combat'} },
	["DamageTakenIfCursed"] = { text = "{V}% damage taken when Cursed", isIncreaseNegative = true, skills = {'Combat'} },
	["DamageTakenWhenSlowed"] = { text = "{V}% damage taken when Slowed", isIncreaseNegative = true, skills = {'Combat'} },
	["DigSiteMapCharges"] = { text = "{V} Dig Site Map excavation actions", skills = {'Cartography'} },
	["DigSiteMapSlots"] = { text = "{V} Dig Site Map slots", skills = {'Cartography'} },
	["disableAttackDamage"] = { text = "Disables all damage from Attacks", skills = {'Combat'} },
	["disabledSpecialAttacks"] = { text = "All player special attacks are disabled", isIncreaseNegative = true, skills = {'Combat'} },
	["disableTownshipHealthDegradation"] = { text = "Township Health no longer degrades", skills = {'Township'} },
	["doubleActiveModifiersCartography"] = { text = "Doubles the effects of all positive Active Modifiers from Point of Interests in Cartography", skills = {'Archaeology'} },
	["doubleConsumablesArchaeology"] = { text = "x{VMUL} Consumable Items received from Archaeology", unsigned = true, skills = {'Archaeology'} },
	["doubleModifiersInAstrologyForMaxedConstellations"] = { text = "All modifiers in a completed Astrology Constellation are doubled", skills = {'Astrology'} },
	["Elusive"] = { text = "When Target is hit, +3% Global Evasion Rating and -1% Attack Interval (Stacks 10 times)", skills = {'Combat'} },
	["enableBarrierBurn"] = { text = "Burns can now damage Barrier", skills = {'Combat'} },
	["enableLemonSeason"] = { text = "There is a 20% chance of a Lemon Season occurring in Township", skills = {'Township'} },
	["EnemyMaximumHitpoints"] = { text = "{V}% Maximum Hitpoints for the Target", skills = {'Combat'}, isIncreaseNegative = true },
	["EvasionIfCursed"] = { text = "{V}% Global Evasion when Cursed", isIncreaseNegative = true, skills = {'Combat'} },
	["FlatBarrierDamage"] = { text = "{VX} Flat Barrier damage dealt by Attacker per Attack Turn", skills = {'Combat'} },
	["FlatBarrierSummonDamage"] = { text = "{VX} Flat Barrier damage added to Summon Familiar", skills = {'Combat'} },
	["FlatBarrierSummonDamageMagic"] = { text = "{VX} Flat Barrier damage added to Summon Familiar if using Magic", skills = {'Combat'} },
	["FlatBarrierSummonDamageMelee"] = { text = "{VX} Flat Barrier damage added to Summon Familiar if using Melee", skills = {'Combat'} },
	["FlatBarrierSummonDamageRanged"] = { text = "{VX} Flat Barrier damage added to Summon Familiar if using Ranged", skills = {'Combat'} },
	["FrostburnReflectChance"] = { text = "{V}% chance to inflict Frostburn to the Attacker when hit", skills = {'Combat'} },
	["gain2MaxHitpointsPerTurn"] = { text = "+2% maximum Hitpoints per Turn (Maximum 10 stacks)", skills = {'Combat'} },
	["GlobalFreezeChance"] = { text = "{V}% chance to apply Freeze for 1 Attack Turn when hitting with any attack (once per turn)", skills = {'Combat'} },
	["GlobalPreservationChanceBypass"] = { text = "{V}% Chance to Preserve Resources in Skills (Bypass Gamemode Limitation)" },
	["GPFlat"] = { text = "{V} GP gained when earning GP, except Alt. Magic and Item Sales" },
	["GPFromBarrierDamage"] = { text = "Grants GP equal to {VD}% damage dealt to Barrier", skills = {'Combat'} },
	["GPFromLogSales"] = { text = "{V}% GP From Log Sales", skills = {'Woodcutting'} },
	["GPFromRawFishSales"] = { text = "{V}% GP From Raw Fish Sales", skills = {'Fishing'} },
	["GPPerArchaeologyLevelNoArtefact"] = { text = "Gain GP equal to {V} per Archaeology Skill Level per excavation action that locates no Artefacts", skills = {'Archaeology'} },
	["halfAttackInterval"] = { text = "UNDEFINED TRANSLATION: :MODIFIER_DATA_halfAttackInterval", skills = {'Combat'} },
	["halfMasteryXP"] = { text = "UNDEFINED TRANSLATION: :MODIFIER_DATA_halfMasteryXP" },
	["halfSkillInterval"] = { text = "UNDEFINED TRANSLATION: :MODIFIER_DATA_halfSkillInterval" },
	["halfSkillXP"] = { text = "UNDEFINED TRANSLATION: :MODIFIER_DATA_halfSkillXP" },
	["HealEvery200Int"] = { text = "Heal for {V}% current Hitpoints every 0.2s", skills = {'Combat'} },
	["HealingWhenHit"] = { text = "{V}% of max hitpoints healed when hit by an attack", skills = {'Combat'} },
	["HexTravelCost"] = { text = "{V}% Cartography travel costs", isIncreaseNegative = true, skills = {'Cartography'} },
	["HiddenSkillLevelBasedOnLevels"] = { text = "{V}% of your {SV0} Level added as Hidden {SV0} Levels", isSkill = true, skills = {'Combat'} },
	["HiddenSkillLevelPer2Levels"] = { text = "{V} Hidden {SV0} Level for every 2 levels of {SV0}", isSkill = true, skills = {'Combat'} },
	["HolyDustFromBlessedOffering"] = { text = "{V} Holy Dust obtained from Blessed Offering Alt. Magic Spell (cannot be doubled)", skills = {'Combat'} },
	["InitialMapArtefactValues"] = { text = "{V}% initial artefact values when creating maps in Cartography", skills = {'Cartography'} },
	["LargeArtefactChance"] = { text = "{V}% chance to find Large Artefacts in Archaeology", skills = {'Archaeology'} },
	["LargeArtefactValue"] = { text = "{V} Large Artefact value", skills = {'Archaeology'} },
	["LemonsPerAction"] = { text = "{V} Lemons granted per non-Combat action", skills = {'Township'} },
	["LifestealDamageBasedOnCurrentHitpoints"] = { text = "{V}% of target's current hitpoints dealt as damage and healed when hitting with an attack", skills = {'Combat'} },
	["MagicMaxHitWithActivePrayer"] = { text = "{V}% Magic Max Hit when at least one Prayer is active", skills = {'Combat'} },
	["MapRefinementCost"] = { text = "{V}% dig site map refinement cost", isIncreaseNegative = true, skills = {'Cartography'} },
	["MapUpgradeActions"] = { text = "{V}% Dig Site Map excavation actions when upgrading in Cartography", skills = {'Cartography'} },
	["MapUpgradeInterval"] = { text = "{V}% Cartography Dig Site Map upgrade interval", isIncreaseNegative = true, skills = {'Cartography'} },
	["MaxHitBasedOnPrayerCost"] = { text = "{V}% Maximum Hit per Prayer Point cost of active Prayers", skills = {'Combat'} },
	["MaxHitIfCursed"] = { text = "{V}% Maximum Hit when Cursed", isIncreaseNegative = true, skills = {'Combat'} },
	["MaxHitPercentBasedOnTargetCurrentHitpoints"] = { text = "{V}% Maximum Hit for each 1% of Target current Hitpoints remaining", skills = {'Combat'} },
	["MediumArtefactChance"] = { text = "{V}% chance to find Medium Artefacts in Archaeology", skills = {'Archaeology'} },
	["MediumArtefactValue"] = { text = "{V} Medium Artefact value", skills = {'Archaeology'} },
	["MeleeAccuracyMaxHitPer8Strength"] = { text = "{V}% Melee Accuracy and Melee Max Hit per 8 Strength Skill Levels (Floored)", skills = {'Combat'} },
	["MeleeAttackIntervalPercent"] = { text = "{V}% Melee Attack Interval", skills = {'Combat', 'Attack'}, isIncreaseNegative = true },
	["MeleeStrengthBonusBasedOnSkillLevel"] = { text = "{V} Melee Strength Bonus based on your current {SV0} Level", isSkill = true, skills = {'Combat'} },
	["MeleeStrengthBonusPer10EnemyDR"] = { text = "{V}% Melee Strength Bonus from equipment per 10% base enemy damage reduction", skills = {'Combat'} },
	["MinimumItemsFoundInArchaeology"] = { text = "{V} minimum Items found in Archaeology", skills = {'Archaeology'} },
	["MinimumTownshipBuildingEfficiency"] = { text = "{V}% minimum Township building efficiency", skills = {'Township'} },
	["MinSpellDmg"] = { text = "{VX} Minimum Spell Damage", skills = {'Combat', 'Magic'} },
	["noDamageFromThievingNPCs"] = { text = "NPCs in Thieving deal no damage", skills = {'Thieving'} },
	["nulled"] = { text = "Unable to apply buffs or modifier effects to self", isIncreaseNegative = true, skills = {'Combat'} },
	["PaperMakingInterval"] = { text = "{V}% Cartography paper making interval", isIncreaseNegative = true, skills = {'Cartography'} },
	["PotionsHerblore"] = { text = "{V} Potions created in Herblore (Cannot be doubled)", skills = {'Herblore'} },
	["PrayerPointsFromBurying"] = { text = "{V} Prayer Points from Burying", skills = {'Combat', 'Prayer'} },
	["PrayerPointsFromBuryingPercent"] = { text = "{V}% Prayer Points gained from burying Bones", skills = {'Combat', 'Prayer'} },
	["PrayerPointsPerMonsterKill"] = { text = "{V} Prayer Points gained per Monster kill", skills = {'Combat'} },
	["RangedStrengthBonusPer8Ranged"] = { text = "{V}% Ranged Strength Bonus per 8 Ranged Skill Levels (Floored)", skills = {'Combat'} },
	["RegenPerDamageTaken"] = { text = "{V}% of damage taken from attacks healed on next hitpoint regeneration", skills = {'Combat'} },
	["removeDebuffsFromAgility"] = { text = "Remove all debuffs from Agility Obstacles", skills = {'Agility'} },
	["RunePreservationBypass"] = { text = "{V}% Rune Preservation (Bypass Gamemode Limitation)", skills = {'Combat', 'Magic'} },
	["SelfDamageBasedOnCurrentHitpoints"] = { text = "Deal damage to self equal to {V}% of your current Hitpoints per hit", isIncreaseNegative = true, skills = {'Combat'} },
	["ShovelToolLevel"] = { text = "{V} Shovel tool level", skills = {'Archaeology'} },
	["SieveToolLevel"] = { text = "{V} Sieve tool level", skills = {'Archaeology'} },
	["SightRange"] = { text = "{V} Cartography sight range", skills = {'Cartography'} },
	["SmallArtefactChance"] = { text = "{V}% chance to find Small Artefacts in Archaeology", skills = {'Archaeology'} },
	["SmallArtefactValue"] = { text = "{V} Small Artefact value", skills = {'Archaeology'} },
	["StandardRuneProduction"] = { text = "{V} Standard Runes produced per action in Runecrafting", skills = {'Runecrafting'} },
	["SurveyInterval"] = { text = "{V}% Cartography survey interval", isIncreaseNegative = true, skills = {'Cartography'} },
	["SurveyRange"] = { text = "{V} Cartography survey range", skills = {'Cartography'} },
	["SurveyXP"] = { text = "{V}% Cartography survey XP", skills = {'Cartography'} },
	["TinyArtefactChance"] = { text = "{V}% chance to find Tiny Artefacts in Archaeology", skills = {'Archaeology'} },
	["TinyArtefactValue"] = { text = "{V} Tiny Artefact value", skills = {'Archaeology'} },
	["TravelEventChance"] = { text = "{V}% increased travel event chance in Cartography", skills = {'Cartography'} },
	["TrowelToolLevel"] = { text = "{V} Trowel tool level", skills = {'Archaeology'} },
	["underwaterEffect"] = { text = "Each Attack Turn, Attacker's Attack interval is decreased by -1% and the Target is slow by +1%. Stacks 20 times.", skills = {'Combat'} },
	["UnholyMarkOnHit"] = { text = "{V} Unholy Mark stacks applied when hitting with an attack", skills = {'Combat'} },
	["unlockAllSummoningSynergies"] = { text = "All Summoning Synergies are unlocked", skills = {'Summoning'} },
	["XPFromMasteryTokens"] = { text = "All Mastery Tokens grant {V}% of the maximum Mastery Pool XP for the respective Skill" },
	["HiddenSkillLevelPer3Levels"] = { text = "{V} Hidden {SV0} Level for every 3 levels of {SV0}" },
	-- New 1.2.2 modifiers
	["MinElementalSpellDmg"] = { text = "{VX} minimum Elemental Spell Damage", skills = {'Combat'} },
	["SummoningAttackIntervalPercent"] = { text = "{V}% Summoning Familiar Attack Interval", isIncreaseNegative = true, skills = {'Combat'} },
	["barrierRegenTurns"] = { text = "Regenerates 25% Barrier every {V} Attack Turns", skills = {'Combat'} }
}


function p.getTriangleAttribute(attribute, attackerStyle, targetStyle, modeName)
	if type(attribute) ~= 'string' then
		error("Parameter 'attribute' must be a string", 2)
	elseif type(attackerStyle) ~= 'string' then
		error("Parameter 'attackerStyle' must be a string", 2)
	elseif type(targetStyle) ~= 'string' then
		error("Parameter 'targetStyle' must be a string", 2)
	elseif type(modeName) ~= 'string' then
		error("Parameter 'modeName' must be a string", 2)
	end
	
	local mode = GameData.getEntityByName('gamemodes', modeName)
	if mode == nil then
		error("Invalid gamemode '" .. modeName .. "'", 2)
	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 combatTriangle = GameData.getEntityByID('combatTriangles', mode.combatTriangle)
	if combatTriangle == nil then
		error("No such combat triangle: " .. mode.combatTriangle)
	end
	local attrData = combatTriangle[attribute]
	if attrData == nil then
		error("No such attribute: " .. attribute)
	else
		return attrData[attStyle][targStyle]
	end
end

function p.getTriangleDamageModifier(attackerStyle, targetStyle, mode)
	return p.getTriangleAttribute('damageModifier', attackerStyle, targetStyle, mode)
end

--Syntax is like p.getTriangleDRModifier('Melee', 'Ranged', 'Normal')
--Returns a multiplier that can be multiplied with base DR to get the post-Triangle result
function p.getTriangleDRModifier(attackerStyle, targetStyle, mode)
	return p.getTriangleAttribute('reductionModifier', attackerStyle, targetStyle, mode)
end

function p.getDifficultyString(difficulty)
	return GameData.rawData.combatAreaDifficulties[difficulty + 1]
end

function p.getSkillName(skillID)
	local skill = GameData.getSkillData(skillID)
	if skill ~= nil then
		return skill.name
	end
end

function p.getSkillID(skillName)
	for i, skillData in ipairs(GameData.rawData.skillData) do
		if skillData.data.name == skillName then
			return skillData.skillID
		end
	end
end

function p.getEquipmentSlotName(id)
	local slotData = GameData.getEntityByID('equipmentSlots', id)
	if slotData ~= nil then
		return slotData.name
	end
end

function p.getEquipmentSlotID(name)
	local slotData = GameData.getEntityByName('equipmentSlots', name)
	if slotData ~= nil then
		return slotData.id
	end
end

function p.getCombatStyleName(styleNum)
	if type(styleNum) == 'number' then
		local styleName = GameData.rawData.attackTypes[styleNum]
		if styleName ~= nil then
			return Shared.titleCase(styleName)
		end
	elseif type(styleNum) == 'string' and type(GameData.rawData.attackTypes[string.lower(styleNum)]) == 'number' then
		return Shared.titleCase(styleNum)
	end
	return Shared.printError('Invalid combat style')
end


--- Slayer functions
--
function p.getSlayerTierByID(tierID)
	if type(tierID) ~= 'number' then
		return nil
	else
		return GameData.rawData.slayerTiers[tierID + 1]
	end
end

function p.getSlayerTier(name)
	return GameData.getEntityByProperty('slayerTiers', 'display', name)
end

function p.getSlayerTierByLevel(level)
	if type(level) ~= 'number' or level < 1 then
		return Shared.printError('Invalid Slayer level')
	end
	
	for i, tier in ipairs(GameData.rawData.slayerTiers) do
		if tier.minLevel <= level and (tier.maxLevel == nil or tier.maxLevel >= level) then
			return tier
		end
	end
end

--
-- the following functions just return subsets of the slayer functions above
--

function p.getSlayerTierName(tierID)
	if type(tierID) == 'number' then
		local tier = p.getSlayerTierByID(tierID)
		if tier ~= nil then
			return tier.display
		end
	end
	return Shared.printError('Invalid Slayer tier')
end

function p.getSlayerTierNameByLevel(lvl)
	local tier = p.getSlayerTierByLevel(lvl)
	if type(tier) == 'table' then
		return tier.display
	else
		return Shared.printError('Invalid Slayer tier')
	end
end

--
--- End of slayer functions

--Turns a modifier name like 'increasedHPRegenFlat' into several pieces of data:
--Base Name, Description, IsNegative, and modifyValue
--ex. "HPRegenFlat", "+${value} Flat Hitpoints Regeneration", false, "multiplyByNumberMultiplier"
function p.getModifierDetails(modifierName)
	local baseName = modifierName
	local modifier = GameData.rawData.modifierData[modifierName]

	if modifier == nil then
		return nil
	end

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

	return baseName, modifier.description, modifier.isNegative, modifier.modifyValue
end

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

	if modName == nil then
		return Shared.printError('Invalid modifier type for "' .. modifier .. '"')
	end

	if modifyValue ~= nil and string.match(modifyValue, 'ToolLevels') then
		modifyValue = 'ArchaeologyToolLevels'
	end

	local formatModValue = function(value, rule)
		local ruleFunctions = {
			['value'] = function(val) return val end,
			['multiplyByNumberMultiplier'] = function(val) return val * 10 end,
			['divideByNumberMultiplier'] = function(val) return val / 10 end,
			['milliToSeconds'] = function(val) return val / 1000 end,
			['(value)=>value*100'] = function(val) return val * 100 end,
			['(value)=>100+value'] = function(val) return val + 100 end,
			['(value)=>value+1'] = function(val) return val + 1 end,
			['(value)=>Math.pow(2,value)'] = function(val) return 2^val end,
			["(value)=>{if(value>=2){return getLangString('ALLOW_UNHOLY_PRAYERS');}\nelse if(value>=1){return getLangString('ALLOW_UNHOLY_PRAYERS_WITH_EQUIPMENT');}\nelse{return 'Invalid modifier value.';}}"] = function(val) return 'Allows for Unholy Prayers to be used' end,
			['ArchaeologyToolLevels'] = function(val)
				local toolLevel = '+' .. val
				if string.match(modName, 'Sieve') then
					toolLevel = toolLevel ..  ' level of the Sieve Tool in Archaeology'
				elseif string.match(modName, 'Trowel') then
					toolLevel = toolLevel ..  ' level of the Trowel Tool in Archaeology'
				elseif string.match(modName, 'Brush') then
					toolLevel = toolLevel ..  ' level of the Brush Tool in Archaeology'
				elseif string.match(modName, 'Shovel') then
					toolLevel = toolLevel ..  ' level of the Shovel Tool in Archaeology'
				end
				if val > 1 then
					return string.gsub(toolLevel, 'level', 'levels')
				else
					return toolLevel
				end
			end,
			['(value)=>game.golbinRaid.startingWeapons[value].name'] = function(val)
				-- For golbin raid starting weapons
				local startingWeapons = { 'melvorD:Bronze_Scimitar', 'melvorD:Adamant_Scimitar' }
				local itemID = startingWeapons[val + 1]
				local item = GameData.getEntityByID('items', itemID)
				if item ~= nil then
					return item.name
				else
					return 'Unknown'
				end
			end
		}
		local ruleFunc = ruleFunctions[modifyValue] or ruleFunctions['value']

		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 valueArray, resultArray = nil, {}
	if type(value) ~= 'table' then
		valueArray = {value}
	else
		valueArray = value
	end

	for i, subVal in ipairs(valueArray) do
		local resultText = modText
		-- A few modifiers don't have official descriptions; Fallback to manual ones instead
		if string.match(resultText, 'UNDEFINED TRANSLATION') then
			resultText = modifierTypes[modName].text
		end
		local modMagnitude = nil
		if type(subVal) == 'table' and subVal.skillID ~= nil then
			-- Modifier value is skill specific
			modMagnitude = subVal.value
			local skillName = p.getSkillName(subVal.skillID)
			if skillName ~= nil then
				resultText = string.gsub(resultText, '${skillName}', skillName)
			end
		else
			-- Modifier value is the magnitude only
			modMagnitude = subVal
		end

		resultText = string.gsub(resultText, '${value}', function(rule) return (formatModValue(modMagnitude, rule) or '') end)

		if doColor then
			local colorCode = (isNegative ~= nil and isNegative and 'color:red' or 'color:green')
			resultText = '<span style="' .. colorCode .. '">' .. resultText .. '</span>'
		end
		table.insert(resultArray, resultText)
	end

	return table.concat(resultArray, '<br/>')
end

function p.getModifierText(frame)
	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 skill = frame.args ~= nil and frame.args.skill or frame.skill
	local doColor = frame.args ~= nil and frame.args[3] or frame[3]

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

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

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

function p.getModifiersText(modifiers, doColor, inline, maxVisible)
	if inline == nil then inline = false end
	if type(maxVisible) ~= 'number' then maxVisible = nil end
	if modifiers == nil or Shared.tableIsEmpty(modifiers) then
		return ''
	end

	local modArray = { ["visible"] = {}, ["overflow"] = {} }
	local modCount = { ["visible"] = 0, ["overflow"] = 0 }
	local insertKey = 'visible'
	for bonus, value in pairs(modifiers) do
		-- If there is a single by skill modifier with multiple values, this will
		-- appear as multiple rows. Split these so the number of visible lines is
		-- always accurate
		local valueArray = nil
		if type(value) == 'table' then 
			valueArray = value
		else
			valueArray = {value}
		end
		for i, subVal in ipairs(valueArray) do
			if type(subVal) == 'table' and subVal.skillID ~= nil then
				subVal = {subVal}
			end
			if maxVisible ~= nil and not inline and insertKey == 'visible' and modCount[insertKey] >= maxVisible then
				insertKey = 'overflow'
			end
			table.insert(modArray[insertKey], p._getModifierText(bonus, subVal, doColor))
			modCount[insertKey] = modCount[insertKey] + 1
		end
	end
	if inline then 
		return table.concat(modArray['visible'], ' and ')
	else
		if modCount['overflow'] == 1 then
			table.insert(modArray['visible'], modArray['overflow'][1])
		end
		local overflowText = ''
		if modCount['overflow'] > 1 then
			-- Number of other modifiers has exceeded the specified maximum
			overflowText = table.concat({
				'<br/><span class="mw-collapsible mw-collapsed" ',
				'data-expandtext="Show ' .. Shared.formatnum(modCount['overflow']) .. ' more modifiers" ',
				'data-collapsetext="Hide">',
				table.concat(modArray['overflow'], '<br/>'),
				'</span>'
			})
		end
		return table.concat(modArray['visible'], '<br/>') .. overflowText
	end
end

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

	for modifier, value in pairs(modifiers) do
		if type(value) == 'table' then
			for i, subVal in ipairs(value) do
				if type(subVal) == 'table' and subVal.skillID ~= nil then
					local skillName = p.getSkillName(subVal.skillID)
					if not Shared.contains(skillArray, skillName) then
						table.insert(skillArray, skillName)
					end
				end
			end
		end

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

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

	return skillArray
end

-- Returns a modifiers table indicating modifiersNew less modifiersOld
-- The returned table can be passed to getModifiersText to obtain the
-- result in a human readable format
function p.getModifiersDifference(modifiersOld, modifiersNew)
	local modHasPrefix = {}
	local modDiff, modDiffBase = {}, {}
	local allMods = {
		{ ["mods"] = (modifiersNew or {}), ["mult"] = 1 },
		{ ["mods"] = (modifiersOld or {}), ["mult"] = -1 }
	}

	-- Generate modifiers table containing only variances
	-- Create modDiffBase with mod base names (less 'increased'/'decreased' prefixes),
	for i, modDef in ipairs(allMods) do
		for modName, value in pairs(modDef.mods) do
			local modBaseName, modIsIncrease = modName, true
			if Shared.startsWith(modName, "increased") or Shared.startsWith(modName, "decreased") then
				modBaseName = string.sub(modName, 10)
				modIsIncrease = Shared.startsWith(modName, "increased")
				modHasPrefix[modBaseName] = true
			end
			local modMult = (modIsIncrease and 1 or -1) * modDef.mult

			if type(value) == 'table' then
				-- Skill specific modifier
				if modDiffBase[modBaseName] == nil then
					modDiffBase[modBaseName] = {}
				end
				for j, subVal in ipairs(value) do
					if type(subVal) == 'table' and subVal.skillID ~= nil then
						modDiffBase[modBaseName][subVal.skillID] = (modDiffBase[modBaseName][subVal.skillID] or 0) + subVal.value * modMult
					end
				end
			else
				modDiffBase[modBaseName] = (modDiffBase[modBaseName] or 0) + value * modMult
			end
		end
	end

	-- Transform modDiffBase into modDiff with the appropriate mod name within the return value
	for modBaseName, value in pairs(modDiffBase) do
		if type(value) == 'table' then
			-- Skill specific modifier
			for skillID, subVal in pairs(value) do
				if subVal ~= 0 then
					local modName = nil
					if modHasPrefix[modBaseName] then
						modName = (subVal < 0 and 'decreased' or 'increased') .. modBaseName
					else
						modName = modBaseName
					end
					if modDiff[modName] == nil then
						modDiff[modName] = {}
					end
					table.insert(modDiff[modName], { ["skillID"] = skillID, ["value"] = math.abs(subVal) })
				end
			end
		elseif value ~= 0 then
			local modName = nil
			if modHasPrefix[modBaseName] then
				modName = (value < 0 and 'decreased' or 'increased') .. modBaseName
			else
				modName = modBaseName
			end
			modDiff[modName] = (modDiff[modName] or 0) + math.abs(value)
			if GameData.rawData.modifierData[modName] == nil then
				modDiff[modName] = nil
			end
		end
	end

	return modDiff
end

-- From game version 1.1 onwards, some entities have custom descriptions, while
-- many are generated based on the modifiers associated to that entity. This
-- function handles that logic given a custom description (may be nil) and
-- a modifiers object
function p.getDescription(customDescription, modifiers)
	if customDescription ~= nil then
		return customDescription
	else
		return p.getModifiersText(modifiers, false)
	end
end

return p