Anonymous

Module:Skills: Difference between revisions

From Melvor Idle
Added 'no item' drop chance to NPC table
(formatting fix for firemaking table)
(Added 'no item' drop chance to NPC table)
(14 intermediate revisions by 2 users not shown)
Line 1: Line 1:
--Some skills have their own modules:
--Some skills have their own modules:
--Module:Magic and Module:Prayer being the current two examples.
--Module:Magic for Magic
--Module:Prayer for Prayer
--Module:Agility for Agility
--Module:Skills/Gathering for Mining, Fishing, Woodcutting
--Module:Skills/Artisan for Smithing, Cooking, Herblore, etc.


local p = {}
local p = {}
Line 31: Line 35:
   end
   end
   return nil
   return nil
end
function p.getThievingNPCByID(ID)
  local result = Shared.clone(SkillData.Thieving[ID + 1])
  if result ~= nil then
    result.id = ID
  end
  return result
end
function p.getThievingNPC(name)
  local result = nil
  for i, npc in pairs(SkillData.Thieving) do
    if name == npc.name then
      result = Shared.clone(npc)
      result.id = i - 1
      break
    end
  end
  return result
end
function p.getThievingNPCStat(frame)
  local args = frame.args ~= nil and frame.args or frame
  local npcName = args[1]
  local statName = args[2]
  local npc = p.getThievingNPC(npcName)
  if npc == nil then
    return 'ERROR: Failed to find Thieving NPC with name ' .. name .. '[[Category:Pages with script errors]]'
  end
 
  return p._getThievingNPCStat(npc, statName)
end
function p._getThievingNPCStat(npc, stat)
  local result = npc[stat]
  -- Overrides below
  if stat == 'maxHit' then
    result = result * 10
  elseif stat == 'lootTable' then
    return p._formatLootTable(npc['lootTable'], 0.75)
  elseif stat == 'requirements' then
  if npc['level'] ~= nil then
    result = Icons._SkillReq('Thieving', npc['level'], true)
  else
    result = 'None'
  end
  end
  return result
end
function p._formatLootTable(lootTableIn, chanceMultIn)
  -- Expects lootTableIn to be in format {{itemID_1, itemWeight_1}, ..., {itemID_n, itemWeight_n}}
  if Shared.tableCount(lootTableIn) == 0 then
    return ''
  end
  local chanceMult = (chanceMultIn or 1) * 100
  local lootTable = Shared.clone(lootTableIn)
  -- Sort table from most to least common drop
  table.sort(lootTable, function(a, b)
                          if a[2] == b[2] then
                            return a[1] < b[1]
                          else
                            return a[2] > b[2]
                          end
                        end)
  local totalWeight = 0
  for i, drop in pairs(lootTable) do
    totalWeight = totalWeight + drop[2]
  end
  if totalWeight == 0 then
    return ''
  end
  -- Get the length (in characters) of the largest drop chance so that they can be right aligned
  -- [4/16/21]: Adding info for no drop
  local maxDropLen = math.max(string.len(Shared.round(25, 2, 2)), string.len(Shared.round(lootTable[1][2] / totalWeight * chanceMult, 2, 2)))
  local returnPart = {}
  table.insert(returnPart, '* ' .. string.rep('&nbsp;', math.max(0, (maxDropLen - string.len(Shared.round(25, 2, 2))) * 2)) .. '25.00% No Item')
  for i, drop in pairs(lootTable) do
    local item, itemText, dropChance = Items.getItemByID(drop[1]), nil, Shared.round(drop[2] / totalWeight * chanceMult, 2, 2)
    if item == nil then
      itemText = 'Unknown'
    else
      itemText = Icons.Icon({item.name, type='item'})
    end
    table.insert(returnPart, '* ' .. string.rep('&nbsp;', math.max(0, (maxDropLen - string.len(dropChance)) * 2)) .. dropChance .. '% ' .. itemText)
  end
  return table.concat(returnPart, '\r\n')
end
function p.getThievingNPCTable()
  local returnPart = {}
  -- Create table header
  table.insert(returnPart, '{| class="wikitable sortable stickyHeader"')
  table.insert(returnPart, '|- class="headerRow-0"\r\n!Target!!Name!!' .. Icons.Icon({'Thieving', type='skill', notext=true}).. ' Level!!Experience!!Max Hit!!Max Coins')
 
  local linkOverrides = { ['Golbin'] = 'Golbin (thieving)' }
  -- Create row for each NPC
  for i, npc in Shared.skpairs(SkillData.Thieving) do
    local linkText = npc.name
    if linkOverrides[npc.name] ~= nil then
      linkText = linkOverrides[npc.name] .. '|' .. npc.name
    end
    table.insert(returnPart, '|-\r\n|style="text-align: left;" |' .. Icons.Icon({npc.name, type='thieving', size=50, notext=true}))
    table.insert(returnPart, '|style="text-align: left;" |[[' .. linkText .. ']]')
    table.insert(returnPart, '|style="text-align: right;" |' .. p._getThievingNPCStat(npc, 'level'))
    table.insert(returnPart, '|style="text-align: right;" |' .. p._getThievingNPCStat(npc, 'xp'))
    table.insert(returnPart, '|style="text-align: right;" |' .. p._getThievingNPCStat(npc, 'maxHit'))
    table.insert(returnPart, '|style="text-align: right;" |' .. p._getThievingNPCStat(npc, 'maxCoins'))
  end
  table.insert(returnPart, '|}')
  return table.concat(returnPart, '\r\n')
end
function p.getThievingNavbox()
  local returnPart = {}
  -- Create table header
  table.insert(returnPart, '{| class="wikitable" style="text-align:center; clear:both; margin:auto; margin-bottom:1em;"')
  table.insert(returnPart, '|-\r\n!' .. Icons.Icon({'Thieving', type='skill', notext=true}) .. '[[Thieving|Thieving Targets]]')
  table.insert(returnPart, '|-\r\n|')
 
  local npcList = {}
  local linkOverrides = { ['Golbin'] = 'Golbin (thieving)' }
  -- Create row for each NPC
  for i, npc in Shared.skpairs(SkillData.Thieving) do
    local linkText = npc.name
    if linkOverrides[npc.name] ~= nil then
      linkText = linkOverrides[npc.name] .. '|' .. npc.name
    end
    table.insert(npcList, Icons.Icon({npc.name, type='thieving', notext=true}) .. ' [[' .. linkText .. ']]')
  end
  table.insert(returnPart, table.concat(npcList, ' • '))
  table.insert(returnPart, '|}')
  return table.concat(returnPart, '\r\n')
end
end


Line 129: Line 277:
end
end


function p.getMiningTable(frame)
function p.getFarmingFoodTable(frame)
   local result = '{|class="wikitable sortable stickyHeader"'
   local result = '{| class="wikitable sortable stickyHeader"'
   result = result..'\r\n|- class="headerRow-0"'
   result = result..'\r\n|- class="headerRow-0"'
   result = result..'\r\n!colspan=2|Ore!!'..Icons.Icon({'Mining', type='skill', notext=true})..' Level'
   result = result..'\r\n!colspan="2"|Crop!!'..Icons.Icon({"Farming", type="skill", notext=true})..' Level'
   result = result..'!!XP!!Respawn Time!!Ore Value'
   result = result..'!!Healing!!Value'
   local mineData = Shared.clone(SkillData.Mining)
 
   table.sort(mineData, function(a, b) return a.level < b.level end)
   local itemArray = Items.getItems(function(item) return item.grownItemID ~= nil end)
   for i, oreData in Shared.skpairs(mineData) do
 
     local ore = Items.getItemByID(oreData.ore)
   table.sort(itemArray, function(a, b) return a.farmingLevel < b.farmingLevel end)
     result = result..'\r\n|-\r\n|'..Icons.Icon({ore.name, type='item', size='50', notext=true})..'||'..ore.name
 
    result = result..'||style="text-align:right"|'..oreData.level..'||style="text-align:right"|'..ore.miningXP
   for i, item in Shared.skpairs(itemArray) do
    result = result..'||style="text-align:right" data-sort-value="'..oreData.respawnInterval..'"|'
     local crop = Items.getItemByID(item.grownItemID)
     result = result..Shared.timeString(oreData.respawnInterval / 1000, true)
     if crop.healsFor ~= nil and crop.healsFor > 0 then
     result = result..'||data-sort-value="'..ore.sellsFor..'"|'..Icons.GP(ore.sellsFor)
      result = result..'\r\n|-'
      result = result..'\r\n|'..Icons.Icon({crop.name, type='item', notext='true', size='50'})..'||[['..crop.name..']]'
      result = result..'||style="text-align:right;"|'..item.farmingLevel
      result = result..'||style="text-align:right" data-sort-value="'..crop.healsFor..'"|'..Icons.Icon({"Hitpoints", type="skill", notext=true})..' '..(crop.healsFor * 10)
      result = result..'||style="text-align:right" data-sort-value="'..crop.sellsFor..'"|'..Icons.GP(crop.sellsFor)
     end
  end
 
  result = result..'\r\n|}'
 
  return result
end
 
function p.getFarmingPlotTable(frame)
  local areaName = frame.args ~= nil and frame.args[1] or frame
  local patches = nil
  for i, area in Shared.skpairs(SkillData.Farming.Patches) do
    if area.areaName == areaName then
      patches = area.patches
      break
    end
  end
  if patches == nil then
    return "ERROR: Invalid area name.[[Category:Pages with script errors"
  end
 
  local result = '{|class="wikitable"'
  result = result..'\r\n!Plot!!'..Icons.Icon({'Farming', type='skill', notext=true})..' Level!!Cost'
 
  for i, patch in Shared.skpairs(patches) do
    result = result..'\r\n|-\r\n|'..i
     result = result..'||style="text-align:right;" data-sort-value="0"|'..patch.level
    if patch.cost == 0 then
      result = result..'||Free'
    else
      result = result..'||style="text-align:right;" data-sort-value="'..patch.cost..'"|'..Icons.GP(patch.cost)
    end
   end
   end


Line 173: Line 357:
   result = result..'|'..table.concat(SkillPots, ' • ')
   result = result..'|'..table.concat(SkillPots, ' • ')
   result = result..'\r\n|}'
   result = result..'\r\n|}'
  return result
end
function p.getSpecialFishingTable(frame)
  local lootValue = 0
  local totalWt = Items.specialFishWt
  local result = ''
  result = result..'\r\n{|class="wikitable sortable"'
  result = result..'\r\n!Item'
  result = result..'!!Price!!colspan="2"|Chance'
  --Sort the loot table by weight in descending order
  table.sort(Items.specialFishLoot, function(a, b) return a[2] > b[2] end)
  for i, row in pairs(Items.specialFishLoot) do
    local thisItem = Items.getItemByID(row[1])
    result = result..'\r\n|-\r\n|'..Icons.Icon({thisItem.name, type='item'})
    result = result..'||style="text-align:left" data-sort-value="'..thisItem.sellsFor..'"'
    result = result..'|'..Icons.GP(thisItem.sellsFor)
    local dropChance = (row[2] / totalWt) * 100
    result = result..'||style="text-align:right" data-sort-value="'..row[2]..'"'
    result = result..'|'..Shared.fraction(row[2], totalWt)
    result = result..'||style="text-align:right"|'..Shared.round(dropChance, 2, 2)..'%'
    lootValue = lootValue + (dropChance * 0.01 * thisItem.sellsFor)
  end
  result = result..'\r\n|}'
  result = result..'\r\nThe average value of a roll on the special fishing loot table is '..Icons.GP(Shared.round(lootValue, 2, 0))
   return result
   return result
end
end
Line 237: Line 392:
   result = result..'\r\n|-class="headerRow-0"'
   result = result..'\r\n|-class="headerRow-0"'
   result = result..'\r\n!Item!!Name!!'..Icons.Icon({'Smithing', type='skill', notext=true})..' Level!!XP!!Value!!Ingredients'
   result = result..'\r\n!Item!!Name!!'..Icons.Icon({'Smithing', type='skill', notext=true})..' Level!!XP!!Value!!Ingredients'
  --Adding value/bar for things other than smelting
  if bar ~= nil then result = result..'!!Value/Bar' end


   table.sort(smithList, function(a, b)
   table.sort(smithList, function(a, b)
Line 254: Line 411:
     result = result..'||data-sort-value="'..item.smithingLevel..'"|'..Icons._SkillReq('Smithing', item.smithingLevel)
     result = result..'||data-sort-value="'..item.smithingLevel..'"|'..Icons._SkillReq('Smithing', item.smithingLevel)
     result = result..'||'..item.smithingXP
     result = result..'||'..item.smithingXP
     result = result..'||data-sort-value="'..item.sellsFor * qty..'"|'..Icons.GP(item.sellsFor)
    local totalValue = item.sellsFor * qty
     result = result..'||data-sort-value="'..totalValue..'"|'..Icons.GP(item.sellsFor)
     if qty > 1 then
     if qty > 1 then
       result = result..' (x'..qty..')'
       result = result..' (x'..qty..')'
     end
     end
     result = result..'||'
     result = result..'||'
    local barQty = 0
     for i, mat in Shared.skpairs(item.smithReq) do
     for i, mat in Shared.skpairs(item.smithReq) do
       matItem = Items.getItemByID(mat.id)
       matItem = Items.getItemByID(mat.id)
       if i > 1 then result = result..', ' end
       if i > 1 then result = result..', ' end
       result = result..Icons.Icon({matItem.name, type='item', qty=mat.qty, notext=true})
       result = result..Icons.Icon({matItem.name, type='item', qty=mat.qty, notext=true})
      if bar ~= nil and mat.id == bar.id then
        barQty = mat.qty
      end
    end
    --Add the data for the value per bar
    if bar ~= nil then
      if barQty == 0 then
        result = result..'||data-sort-value="0"|N/A'
      else
        local barVal = totalValue / barQty
        result = result..'||data-sort-value="'..barVal..'"|'..Icons.GP(Shared.round(barVal, 1, 1))
      end
     end
     end
   end
   end
Line 280: Line 451:
     local name = Shared.titleCase(logData.type..' Logs')
     local name = Shared.titleCase(logData.type..' Logs')
     result = result..'\r\n|data-sort-value="'..name..'"|'..Icons.Icon({name, type='item', size='50', notext=true})
     result = result..'\r\n|data-sort-value="'..name..'"|'..Icons.Icon({name, type='item', size='50', notext=true})
     result = result..'||'..name
     result = result..'||[['..name..']]'
     result = result..'||style ="text-align: right;"|'..logData.level
     result = result..'||style ="text-align: right;"|'..logData.level
     result = result..'||style ="text-align: right;"|'..logData.xp
     result = result..'||style ="text-align: right;"|'..logData.xp