Anonymous

Module:Monsters: Difference between revisions

From Melvor Idle
_getMonsterStyleIcon: Revert change to use adjusted Icon override instead
mNo edit summary
(_getMonsterStyleIcon: Revert change to use adjusted Icon override instead)
(25 intermediate revisions by 4 users not shown)
Line 19: Line 19:


for i, monster in pairs(MonsterData.Monsters) do
for i, monster in pairs(MonsterData.Monsters) do
if(monster.name == name) then
if monster.name == name then
result = Shared.clone(monster)
result = Shared.clone(monster)
--Make sure every monster has an ID, and account for the 1-based indexing of Lua
--Make sure every monster has an ID, and account for the 1-based indexing of Lua
Line 31: Line 31:
function p.getMonsterByID(ID)
function p.getMonsterByID(ID)
local result = Shared.clone(MonsterData.Monsters[ID + 1])
local result = Shared.clone(MonsterData.Monsters[ID + 1])
result.id = ID
if result ~= nil then
return result
result.id = ID
return result
else
return nil
end
end
end


Line 104: Line 108:


local iconText = ''
local iconText = ''
if monster.attackType == 'melee' then
if monster.attackType == 'melee' then
iconText = Icons.Icon({'Melee', notext=notext, nolink=nolink})
iconText = Icons.Icon({'Melee', notext=notext, nolink=nolink})
elseif monster.attackType == 'ranged' then
elseif monster.attackType == 'ranged' then
Line 215: Line 219:
local range = 0.325 * (1.5 * p._getMonsterLevel(monster, 'Ranged'))
local range = 0.325 * (1.5 * p._getMonsterLevel(monster, 'Ranged'))
local magic = 0.325 * (1.5 * p._getMonsterLevel(monster, 'Magic'))
local magic = 0.325 * (1.5 * p._getMonsterLevel(monster, 'Magic'))
if melee > range and melee > magic then
return math.floor(base + math.max(melee, range, magic))
return math.floor(base + melee)
elseif range > magic then
return math.floor(base + range)
else
return math.floor(base + magic)
end
end
end


Line 304: Line 302:
-- Determines if the monster is capable of dropping bones, and returns the bones
-- Determines if the monster is capable of dropping bones, and returns the bones
-- item if so, or nil otherwise
-- item if so, or nil otherwise
function p.getMonsterBones(monster)
function p._getMonsterBones(monster)
if monster.bones ~= nil and monster.bones >= 0 then
if monster.bones ~= nil and monster.bones >= 0 then
local boneItem = Items.getItemByID(monster.bones)
local boneItem = Items.getItemByID(monster.bones)
Line 344: Line 342:


function p._getMonsterAreas(monster, excludeDungeons)
function p._getMonsterAreas(monster, excludeDungeons)
local result = ''
local resultPart = {}
local hideDungeons = excludeDungeons ~= nil and excludeDungeons or false
local hideDungeons = excludeDungeons ~= nil and excludeDungeons or false
local areaList = Areas.getMonsterAreas(monster.id)
local areaList = Areas.getMonsterAreas(monster.id)
for i, area in pairs(areaList) do
for i, area in ipairs(areaList) do
if area.type ~= 'dungeon' or not hideDungeons then
if area.type ~= 'dungeon' or not hideDungeons then
if i > 1 then result = result..'<br/>' end
table.insert(resultPart, Icons.Icon({area.name, type = area.type}))
result = result..Icons.Icon({area.name, type = area.type})
end
end
end
end
return result
return table.concat(resultPart, '<br/>')
end
end


Line 475: Line 472:
local mSpell = nil
local mSpell = nil
if monster.selectedSpell ~= nil then mSpell = Magic.getSpellByID('Spells', monster.selectedSpell) end
if monster.selectedSpell ~= nil then mSpell = Magic.getSpellByID('Spells', monster.selectedSpell) end
 
bonus = p.getEquipmentStat(monster, 'magicDamageBonus')
bonus = p.getEquipmentStat(monster, 'magicDamageBonus')
baseLevel = p._getMonsterLevel(monster, 'Magic')
baseLevel = p._getMonsterLevel(monster, 'Magic')
Line 534: Line 531:
local iconText = p._getMonsterStyleIcon({monster, notext=true})
local iconText = p._getMonsterStyleIcon({monster, notext=true})
local typeText = ''
local typeText = ''
if monster.attackType == 'melee' then
if monster.attackType == 'melee' then
typeText = 'Melee'
typeText = 'Melee'
elseif monster.attackType == 'ranged' then
elseif monster.attackType == 'ranged' then
Line 588: Line 585:


local result = ''
local result = ''
 
if type(monster.passiveID) == 'table' and Shared.tableCount(monster.passiveID) > 0 then
if monster.hasPassive then
result = result .. '===Passives==='
result = result .. '===Passives==='
for i, passiveID in pairs(monster.passiveID) do
for i, passiveID in pairs(monster.passiveID) do
Line 679: Line 675:
local result = ''
local result = ''


local bones = p.getMonsterBones(monster)
local bones = p._getMonsterBones(monster)
local boneVal = 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 = (monster.boneQty ~= nil and monster.boneQty or 1)
result = result.."'''Always Drops:'''"
result = result.."'''Always Drops:'''"
result = result..'\r\n{|class="wikitable" id="itemdrops"'
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.name, type='item'})
result = result..'\r\n|-\r\n|'..Icons.Icon({bones.name, type='item'})
result = result..'||'..(monster.boneQty ~= nil and monster.boneQty or 1)..'\r\n'..'|}'
result = result..'||'..boneQty..'\r\n'..'|}'
boneVal = boneQty * bones.sellsFor
end
end


Line 714: Line 713:
--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[2] > b[2] end)
table.sort(monster.lootTable, function(a, b) return a[2] > b[2] end)
for i, row in Shared.skpairs(monster.lootTable) do
for i, row in ipairs(monster.lootTable) do
local thisItem = Items.getItemByID(row[1])
local thisItem = Items.getItemByID(row[1])
local maxQty = row[3]
local maxQty = row[3]
if thisItem ~= nil then
if thisItem ~= nil then
result = result..'\r\n|-\r\n|'..Icons.Icon({thisItem.name, type='item'})
result = result..'\r\n|-\r\n|'..Icons.Icon({thisItem.name, type='item'})
else
else
result = result..'\r\n|-\r\n|Unknown Item[[Category:Pages with script errors]]'
result = result..'\r\n|-\r\n|Unknown Item[[Category:Pages with script errors]]'
end
end
Line 731: Line 730:


--Adding price columns
--Adding price columns
local itemPrice = 0
local itemPrice = 0
if thisItem == nil then
if thisItem == nil then
result = result..'||data-sort-value="0"|???'
result = result..'||data-sort-value="0"|???'
else
else
itemPrice = thisItem.sellsFor ~= nil and thisItem.sellsFor or 0
itemPrice = thisItem.sellsFor ~= nil and thisItem.sellsFor or 0
if itemPrice == 0 or maxQty == 1 then
if itemPrice == 0 or maxQty == 1 then
result = result..'||'..Icons.GP(itemPrice)
result = result..'||'..Icons.GP(itemPrice)
Line 745: Line 744:
--Getting the drop chance
--Getting the drop chance
local dropChance = (row[2] / totalWt * lootChance)
local dropChance = (row[2] / totalWt * lootChance)
if dropChance ~= 100 then
if dropChance < 100 then
--Show fraction as long as it isn't going to be 1/1
--Show fraction as long as it isn't going to be 1/1
result = result..'||style="text-align:right" data-sort-value="'..row[2]..'"'
result = result..'||style="text-align:right" data-sort-value="'..row[2]..'"'
Line 753: Line 752:
result = result..'||colspan="2" data-sort-value="'..row[2]..'"'
result = result..'||colspan="2" data-sort-value="'..row[2]..'"'
end
end
result = result..'style="text-align:right"|'..Shared.round(dropChance, 2, 2)..'%'
-- If chance is less than 0.10% then show 2 significant figures, otherwise 2 decimal places
local fmt = (dropChance < 0.10 and '%.2g') or '%.2f'
result = result..'style="text-align:right"|'..string.format(fmt, dropChance)..'%'


--Adding to the average loot value based on price & dropchance
--Adding to the average loot value based on price & dropchance
Line 770: Line 771:
result = result..'\r\nThe loot dropped by the average kill is worth '..Icons.GP(Shared.round(lootValue, 2, 0)).." if sold."
result = result..'\r\nThe loot dropped by the average kill is worth '..Icons.GP(Shared.round(lootValue, 2, 0)).." if sold."
if avgGp > 0 then
if avgGp > 0 then
result = result..'<br/>Including GP, the average kill is worth '..Icons.GP(Shared.round(avgGp + lootValue, 2, 0))..'.'
result = result.."<br/>Including GP"
if boneVal > 0 then
result = result..' and bones'
end
result = result..', the average kill is worth '..Icons.GP(Shared.round(avgGp + lootValue + boneVal, 2, 0))..'.'
end
end
end
end
Line 776: Line 781:
--If no other drops, make sure to at least say so.
--If no other drops, make sure to at least say so.
if result == '' then result = 'None' end
if result == '' then result = 'None' end
return result
end
function p._getMonsterLootValue(monster)
if monster == nil then
return "ERROR: No monster with that name found[[Category:Pages with script errors]]"
end
local result = 0
local boneVal = 0
local bones = p._getMonsterBones(monster)
--Show the bones only if either the monster shows up outside of dungeons _or_ the monster drops shards
if bones ~= nil then
local boneQty = monster.boneQty ~= nil and monster.boneQty or 1
boneVal = bones.sellsFor * boneQty
result = result + boneVal
end
--Likewise, seeing the loot table is tied to the monster appearing outside of dungeons
if not p._isDungeonOnlyMonster(monster) then
local lootChance = monster.lootChance ~= nil and monster.lootChance or 100
local lootValue = 0
local avgGp = 0
if monster.dropCoins ~= nil and monster.dropCoins[2] > 1 then
avgGp = (monster.dropCoins[1] + monster.dropCoins[2]) / 2
end
local multiDrop = Shared.tableCount(monster.lootTable) > 1
local totalWt = 0
for i, row in pairs(monster.lootTable) do
totalWt = totalWt + row[2]
end
for i, row in ipairs(monster.lootTable) do
local thisItem = Items.getItemByID(row[1])
local maxQty = row[3]
--Adding price columns
local itemPrice = 0
if thisItem ~= nil then
itemPrice = thisItem.sellsFor ~= nil and thisItem.sellsFor or 0
end
--Getting the drop chance
local dropChance = (row[2] / totalWt * lootChance)
--Adding to the average loot value based on price & dropchance
lootValue = lootValue + (dropChance * 0.01 * itemPrice * ((1 + maxQty) / 2))
end
if avgGp > 0 then
result = result + avgGp + lootValue
end
end
return result
return result
end
end
Line 798: Line 860:
local lootChance = monster.lootChance ~= nil and monster.lootChance or 100
local lootChance = monster.lootChance ~= nil and monster.lootChance or 100


local totalWt = 0
local totalWt = 0
--for i, row in pairs(monster.lootTable) do
--for i, row in pairs(monster.lootTable) do
--totalWt = totalWt + row[2]
--totalWt = totalWt + row[2]
--end
--end
local dropChance = 0
local dropChance = 0
local dropWt = 0
local dropWt = 0
for i, row in Shared.skpairs(monster.lootTable) do
for i, row in ipairs(monster.lootTable) do
local thisItem = Items.getItemByID(row[1])
totalWt = totalWt + row[2]
totalWt = totalWt + row[2]
if item.id == row[1] then
if item['id'] == thisItem['id'] then
dropWt = row[2]
dropWt = row[2]
end
end
end
end
dropChance = (dropWt / totalWt * lootChance)
dropChance = (dropWt / totalWt * lootChance)
return Shared.round(dropChance, 2, 2)
return Shared.round(dropChance, 2, 2)
end
end
end
end
Line 824: Line 885:
return "ERROR: No item named "..ChestName..' found[[Category:Pages with script errors]]'
return "ERROR: No item named "..ChestName..' found[[Category:Pages with script errors]]'
end
end
local result = ''
local result = ''


Line 843: Line 903:


--Sort the loot table by weight in descending order
--Sort the loot table by weight in descending order
local chestDrops, dropIdx = {}, 0
local hasQty = type(chest.dropQty) == 'table'
for i, row in pairs(chest.dropTable) do
for i, row in pairs(chest.dropTable) do
if chest.dropQty ~= nil then
local qty = hasQty and chest.dropQty[i] or 1
table.insert(row, chest.dropQty[i])
dropIdx = dropIdx + 1
else
chestDrops[dropIdx] = {row[1], row[2], qty}
table.insert(row, 1)
end
end
end
table.sort(chest.dropTable, function(a, b) return a[2] > b[2] end)
table.sort(chestDrops, function(a, b) return a[2] > b[2] end)
for i, row in Shared.skpairs(chest.dropTable) do
for i, row in ipairs(chestDrops) do
local thisItem = Items.getItemByID(row[1])
local thisItem = Items.getItemByID(row[1])
local qty = row[3]
local qty = row[3]
Line 870: Line 930:
result = result..'||style="text-align:left" data-sort-value="'..thisItem.sellsFor..'"'
result = result..'||style="text-align:left" data-sort-value="'..thisItem.sellsFor..'"'
if qty > 1 then
if qty > 1 then
result = result..'|'..Icons.GP(thisItem.sellsFor, thisItem.sellsFor * qty)
result = result..'|'..Icons.GP(thisItem.sellsFor, thisItem.sellsFor * qty)
else
else
result = result..'|'..Icons.GP(thisItem.sellsFor)
result = result..'|'..Icons.GP(thisItem.sellsFor)
Line 900: Line 960:
tableTxt = tableTxt..'\r\n|-\r\n|'..Icons.Icon({monster.name, type='monster'})
tableTxt = tableTxt..'\r\n|-\r\n|'..Icons.Icon({monster.name, type='monster'})
tableTxt = tableTxt..'||'..p._getMonsterCombatLevel(monster)
tableTxt = tableTxt..'||'..p._getMonsterCombatLevel(monster)
tableTxt = tableTxt..'||'..Shared.formatnum(p.getMonsterHP(monster.name))
tableTxt = tableTxt..'||'..Shared.formatnum(p._getMonsterHP(monster))
tableTxt = tableTxt..'||'..Shared.formatnum(p.getMonsterMaxHit(monster.name))
tableTxt = tableTxt..'||'..Shared.formatnum(p._getMonsterMaxHit(monster))
tableTxt = tableTxt..'||'..p.getMonsterStyleIcon({monster.name, nolink=true})
tableTxt = tableTxt..'||'..p._getMonsterStyleIcon({monster, nolink=true})
end
end
tableTxt = tableTxt..'\r\n|}'
tableTxt = tableTxt..'\r\n|}'
Line 929: Line 989:
-- 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
local monData = {}
local monData = {}
if specialType ~= nil and Shared.contains({'Afflicted', 'SlayerArea'}, specialType) then
if specialType ~= nil and Shared.contains({'Afflicted', 'SlayerArea'}, specialType) then
-- Special handling for Into the Mist
-- Special handling for Into the Mist
if specialType == 'Afflicted' then
if specialType == 'Afflicted' then
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'})
Line 948: Line 1,008:
monCount = monsterCount
monCount = monsterCount
end
end
else
else
-- 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({monster.name, type='monster'})
monLevel = p._getMonsterCombatLevel(monster)
monLevel = p._getMonsterCombatLevel(monster)
monHP = p._getMonsterHP(monster)
monHP = p._getMonsterHP(monster)
monMaxHit = p._getMonsterMaxHit(monster)
monMaxHit = p._getMonsterMaxHit(monster)
monStyle = p._getMonsterStyleIcon({monster})
monStyle = p._getMonsterStyleIcon({monster})
monCount = monsterCount
monCount = monsterCount
end
end
local getValSort = function(val)
local getValSort = function(val)
if type(val) == 'table' then
if type(val) == 'table' then
if type(val[1]) == 'number' and type(val[2]) == 'number' then
if type(val[1]) == 'number' and type(val[2]) == 'number' then
return (val[1] + val[2]) / 2
return (val[1] + val[2]) / 2
else
return (type(val[1]) == 'number' and val[1]) or 0
end
else
else
return (type(val) == 'number' and val) or 0
return (type(val[1]) == 'number' and val[1]) or 0
end
end
else
return (type(val) == 'number' and val) or 0
end
end
local getValText = function(val)
end
if type(val) == 'table' and Shared.tableCount(val) == 2 then
local getValText = function(val)
if type(val[1]) == 'number' and type(val[2]) == 'number' then
if type(val) == 'table' and Shared.tableCount(val) == 2 then
return Shared.formatnum(val[1]) .. ' - ' .. Shared.formatnum(val[2])
if type(val[1]) == 'number' and type(val[2]) == 'number' then
else
return Shared.formatnum(val[1]) .. ' - ' .. Shared.formatnum(val[2])
return val[1] .. ' - ' .. val[2]
end
elseif type(val) == 'number' then
return Shared.formatnum(val)
else
else
return val
return val[1] .. ' - ' .. val[2]
end
end
elseif type(val) == 'number' then
return Shared.formatnum(val)
else
return val
end
end
end
local resultPart = {}
local resultPart = {}
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))
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))
table.insert(resultPart, '\r\n|style="text-align:right;" data-sort-value="' .. getValSort(monMaxHit) .. '"| ' .. getValText(monMaxHit))
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))
return table.concat(resultPart)
return table.concat(resultPart)
end
end


local returnPart = {}
local returnPart = {}
Line 1,107: Line 1,167:
if not p._isDungeonOnlyMonster(monster) then
if not p._isDungeonOnlyMonster(monster) then
if monster.dropCoins ~= nil and monster.dropCoins[2] > 1 then
if monster.dropCoins ~= nil and monster.dropCoins[2] > 1 then
local avgGp = (monster.dropCoins[1] + monster.dropCoins[2]) / 2
local avgGp = (monster.dropCoins[1] + monster.dropCoins[2]) / 2
result = result..'<br/>'..monster.name..','..monster.dropCoins[1]..','..(monster.dropCoins[2])..','..avgGp
result = result..'<br/>'..monster.name..','..monster.dropCoins[1]..','..(monster.dropCoins[2])..','..avgGp
end
end
end
end
Line 1,119: Line 1,179:
local totalGP = 0
local totalGP = 0


local bones = p.getMonsterBones(monster)
local bones = p._getMonsterBones(monster)
if bones ~= nil then
if bones ~= nil then
totalGP = totalGP + bones.sellsFor * (type(monster.boneQty) == 'number' and monster.boneQty or 1)
totalGP = totalGP + bones.sellsFor * (type(monster.boneQty) == 'number' and monster.boneQty or 1)
Line 1,257: Line 1,317:
table.insert(tableParts, '!!' .. Icons.Icon({'Coins', notext=true, nolink=true}) .. ' Coins !!Bones !!Locations')
table.insert(tableParts, '!!' .. Icons.Icon({'Coins', notext=true, nolink=true}) .. ' Coins !!Bones !!Locations')


-- Generate row per monster
-- Generate row per monster
for i, monsterID in Shared.skpairs(monsterIDs) do
for i, monsterID in Shared.skpairs(monsterIDs) do
local monster = p.getMonsterByID(monsterID)
local monster = p.getMonsterByID(monsterID)
Line 1,276: Line 1,336:
gpTxt = Shared.formatnum(gpRange[1]) .. ' - ' .. Shared.formatnum(gpRange[2])
gpTxt = Shared.formatnum(gpRange[1]) .. ' - ' .. Shared.formatnum(gpRange[2])
end
end
local bones = p.getMonsterBones(monster)
local bones = p._getMonsterBones(monster)
local boneTxt = (bones ~= nil and Icons.Icon({bones.name, type='item', notext=true})) or 'None'
local boneTxt = (bones ~= nil and Icons.Icon({bones.name, type='item', notext=true})) or 'None'


Line 1,294: Line 1,354:
table.insert(tableParts, '\r\n|style="text-align:center" |' .. boneTxt)
table.insert(tableParts, '\r\n|style="text-align:center" |' .. boneTxt)
table.insert(tableParts, '\r\n|style="text-align:right;width:190px" |' .. p._getMonsterAreas(monster, hideDungeons))
table.insert(tableParts, '\r\n|style="text-align:right;width:190px" |' .. p._getMonsterAreas(monster, hideDungeons))
end
table.insert(tableParts, '\r\n|}')
return table.concat(tableParts)
end
function p.getMattMonsterTable(frame)
--Making a single function for getting a table of monsters given a list of IDs.
local tableParts = {}
table.insert(tableParts, '{| class="wikitable sortable stickyHeader"')
-- Second header row
table.insert(tableParts, '\r\n|- class="headerRow-1"\r\n!Monster !!Name !!ID !!Combat Level ')
table.insert(tableParts, '!!style="padding:0 1em 0 0"|' .. Icons.Icon({'Hitpoints', type='skill'}))
table.insert(tableParts, '!!' .. Icons.Icon({'Coins', notext=true, nolink=true}) .. ' Coins !!Avg. Kill Value!!Locations')
-- Generate row per monster
for i, monster in Shared.skpairs(MonsterData.Monsters) do
local cmbLevel = p._getMonsterCombatLevel(monster)
local gpRange = {0, 0}
if monster.dropCoins ~= nil and monster.dropCoins[2] > 1 then
gpRange = {monster.dropCoins[1], monster.dropCoins[2]}
end
local gpTxt = nil
if gpRange[1] >= gpRange[2] then
gpTxt = Shared.formatnum(gpRange[1])
else
gpTxt = Shared.formatnum(gpRange[1]) .. ' - ' .. Shared.formatnum(gpRange[2])
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="' .. (gpRange[1] + gpRange[2]) / 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, hideDungeons))
end
table.insert(tableParts, '\r\n|}')
return table.concat(tableParts)
end
function p.getMattMonsterTableV2(frame)
--Making a single function for getting a table of monsters given a list of IDs.
local tableParts = {}
table.insert(tableParts, '{| class="wikitable sortable stickyHeader"')
-- Second header row
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({'Defence', type='skill', notext=true}))
table.insert(tableParts, '!!Attack Speed (s) !!colspan="2"|Max Hit !!Accuracy ')
-- 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, '!!' .. Icons.Icon({'Coins', notext=true, nolink=true}) .. ' Coins !!Avg. Kill Value !!Bones')
-- Generate row per monster
for i, monster in Shared.skpairs(MonsterData.Monsters) do
local cmbLevel = p._getMonsterCombatLevel(monster)
local gpRange = {0, 0}
if monster.dropCoins ~= nil and monster.dropCoins[2] > 1 then
gpRange = {monster.dropCoins[1], monster.dropCoins[2]}
end
local gpTxt = nil
if gpRange[1] >= gpRange[2] then
gpTxt = Shared.formatnum(gpRange[1])
else
gpTxt = Shared.formatnum(gpRange[1]) .. ' - ' .. Shared.formatnum(gpRange[2])
end
local lootVal = p._getMonsterLootValue(monster)
local lootTxt = '0'
if lootVal ~= 0 then
lootTxt = Shared.formatnum(Shared.round(lootVal, 2, 2))
end
local atkSpeed = p._getMonsterAttackSpeed(monster)
local maxHit = p._getMonsterMaxHit(monster)
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.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|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="' .. 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="' .. maxHit .. '" |' .. Shared.formatnum(maxHit))
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[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="' .. (gpRange[1] + gpRange[2]) / 2 .. '" |' .. gpTxt)
table.insert(tableParts, '\r\n|style="text-align:right" data-sort-value="' .. lootVal .. '" |' .. lootTxt)
table.insert(tableParts, '\r\n|style="text-align:center" |' .. boneTxt)
-- table.insert(tableParts, '\r\n|style="text-align:right;width:190px" |' .. p._getMonsterAreas(monster, hideDungeons))
end
end


Line 1,301: Line 1,472:


function p.getSpecialAttackTable(frame)
function p.getSpecialAttackTable(frame)
local spAttTable = {}
local spAttTable = {}


for i, monster in ipairs(MonsterData.Monsters) do
for i, monster in ipairs(MonsterData.Monsters) do
if monster.specialAttacks ~= nil and Shared.tableCount(monster.specialAttacks) > 0 then
if monster.specialAttacks ~= nil and Shared.tableCount(monster.specialAttacks) > 0 then
local overrideChance = (monster.overrideSpecialChances ~= nil and Shared.tableCount(monster.overrideSpecialChances) > 0)
local overrideChance = (monster.overrideSpecialChances ~= nil and Shared.tableCount(monster.overrideSpecialChances) > 0)
for j, spAtt in ipairs(monster.specialAttacks) do
for j, spAtt in ipairs(monster.specialAttacks) do
local attChance = (overrideChance and monster.overrideSpecialChances[j] or spAtt.defaultChance)
local attChance = (overrideChance and monster.overrideSpecialChances[j] or spAtt.defaultChance)
if spAttTable[spAtt.id] == nil then
if spAttTable[spAtt.id] == nil then
    spAttTable[spAtt.id] = { ['defn'] = spAtt, ['icons'] = {} }
spAttTable[spAtt.id] = { ['defn'] = spAtt, ['icons'] = {} }
end
end
if spAttTable[spAtt.id]['icons'][attChance] == nil then
if spAttTable[spAtt.id]['icons'][attChance] == nil then
    spAttTable[spAtt.id]['icons'][attChance] = {}
spAttTable[spAtt.id]['icons'][attChance] = {}
end
table.insert(spAttTable[spAtt.id]['icons'][attChance], Icons.Icon({ monster.name, type = 'monster' }))
end
end
end
table.insert(spAttTable[spAtt.id]['icons'][attChance], Icons.Icon({ monster.name, type = 'monster' }))
end
end
end
end


local resultPart = {}
local resultPart = {}
table.insert(resultPart, '{|class="wikitable sortable stickyHeader"')
table.insert(resultPart, '{|class="wikitable sortable stickyHeader"')
table.insert(resultPart, '\r\n|- class="headerRow-0"')
table.insert(resultPart, '\r\n|- class="headerRow-0"')
table.insert(resultPart, '\r\n!Name!!style="min-width:225px"|Monsters!!Chance!!Effect')
table.insert(resultPart, '\r\n!Name!!style="min-width:225px"|Monsters!!Chance!!Effect')


for i, spAttData in Shared.skpairs(spAttTable) do
for i, spAttData in Shared.skpairs(spAttTable) do
local spAtt = spAttData.defn
local spAtt = spAttData.defn
local firstRow = true
local firstRow = true
local rowsSpanned = Shared.tableCount(spAttData.icons)
local rowsSpanned = Shared.tableCount(spAttData.icons)
local rowSuffix = ''
local rowSuffix = ''
if rowsSpanned > 1 then
if rowsSpanned > 1 then
rowSuffix = '|rowspan="' .. rowsSpanned .. '"'
rowSuffix = '|rowspan="' .. rowsSpanned .. '"'
end
end
for chance, iconList in Shared.skpairs(spAttData.icons) do
for chance, iconList in Shared.skpairs(spAttData.icons) do
table.insert(resultPart, '\r\n|-')
table.insert(resultPart, '\r\n|-')
if firstRow then
if firstRow then
table.insert(resultPart, '\r\n' .. rowSuffix .. '| ' .. spAtt.name)
table.insert(resultPart, '\r\n' .. rowSuffix .. '| ' .. spAtt.name)
end
end
table.insert(resultPart, '\r\n|data-sort-value="' .. spAtt.name .. '"| ' .. table.concat(iconList, '<br/>'))
table.insert(resultPart, '\r\n|data-sort-value="' .. spAtt.name .. '"| ' .. table.concat(iconList, '<br/>'))
table.insert(resultPart, '\r\n|data-sort-value="' .. chance .. '"| ' .. Shared.round(chance, 2, 0) .. '%')
table.insert(resultPart, '\r\n|data-sort-value="' .. chance .. '"| ' .. Shared.round(chance, 2, 0) .. '%')
if firstRow then
if firstRow then
table.insert(resultPart, '\r\n' .. rowSuffix .. '| ' .. spAtt.description)
table.insert(resultPart, '\r\n' .. rowSuffix .. '| ' .. spAtt.description)
firstRow = false
firstRow = false
end
end
end
end
end
table.insert(resultPart, '\r\n|}')
end
table.insert(resultPart, '\r\n|}')


return table.concat(resultPart)
return table.concat(resultPart)
end
end


return p
return p