Module:Skills

From Melvor Idle
Revision as of 21:32, 2 December 2020 by Falterfire (talk | contribs) (Initial pass at getSmithingTable)
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.

Data pulled from Module:Skills/data


--Some skills have their own modules:
--Module:Magic and Module:Prayer being the current two examples.

local p = {}

local ItemData = mw.loadData('Module:Items/data')
local SkillData = mw.loadData('Module:Skills/data')
local Constants = mw.loadData('Module:Constants/data')

local Shared = require('Module:Shared')
local Items = require('Module:Items')
local ItemSourceTables = require('Module:Items/SourceTables')
local Icons = require('Module:Icons')

local MasteryCheckpoints = {.1, .25, .5, .95}

function p.getSkillID(skillName)
  for skName, ID in Shared.skpairs(Constants.skill) do
    if skName == skillName then
      return ID
    end
  end
  return nil
end

function p.getMasteryUnlockTable(frame)
  local skillName = frame.args ~= nil and frame.args[1] or frame
  local skillID = p.getSkillID(skillName)
  if skillID == nil then
    return "ERROR: Failed to find a skill ID for "..skillName
  end

  local unlockTable = SkillData.MasteryUnlocks[skillID]
  if unlockTable == nil then
    return 'ERROR: Failed to find Mastery Unlock data for '..skillName
  end

  local result = '{|class="wikitable"\r\n!Level!!Unlock'
  for i, unlock in Shared.skpairs(unlockTable) do
    result = result..'\r\n|-'
    result = result..'\r\n|'..unlock.level..'||'..unlock.unlock
  end
  result = result..'\r\n|}'
  return result
end

function p.getMasteryCheckpointTable(frame)
  local skillName = frame.args ~= nil and frame.args[1] or frame
  local skillID = p.getSkillID(skillName)
  if skillID == nil then
    return "ERROR: Failed to find a skill ID for "..skillName
  end

  if SkillData.MasteryCheckpoints[skillID] == nil then
    return 'ERROR: Failed to find Mastery Unlock data for '..skillName
  end

  local bonuses = SkillData.MasteryCheckpoints[skillID].bonuses
  local totalPoolXP = SkillData.MasteryPoolXP[skillID + 1]

  local result = '{|class="wikitable"\r\n!Pool %!!style="width:100px"|Pool XP!!Bonus'
  for i, bonus in Shared.skpairs(bonuses) do
    result = result..'\r\n|-'
    result = result..'\r\n|'..(MasteryCheckpoints[i] * 100)..'%||'
    result = result..Shared.formatnum(totalPoolXP * MasteryCheckpoints[i])..' xp||'..bonus
  end
  result = result..'\r\n|-\r\n!colspan="2"|Total Mastery Pool XP'
  result = result..'\r\n|'..Shared.formatnum(totalPoolXP)
  result = result..'\r\n|}'
  return result
end

function p._getFarmingTable(category)
  local seedList = {}
  if category == 'Allotment' or category == 'Herb' or category == 'Tree' then
    seedList = Items.getItems(function(item) return item.tier == category end)
  else
    return 'ERROR: Invalid farming category. Please choose Allotment, Herb, or Tree'
  end

  local result = '{|class="wikitable sortable stickyHeader"'
  result = result..'\r\n|- class="headerRow-0"'
  result = result..'\r\n!colspan=2|Seeds!!'..Icons.Icon({'Farming', type='skill', notext=true})..' Level'
  result = result..'!!XP!!Growth Time!!Seed Value'
  if category == 'Allotment' then
    result = result..'!!colspan="2"|Crop!!Crop Healing!!Crop Value'
  elseif category == 'Herb' then
    result = result..'!!colspan="2"|Herb!!Herb Value'
  elseif category == 'Tree' then
    result = result..'!!colspan="2"|Logs!!Log Value'
  end
  result = result..'!!Seed Sources'
  
  table.sort(seedList, function(a, b) return a.farmingLevel < b.farmingLevel end)

  for i, seed in pairs(seedList) do
    result = result..'\r\n|-'
    result = result..'\r\n|'..Icons.Icon({seed.name, type='item', size='50', notext=true})..'||[['..seed.name..']]'
    result = result..'||'..seed.farmingLevel..'||'..Shared.formatnum(seed.farmingXP)
    result = result..'||data-sort-value="'..seed.timeToGrow..'"|'..Shared.timeString(seed.timeToGrow, true)
    result = result..'||data-sort-value="'..seed.sellsFor..'"|'..Icons.GP(seed.sellsFor)

    local crop = Items.getItemByID(seed.grownItemID)
    result = result..'||'..Icons.Icon({crop.name, type='item', size='50', notext=true})..'||[['..crop.name..']]'
    if category == 'Allotment' then
      result = result..'||'..Icons.Icon({'Hitpoints', type='skill', notext=true})..' '..(crop.healsFor * 10)
    end
    result = result..'||data-sort-value="'..crop.sellsFor..'"|'..Icons.GP(crop.sellsFor)
    result = result..'||'..ItemSourceTables._getItemSources(seed)
  end

  result = result..'\r\n|}'
  return result
end

function p.getFarmingTable(frame)
  local category = frame.args ~= nil and frame.args[1] or frame

  return p._getFarmingTable(category)
end

function p.getMiningTable(frame)
  local result = '{|class="wikitable sortable stickyHeader"'
  result = result..'\r\n|- class="headerRow-0"'
  result = result..'\r\n!colspan=2|Ore!!'..Icons.Icon({'Mining', type='skill', notext=true})..' Level'
  result = result..'!!XP!!Respawn Time!!Ore Value'
  local mineData = Shared.clone(SkillData.Mining)
  table.sort(mineData, function(a, b) return a.level < b.level end)
  for i, oreData in Shared.skpairs(mineData) do
    local ore = Items.getItemByID(oreData.ore)
    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
    result = result..'||style="text-align:right" data-sort-value="'..oreData.respawnInterval..'"|'
    result = result..Shared.timeString(oreData.respawnInterval / 1000, true)
    result = result..'||data-sort-value="'..ore.sellsFor..'"|'..Icons.GP(ore.sellsFor)
  end

  result = result..'\r\n|}'
  return result
end

function p.getPotionNavbox(frame)
  --•
  local result = '{| class="wikitable" style="margin:auto; clear:both; width: 100%"'
  result = result..'\r\n!colspan=2|'..Icons.Icon({'Herblore', 'Potions', type='skill'})

  local CombatPots = {}
  local SkillPots = {}
  for i, potData in Shared.skpairs(SkillData.Herblore.ItemData) do
    if potData.category == 0 then
      table.insert(CombatPots, Icons.Icon({potData.name, type='item', img=(potData.name..' I')}))
    else
      if potData.name == 'Bird Nests Potion' then
        table.insert(SkillPots, Icons.Icon({"Bird Nest Potion", type='item', img="Bird Nest Potion I"}))
      else
        table.insert(SkillPots, Icons.Icon({potData.name, type='item', img=(potData.name..' I')}))
      end
    end
  end

  result = result..'\r\n|-\r\n!Combat Potions\r\n|class="center" style="vertical-align:middle;"'
  result = result..'|'..table.concat(CombatPots, ' • ')
  result = result..'\r\n|-\r\n!Skill Potions\r\n|class="center" style="vertical-align:middle;"'
  result = result..'|'..table.concat(SkillPots, ' • ')
  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
end

function p.getSmithingTable(frame)
  local tableType = frame.args ~= nil and frame.args[1] or frame
  local bar = nil
  if tableType ~= 'Smelting' then
    bar = Items.getItem(tableType)
    if bar == nil then
      return 'ERROR: Could not find an item named '..tableType..' to build a smithing table with'
    elseif bar.type ~= 'Bar' then
      return 'ERROR: '..tableType.." is not a bar and thus can't be used for smithing"
    end
  end

  local smithList = {}
  for i, item in pairs(ItemData.Items) do
    if item.smithingLevel ~= nil then
      if tableType == 'Smelting' then
        if item.type == 'Bar' then
          table.insert(smithList, item)
        end
      else
        for j, req in pairs(item.smithReq) do
          if req.id == bar.id then
            table.insert(smithList, item)
          end
        end
      end
    end
  end

  local result = '{|class="wikitable sortable stickyHeader"'
  result = result..'\r\n|-class="headerRow-0"'
  result = result..'\r\n!Item!!Name!!'..Icons.Icon({'Smithing', 'skill', notext=true})..'!!XP!!Value!!Ingredients'

  table.sort(smithList, function(a, b)
                          if a.smithingLevel ~= b.smithingLevel then
                            return a.smithingLevel < b.smithingLevel
                          else
                            return a.name < b.name
                          end end)
  for i, item in Shared.skpairs(smithList) do
    result = result..'\r\n|-'
    result = result..'\r\n|'..Icons.Icon({item.name, type='item', size='50', notext=true})..'||'
    local qty = item.smithingQty ~= nil and item.smithingQty or 1
    if qty > 1 then
      result = result..item.smithingQty..'x '
    end
    result = result..'||[['..item.name..']]'
    result = result..'||data-sort-value="'..item.smithingLevel..'"|'..Icons._SkillReq('Smithing', item.smithingLevel)
    result = result..'||'..item.smithingXP
    result = result..'||data-sort-value="'..item.sellsFor * qty..'"|'..Icons.GP(item.sellsFor)
    if qty > 1 then
      result = result..' (x'..qty..')'
    end
    result = result..'||'
    for i, mat in Shared.skpairs(item.smithReq) do
      matItem = Items.getItemByID(mat.id)
      if i > 1 then result = result..', ' end
      result = result..Icons.Icon({matItem.name, type='item', qty=mat.qty, notext=true})
    end
  end

  result = result..'\r\n|}'
  return result
end

return p