Anonymous

Module:Monsters: Difference between revisions

From Melvor Idle
Add column name for average healing
(Added slayer area effect to getMonsterAreas to try out)
(Add column name for average healing)
(36 intermediate revisions by 5 users not shown)
Line 10: Line 10:


function p.getMonster(name)
function p.getMonster(name)
    return GameData.getEntityByName('monsters', name)
if name == 'Earth Golem (AoD)' then
-- Special case for ambiguous monster name
return p.getMonsterByID('melvorAoD:EarthGolem')
else
    return GameData.getEntityByName('monsters', name)
    end
end
end


function p.getMonsterByID(ID)
function p.getMonsterByID(ID)
     return GameData.getEntityByID('monsters', ID)
     return GameData.getEntityByID('monsters', ID)
end
function p.getMonsterName(monster)
if monster.id == 'melvorAoD:EarthGolem' then
-- Special case for ambiguous monster name
return 'Earth Golem (AoD)'
else
return monster.name
end
end
end


Line 39: Line 53:


function p._getMonsterStat(monster, statName)
function p._getMonsterStat(monster, statName)
if statName == 'HP' then
if statName == 'Barrier' then
return p._getMonsterBarrier(monster)
elseif statName == 'HP' then
return p._getMonsterHP(monster)
return p._getMonsterHP(monster)
elseif statName == 'maxHit' then
elseif statName == 'maxHit' then
Line 53: Line 69:
elseif statName == 'damageReduction' then
elseif statName == 'damageReduction' then
return p.getEquipmentStat(monster, 'damageReduction')
return p.getEquipmentStat(monster, 'damageReduction')
elseif statName == 'drReduction' then
return p._getMonsterDrReduction(monster)
end
end


Line 63: Line 81:
local monster = p.getMonster(MonsterName)
local monster = p.getMonster(MonsterName)
if monster == nil then
if monster == nil then
return "ERROR: No monster with that name found[[Category:Pages with script errors]]"
return Shared.printError('No monster with that name found')
end
end


Line 83: Line 101:
iconText = Icons.Icon({'Magic', type='skill', notext=notext, nolink=nolink})
iconText = Icons.Icon({'Magic', type='skill', notext=notext, nolink=nolink})
elseif monster.attackType == 'random' then
elseif monster.attackType == 'random' then
iconText = Icons.Icon({monster.name, notext=notext, nolink=nolink, img='Question'})
iconText = Icons.Icon({p.getMonsterName(monster), notext=notext, nolink=nolink, img='Question'})
end
end


Line 95: Line 113:


if monster == nil then
if monster == nil then
return "ERROR: No monster with that name found[[Category:Pages with script errors]]"
return Shared.printError('No monster with that name found')
end
end


Line 104: Line 122:
function p._getMonsterHP(monster)
function p._getMonsterHP(monster)
return 10 * p._getMonsterLevel(monster, 'Hitpoints')
return 10 * p._getMonsterLevel(monster, 'Hitpoints')
end
function p._getMonsterBarrier(monster)
--Monster Barrier is a percentage of its max health
local barPercent = 0
if monster.barrierPercent ~= nil then
barPercent = monster.barrierPercent
end
return p._getMonsterHP(monster) * barPercent * 0.01
end
end


Line 112: Line 139:
return math.floor((p._getMonsterHP(monster)/(1 - p._getMonsterStat(monster, 'damageReduction')/100)) + 0.5)
return math.floor((p._getMonsterHP(monster)/(1 - p._getMonsterStat(monster, 'damageReduction')/100)) + 0.5)
else
else
return "ERROR: No monster with that name found[[Category:Pages with script errors]]"
return Shared.printError('No monster with that name found')
end
end
 
function p.getMonsterEffectiveBarrier(frame)
local MonsterName = frame.args ~= nil and frame.args[1] or frame
local monster = p.getMonster(MonsterName)
if monster ~= nil then
return math.floor((p._getMonsterBarrier(monster)/(1 - p._getMonsterStat(monster, 'damageReduction')/100)) + 0.5)
else
return Shared.printError('No monster with that name found')
end
end
 
function p.getMonsterBarrier(frame)
local MonsterName = frame.args ~= nil and frame.args[1] or frame
local monster = p.getMonster(MonsterName)
if monster ~= nil then
return p._getMonsterBarrier(monster)
else
return Shared.printError('No monster with that name found')
end
end
end
end
Line 122: Line 169:
return p._getMonsterHP(monster)
return p._getMonsterHP(monster)
else
else
return "ERROR: No monster with that name found[[Category:Pages with script errors]]"
return Shared.printError('No monster with that name found')
end
end
end
end
Line 140: Line 187:


if monster == nil then
if monster == nil then
return "ERROR: No monster with that name found[[Category:Pages with script errors]]"
return Shared.printError('No monster with that name found')
end
end


Line 175: Line 222:
return p._getMonsterAttackSpeed(monster)
return p._getMonsterAttackSpeed(monster)
else
else
return "ERROR: No monster with that name found[[Category:Pages with script errors]]"
return Shared.printError('No monster with that name found')
end
end
end
end
Line 192: Line 239:


if monster == nil then
if monster == nil then
return "ERROR: No monster with that name found[[Category:Pages with script errors]]"
return Shared.printError('No monster with that name found')
end
end


Line 215: Line 262:
bonus = p.getEquipmentStat(monster, 'stabAttackBonus')
bonus = p.getEquipmentStat(monster, 'stabAttackBonus')
else
else
return "ERROR: This monster has an invalid attack type somehow[[Category:Pages with script errors]]"
return Shared.printError('This monster has an invalid attack type somehow')
end
end


Line 226: Line 273:


if monster == nil then
if monster == nil then
return "ERROR: No monster with that name found[[Category:Pages with script errors]]"
return Shared.printError('No monster with that name found')
end
end


Line 246: Line 293:
bonus = p.getEquipmentStat(monster, 'magicDefenceBonus')
bonus = p.getEquipmentStat(monster, 'magicDefenceBonus')
else
else
return "ERROR: Must choose Melee, Ranged, or Magic[[Category:Pages with script errors]]"
return Shared.printError('Must choose Melee, Ranged, or Magic')
end
end


Line 259: Line 306:


if monster == nil then
if monster == nil then
return "ERROR: No monster with that name found[[Category:Pages with script errors]]"
return Shared.printError('No monster with that name found')
end
end


Line 301: Line 348:


if monster == nil then
if monster == nil then
return "ERROR: No monster with name "..monsterName.." found[[Category:Pages with script errors]]"
return Shared.printError('No monster with name ' .. monsterName .. ' found')
end
end


Line 315: Line 362:
if area.type ~= 'dungeon' or not hideDungeons then
if area.type ~= 'dungeon' or not hideDungeons then
local imgType = (area.type == 'slayerArea' and 'combatArea') or area.type
local imgType = (area.type == 'slayerArea' and 'combatArea') or area.type
table.insert(resultPart, Icons.Icon({area.name, type = imgType}))
local txt = Icons.Icon({area.name, type = imgType})
if area.type == 'slayerArea' then
if area.type == 'slayerArea' then
local areaDescrip = Areas._getAreaStat(area, 'areaEffectDesc')
local areaDescrip = Areas._getAreaStat(area, 'areaEffectDesc')
if areaDescrip ~= 'None' then
if areaDescrip ~= 'None' then
table.insert(resultPart, "'''"..areaDescrip.."'''")
txt = txt.." - ''"..areaDescrip.."''"
end
end
end
end
table.insert(resultPart, txt)
end
end
end
end
Line 334: Line 382:


if monster == nil then
if monster == nil then
return "ERROR: No monster with name "..monsterName.." found[[Category:Pages with script errors]]"
return Shared.printError('No monster with name ' .. monsterName .. ' found')
end
end


Line 340: Line 388:
end
end


function p.getSpecAttackMaxHit(specAttack, normalMaxHit)
function p.getSpecAttackMaxHit(specAttack, normalMaxHit, monster)
local result = 0
local bestHit = 0
for i, dmg in pairs(specAttack.damage) do
for i, dmg in pairs(specAttack.damage) do
if dmg.maxRoll == 'Fixed' then
local thisHit = 0
result = dmg.maxPercent * 10
if dmg.damageType == 'Normal' then
--Account for special attacks that include a normal attack hit
thisHit = normalMaxHit
if dmg.amplitude ~= nil then
thisHit = thisHit * (dmg.amplitude / 100)
end
elseif dmg.maxRoll == 'Fixed' then
thisHit = dmg.maxPercent * 10
elseif dmg.maxRoll == 'MaxHit' then
elseif dmg.maxRoll == 'MaxHit' then
if dmg.character == 'Target' then
if dmg.character == 'Target' then
--Confusion applied damage based on the player's max hit. Gonna just ignore that one
--Confusion applied damage based on the player's max hit. Gonna just ignore that one
result = 0
thisHit = 0
else
else
result = dmg.maxPercent * normalMaxHit * 0.01
thisHit = dmg.maxPercent * normalMaxHit * 0.01
end
end
elseif Shared.contains(dmg.maxRoll, "Fixed100") then
--Handles attacks that are doubled when conditions are met like Trogark's double damage if the player is burning
thisHit = dmg.maxPercent * 20
elseif dmg.maxRoll == 'MaxHitScaledByHP2x' then
thisHit = normalMaxHit * 2
elseif dmg.maxRoll == 'PoisonMax35' then
thisHit = normalMaxHit * 1.35
elseif dmg.maxRoll == "MaxHitDR" then
local monsterDR = 0
if monster ~= nil then
monsterDR = p._getMonsterStat(monster, 'damageReduction')
end
thisHit = normalMaxHit * dmg.maxPercent * 0.01 * (1 + monsterDR * 0.01)
elseif Shared.contains({'Bleeding', 'Poisoned'}, dmg.maxRoll) then
elseif Shared.contains({'Bleeding', 'Poisoned'}, dmg.maxRoll) then
-- TODO: This is limited in that there is no verification that bleed/poison
-- TODO: This is limited in that there is no verification that bleed/poison
-- can be applied to the target, it is assumed that it can and so this applies
-- can be applied to the target, it is assumed that it can and so this applies
result = result + dmg.maxPercent * 10
thisHit = thisHit + dmg.maxPercent * 10
end
if thisHit > bestHit then
bestHit = thisHit
end
end
end
end
return result
return bestHit
end
end


function p.canSpecAttackApplyEffect(specAttack, effectType)
function p.canSpecAttackApplyEffect(specAttack, effectType)
for i, effect in pairs(specAttack.prehitEffects) do
local effectKeys = { 'prehitEffects', 'onhitEffects' }
if effect.type == effectType then
for i, effectKey in ipairs(effectKeys) do
            return true
if type(specAttack[effectKey]) == 'table' then
for j, effect in pairs(specAttack[effectKey]) do
if effect.type == effectType or p.canModifiersApplyEffect(effect.modifiers, effectType) then
return true
end
end
end
end
end
end
return false
end


for i, effect in pairs(specAttack.onhitEffects) do
function p.canModifiersApplyEffect(modifiers, effectType)
if effect.type == effectType then
-- List of modifiers which can result in the application of status effects
return true
local statusModsAll = {
["Stun"] = { 'increasedGlobalStunChance', 'increasedMeleeStunChance' },
["Sleep"] = { 'increasedGlobalSleepChance' },
["Poison"] = { 'increasedChanceToApplyPoison' },
["Slow"] = { 'increased15SlowStunChance2Turns', 'increased30Slow5TurnsChance' }
}
 
local statusMods = statusModsAll[effectType]
if statusMods ~= nil and type(modifiers) == 'table' then
for modName, modMagnitude in pairs(modifiers) do
if Shared.contains(statusMods, modName) then
return true
end
end
end
end
end
Line 385: Line 476:
end
end


local normalChance = 100
-- Damage adjustments are defined as follows:
local specialMaxHit = 0
-- multiplier - Damage from modifier 'increasedDamageTaken' & additional damage while
local normalMaxHit = p._getMonsterBaseMaxHit(monster)
-- stunned, asleep, or poisoned. Defined by in-game function
local hasActiveBuffSpec = false
-- getDamageModifiers(). Applies after other percentage of flat adjustments.
local damageMultiplier = 1
-- percent - Percentage adjustments to the max hit. Applies before flat & multiplier
if monster.specialAttacks ~= nil then
-- adjustments.
local canStun, canSleep = false, false
-- flat - Flat adjustments to the max hit. Applies after percent adjustments, and
for i, specAttackID in pairs(monster.specialAttacks) do
-- after multiplier adjustments.
            local specAttack = GameData.getEntityByID('attacks', specAttackID)
local dmgAdjust = { ["percent"] = 100, ["flat"] = 0, ["multiplier"] = 100 }
if monster.overrideSpecialChances ~= nil then
-- Check passives & effects that apply pre or on hit for damage modifiers
normalChance = normalChance - monster.overrideSpecialChances[i]
local dmgMods = {
else
-- List of modifiers which affect damage dealt, and whether they are percentage or flat adjustments
normalChance = normalChance - specAttack.defaultChance
["increasedDamageTaken"] = { type = 'multiplier', mult = 1 },
end
["increasedMaxHitPercent"] = { type = 'percent', mult = 1 },
local thisMax = p.getSpecAttackMaxHit(specAttack, normalMaxHit)
["increasedMeleeMaxHit"] = { type = 'percent', mult = 1 },
if not canStun and p.canSpecAttackApplyEffect(specAttack, 'Stun') then canStun = true end
["increasedRangedMaxHit"] = { type = 'percent', mult = 1 },
if not canSleep and p.canSpecAttackApplyEffect(specAttack, 'Sleep') then canSleep = true end
["increasedMagicMaxHit"] = { type = 'percent', mult = 1 },
["increasedMaxHitFlat"] = { type = 'flat', mult = 10 },
["increasedMeleeMaxHitFlat"] = { type = 'flat', mult = 10 },
["increasedRangedMaxHitFlat"] = { type = 'flat', mult = 10 },
["increasedMagicMaxHitFlat"] = { type = 'flat', mult = 10 },
-- Rage: +2% max hit per stack, maximum of 10 stacks
["increasedRage"] = { type = 'percent', mult = 1, magnitude = 2, maxStacks = 10 },
-- Dark Blade: +1% max hit per successful hit, maximum of 30 stacks
["increasedChanceDarkBlade"] = { type = 'percent', mult = 1, magnitude = 1, maxStacks = 30 },
-- Growing Madness/Moment in Time/Reign Over Time: +2% max hit per stack, maximum of 25 stacks
["growingMadnessPassive"] = { type = 'percent', mult = 1, magnitude = 2, maxStacks = 25 },
["momentInTimePassive"] = { type = 'percent', mult = 1, magnitude = 2, maxStacks = 25 },
["reignOverTimePassive"] = { type = 'percent', mult = 1, magnitude = 2, maxStacks = 25 }
}
local effectKeys = { 'prehitEffects', 'onhitEffects' }
local dmgStatuses = {
-- List of status effects which can affect damage dealt
["Stun"] = { type = 'multiplier', magnitude = 30 },
["Sleep"] = { type = 'multiplier', magnitude = 20 }
}
local canApplyStatus = {}
-- Initialize table
for statusName, def in pairs(dmgStatuses) do
canApplyStatus[statusName] = false
end
 
local adjustForMod = function(mod, modMagnitude, effect)
local magnitude = mod.magnitude or modMagnitude
local maxStacks = mod.maxStacks or (effect ~= nil and effect.maxStacks) or 1
dmgAdjust[mod.type] = dmgAdjust[mod.type] + magnitude * mod.mult * maxStacks
end


if thisMax > specialMaxHit then specialMaxHit = thisMax end
local adjustForCurse = function(curseID, effect)
if Shared.contains(string.upper(specAttack.description), 'NORMAL ATTACK INSTEAD') then  
local curse = Magic.getSpellByID(curseID, 'curse')
hasActiveBuffSpec = true
if type(curse) == 'table' and type(curse.targetModifiers) == 'table' then
for modName, modMagnitude in pairs(curse.targetModifiers) do
local mod = dmgMods[modName]
if mod ~= nil then
-- The modifier is one which affects damage dealt
adjustForMod(mod, modMagnitude, effect)
end
end
end
end
end
if canSleep and doStuns then damageMultiplier = damageMultiplier * 1.2 end
if canStun and doStuns then damageMultiplier = damageMultiplier * 1.3 end
end
end
--Ensure that if the monster never does a normal attack, the normal max hit is irrelevant
if normalChance == 0 and not hasActiveBuffSpec then normalMaxHit = 0 end
return math.floor(math.max(specialMaxHit, normalMaxHit) * damageMultiplier)
end


function p.getMonsterMaxHit(frame)
-- Check monster passives for modifiers which affect damage dealt, and alo if any modifiers
local MonsterName = frame.args ~= nil and frame.args[1] or frame
-- present can apply stun or sleep
local doStuns = frame.args ~= nil and frame.args[2] or true
if monster ~= nil and type(monster.passives) ~= nil then
local monster = p.getMonster(MonsterName)
for i, passiveID in ipairs(monster.passives) do
 
local passive = p.getPassiveByID(passiveID)
if monster == nil then
if passive ~= nil and type(passive.modifiers) == 'table' then
return "ERROR: No monster with that name found[[Category:Pages with script errors]]"
for modName, modMagnitude in pairs(passive.modifiers) do
local mod = dmgMods[modName]
if modName == 'applyRandomCurseOnSpawn' then
-- Special case in which the enemy can apply a random curse. Currently
-- Anguish III is the curse with the highest +% damage taken, so use this.
adjustForCurse('melvorF:AnguishIII')
elseif mod ~= nil then
-- The modifier is one which affects damage dealt
adjustForMod(mod, modMagnitude)
end
end
-- Check for application of relevant status effects
if doStuns then
for statusName, statusDef in pairs(dmgStatuses) do
if not canApplyStatus[statusName] and p.canModifiersApplyEffect(passive.modifiers, statusName) then
canApplyStatus[statusName] = true
end
end
end
end
end
end
end


return p._getMonsterMaxHit(monster, doStuns)
local normalChance = 100
end
local specialMaxHit = 0
 
local normalMaxHit = p._getMonsterBaseMaxHit(monster)
function p._getMonsterBaseMaxHit(monster)
local hasActiveBuffSpec = false
--8/27/21 - Now references p.calculateStandardMaxHit for Melee & Ranged
if monster.specialAttacks ~= nil then
local result = 0
for i, specAttackID in pairs(monster.specialAttacks) do
local baseLevel = 0
            local specAttack = GameData.getEntityByID('attacks', specAttackID)
local bonus = 0
for i, effectKey in ipairs(effectKeys) do
if monster.attackType == 'melee' then
if type(specAttack[effectKey]) == 'table' then
baseLevel = p._getMonsterLevel(monster, 'Strength')
for j, effect in ipairs(specAttack[effectKey]) do
bonus = p.getEquipmentStat(monster, 'meleeStrengthBonus')
local countsOnPlayer = (effect.countsOn == nil or effect.countsOn == 'Attacker')
result = p.calculateStandardMaxHit(baseLevel, bonus)
if countsOnPlayer then
elseif monster.attackType == 'ranged' then
-- Check for pre or on hit effects for modifiers which affect damage dealt
baseLevel = p._getMonsterLevel(monster, 'Ranged')
if type(effect.modifiers) == 'table' then
bonus = p.getEquipmentStat(monster, 'rangedStrengthBonus')
for modName, modMagnitude in pairs(effect.modifiers) do
result = p.calculateStandardMaxHit(baseLevel, bonus)
local mod = dmgMods[modName]
elseif monster.attackType == 'magic' then
if mod ~= nil then
         if monster.selectedSpell == nil then
-- The modifier is one which affects damage dealt
             result = 0
adjustForMod(mod, modMagnitude, effect)
         else
end
             local mSpell = Magic.getSpellByID(monster.selectedSpell, 'standard')
end
             if mSpell == nil then
end
                 result = 0
-- Check for curses which may cause the player to incur additional damage
             else
if effect.effectType == 'Curse' then
                 baseLevel = p._getMonsterLevel(monster, 'Magic')
-- If isRandom is true then a random curse is selected. Currently
                 bonus = p.getEquipmentStat(monster, 'magicDamageBonus')
-- Anguish III is the curse with the highest +% damage taken, so
                 result = math.floor(10 * mSpell.maxHit * (1 + bonus / 100) * (1 + (baseLevel + 1) / 200))
-- use this.
             end
local curseID = (effect.isRandom and 'melvorF:AnguishIII') or effect.curse
         end
if curseID ~= nil then
elseif monster.attackType == 'random' then
adjustForCurse(curseID, effect)
local hitArray = {}
end
local iconText = Icons.Icon({'Melee', notext=true})
end
end
end
end
end
 
if monster.overrideSpecialChances ~= nil then
normalChance = normalChance - monster.overrideSpecialChances[i]
else
normalChance = normalChance - specAttack.defaultChance
end
-- Check for application of relevant status effects
if doStuns then
for statusName, statusDef in pairs(dmgStatuses) do
if not canApplyStatus[statusName] and p.canSpecAttackApplyEffect(specAttack, statusName) then
canApplyStatus[statusName] = true
end
end
end
 
local thisMax = p.getSpecAttackMaxHit(specAttack, normalMaxHit, monster)
if thisMax > specialMaxHit then specialMaxHit = thisMax end
if Shared.contains(string.upper(specAttack.description), 'NORMAL ATTACK INSTEAD') then
hasActiveBuffSpec = true
end
end
 
if doStuns then
for statusName, statusDef in pairs(dmgStatuses) do
if canApplyStatus[statusName] then
local adjType = statusDef.type
dmgAdjust[adjType] = dmgAdjust[adjType] + statusDef.magnitude
end
end
end
end
--Ensure that if the monster never does a normal attack, the normal max hit is irrelevant
if normalChance == 0 and not hasActiveBuffSpec then normalMaxHit = 0 end
local maxHit = math.floor(math.max(specialMaxHit, normalMaxHit) * dmgAdjust.percent / 100) + dmgAdjust.flat
return math.floor(maxHit * dmgAdjust.multiplier / 100)
end
 
function p.getMonsterMaxHit(frame)
local MonsterName = frame.args ~= nil and frame.args[1] or frame
local doStuns = frame.args ~= nil and frame.args[2] or true
local monster = p.getMonster(MonsterName)
 
if monster == nil then
return Shared.printError('No monster with that name found')
end
 
return p._getMonsterMaxHit(monster, doStuns)
end
 
function p._getMonsterBaseMaxHit(monster)
--8/27/21 - Now references p.calculateStandardMaxHit for Melee & Ranged
local result = 0
local baseLevel = 0
local bonus = 0
if monster.attackType == 'melee' then
baseLevel = p._getMonsterLevel(monster, 'Strength')
bonus = p.getEquipmentStat(monster, 'meleeStrengthBonus')
result = p.calculateStandardMaxHit(baseLevel, bonus)
elseif monster.attackType == 'ranged' then
baseLevel = p._getMonsterLevel(monster, 'Ranged')
bonus = p.getEquipmentStat(monster, 'rangedStrengthBonus')
result = p.calculateStandardMaxHit(baseLevel, bonus)
elseif monster.attackType == 'magic' then
         if monster.selectedSpell == nil then
             result = 0
         else
             local mSpell = Magic.getSpellByID(monster.selectedSpell, 'standard')
             if mSpell == nil then
                 result = 0
             else
                 baseLevel = p._getMonsterLevel(monster, 'Magic')
                 bonus = p.getEquipmentStat(monster, 'magicDamageBonus')
                 result = math.floor(10 * mSpell.maxHit * (1 + bonus / 100) * (1 + (baseLevel + 1) / 200))
             end
         end
elseif monster.attackType == 'random' then
local hitArray = {}
local iconText = Icons.Icon({'Melee', notext=true})
baseLevel = p._getMonsterLevel(monster, 'Strength')
baseLevel = p._getMonsterLevel(monster, 'Strength')
bonus = p.getEquipmentStat(monster, 'meleeStrengthBonus')
bonus = p.getEquipmentStat(monster, 'meleeStrengthBonus')
Line 485: Line 708:
result = max
result = max
else
else
return "ERROR: This monster has an invalid attack type somehow[[Category:Pages with script errors]]"
return Shared.printError('This monster has an invalid attack type somehow')
end
end


Line 496: Line 719:


if monster == nil then
if monster == nil then
return "ERROR: No monster with that name found[[Category:Pages with script errors]]"
return Shared.printError('No monster with that name found')
end
end


Line 507: Line 730:


if monster == nil then
if monster == nil then
return "ERROR: No monster with that name found[[Category:Pages with script errors]]"
return Shared.printError('No monster with that name found')
end
end


Line 525: Line 748:
local buffAttacks = {}
local buffAttacks = {}
local hasActiveBuffSpec = false
local hasActiveBuffSpec = false
local isNormalAttackRelevant = false


local normalAttackChance = 100
local normalAttackChance = 100
Line 539: Line 763:


result = result..'\r\n* '..attChance..'% '..iconText..' '..specAttack.name..'\r\n** '..specAttack.description
result = result..'\r\n* '..attChance..'% '..iconText..' '..specAttack.name..'\r\n** '..specAttack.description
 
--If this special attack applies a curse, let's actually list what that curse does
if specAttack.onhitEffects ~= nil then
for j, hitEffect in ipairs(specAttack.onhitEffects) do
if hitEffect.effectType == 'Curse' then
local curse = Magic.getSpellByID(hitEffect.curse, 'curse')
result = result..'\r\n*** '..Icons.Icon({curse.name, type='curse'})..': '..Magic._getSpellDescription(curse, true)
end
end
end
 
if Shared.contains(string.upper(specAttack.description), 'NORMAL ATTACK INSTEAD') then
if Shared.contains(string.upper(specAttack.description), 'NORMAL ATTACK INSTEAD') then
table.insert(buffAttacks, specAttack.name)
table.insert(buffAttacks, specAttack.name)
hasActiveBuffSpec = true  
hasActiveBuffSpec = true
isNormalAttackRelevant = true
end
if not isNormalAttackRelevant and type(specAttack.damage) == 'table' then
-- Determine if the special attack uses normal damage in some form
for j, dmgData in ipairs(specAttack.damage) do
if dmgData.damageType == 'Normal' then
isNormalAttackRelevant = true
break
end
end
end
end
end
end
end
end
if normalAttackChance == 100 then
result = iconText..' 1 - '..p._getMonsterBaseMaxHit(monster)..' '..typeText..' Damage'
if isNormalAttackRelevant or normalAttackChance > 0 then
elseif normalAttackChance > 0 then
--Reformatting slightly - If there are any special attacks, specifically label the Normal Attack
result = '* '..normalAttackChance..'% '..iconText..' 1 - '..p.getMonsterBaseMaxHit(frame)..' '..typeText..' Damage'..result
elseif hasActiveBuffSpec then
local normalDmgText = ' 1 - '..Shared.formatnum(p._getMonsterBaseMaxHit(monster))..' '..typeText..' Damage'
--If the monster normally has a 0% chance of doing a normal attack but some special attacks can't be repeated, include it
if normalAttackChance > 0 and normalAttackChance < 100 then
--(With a note about when it does it)
normalDmgText = normalAttackChance .. '% ' ..iconText..' Normal Attack\r\n** '..normalDmgText
result = '* '..iconText..' 1 - '..p._getMonsterBaseMaxHit(monster)..' '..typeText..' Damage (Instead of repeating '..table.concat(buffAttacks, ' or ')..' while the effect is already active)'..result
elseif hasActiveBuffSpec and normalAttackChance == 0 then
--If the monster normally has a 0% chance of doing a normal attack but some special attacks can't be repeated, include it
--(With a note about when it does it)
normalDmgText = iconText..' Normal Attack\r\n** '..normalDmgText .. ' (Instead of repeating '..table.concat(buffAttacks, ' or ')..' while the effect is already active)'
end
result = '* ' .. normalDmgText .. result
end
end


Line 559: Line 808:
end
end


function p.getMonsterPassives(frame)
--Function for pulling how much the monster reduces the player DR
--Goes through the passvies to look for the decreasedPlayerDamageReduction modifier
function p._getMonsterDrReduction(monster)
local totalResult = 0
    if type(monster.passives) == 'table' and not Shared.tableIsEmpty(monster.passives) then
for i, passiveID in ipairs(monster.passives) do
local passive = p.getPassiveByID(passiveID)
if passive.modifiers ~= nil then
if passive.modifiers['decreasedPlayerDamageReduction'] ~= nil then
totalResult = totalResult + passive.modifiers['decreasedPlayerDamageReduction']
end
end
end
    end
   
    return totalResult
end
 
function p.getMonsterDrReduction(frame)
local MonsterName = frame.args ~= nil and frame.args[1] or frame
local MonsterName = frame.args ~= nil and frame.args[1] or frame
local monster = p.getMonster(MonsterName)
local monster = p.getMonster(MonsterName)


if monster == nil then
if monster == nil then
return "ERROR: No monster with that name found[[Category:Pages with script errors]]"
return Shared.printError('No monster with that name found')
end
end
return p._getMonsterDrReduction(monster)
end


local result = ''
function p.getMonsterPassives(frame)
     if type(monster.passives) == 'table' and not Shared.tableIsEmpty(monster.passives) then
local MonsterName = frame.args ~= nil and frame.args[1] or frame
local monster = p.getMonster(MonsterName)
 
if monster == nil then
return Shared.printError('No monster with that name found')
end
 
local result = ''
     if type(monster.passives) == 'table' and not Shared.tableIsEmpty(monster.passives) then
result = result .. '===Passives==='
result = result .. '===Passives==='
for i, passiveID in ipairs(monster.passives) do
for i, passiveID in ipairs(monster.passives) do
Line 583: Line 862:


if monster == nil then
if monster == nil then
return "ERROR: No monster with that name found[[Category:Pages with script errors]]"
return Shared.printError('No monster with that name found')
end
end


Line 605: Line 884:


return result
return result
end
function p.getMonsterBoxBarrierText(frame)
local MonsterName = frame.args ~= nil and frame.args[1] or frame
local monster = p.getMonster(MonsterName)
if monster == nil then
return Shared.printError('No monster with that name found')
end
local barrier = p._getMonsterBarrier(monster)
if barrier == 0 then
return ''
end
local result = {}
table.insert(result, '|-\r\n| style="font-weight: bold;" | [[Barrier]]:')
table.insert(result, '\r\n| colspan=15 style="text-align: right" |')
table.insert(result, Icons.Icon({"Barrier", notext="true"}))
table.insert(result, ' '..barrier)
return table.concat(result, '')
end
end


Line 612: Line 912:


if monster == nil then
if monster == nil then
return "ERROR: No monster with that name found[[Category:Pages with script errors]]"
return Shared.printError('No monster with that name found')
end
end


Line 653: Line 953:


if monster == nil then
if monster == nil then
return "ERROR: No monster with that name found[[Category:Pages with script errors]]"
return Shared.printError('No monster with that name found')
end
end


Line 660: Line 960:
local bones = p._getMonsterBones(monster)
local bones = p._getMonsterBones(monster)
local boneVal = 0
local boneVal = 0
local barrierDust = Items.getItemByID("melvorAoD:Barrier_Dust")
local dustVal = 0
--Show the bones only if either the monster shows up outside of dungeons _or_ the monster drops shards
--Show the bones only if either the monster shows up outside of dungeons _or_ the monster drops shards
if bones ~= nil then
if bones ~= nil then
local boneQty = (bones.quantity ~= nil and bones.quantity or 1)
local boneQty = (bones.quantity ~= nil and bones.quantity or 1)
local barrier = p._getMonsterBarrier(monster)
result = result.."'''Always Drops:'''"
result = result.."'''Always Drops:'''"
result = result..'\r\n{|class="wikitable" id="bonedrops"'
result = result..'\r\n{|class="wikitable" id="bonedrops"'
result = result..'\r\n!Item !! Qty'
result = result..'\r\n!Item !! Qty'
result = result..'\r\n|-\r\n|'..Icons.Icon({bones.item.name, type='item'})
result = result..'\r\n|-\r\n|'..Icons.Icon({bones.item.name, type='item'})
result = result..'||'..boneQty..'\r\n'..'|}'
result = result..'||'..boneQty
if barrier > 0 then
local dustQty = math.max(math.floor(barrier / 10 / 20), 1)
result = result..'\r\n|-\r\n|'..Icons.Icon({barrierDust.name, type='item'})
result = result..'||'..dustQty
dustVal = dustQty * barrierDust.sellsFor
end
result = result..'\r\n'..'|}'
boneVal = boneQty * bones.item.sellsFor
boneVal = boneQty * bones.item.sellsFor
end
end
Line 695: Line 1,005:


--Sort the loot table by weight in descending order
--Sort the loot table by weight in descending order
table.sort(monster.lootTable, function(a, b) return a.weight > b.weight end)
local lootTable = Shared.shallowClone(monster.lootTable)
for i, row in ipairs(monster.lootTable) do
table.sort(lootTable, function(a, b)
if a.weight == b.weight then
local aItem, bItem = Items.getItemByID(a.itemID), Items.getItemByID(b.itemID)
if aItem ~= nil and bItem ~= nil then
return aItem.name < bItem.name
else
return a.itemID < b.itemID
end
else
return a.weight > b.weight
end
end)
for i, row in ipairs(lootTable) do
local thisItem = Items.getItemByID(row.itemID)
local thisItem = Items.getItemByID(row.itemID)
Line 757: Line 1,079:
result = result..' and bones'
result = result..' and bones'
end
end
result = result..', the average kill is worth '..Icons.GP(Shared.round(avgGp + lootValue + boneVal, 2, 0))..'.'
if dustVal > 0 then
result = result..' and barrier dust'
end
result = result..', the average kill is worth '..Icons.GP(Shared.round(avgGp + lootValue + boneVal + dustVal, 2, 0))..'.'
end
end
end
end
Line 768: Line 1,093:
function p._getMonsterLootValue(monster)
function p._getMonsterLootValue(monster)
if monster == nil then
if monster == nil then
return "ERROR: No monster with that name found[[Category:Pages with script errors]]"
return Shared.printError('No monster with that name found')
end
end


Line 831: Line 1,156:
if monster == nil then
if monster == nil then
return "ERROR: No monster with that name found[[Category:Pages with script errors]]"
return Shared.printError('No monster with that name found')
end
end
if item == nil then
if item == nil then
return "ERROR: No item with that name found[[Category:Pages with script errors]]"
return Shared.printError('No item with that name found')
end
end
Line 863: Line 1,188:


if chest == nil then
if chest == nil then
return "ERROR: No item named "..chestName..' found[[Category:Pages with script errors]]'
return Shared.printError('No item named ' .. chestName .. ' found')
end
end
local result = ''
local result = ''


if chest.dropTable == nil then
if chest.dropTable == nil then
return "ERROR: "..chestName.." does not have a drop table[[Category:Pages with script errors]]"
return Shared.printError(chestName .. ' does not have a drop table')
else
else
local lootValue = 0
 
local function formatNumRange(minValue, maxValue)
if maxValue ~= nil and maxValue > minValue then
return Shared.formatnum(minValue) .. ' - ' .. Shared.formatnum(maxValue)
else
return Shared.formatnum(minValue)
end
end
 
local lootValue, foodValue = 0, 0
local totalWt = 0
local totalWt = 0
for i, row in pairs(chest.dropTable) do
local isAllFood = true
for i, row in ipairs(chest.dropTable) do
totalWt = totalWt + row.weight
totalWt = totalWt + row.weight
if isAllFood then
-- If the container's contents are entirely food then we add additional
-- information to the output, so we determine this here
local item = Items.getItemByID(row.itemID)
if item ~= nil and item.healsFor == nil then
isAllFood = false
end
end
end
end
result = result..'\r\n{|class="wikitable sortable"'
result = result..'\r\n{|class="wikitable sortable"'
result = result..'\r\n!Item!!Qty'
result = result..'\r\n!Item!!Qty'
result = result..'!!colspan="2"|Chance!!Price'
result = result..'!!colspan="2"|Chance!!Price' .. (isAllFood and '!!Healing!!Avg. Healing' or '')


--Sort the loot table by weight in descending order
--Sort the loot table by weight in descending order
local chestDrops = {}
local chestDrops = Shared.shallowClone(chest.dropTable)
for i, row in ipairs(chest.dropTable) do
table.insert(chestDrops, row)
end
table.sort(chestDrops, function(a, b) return a.weight > b.weight end)
table.sort(chestDrops, function(a, b) return a.weight > b.weight end)
for i, row in ipairs(chestDrops) do
for i, row in ipairs(chestDrops) do
local thisItem = Items.getItemByID(row.itemID)
local thisItem = Items.getItemByID(row.itemID)
result = result..'\r\n|-\r\n|'..Icons.Icon({thisItem.name, type='item'})
result = result..'\r\n|-\r\n|'..Icons.Icon({thisItem.name, type='item'})
result = result..'||style="text-align:right" data-sort-value="'..(row.minQuantity + row.maxQuantity)..'"|'
result = result..'||style="text-align:right" data-sort-value="'..(row.minQuantity + row.maxQuantity)..'"| ' .. formatNumRange(row.minQuantity, row.maxQuantity)
 
if row.minQuantity < row.maxQuantity then
result = result .. Shared.formatnum(row.minQuantity) .. ' - ' .. Shared.formatnum(row.maxQuantity)
else
result = result .. Shared.formatnum(row.minQuantity)
end


local dropChance = (row.weight / totalWt) * 100
local dropChance = (row.weight / totalWt) * 100
Line 909: Line 1,243:
end
end
lootValue = lootValue + (dropChance * 0.01 * thisItem.sellsFor * ((row.minQuantity + row.maxQuantity)/ 2))
lootValue = lootValue + (dropChance * 0.01 * thisItem.sellsFor * ((row.minQuantity + row.maxQuantity)/ 2))
if isAllFood then
local hp = thisItem.healsFor * 10
local minHeal, maxHeal = hp * row.minQuantity, hp * row.maxQuantity
local avgHpPerLoot = (dropChance * 0.01 * (minHeal + maxHeal) / 2)
foodValue = foodValue + avgHpPerLoot
result = result .. '||data-sort-value="' .. thisItem.healsFor .. '"'
result = result .. '|' .. Icons.Icon({'Hitpoints', type='skill', notext=true, nolink=true}) .. ' ' .. formatNumRange(minHeal, maxHeal)
result = result .. '||data-sort-value="' .. avgHpPerLoot .. '"'
result = result .. '|' .. Icons.Icon({'Hitpoints', type='skill', notext=true, nolink=true}) .. ' ' .. Shared.round(avgHpPerLoot, 2, 0)
end
end
end
result = result..'\r\n|}'
result = result..'\r\n|}'
result = result..'\r\nThe average value of the contents of one chest is '..Icons.GP(Shared.round(lootValue, 2, 0))..'.'
result = result..'\r\nThe average value of the contents of one chest is '..Icons.GP(Shared.round(lootValue, 2, 0))..'.'
if isAllFood then
result = result..'\r\n\r\nThe average healing of the contents of one chest is ' .. Icons.Icon({'Hitpoints', type='skill', notext=true, nolink=true}) .. ' ' .. Shared.round(foodValue, 2, 0) .. '.'
end
end
end


Line 921: Line 1,269:
local area = Areas.getArea(areaName)
local area = Areas.getArea(areaName)
if area == nil then
if area == nil then
return "ERROR: Could not find an area named "..areaName..'[[Category:Pages with script errors]]'
return Shared.printError('Could not find an area named ' .. areaName)
end
end


Line 927: Line 1,275:
return p.getDungeonMonsterTable(frame)
return p.getDungeonMonsterTable(frame)
end
end
 
local tableTxt = '{| class="wikitable sortable"'
tableTxt = tableTxt..'\r\n! Name !! Combat Level !! Hitpoints !! Max Hit !! [[Combat Triangle|Combat Style]]'
local monsters = {}
local hasBarrier = false
for i, monsterID in ipairs(area.monsterIDs) do
for i, monsterID in ipairs(area.monsterIDs) do
local monster = p.getMonsterByID(monsterID)
local monster = p.getMonsterByID(monsterID)
tableTxt = tableTxt..'\r\n|-\r\n|'..Icons.Icon({monster.name, type='monster'})
if not hasBarrier and p._getMonsterBarrier(monster) > 0 then
tableTxt = tableTxt..'||'..p._getMonsterCombatLevel(monster)
hasBarrier = true
tableTxt = tableTxt..'||'..Shared.formatnum(p._getMonsterHP(monster))
end
tableTxt = tableTxt..'||'..Shared.formatnum(p._getMonsterMaxHit(monster))
table.insert(monsters, monster)
tableTxt = tableTxt..'||'..p._getMonsterStyleIcon({monster, nolink=true})
end
end
tableTxt = tableTxt..'\r\n|}'
return tableTxt
end


function p.getDungeonMonsterTable(frame)
local tableBits = {}
local areaName = frame.args ~= nil and frame.args[1] or frame
table.insert(tableBits, '{| class="wikitable sortable"')
local area = Areas.getArea(areaName)
table.insert(tableBits, '\r\n! Name !! Combat Level ')
if area == nil then
if hasBarrier then
return "ERROR: Could not find a dungeon named "..areaName..'[[Category:Pages with script errors]]'
table.insert(tableBits, '!! [[Barrier]] ')
end
table.insert(tableBits, '!! Hitpoints !! colspan=2| Max Hit !! [[Combat Triangle|Combat Style]]')
for i, monster in ipairs(monsters) do
local rowBits = {}
table.insert(tableBits, '\r\n|-\r\n|'..Icons.Icon({p.getMonsterName(monster), type='monster'}))
table.insert(tableBits, '||'..p._getMonsterCombatLevel(monster))
if hasBarrier then
table.insert(tableBits, '||'..Shared.formatnum(p._getMonsterBarrier(monster)))
end
table.insert(tableBits, '||'..Shared.formatnum(p._getMonsterHP(monster)))
local drReduction = p._getMonsterDrReduction(monster)
local maxHit = p._getMonsterMaxHit(monster)
if drReduction > 0 then
table.insert(tableBits, '||style="text-align:right" data-sort-value="'..maxHit..'"| -'..drReduction..'% DR')
table.insert(tableBits, '||style="text-align:right"|'..Shared.formatnum(maxHit))
else
table.insert(tableBits, '||style="text-align:right" colspan="2" data-sort-value="'..maxHit..'"|'..Shared.formatnum(maxHit))
end
table.insert(tableBits, '||'..p._getMonsterStyleIcon({monster, nolink=true}))
end
table.insert(tableBits, '\r\n|}')
return table.concat(tableBits, '')
end
 
function p.getDungeonMonsterTable(frame)
local areaName = frame.args ~= nil and frame.args[1] or frame
local area = Areas.getArea(areaName)
if area == nil then
return Shared.printError('Could not find a dungeon named ' .. areaName)
end
end


--For Dungeons, go through and count how many of each monster are in the dungeon first
--For Dungeons, go through and count how many of each monster are in the dungeon first
local monsterCounts = {}
local monsterCounts = {}
local monsters = {}
local hasBarrier = false
for i, monsterID in ipairs(area.monsterIDs) do
for i, monsterID in ipairs(area.monsterIDs) do
if monsterCounts[monsterID] == nil then
if monsterCounts[monsterID] == nil then
Line 956: Line 1,334:
else
else
monsterCounts[monsterID] = monsterCounts[monsterID] + 1
monsterCounts[monsterID] = monsterCounts[monsterID] + 1
if monsterID ~= 'melvorF:RandomITM' and monsterID ~= 'melvorTotH:RandomSpiderLair' then
monsters[monsterID] = p.getMonsterByID(monsterID)
if not hasBarrier and p._getMonsterBarrier(monsters[monsterID]) > 0 then
hasBarrier = true
end
end
end
end
end
end
Line 963: Line 1,347:
-- Declare function for building table rows to avoid repeating code
-- Declare function for building table rows to avoid repeating code
local buildRow = function(entityID, monsterCount, specialType)
local buildRow = function(entityID, monsterCount, specialType)
local monIcon, monLevel, monHP, monMaxHit, monStyle, monCount
local monIcon, monLevel, monHP, monMaxHit, monStyle, monCount, monDrReduce, monBarrier
local monData = {}
local monData = {}
if specialType ~= nil and Shared.contains({'Afflicted', 'Spider', 'SlayerArea'}, specialType) then
if specialType ~= nil and Shared.contains({'Afflicted', 'Spider', 'SlayerArea'}, specialType) then
Line 970: Line 1,354:
local iconQ = Icons.Icon({'Into the Mist', notext=true, nolink=true, img='Question'})
local iconQ = Icons.Icon({'Into the Mist', notext=true, nolink=true, img='Question'})
monIcon = Icons.Icon({'Into the Mist', 'Afflicted Monster', nolink=true, img='Question'})
monIcon = Icons.Icon({'Into the Mist', 'Afflicted Monster', nolink=true, img='Question'})
monLevel, monHP, monMaxHit, monStyle, monCount = iconQ, iconQ, iconQ, iconQ, monsterCount
monLevel, monBarrier, monHP, monMaxHit, monDrReduce, monStyle, monCount = iconQ, iconQ, iconQ, iconQ, iconQ, iconQ, monsterCount
elseif specialType == 'Spider' then
elseif specialType == 'Spider' then
local iconQ = Icons.Icon({'', notext=true, nolink=true, img='Question'})
local iconQ = Icons.Icon({'', notext=true, nolink=true, img='Question'})
Line 977: Line 1,361:
local monster = p.getMonsterByID(monsterID)
local monster = p.getMonsterByID(monsterID)
if monster ~= nil then
if monster ~= nil then
table.insert(monIconPart, Icons.Icon({monster.name, type='monster'}))
table.insert(monIconPart, Icons.Icon({p.getMonsterName(monster), type='monster'}))
end
end
end
end
monIcon = table.concat(monIconPart, '<br/>')
monIcon = table.concat(monIconPart, '<br/>')
monLevel, monHP, monMaxHit, monStyle, monCount = iconQ, iconQ, iconQ, iconQ, monsterCount
monLevel, monBarrier, monHP, monMaxHit, monDrReduce, monStyle, monCount = iconQ, iconQ, iconQ, iconQ, iconQ, iconQ, monsterCount
elseif specialType == 'SlayerArea' then
elseif specialType == 'SlayerArea' then
-- entityID corresponds to a slayer area
-- entityID corresponds to a slayer area
Line 987: Line 1,371:
monIcon = Icons.Icon({area.name, type='combatArea'}) .. ' Monsters'
monIcon = Icons.Icon({area.name, type='combatArea'}) .. ' Monsters'
monLevel = {p.getLowHighStat(area.monsterIDs, function(monster) return p._getMonsterCombatLevel(monster) end)}
monLevel = {p.getLowHighStat(area.monsterIDs, function(monster) return p._getMonsterCombatLevel(monster) end)}
if hasBarrier then
monBarrier = {p.getLowHighStat(area.monsterIDs, function(monster) return p._getMonsterBarrier(monster) end)}
end
monHP = {p.getLowHighStat(area.monsterIDs, function(monster) return p._getMonsterHP(monster) end)}
monHP = {p.getLowHighStat(area.monsterIDs, function(monster) return p._getMonsterHP(monster) end)}
local lowMaxHit, highMaxHit = p.getLowHighStat(area.monsterIDs, function(monster) return p._getMonsterMaxHit(monster) end)
local lowMaxHit, highMaxHit = p.getLowHighStat(area.monsterIDs, function(monster) return p._getMonsterMaxHit(monster) end)
local lowDrReduce, highDrReduce = p.getLowHighStat(area.monsterIDs, function(monster) return p._getMonsterDrReduction(monster) end)
monMaxHit = highMaxHit
monMaxHit = highMaxHit
monDrReduce = highDrReduce
monStyle = Icons.Icon({area.name, area.name, notext=true, nolink=true, img='Question'})
monStyle = Icons.Icon({area.name, area.name, notext=true, nolink=true, img='Question'})
monCount = monsterCount
monCount = monsterCount
Line 996: Line 1,385:
-- entityID corresponds to a monster
-- entityID corresponds to a monster
local monster = p.getMonsterByID(entityID)
local monster = p.getMonsterByID(entityID)
monIcon = Icons.Icon({monster.name, type='monster'})
monIcon = Icons.Icon({p.getMonsterName(monster), type='monster'})
monLevel = p._getMonsterCombatLevel(monster)
monLevel = p._getMonsterCombatLevel(monster)
if hasBarrier then
monBarrier = p._getMonsterBarrier(monster)
end
monHP = p._getMonsterHP(monster)
monHP = p._getMonsterHP(monster)
monDrReduce = p._getMonsterDrReduction(monster)
monMaxHit = p._getMonsterMaxHit(monster)
monMaxHit = p._getMonsterMaxHit(monster)
monStyle = p._getMonsterStyleIcon({monster})
monStyle = p._getMonsterStyleIcon({monster})
Line 1,031: Line 1,424:
table.insert(resultPart, '\r\n|-\r\n| ' .. monIcon)
table.insert(resultPart, '\r\n|-\r\n| ' .. monIcon)
table.insert(resultPart, '\r\n|style="text-align:right;" data-sort-value="' .. getValSort(monLevel) .. '"| ' .. getValText(monLevel))
table.insert(resultPart, '\r\n|style="text-align:right;" data-sort-value="' .. getValSort(monLevel) .. '"| ' .. getValText(monLevel))
if hasBarrier then
table.insert(resultPart, '\r\n|style="text-align:right;" data-sort-value="' .. getValSort(monBarrier) .. '"| ' .. getValText(monBarrier))
end
table.insert(resultPart, '\r\n|style="text-align:right;" data-sort-value="' .. getValSort(monHP) .. '"| ' .. getValText(monHP))
table.insert(resultPart, '\r\n|style="text-align:right;" data-sort-value="' .. getValSort(monHP) .. '"| ' .. getValText(monHP))
table.insert(resultPart, '\r\n|style="text-align:right;" data-sort-value="' .. getValSort(monMaxHit) .. '"| ' .. getValText(monMaxHit))
if type(monDrReduce) == 'number' and monDrReduce > 0 then
table.insert(resultPart, '\r\n|style="text-align:right" data-sort-value="'..getValSort(monMaxHit)..'"| -'..monDrReduce..'% DR')
table.insert(resultPart, '\r\n|style="text-align:right"|'..getValText(monMaxHit))
else
table.insert(resultPart, '\r\n|style="text-align:right" colspan="2" data-sort-value="'..getValSort(monMaxHit)..'"|'..getValText(monMaxHit))
end
table.insert(resultPart, '\r\n| ' .. monStyle)
table.insert(resultPart, '\r\n| ' .. monStyle)
table.insert(resultPart, '\r\n|style="text-align:right;" data-sort-value="' .. getValSort(monCount) .. '"| ' .. getValText(monCount))
table.insert(resultPart, '\r\n|style="text-align:right;" data-sort-value="' .. getValSort(monCount) .. '"| ' .. getValText(monCount))
Line 1,040: Line 1,441:
local returnPart = {}
local returnPart = {}
table.insert(returnPart, '{| class="wikitable sortable"')
table.insert(returnPart, '{| class="wikitable sortable"')
table.insert(returnPart, '\r\n! Name !! Combat Level !! Hitpoints !! Max Hit !! [[Combat Triangle|Combat Style]] !! Count')
table.insert(returnPart, '\r\n! Name !! Combat Level ')
if hasBarrier then
table.insert(returnPart, '!! [[Barrier]] ')
end
table.insert(returnPart, '!! Hitpoints !! colspan="2" | Max Hit !! [[Combat Triangle|Combat Style]] !! Count')
-- Special handing for Impending Darkness event
-- Special handing for Impending Darkness event
-- TODO needs to be revised once there is a better understanding of how the event works
-- TODO needs to be revised once there is a better understanding of how the event works
--if area.isEvent ~= nil and area.isEvent then
-- for i, eventAreaID in ipairs(Areas.eventData.slayerAreas) do
-- table.insert(returnPart, buildRow(eventAreaID, {5, 8}, 'SlayerArea'))
-- end
--  -- Add Bane * 4
--  table.insert(returnPart, buildRow(152, 4))
--end
for i, monsterID in ipairs(area.monsterIDs) do
for i, monsterID in ipairs(area.monsterIDs) do
if not Shared.contains(usedMonsters, monsterID) then
if not Shared.contains(usedMonsters, monsterID) then
Line 1,058: Line 1,456:
table.insert(returnPart, buildRow(monsterID, monsterCounts[monsterID], 'Spider'))
table.insert(returnPart, buildRow(monsterID, monsterCounts[monsterID], 'Spider'))
else
else
table.insert(returnPart, buildRow(monsterID, monsterCounts[monsterID]))
table.insert(returnPart, buildRow(monsterID, monsterCounts[monsterID], hasBarrier))
end
end
table.insert(usedMonsters, monsterID)
table.insert(usedMonsters, monsterID)
Line 1,071: Line 1,469:
local area = Areas.getArea(areaName)
local area = Areas.getArea(areaName)
if area == nil then
if area == nil then
return "ERROR: Could not find a dungeon named "..areaName..'[[Category:Pages with script errors]]'
return Shared.printError('Could not find a dungeon named ' .. areaName)
end
end
local totalHP = 0
local totalHP = 0
Line 1,086: Line 1,484:
for i, monsterID in ipairs(area.monsterIDs) do
for i, monsterID in ipairs(area.monsterIDs) do
local monster = p.getMonsterByID(monsterID)
local monster = p.getMonsterByID(monsterID)
table.insert(monsterList, Icons.Icon({monster.name, type='monster'}))
table.insert(monsterList, Icons.Icon({p.getMonsterName(monster), type='monster'}))
end
end
return table.concat(monsterList, '<br/>')
return table.concat(monsterList, '<br/>')
Line 1,095: Line 1,493:
local lastID = ''
local lastID = ''
local count = 0
local count = 0
-- Special handing for Impending Darkness event
-- TODO needs to be revised once there is a better understanding of how the event works
--if area.isEvent ~= nil and area.isEvent then
-- for i, eventAreaID in ipairs(Areas.eventData.slayerAreas) do
-- local eventArea = Areas.getAreaByID('slayer', eventAreaID)
-- table.insert(monsterList, '5-8 ' .. Icons.Icon({eventArea.name, type='combatArea'}) .. ' Monsters')
-- end
-- table.insert(monsterList, '4 ' .. Icons.Icon({'Bane', type='monster'}))
--end
local monsterCounts = {}
local monsterCounts = {}
Line 1,129: Line 1,518:
local monster = p.getMonsterByID(monsterID)
local monster = p.getMonsterByID(monsterID)
if monster ~= nil then
if monster ~= nil then
table.insert(monIconPart, '&nbsp;&nbsp;&nbsp;' .. Icons.Icon({monster.name, type='monster'}))
table.insert(monIconPart, '&nbsp;&nbsp;&nbsp;' .. Icons.Icon({p.getMonsterName(monster), type='monster'}))
end
end
end
end
Line 1,135: Line 1,524:
else
else
local monsterObj = p.getMonsterByID(monster.id)
local monsterObj = p.getMonsterByID(monster.id)
table.insert(monsterList, Icons.Icon({monsterObj.name, type='monster', qty=monster.count}))
table.insert(monsterList, Icons.Icon({p.getMonsterName(monsterObj), type='monster', qty=monster.count}))
end
end
end
end
Line 1,146: Line 1,535:
local area = Areas.getArea(areaName)
local area = Areas.getArea(areaName)
if area == nil then
if area == nil then
return "ERROR: Could not find an area named "..areaName..'[[Category:Pages with script errors]]'
return Shared.printError('Could not find an area named ' .. areaName)
end
end


Line 1,162: Line 1,551:
if monster.gpDrops ~= nil and monster.gpDrops.max > 0 then
if monster.gpDrops ~= nil and monster.gpDrops.max > 0 then
local avgGp = (monster.gpDrops.min + monster.gpDrops.max) / 2
local avgGp = (monster.gpDrops.min + monster.gpDrops.max) / 2
result = result .. '<br/>' .. monster.name .. ',' .. monster.gpDrops.min .. ',' .. monster.gpDrops.max .. ',' .. avgGp
result = result .. '<br/>' .. p.getMonsterName(monster) .. ',' .. monster.gpDrops.min .. ',' .. monster.gpDrops.max .. ',' .. avgGp
end
end
end
end
Line 1,219: Line 1,608:


if monster == nil then
if monster == nil then
return "ERROR: No monster with that name found[[Category:Pages with script errors]]"
return Shared.printError('No monster with that name found')
end
end


Line 1,232: Line 1,621:
local monsterGP = p._getMonsterAverageGP(monster)
local monsterGP = p._getMonsterAverageGP(monster)
local combatLevel = p._getMonsterCombatLevel(monster)
local combatLevel = p._getMonsterCombatLevel(monster)
result = result..'\r\n|-\r\n|'..Icons.Icon({monster.name, type='monster', noicon=true})..'||'..combatLevel..'||'..monsterGP
result = result..'\r\n|-\r\n|'..Icons.Icon({p.getMonsterName(monster), type='monster', noicon=true})..'||'..combatLevel..'||'..monsterGP
end
end
end
end
Line 1,245: Line 1,634:


if tier == nil then
if tier == nil then
return "ERROR: No tier specified[[Category:Pages with script errors]]"
return Shared.printError('No tier specified')
end
end


Line 1,255: Line 1,644:


if slayerTier == nil then
if slayerTier == nil then
return "ERROR: Invalid slayer tier[[Category:Pages with script errors]]"
return Shared.printError('Invalid slayer tier')
end
end


Line 1,291: Line 1,680:
table.insert(tableParts, '{| class="wikitable sortable stickyHeader"')
table.insert(tableParts, '{| class="wikitable sortable stickyHeader"')
-- First header row
-- First header row
table.insert(tableParts, '\r\n|- class="headerRow-0"\r\n! colspan="5" | !! colspan="4" |Offensive Stats !! colspan="3" |Evasion Rating !! colspan="4" |')
table.insert(tableParts, '\r\n|- class="headerRow-0"\r\n! colspan="4" | !! colspan="5" |Offensive Stats !! colspan="3" |Evasion Rating !! colspan="4" |')
-- Second header row
-- Second header row
table.insert(tableParts, '\r\n|- class="headerRow-1"\r\n!Monster !!Name !!Combat Level ')
table.insert(tableParts, '\r\n|- class="headerRow-1"\r\n!Monster !!Name !!Combat Level ')
table.insert(tableParts, '!!style="padding:0 1em 0 0"|' .. Icons.Icon({'Hitpoints', type='skill'}))
table.insert(tableParts, '!!style="padding:0 1em 0 0"|' .. Icons.Icon({'Hitpoints', type='skill'}))
table.insert(tableParts, '!!Attack Speed (s) !!colspan="2"|Max Hit !!Accuracy ')
table.insert(tableParts, '!!Attack Speed (s) !!colspan="3"|Max Hit !!Accuracy ')
table.insert(tableParts, '!!style="padding:0 1em 0 0"|' .. Icons.Icon({'Defence', type='skill', notext=true}))
table.insert(tableParts, '!!style="padding:0 1em 0 0"|' .. Icons.Icon({'Defence', type='skill', notext=true}))
table.insert(tableParts, '!!style="padding:0 1em 0 0"|' .. Icons.Icon({'Ranged', type='skill', notext=true}))
table.insert(tableParts, '!!style="padding:0 1em 0 0"|' .. Icons.Icon({'Ranged', type='skill', notext=true}))
table.insert(tableParts, '!!style="padding:0 1em 0 0"|' .. Icons.Icon({'Magic', type='skill', notext=true}))
table.insert(tableParts, '!!style="padding:0 1em 0 0"|' .. Icons.Icon({'Magic', type='skill', notext=true}))
table.insert(tableParts, '!!' .. Icons.Icon({'Coins', notext=true, nolink=true}) .. ' Coins !!Bones !!Locations')
table.insert(tableParts, '!!DR!!' .. Icons.Icon({'Coins', notext=true, nolink=true}) .. ' Coins !!Bones !!Locations')


-- Generate row per monster
-- Generate row per monster
Line 1,311: Line 1,700:
local atkSpeed = p._getMonsterAttackSpeed(monster)
local atkSpeed = p._getMonsterAttackSpeed(monster)
local maxHit = p._getMonsterMaxHit(monster)
local maxHit = p._getMonsterMaxHit(monster)
local dr = p._getMonsterStat(monster, 'damageReduction')
local drReduce = p._getMonsterDrReduction(monster)
local accR = p._getMonsterAR(monster)
local accR = p._getMonsterAR(monster)
local evaR = {p._getMonsterER(monster, "Melee"), p._getMonsterER(monster, "Ranged"), p._getMonsterER(monster, "Magic")}
local evaR = {p._getMonsterER(monster, "Melee"), p._getMonsterER(monster, "Ranged"), p._getMonsterER(monster, "Magic")}
Line 1,323: Line 1,714:
local boneTxt = (bones ~= nil and Icons.Icon({bones.item.name, type='item', notext=true})) or 'None'
local boneTxt = (bones ~= nil and Icons.Icon({bones.item.name, type='item', notext=true})) or 'None'
table.insert(tableParts, '\r\n|-\r\n|style="text-align: center;" |' .. Icons.Icon({monster.name, type='monster', size=50, notext=true}))
table.insert(tableParts, '\r\n|-\r\n|style="text-align: center;" |' .. Icons.Icon({p.getMonsterName(monster), type='monster', size=50, notext=true}))
table.insert(tableParts, '\r\n|style="text-align:left" |' .. Icons.Icon({monster.name, type='monster', noicon=true}))
table.insert(tableParts, '\r\n|style="text-align:left" |' .. Icons.Icon({p.getMonsterName(monster), type='monster', noicon=true}))
table.insert(tableParts, '\r\n|style="text-align:right" data-sort-value="' .. cmbLevel .. '" |' .. Shared.formatnum(cmbLevel))
table.insert(tableParts, '\r\n|style="text-align:right" data-sort-value="' .. cmbLevel .. '" |' .. Shared.formatnum(cmbLevel))
table.insert(tableParts, '\r\n|style="text-align:right" data-sort-value="' .. p._getMonsterHP(monster) .. '" |' .. Shared.formatnum(p._getMonsterHP(monster)))
table.insert(tableParts, '\r\n|style="text-align:right" data-sort-value="' .. p._getMonsterHP(monster) .. '" |' .. Shared.formatnum(p._getMonsterHP(monster)))
table.insert(tableParts, '\r\n|style="text-align:right" data-sort-value="' .. atkSpeed .. '" |' .. Shared.round(atkSpeed, 1, 1))
table.insert(tableParts, '\r\n|style="text-align:right" data-sort-value="' .. atkSpeed .. '" |' .. Shared.round(atkSpeed, 1, 1))
table.insert(tableParts, '\r\n|style="text-align:center;border-right:hidden" |' .. p._getMonsterStyleIcon({monster, notext=true}))
if drReduce > 0 then
table.insert(tableParts, '\r\n|style="text-align:right" data-sort-value="' .. maxHit .. '" |' .. Shared.formatnum(maxHit))
table.insert(tableParts, '\r\n|style="text-align:right" data-sort-value="' .. maxHit .. '"| -' .. drReduce..'% DR')
table.insert(tableParts, '\r\n|style="text-align:right;border-right:hidden" |' .. p._getMonsterStyleIcon({monster, notext=true}))
table.insert(tableParts, '\r\n|style="text-align:right" |' .. Shared.formatnum(maxHit))
else
table.insert(tableParts, '\r\n|style="text-align:right;border-right:hidden" colspan="2" data-sort-value="' .. maxHit .. '"|' .. p._getMonsterStyleIcon({monster, notext=true}))
table.insert(tableParts, '\r\n|style="text-align:right"|' .. Shared.formatnum(maxHit))
end
table.insert(tableParts, '\r\n|style="text-align:right" data-sort-value="' .. accR .. '" |' .. Shared.formatnum(accR))
table.insert(tableParts, '\r\n|style="text-align:right" data-sort-value="' .. accR .. '" |' .. Shared.formatnum(accR))
table.insert(tableParts, '\r\n|style="text-align:right" data-sort-value="' .. evaR[1] .. '" |' .. Shared.formatnum(evaR[1]))
table.insert(tableParts, '\r\n|style="text-align:right" data-sort-value="' .. evaR[1] .. '" |' .. Shared.formatnum(evaR[1]))
table.insert(tableParts, '\r\n|style="text-align:right" data-sort-value="' .. evaR[2] .. '" |' .. Shared.formatnum(evaR[2]))
table.insert(tableParts, '\r\n|style="text-align:right" data-sort-value="' .. evaR[2] .. '" |' .. Shared.formatnum(evaR[2]))
table.insert(tableParts, '\r\n|style="text-align:right" data-sort-value="' .. evaR[3] .. '" |' .. Shared.formatnum(evaR[3]))
table.insert(tableParts, '\r\n|style="text-align:right" data-sort-value="' .. evaR[3] .. '" |' .. Shared.formatnum(evaR[3]))
table.insert(tableParts, '\r\n|style="text-align:right" data-sort-value="' .. dr .. '" |' .. dr..'%')
table.insert(tableParts, '\r\n|style="text-align:right" data-sort-value="' .. (monster.gpDrops.min + monster.gpDrops.max) / 2 .. '" |' .. gpTxt)
table.insert(tableParts, '\r\n|style="text-align:right" data-sort-value="' .. (monster.gpDrops.min + monster.gpDrops.max) / 2 .. '" |' .. gpTxt)
table.insert(tableParts, '\r\n|style="text-align:center" |' .. boneTxt)
table.insert(tableParts, '\r\n|style="text-align:center" |' .. boneTxt)
Line 1,355: Line 1,753:
-- Generate row per monster
-- Generate row per monster
for i, monster in ipairs(GameData.rawData.monsters) do
for i, monster in ipairs(GameData.rawData.monsters) do
local cmbLevel = p._getMonsterCombatLevel(monster)
if p.getMonsterName(monster) ~= nil then
 
local cmbLevel = p._getMonsterCombatLevel(monster)
local gpTxt = nil
if monster.gpDrops.min >= monster.gpDrops.max then
local gpTxt = nil
gpTxt = Shared.formatnum(monster.gpDrops.min)
if monster.gpDrops.min >= monster.gpDrops.max then
else
gpTxt = Shared.formatnum(monster.gpDrops.min)
gpTxt = Shared.formatnum(monster.gpDrops.min) .. ' - ' .. Shared.formatnum(monster.gpDrops.max)
else
gpTxt = Shared.formatnum(monster.gpDrops.min) .. ' - ' .. Shared.formatnum(monster.gpDrops.max)
end
local lootVal = p._getMonsterLootValue(monster)
local lootTxt = '0'
if lootVal ~= 0 then
lootTxt = Shared.formatnum(Shared.round(lootVal, 2, 2))
end
table.insert(tableParts, '\r\n|-\r\n|style="text-align: center;" |' .. Icons.Icon({p.getMonsterName(monster), type='monster', size=50, notext=true}))
table.insert(tableParts, '\r\n|style="text-align:left" |' .. Icons.Icon({p.getMonsterName(monster), type='monster', noicon=true}))
table.insert(tableParts, '\r\n|style="text-align:right" |' .. monster.id)
table.insert(tableParts, '\r\n|style="text-align:right" data-sort-value="' .. cmbLevel .. '" |' .. Shared.formatnum(cmbLevel))
table.insert(tableParts, '\r\n|style="text-align:right" data-sort-value="' .. p._getMonsterHP(monster) .. '" |' .. Shared.formatnum(p._getMonsterHP(monster)))
table.insert(tableParts, '\r\n|style="text-align:right" data-sort-value="' .. (monster.gpDrops.min + monster.gpDrops.max) / 2 .. '" |' .. gpTxt)
table.insert(tableParts, '\r\n|style="text-align:right" data-sort-value="' .. lootVal .. '" |' .. lootTxt)
table.insert(tableParts, '\r\n|style="text-align:right;width:190px" |' .. p._getMonsterAreas(monster, false))
end
end
local lootVal = p._getMonsterLootValue(monster)
local lootTxt = '0'
if lootVal ~= 0 then
lootTxt = Shared.formatnum(Shared.round(lootVal, 2, 2))
end
table.insert(tableParts, '\r\n|-\r\n|style="text-align: center;" |' .. Icons.Icon({monster.name, type='monster', size=50, notext=true}))
table.insert(tableParts, '\r\n|style="text-align:left" |' .. Icons.Icon({monster.name, type='monster', noicon=true}))
table.insert(tableParts, '\r\n|style="text-align:right" |' .. monster.id)
table.insert(tableParts, '\r\n|style="text-align:right" data-sort-value="' .. cmbLevel .. '" |' .. Shared.formatnum(cmbLevel))
table.insert(tableParts, '\r\n|style="text-align:right" data-sort-value="' .. p._getMonsterHP(monster) .. '" |' .. Shared.formatnum(p._getMonsterHP(monster)))
table.insert(tableParts, '\r\n|style="text-align:right" data-sort-value="' .. (monster.gpDrops.min + monster.gpDrops.max) / 2 .. '" |' .. gpTxt)
table.insert(tableParts, '\r\n|style="text-align:right" data-sort-value="' .. lootVal .. '" |' .. lootTxt)
table.insert(tableParts, '\r\n|style="text-align:right;width:190px" |' .. p._getMonsterAreas(monster, false))
end
end


Line 1,401: Line 1,801:
-- Generate row per monster
-- Generate row per monster
for i, monster in ipairs(GameData.rawData.monsters) do
for i, monster in ipairs(GameData.rawData.monsters) do
local cmbLevel = p._getMonsterCombatLevel(monster)
if p.getMonsterName(monster) ~= nil then
 
local cmbLevel = p._getMonsterCombatLevel(monster)
local gpTxt = nil
if monster.gpDrops.min >= monster.gpDrops.max then
local gpTxt = nil
gpTxt = Shared.formatnum(monster.gpDrops.min)
if monster.gpDrops.min >= monster.gpDrops.max then
else
gpTxt = Shared.formatnum(monster.gpDrops.min)
gpTxt = Shared.formatnum(monster.gpDrops.min) .. ' - ' .. Shared.formatnum(monster.gpDrops.max)
else
end
gpTxt = Shared.formatnum(monster.gpDrops.min) .. ' - ' .. Shared.formatnum(monster.gpDrops.max)
end
local lootVal = p._getMonsterLootValue(monster)
local lootTxt = '0'
local lootVal = p._getMonsterLootValue(monster)
if lootVal ~= 0 then
local lootTxt = '0'
lootTxt = Shared.formatnum(Shared.round(lootVal, 2, 2))
if lootVal ~= 0 then
end
lootTxt = Shared.formatnum(Shared.round(lootVal, 2, 2))
end
local atkSpeed = p._getMonsterAttackSpeed(monster)
local maxHit = p._getMonsterMaxHit(monster)
local atkSpeed = p._getMonsterAttackSpeed(monster)
local accR = p._getMonsterAR(monster)
local maxHit = p._getMonsterMaxHit(monster)
local evaR = {p._getMonsterER(monster, "Melee"), p._getMonsterER(monster, "Ranged"), p._getMonsterER(monster, "Magic")}
local accR = p._getMonsterAR(monster)
local evaR = {p._getMonsterER(monster, "Melee"), p._getMonsterER(monster, "Ranged"), p._getMonsterER(monster, "Magic")}
local bones = p._getMonsterBones(monster)
local boneTxt = (bones ~= nil and Icons.Icon({bones.item.name, type='item', notext=true})) or 'None'
local bones = p._getMonsterBones(monster)
 
local boneTxt = (bones ~= nil and Icons.Icon({bones.item.name, type='item', notext=true})) or 'None'
table.insert(tableParts, '\r\n|-\r\n|style="text-align: center;" |' .. Icons.Icon({monster.name, type='monster', size=50, notext=true}))
table.insert(tableParts, '\r\n|style="text-align:left" |' .. Icons.Icon({monster.name, type='monster', noicon=true}))
table.insert(tableParts, '\r\n|-\r\n|style="text-align: center;" |' .. Icons.Icon({p.getMonsterName(monster), type='monster', size=50, notext=true}))
-- table.insert(tableParts, '\r\n|style="text-align:right" |' .. monster.id)
table.insert(tableParts, '\r\n|style="text-align:left" |' .. Icons.Icon({p.getMonsterName(monster), type='monster', noicon=true}))
table.insert(tableParts, '\r\n|style="text-align:right" data-sort-value="' .. cmbLevel .. '" |' .. Shared.formatnum(cmbLevel))
-- table.insert(tableParts, '\r\n|style="text-align:right" |' .. monster.id)
table.insert(tableParts, '\r\n|style="text-align:right" data-sort-value="' .. p._getMonsterHP(monster) .. '" |' .. Shared.formatnum(p._getMonsterHP(monster)))
table.insert(tableParts, '\r\n|style="text-align:right" data-sort-value="' .. cmbLevel .. '" |' .. Shared.formatnum(cmbLevel))
table.insert(tableParts, '\r\n|style="text-align:right" data-sort-value="' .. evaR[1] .. '" |' .. Shared.formatnum(evaR[1]))
table.insert(tableParts, '\r\n|style="text-align:right" data-sort-value="' .. p._getMonsterHP(monster) .. '" |' .. Shared.formatnum(p._getMonsterHP(monster)))
 
table.insert(tableParts, '\r\n|style="text-align:right" data-sort-value="' .. evaR[1] .. '" |' .. Shared.formatnum(evaR[1]))
table.insert(tableParts, '\r\n|style="text-align:right" data-sort-value="' .. atkSpeed .. '" |' .. Shared.round(atkSpeed, 1, 1))
table.insert(tableParts, '\r\n|style="text-align:center;border-right:hidden" |' .. p._getMonsterStyleIcon({monster, notext=true}))
table.insert(tableParts, '\r\n|style="text-align:right" data-sort-value="' .. atkSpeed .. '" |' .. Shared.round(atkSpeed, 1, 1))
table.insert(tableParts, '\r\n|style="text-align:right" data-sort-value="' .. maxHit .. '" |' .. Shared.formatnum(maxHit))
table.insert(tableParts, '\r\n|style="text-align:center;border-right:hidden" |' .. p._getMonsterStyleIcon({monster, notext=true}))
table.insert(tableParts, '\r\n|style="text-align:right" data-sort-value="' .. accR .. '" |' .. Shared.formatnum(accR))
table.insert(tableParts, '\r\n|style="text-align:right" data-sort-value="' .. maxHit .. '" |' .. Shared.formatnum(maxHit))
--table.insert(tableParts, '\r\n|style="text-align:right" data-sort-value="' .. evaR[2] .. '" |' .. Shared.formatnum(evaR[2]))
table.insert(tableParts, '\r\n|style="text-align:right" data-sort-value="' .. accR .. '" |' .. Shared.formatnum(accR))
--table.insert(tableParts, '\r\n|style="text-align:right" data-sort-value="' .. evaR[3] .. '" |' .. Shared.formatnum(evaR[3]))
--table.insert(tableParts, '\r\n|style="text-align:right" data-sort-value="' .. evaR[2] .. '" |' .. Shared.formatnum(evaR[2]))
table.insert(tableParts, '\r\n|style="text-align:right" data-sort-value="' .. (monster.gpDrops.min + monster.gpDrops.max) / 2 .. '" |' .. gpTxt)
--table.insert(tableParts, '\r\n|style="text-align:right" data-sort-value="' .. evaR[3] .. '" |' .. Shared.formatnum(evaR[3]))
table.insert(tableParts, '\r\n|style="text-align:right" data-sort-value="' .. lootVal .. '" |' .. lootTxt)
table.insert(tableParts, '\r\n|style="text-align:right" data-sort-value="' .. (monster.gpDrops.min + monster.gpDrops.max) / 2 .. '" |' .. gpTxt)
table.insert(tableParts, '\r\n|style="text-align:center" |' .. boneTxt)
table.insert(tableParts, '\r\n|style="text-align:right" data-sort-value="' .. lootVal .. '" |' .. lootTxt)
-- table.insert(tableParts, '\r\n|style="text-align:right;width:190px" |' .. p._getMonsterAreas(monster, hideDungeons))
table.insert(tableParts, '\r\n|style="text-align:center" |' .. boneTxt)
end
-- table.insert(tableParts, '\r\n|style="text-align:right;width:190px" |' .. p._getMonsterAreas(monster, hideDungeons))
 
end
table.insert(tableParts, '\r\n|}')
end
return table.concat(tableParts)
 
table.insert(tableParts, '\r\n|}')
return table.concat(tableParts)
end
end


Line 1,462: Line 1,864:
spAttTable[spAtt.id]['icons'][attChance] = {}
spAttTable[spAtt.id]['icons'][attChance] = {}
end
end
table.insert(spAttTable[spAtt.id]['icons'][attChance], Icons.Icon({ monster.name, type = 'monster' }))
table.insert(spAttTable[spAtt.id]['icons'][attChance], Icons.Icon({ p.getMonsterName(monster), type = 'monster' }))
end
end
end
end
Line 1,507: Line 1,909:
for i, monsterID in ipairs(area.monsterIDs) do
for i, monsterID in ipairs(area.monsterIDs) do
local monster = p.getMonsterByID(monsterID)
local monster = p.getMonsterByID(monsterID)
table.insert(outArray, "===={{MonsterIcon|"..monster.name.."|size=40}}====")
table.insert(outArray, "===={{MonsterIcon|"..p.getMonsterName(monster).."|size=40}}====")
table.insert(outArray, "{{MonsterDrops|"..monster.name.."|size=40}}")
table.insert(outArray, "{{MonsterDrops|"..p.getMonsterName(monster).."|size=40}}")
end
end
return table.concat(outArray, "\r\n")
return table.concat(outArray, "\r\n")
end
end
local fullArray = {}
local fullArray = {}
local areaArray = Areas.getAreas(function(a) return a.type == 'combatArea' end)
local areaArray = Areas.getAreas(function(a) return a.type == 'combatArea' end)
for i, area in ipairs(areaArray) do
for i, area in ipairs(areaArray) do
table.insert(fullArray, getAreaText(area))
table.insert(fullArray, getAreaText(area))
end
areaArray = Areas.getAreas(function(a) return a.type == 'slayerArea' end)
for i, area in ipairs(areaArray) do
table.insert(fullArray, getAreaText(area))
end
return table.concat(fullArray, "\r\n\r\n----\r\n")
end
 
--NOTE: This is not a function that should be called directly. It generates text to be pasted into Chest Loot Tables
--It exists because I'm too lazy to manually type up all the new chests - User:Falterfire
function p.getChestLootTables()
local items = Items.getItems(function(item) return item.dropTable ~= nil end)
local outArray = {}
for i, item in ipairs(items) do
table.insert(outArray, "==={{ItemIcon|"..item.name.."|size=30}}===")
table.insert(outArray, "{{ChestDrops|"..item.name.."}}")
end
return table.concat(outArray, "\r\n")
end
 
--Returns the expansion icon for the item if it has one
function p.getExpansionIcon(frame)
local monsterName = frame.args ~= nil and frame.args[1] or frame
local monster = p.getMonster(monsterName)
 
if monster == nil then
return Shared.printError('No monster with that name found')
end
end
areaArray = Areas.getAreas(function(a) return a.type == 'slayerArea' end)
return Icons.getExpansionIcon(monster.id)
for i, area in ipairs(areaArray) do
table.insert(fullArray, getAreaText(area))
end
return table.concat(fullArray, "\r\n\r\n----\r\n")
end
 
--NOTE: This is not a function that should be called directly. It generates text to be pasted into Chest Loot Tables
--It exists because I'm too lazy to manually type up all the new chests - User:Falterfire
function p.getChestLootTables()
local items = Items.getItems(function(item) return item.dropTable ~= nil end)
local outArray = {}
for i, item in ipairs(items) do
table.insert(outArray, "==={{ItemIcon|"..item.name.."|size=30}}===")
table.insert(outArray, "{{ChestDrops|"..item.name.."}}")
end
return table.concat(outArray, "\r\n")
end
end


return p
return p
3

edits