Module:Sandbox/AuronTest: Difference between revisions

From Melvor Idle
m (Test amend to support familiars)
m (1.0 testing: Constants)
Line 1: Line 1:
-- For tables & other outputs generated with attack data, see: Module:Attacks/Tables
local p = {}
local p = {}


local AttackData = mw.loadData('Module:AuronTest/data')
local ConstantData = mw.loadData('Module:AuronTest/data')
local ItemData = mw.loadData('Module:Items/data')


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


p.effectDefinition = {
--Just hardcoding these because I guess that's where we're at
    ["Burn"] = {
local modifierTypes = {
        {
  ["MeleeStrengthBonus"] = { text = "{V}% Melee Strength Bonus", skills = {'Combat'} },
            ["type"] = 'DOT',
  ["DamageToDungeonMonsters"] = { text = "{V}% Damage To Dungeon Monsters", skills = {'Combat'} },
            ["subtype"] = 'Burn'
  ["GlobalMasteryXP"] = { text = "{V}% Global Mastery XP", skills = {'Woodcutting', 'Fishing', 'Firemaking', 'Cooking', 'Mining', 'Smithing', 'Thieving', 'Farming', 'Fletching', 'Crafting', 'Runecrafting', 'Herblore', 'Agility', 'Summoning'} }, -- TODO Astrology
        },
  ["ChanceRandomPotionHerblore"] = { text = "{V}% chance to gain a second potion of a random tier", skills = {'Herblore'} },
        -- Alternative definition specifically for familiars like Dragon
  ["FlatPrayerCostReduction"] = { text = "{V} Prayer Point Cost for Prayers", inverseSign = true, skills = {'Prayer'} },
        {
  ["MinEarthSpellDmg"] = { text = "{VX} Min Earth Spell Dmg", skills = {'Magic'} },
            ["type"] = 'Modifier',
  ["SlayerTaskLength"] = { text = "{V}% Slayer Task Length/Qty", skills = {'Slayer'} },
            ["subtype"] = 'Familiar',
  ["ChanceToDoubleLootCombat"] = { text = "{V}% Chance To Double Loot in Combat", skills = {'Combat'} },
            ["modifiers"] = {
  ["GPFromAgility"] = { text = "{V}% GP From Agility", skills = {'Agility'} },
                ["include"] = { 'increasedChanceToApplyBurn' }
  ["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'} },
    ["Poison"] = {
  ["GlobalPreservationChance"] = { text = "{V}% Chance to Preserve Resources in Skills" },
        ["type"] = 'DOT',
  ["RunePreservation"] = { text = "{V}% Rune Preservation", skills = {'Magic'} },
        ["subtype"] = 'Poison'
  ["MaxHitpoints"] = { text = "{VX} Maximum Hitpoints", skills = {'Combat'} },
    },
  ["ChanceToDoubleItemsSkill"] = { text = "{V}% Chance to Double Items in {SV0}" },
    ["Slow"] = {
  ["autoSlayerUnlocked"] = { text = "{V} Auto Slayer Unlocked", skills = {'Slayer'} },
        ["type"] = 'Modifier',
  ["HitpointRegeneration"] = { text = "{V}% Hitpoint Regeneration", skills = {'Combat'} },
        ["modifiers"] = {
  ["PotionChargesFlat"] = { text = "{V} Charges per Potion" },
            ["include"] = { 'increasedAttackIntervalPercent' },
  ["SkillInterval"] = { text = "{VMS}s {SV0} Interval", isIncreaseNegative = true },
            ["exclude"] = { 'increasedFrostburn' }
  ["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'} },
    ["Bleed"] = {
  ["Lifesteal"] = { text = "{V}% Lifesteal", skills = {'Combat'} },
        ["type"] = 'DOT',
  ["HPRegenFlat"] = { text = "{VX} Flat HP Regen", skills = {'Combat'} },
        ["subtype"] = 'Bleed'
  ["ChanceToDoubleOres"] = { text = "{V}% Chance to Double Ores in Mining", skills = {'Combat'} },
    },
  ["MonsterRespawnTimer"] = { text = "{VMS}s Monster Respawn Timer", isIncreaseNegative = true, skills = {'Combat'} },
    ["Frostburn"] = {
  ["SkillPreservationChance"] = { text = "{V}% Chance to Preserve Resources in {SV0}" },
        ["type"] = 'Modifier',
  ["DamageToCombatAreaMonsters"] = { text = "{V}% Damage To Combat Area Monsters", skills = {'Combat'} },
        ["modifiers"] = {
  ["TreeCutLimit"] = { text = "{V} Tree Cut Limit", skills = {'Woodcutting'} },
            ["include"] = { 'increasedFrostburn', 'increasedAttackIntervalPercent' }
  ["EquipmentSets"] = { text = "{V} Equipment Sets" },
        }
  ["HiddenSkillLevel"] = { text = "{V} Hidden {SV0} Level" },
    },
  ["ChanceToPreservePrayerPoints"] = { text = "{V}% Chance To Preserve Prayer Points", skills = {'Prayer'} },
    ["Mark of Death"] = {
  ["ReflectDamage"] = { text = "{V}% Reflect Damage", skills = {'Combat'} },
        ["type"] = 'Stacking',
  ["MeleeEvasion"] = { text = "{V}% Melee Evasion", skills = {'Combat'} },
        ["modifiers"] = {
  ["DamageToSlayerAreaMonsters"] = { text = "{V}% Damage To Slayer Area Monsters", skills = {'Combat'} },
            ["include"] = { 'decreasedDamageReductionPercent' }
  ["GPFromMonsters"] = { text = "{V}% GP From Monsters", skills = {'Combat'} },
        }
  ["MagicEvasion"] = { text = "{V}% Magic Evasion", skills = {'Combat'} },
    },
  ["DamageReduction"] = { text = "{V}% Damage Reduction", skills = {'Combat'} },
    ["Affliction"] = {
  ["MinWaterSpellDmg"] = { text = "{VX} Min Water Spell Dmg", skills = {'Magic'} },
        ["type"] = 'Modifier',
  ["DamageToAllMonsters"] = { text = "{V}% Damage To All Monsters", skills = {'Combat'} },
        ["modifiers"] = {
  ["golbinRaidIncreasedStartingRuneCount"] = { text = "{V} to starting Elemental Rune count" },
            ["include"] = { 'decreasedMaxHitpoints' }
  ["FoodHealingValue"] = { text = "{V}% Food Healing Value", skills = {'Combat'} },
        }
  ["MinFireSpellDmg"] = { text = "{VX} Min Fire Spell Dmg", skills = {'Magic'} },
    },
  ["SlayerCoins"] = { text = "{V}% Slayer Coins", skills = {'Slayer'} },
    ["Sleep"] = {
  ["GPFromThievingFlat"] = { text = "{V} GP From Thieving", skills = {'Thieving'} },
        ["type"] = 'Sleep'
  ["GlobalAccuracy"] = { text = "{V}% Global Accuracy", skills = {'Combat'} },
    },
  ["SlayerAreaEffectNegationFlat"] = { text = "{V}% Flat Slayer Area Effect Negation", skills = {'Combat'} },
    ["Freeze"] = {
  ["MagicAccuracyBonus"] = { text = "{V}% Magic Accuracy Bonus", skills = {'Combat'} },
        ["type"] = 'Stun',
  ["SkillIntervalPercent"] = { text = "{V}% {SV0} Interval", isIncreaseNegative = true },
        ["flavour"] = 'Freeze'
  ["GlobalSkillXP"] = { text = "{V}% Global Skill XP" },
    },
  ["MeleeAccuracyBonus"] = { text = "{V}% Melee Accuracy Bonus", skills = {'Combat'} },
    ["Stun"] = {
  ["DamageToBosses"] = { text = "{V}% Damage To Bosses", skills = {'Combat'} },
        ["type"] = 'Stun',
  ["ChanceToPreservePotionCharge"] = { text = "{V}% Chance To Preserve Potion Charge" },
        ["flavour"] = 'Stun'
  ["MaxHitPercent"] = { text = "{V}% Max Hit", skills = {'Combat'} },
    },
  ["AltMagicSkillXP"] = { text = "{V}% Alt. Magic Skill XP", skills = {'Magic'} },
    ["Regen"] = {
  ["MinAirSpellDmg"] = { text = "{VX} Min Air Spell Dmg", skills = {'Combat'} },
        ["type"] = 'DOT',
  ["AutoEatEfficiency"] = { text = "{V}% Auto Eat Efficiency", skills = {'Combat'} },
        ["subtype"] = 'Regen'
  ["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 = "+ Automatically relight bonfires for free", 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 {IV}" },
  ["AttackRolls"] = { text = "+Lucky Hit Chance (Roll twice, take the better result)", skills = {'Combat'} },
  ["AmmoPreservation"] = { text = "{V}% Ammo Preservation", skills = {'Ranged'} },
  ["RangedStrengthBonus"] = { text = "{V}% Ranged Strength Bonus", skills = {'Combat'} },
  ["MagicDamageBonus"] = { text = "{V}% Magic Damage Bonus", 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"}},
  ["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'}},
  ["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'}},
  ["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 recieve a Diamond per action in Firemaking.", skills = {'Firemaking'}},
  ["summoningSynergy_5_9"] = {text = "{V}% chance to recieve 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'}},
  ["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'}},
  ["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'}},
  ["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.", 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."},
  ["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"}},
  ["summoningSynergy_13_14"] = {text = "{V}% Hitpoints Regeneration if you have less than 75% Current HP.", skills = {"Combat"}},
  ["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", skills = {'Prayer'} },
  ["autoLooting"] = { text = "Combat loot is automatically collected", skills = {'Combat'} },
  ["bleedImmunity"] = { text = "Immune to bleeding", skills = {'Combat'} },
  ["BleedLifesteal"] = { text = "{V}% Bleed lifsteal", skills = {'Combat'} },
  ["BonusCoalMining"] = { text = "{V} Coal Ore per Ore Mined. (Item doubling does not apply)", skills = {'Mining'} },
  ["bonusCoalOnDungeonCompletion"] = { text = "1% chance to recieve {V} Coal when completing a dungeon", skills = {'Combat'} },
  ["burnImmunity"] = { text = "Immune to burning", 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 = "Take {V}% of remaining HP as damage on a succesful attack", isIncreaseNegative = true, skills = {'Combat'} },
  ["curseImmunity"] = { text = "Immune to curses", skills = {'Combat'} },
  ["DamageReductionPercent"] = { text = "{V}% increased damage reduction", skills = {'Combat'} },
  ["DamageTaken"] = { text = "Take {V}% more Damage from attacks", isIncreaseNegative = true, skills = {'Combat'} },
  ["debuffImmunity"] = { text = "Immune to debuffs", skills = {'Combat'} },
  ["Decay"] = { text = "Take {V}% of Max HP as damage on a succesful attack", isIncreaseNegative = true, skills = {'Combat'} },
  ["doubleItemsSkill"] = { text = "x{VMUL} Items recieved from {SV0}" },
  ["doubleOresMining"] = { text = "x{VMUL} Ores recieved from Mining", skills = {'Mining'} },
  ["DragonBreathDamage"] = { text = "{V}% damage taken from dragonbreath", isIncreaseNegative = true, skills = {'Combat'} },
  ["FiremakingCoalChance"] = { text = "{V}% chance to recieve 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}% increased Evasion Ratings", 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 = "{MX} Max Air Spell Dmg", skills = {'Magic'} },
  ["MaxEarthSpellDmg"] = { text = "{MX} Max Earth Spell Dmg", skills = {'Magic'} },
  ["MaxFireSpellDmg"] = { text = "{MX} Max Fire Spell Dmg", skills = {'Magic'} },
  ["MaxWaterSpellDmg"] = { text = "{MX} 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 recieve gems from Mining (Does not work for Rune Essence)", skills = {'Combat'} },
  ["OffItemChance"] = { text = "{V}% increased chance to recieve an off-item (An item from a skill that is not the main resource you are gathering)" },
  ["poisonImmunity"] = { text = "Immune to poison", skills = {'Combat'} },
  ["PoisonLifesteal"] = { text = "{V}% Poison lifesteal", skills = {'Combat'} },
  ["PrayerCost"] = { text = "{V}% Prayer Point Cost for Prayers", 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-{V} Reflect Damage", isIncreaseNegative = true, unsigned = true, skills = {'Combat'} },
  ["RuneProvision"] = { text = "Rune providing items provide {VMUL}x as many runes", 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 = "Immune to 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'} }, -- TODO 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 = {''} }, -- TODO 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'} },
  ["EndOfTurnHealing3"] = { text = "{V}% of current hitpoints every 3 turns", skills = {'Combat'} },
  ["EndOfTurnHealing5"] = { text = "{V}% of current hitpoints every 5 turns", skills = {'Combat'} },
  ["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'} },
  ["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 = "{V}% Hitpoint Regeneration interval", skills = {'Combat'} },
  ["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'} },
}
 
--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
local CombatTriangle = {
  damageBonus = 1.1,
  drBonus = 1.25,
  damagePenalty = { Normal = 0.85,
                    Hardcore = 0.75 },
  drPenalty = { Melee = { Normal = 0.5,
                          Hardcore = 0.25 },
                Ranged = { Normal = 0.95,
                          Hardcore = 0.75 },
                Magic = { Normal = 0.85,
                          Hardcore = 0.75 }},
  Melee = { bonus = "Ranged", penalty = "Magic" },
  Ranged = { bonus = "Magic", penalty = "Melee" },
  Magic = { bonus = "Melee", penalty = "Ranged" },
}
}


function p.getAttackByID(ID)
function p.getTriangleDamageModifier(playerStyle, enemyStyle, mode)
     return AttackData.Attacks[ID + 1]
  if CombatTriangle[playerStyle].bonus == enemyStyle then
    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
 
--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(playerStyle, enemyStyle, mode)
  if CombatTriangle[playerStyle].bonus == enemyStyle then
    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
 
function p.getDifficultyString(difficulty)
  return Difficulties[difficulty]
end
 
function p.getSkillName(skillID)
  for skName, ID in Shared.skpairs(ConstantData.skill) do
    if ID == skillID then
      return skName
    end
  end
  return nil
end
 
function p.getSkillID(skillName)
  return ConstantData.skill[skillName]
end
 
function p.getEquipmentSlotName(id)
  for slotName, i in Shared.skpairs(ConstantData.equipmentSlot) do
     if i == id then
      return slotName
    end
  end
  return 'Invalid'
end
 
function p.getEquipmentSlotID(name)
  return ConstantData.equipmentSlot[name]
end
end


function p.getAttack(name)
function p.getCombatStyleName(styleNum)
    name = string.gsub(name, "%%27", "'")
  for name, num in Shared.skpairs(ConstantData.attackType) do
    name = string.gsub(name, "'", "'")
    if num == styleNum then
    name = string.gsub(name, "'", "'")
      return name
    for i, attack in ipairs(AttackData.Attacks) do
        if name == attack.name then
            return attack
        end
     end
     end
  end
  return "ERROR: Invalid combat style[[Category:Pages with script errors]]"
end
end


function p.getAttacks(checkFunc)
function p.getSlayerTierName(tier)
    local result = {}
  for name, num in Shared.skpairs(ConstantData.slayerTier) do
    for i, attack in ipairs(AttackData.Attacks) do
    if num == tier then
        if checkFunc(attack) then
      return name
            table.insert(result, attack)
        end
     end
     end
    return result
  end
  return "ERROR: Invalid Slayer tier[[Category:Pages with script errors]]"
end
end


function p.getAttackEffects(attack)
function p.getSlayerTierNameByLevel(lvl)
    local attackEffects = {}
  for i, tier in Shared.skpairs(ConstantData.Slayer.Tiers) do
    for effectName, effectDefn in pairs(p.effectDefinition) do
    if tier.minLevel <= lvl and (tier.maxLevel == nil or tier.maxLevel >= lvl) then
        if p.attackHasEffect(attack, effectDefn) then
      return tier.display
            table.insert(attackEffects, effectName)
        end
     end
     end
    return attackEffects
  end
  return 'N/A'
end
end


-- Determines if attack applies the effect defined in effectDefinition
function p.getSlayerTier(name)
function p.attackHasEffect(attack, effectDefn)
  for i, tier in Shared.skpairs(ConstantData.Slayer.Tiers) do
    if type(attack) == 'table' and type(effectDefn) == 'table' then
    if tier.display == name then
        -- Process pre-hit effects
      local result = Shared.clone(tier)
        for i, effect in ipairs(attack.prehitEffects) do
      result.id = i - 1
            if p.effectMatchesDefn(effect, effectDefn) then
      return result
                return true
            end
        end
        -- Process on hit effects
        for i, effect in ipairs(attack.onhitEffects) do
            if p.effectMatchesDefn(effect, effectDefn) then
                return true
            end
        end
     end
     end
     return false
  end
end
 
function p.getSlayerTierByID(tierID)
  if ConstantData.Slayer.Tiers[tierID + 1] == nil then
     return nil
  end
 
  local result = Shared.clone(ConstantData.Slayer.Tiers[tierID + 1])
  result.id = tierID
  return result
end
 
--Turns a modifier name like 'increasedMeleeAccuracyBonus' into several pieces of data:
--Base Name, Text, Sign, and IsNegative
--ex. "MeleeAccuracyBonus", "+{V}% Melee Accuracy", "+", false
function p.getModifierDetails(modifierName)
  local baseName = modifierName
  local isIncrease = true
  local isNegative = false
  local valueUnsigned = false
 
  if Shared.startsWith(modifierName, "increased") or Shared.startsWith(modifierName, "decreased") then
    baseName = string.sub(modifierName, 10)
    isIncrease = Shared.startsWith(modifierName, "increased")
  end
 
  local modifier = modifierTypes[baseName]
  if modifier == nil then
    return nil
  end
 
  local isPositive = isIncrease
  if modifier.isIncreaseNegative then
    isPositive = not isPositive
  end
 
  local sign = "+"
  if (not isIncrease and not modifier.inverseSign) or (isIncrease and modifier.inverseSign) then
    sign = "-"
  end
 
  if type(modifier.unsigned) == 'boolean' then valueUnsigned = modifier.unsigned end
 
  return baseName, modifier.text, sign, not isPositive, valueUnsigned
end
end


function p.effectMatchesDefn(effect, effectDefnIn)
function p._getModifierText(modifier, value, doColor)
    -- Some effects (e.g. Burn) have multiple definitions, so handle these correctly
  if doColor == nil then doColor = true end
    local effectDefnList = nil
  local modName, modText, sign, isNegative, valueUnsigned = p.getModifierDetails(modifier)
     if effectDefnIn[1] ~= nil and type(effectDefnIn[1]) == 'table' then
 
        -- Definition is actually multiple definitions
  if modName == nil then
         effectDefnList = effectDefnIn
     return 'ERROR: Invalid modifier type for ' .. modifier .. '[[Category:Pages with script errors]]'
  end
 
  local result = modText
 
  if type(value) == 'table' then
    if Shared.tableCount(value) > 0 and type(value[1]) == 'table' then
      --Potentially return multiple rows if necessary
      local resultArray = {}
      for i, subVal in Shared.skpairs(value) do
         table.insert(resultArray, p._getModifierText(modifier, subVal, doColor))
      end
      return table.concat(resultArray, '<br/>')
     else
     else
         -- Definition is singular, wrap it within a table so we can iterate
      if value[1] ~= nil then
         effectDefnList = { effectDefnIn }
         local skillName = p.getSkillName(value[1])
         if skillName ~= nil then
          result = string.gsub(result, '{SV0}', p.getSkillName(value[1]))
        end
      end
      if value[2] ~= nil then value = value[2] end
     end
     end
  end
  -- Re-check the type of value, as it may have been modified above even if it was originally a table
  if type(value) ~= 'table' then
    local valSign = (valueUnsigned and '' or sign)
    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}', valSign..value)
    result = string.gsub(result, '{VD}', valSign..(value / 10))
    result = string.gsub(result, '{VMS}', valSign..(value / 1000))
    result = string.gsub(result, '{VX}', valSign..(value * 10))
    result = string.gsub(result, '{VX100}', valSign..(value * 100))
    result = string.gsub(result, '{V%+100}', valSign..(value + 100))
    result = string.gsub(result, '{VMUL}', 2^value)
    result = string.gsub(result, '{S}', sign)
  end


     for i, effectDefn in pairs(effectDefnList) do
  if doColor then
        if p.effectMatchesDefnSingle(effect, effectDefn) then
     if isNegative ~= nil and isNegative then
            return true
      result = '<span style="color:red">'..result..'</span>'
        end
    else
      result = '<span style="color:green">'..result..'</span>'
     end
     end
     return false
  end
 
  return result
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 = {p.getSkillID(skill), value}
  end
 
  return p._getModifierText(modifier, value, doColor)
end
end


function p.effectMatchesDefnSingle(effect, effectDefn)
function p.getModifiersText(modifiers, doColor)
    if effectDefn.type ~= effect.type then
  if modifiers == nil or Shared.tableCount(modifiers) == 0 then
        -- Effect's type doesn't match that of the effect definition
    return ''
        return false
  end
    elseif (effectDefn.subtype ~= nil and (effect.subtype == nil or effect.subtype ~= effectDefn.subtype))
 
          or (effectDefn.flavour ~= nil and (effect.flavour == nil or effect.flavour ~= effectDefn.flavour)) then
  local modArray = {}
        -- Effect's subtype or flavour doesn't match that of the effect definition
  for bonus, value in Shared.skpairs(modifiers) do
        return false
    table.insert(modArray, p._getModifierText(bonus, value, doColor))
    elseif type(effectDefn.modifiers) == 'table' and (effectDefn.modifiers.include ~= nil or effectDefn.modifiers.exclude ~= nil) then
  end
        -- Definition contains modifiers which need to be checked
  return table.concat(modArray, "<br/>")
        local modsIncl, modsExcl = (effectDefn.modifiers.include or {}), (effectDefn.modifiers.exclude or {})
end
        local modsInclFound = {}
 
        if Shared.tableCount(modsIncl) > 0 and (type(effect.modifiers) ~= 'table' or Shared.tableCount(effect.modifiers) < Shared.tableCount(modsIncl)) then
function p.getModifierSkills(modifiers)
            -- Definition has 1+ included modifiers but effect has fewer modifiers than the definition
  local skillArray = {}
            return false
 
  for modifier, value in Shared.skpairs(modifiers) do
    if type(value) == 'table' then
      for i, subVal in Shared.skpairs(value) do
        local skillName = p.getSkillName(subVal[1])
        if not Shared.contains(skillArray, skillName) then
          table.insert(skillArray, skillName)
         end
         end
      end
    end


        for modName, modVal in pairs(effect.modifiers) do
    local baseName = p.getModifierDetails(modifier)
            if Shared.contains(modsExcl, modName, false) then
    if baseName == nil then
                -- Effect contains a modifier on the exclusion list
      return { 'ERROR: Modifier '..modifier..' is invalid' }
                return false
    end
            elseif Shared.contains(modsIncl, modName, false) then
 
                -- Flag included modifier as found
    if modifierTypes[baseName].skills ~= nil then
                modsInclFound[modName] = true
      for i, skillName in Shared.skpairs(modifierTypes[baseName].skills) do
            end
         if not Shared.contains(skillArray, skillName) then
        end
          table.insert(skillArray, skillName)
         if Shared.tableCount(modsInclFound) < Shared.tableCount(modsIncl) then
            -- Effect doesn't have all of the included modifiers
            return false
         end
         end
      end
     end
     end
    return true
  end
 
  return skillArray
end
end


return p
return p

Revision as of 00:53, 12 November 2021

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

local p = {}

local ConstantData = mw.loadData('Module:AuronTest/data')
local ItemData = mw.loadData('Module:Items/data')

local Shared = require('Module:Shared')

--Just hardcoding these because I guess that's where we're at
local modifierTypes = {
  ["MeleeStrengthBonus"] = { text = "{V}% Melee Strength Bonus", 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'} }, -- TODO Astrology
  ["ChanceRandomPotionHerblore"] = { text = "{V}% chance to gain a second potion of a random tier", skills = {'Herblore'} },
  ["FlatPrayerCostReduction"] = { text = "{V} Prayer Point Cost for Prayers", inverseSign = true, skills = {'Prayer'} },
  ["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'} },
  ["ChanceToDoubleItemsSkill"] = { text = "{V}% Chance to Double Items in {SV0}" },
  ["autoSlayerUnlocked"] = { text = "{V} Auto Slayer Unlocked", skills = {'Slayer'} },
  ["HitpointRegeneration"] = { text = "{V}% Hitpoint Regeneration", skills = {'Combat'} },
  ["PotionChargesFlat"] = { text = "{V} Charges per Potion" },
  ["SkillInterval"] = { text = "{VMS}s {SV0} Interval", isIncreaseNegative = 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'} },
  ["ChanceToDoubleOres"] = { text = "{V}% Chance to Double Ores in Mining", skills = {'Combat'} },
  ["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 },
  ["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 = {'Combat'} },
  ["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 = "+ Automatically relight bonfires for free", 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 {IV}" },
  ["AttackRolls"] = { text = "+Lucky Hit Chance (Roll twice, take the better result)", skills = {'Combat'} },
  ["AmmoPreservation"] = { text = "{V}% Ammo Preservation", skills = {'Ranged'} },
  ["RangedStrengthBonus"] = { text = "{V}% Ranged Strength Bonus", skills = {'Combat'} },
  ["MagicDamageBonus"] = { text = "{V}% Magic Damage Bonus", 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"}},
  ["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'}},
  ["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'}},
  ["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 recieve a Diamond per action in Firemaking.", skills = {'Firemaking'}},
  ["summoningSynergy_5_9"] = {text = "{V}% chance to recieve 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'}},
  ["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'}},
  ["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'}},
  ["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.", 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."},
  ["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"}},
  ["summoningSynergy_13_14"] = {text = "{V}% Hitpoints Regeneration if you have less than 75% Current HP.", skills = {"Combat"}},
  ["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", skills = {'Prayer'} },
  ["autoLooting"] = { text = "Combat loot is automatically collected", skills = {'Combat'} },
  ["bleedImmunity"] = { text = "Immune to bleeding", skills = {'Combat'} },
  ["BleedLifesteal"] = { text = "{V}% Bleed lifsteal", skills = {'Combat'} },
  ["BonusCoalMining"] = { text = "{V} Coal Ore per Ore Mined. (Item doubling does not apply)", skills = {'Mining'} },
  ["bonusCoalOnDungeonCompletion"] = { text = "1% chance to recieve {V} Coal when completing a dungeon", skills = {'Combat'} },
  ["burnImmunity"] = { text = "Immune to burning", 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 = "Take {V}% of remaining HP as damage on a succesful attack", isIncreaseNegative = true, skills = {'Combat'} },
  ["curseImmunity"] = { text = "Immune to curses", skills = {'Combat'} },
  ["DamageReductionPercent"] = { text = "{V}% increased damage reduction", skills = {'Combat'} },
  ["DamageTaken"] = { text = "Take {V}% more Damage from attacks", isIncreaseNegative = true, skills = {'Combat'} },
  ["debuffImmunity"] = { text = "Immune to debuffs", skills = {'Combat'} },
  ["Decay"] = { text = "Take {V}% of Max HP as damage on a succesful attack", isIncreaseNegative = true, skills = {'Combat'} },
  ["doubleItemsSkill"] = { text = "x{VMUL} Items recieved from {SV0}" },
  ["doubleOresMining"] = { text = "x{VMUL} Ores recieved from Mining", skills = {'Mining'} },
  ["DragonBreathDamage"] = { text = "{V}% damage taken from dragonbreath", isIncreaseNegative = true, skills = {'Combat'} },
  ["FiremakingCoalChance"] = { text = "{V}% chance to recieve 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}% increased Evasion Ratings", 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 = "{MX} Max Air Spell Dmg", skills = {'Magic'} },
  ["MaxEarthSpellDmg"] = { text = "{MX} Max Earth Spell Dmg", skills = {'Magic'} },
  ["MaxFireSpellDmg"] = { text = "{MX} Max Fire Spell Dmg", skills = {'Magic'} },
  ["MaxWaterSpellDmg"] = { text = "{MX} 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 recieve gems from Mining (Does not work for Rune Essence)", skills = {'Combat'} },
  ["OffItemChance"] = { text = "{V}% increased chance to recieve an off-item (An item from a skill that is not the main resource you are gathering)" },
  ["poisonImmunity"] = { text = "Immune to poison", skills = {'Combat'} },
  ["PoisonLifesteal"] = { text = "{V}% Poison lifesteal", skills = {'Combat'} },
  ["PrayerCost"] = { text = "{V}% Prayer Point Cost for Prayers", 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-{V} Reflect Damage", isIncreaseNegative = true, unsigned = true, skills = {'Combat'} },
  ["RuneProvision"] = { text = "Rune providing items provide {VMUL}x as many runes", 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 = "Immune to 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'} }, -- TODO 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 = {''} }, -- TODO 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'} },
  ["EndOfTurnHealing3"] = { text = "{V}% of current hitpoints every 3 turns", skills = {'Combat'} },
  ["EndOfTurnHealing5"] = { text = "{V}% of current hitpoints every 5 turns", skills = {'Combat'} },
  ["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'} },
  ["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 = "{V}% Hitpoint Regeneration interval", skills = {'Combat'} },
  ["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'} },
}

--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
local CombatTriangle = {
  damageBonus = 1.1, 
  drBonus = 1.25,
  damagePenalty = { Normal = 0.85,
                    Hardcore = 0.75 },
  drPenalty = { Melee = { Normal = 0.5,
                          Hardcore = 0.25 },
                Ranged = { Normal = 0.95,
                           Hardcore = 0.75 },
                Magic = { Normal = 0.85,
                          Hardcore = 0.75 }},
  Melee = { bonus = "Ranged", penalty = "Magic" },
  Ranged = { bonus = "Magic", penalty = "Melee" },
  Magic = { bonus = "Melee", penalty = "Ranged" },
}

function p.getTriangleDamageModifier(playerStyle, enemyStyle, mode)
  if CombatTriangle[playerStyle].bonus == enemyStyle then
    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

--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(playerStyle, enemyStyle, mode)
  if CombatTriangle[playerStyle].bonus == enemyStyle then
    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

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

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

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

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

function p.getEquipmentSlotID(name)
  return ConstantData.equipmentSlot[name]
end

function p.getCombatStyleName(styleNum)
  for name, num in Shared.skpairs(ConstantData.attackType) do
    if num == styleNum then
      return name
    end
  end
  return "ERROR: Invalid combat style[[Category:Pages with script errors]]"
end

function p.getSlayerTierName(tier)
  for name, num in Shared.skpairs(ConstantData.slayerTier) do
    if num == tier then
      return name
    end
  end
  return "ERROR: Invalid Slayer tier[[Category:Pages with script errors]]"
end

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

function p.getSlayerTier(name)
  for i, tier in Shared.skpairs(ConstantData.Slayer.Tiers) do
    if tier.display == name then
      local result = Shared.clone(tier)
      result.id = i - 1
      return result
    end
  end
end

function p.getSlayerTierByID(tierID)
  if ConstantData.Slayer.Tiers[tierID + 1] == nil then
    return nil
  end

  local result = Shared.clone(ConstantData.Slayer.Tiers[tierID + 1])
  result.id = tierID
  return result
end

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

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

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

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

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

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

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

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

  if modName == nil then
    return 'ERROR: Invalid modifier type for ' .. modifier .. '[[Category:Pages with script errors]]'
  end

  local result = modText

  if type(value) == 'table' then
    if Shared.tableCount(value) > 0 and type(value[1]) == 'table' then
      --Potentially return multiple rows if necessary
      local resultArray = {}
      for i, subVal in Shared.skpairs(value) do
        table.insert(resultArray, p._getModifierText(modifier, subVal, doColor))
      end
      return table.concat(resultArray, '<br/>')
    else
      if value[1] ~= nil then
        local skillName = p.getSkillName(value[1])
        if skillName ~= nil then
          result = string.gsub(result, '{SV0}', p.getSkillName(value[1]))
        end
      end
      if value[2] ~= nil then value = value[2] end
    end
  end
  -- Re-check the type of value, as it may have been modified above even if it was originally a table
  if type(value) ~= 'table' then
    local valSign = (valueUnsigned and '' or sign)
    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}', valSign..value)
    result = string.gsub(result, '{VD}', valSign..(value / 10))
    result = string.gsub(result, '{VMS}', valSign..(value / 1000))
    result = string.gsub(result, '{VX}', valSign..(value * 10))
    result = string.gsub(result, '{VX100}', valSign..(value * 100))
    result = string.gsub(result, '{V%+100}', valSign..(value + 100))
    result = string.gsub(result, '{VMUL}', 2^value)
    result = string.gsub(result, '{S}', sign)
  end

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

  return result
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 = {p.getSkillID(skill), value}
  end

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

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

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

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

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

    local baseName = p.getModifierDetails(modifier)
    if baseName == nil then
      return { 'ERROR: 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

return p