Module:Skills/Gathering

From Melvor Idle
< Module:Skills
Revision as of 19:48, 11 September 2021 by ByteFoolish (talk | contribs) (Switch to spairs in getMiningGemsTable)

Documentation for this module may be created at Module:Skills/Gathering/doc

--Splitting some functions into here to avoid bloating a single file
local p = {}

local SkillData = mw.loadData('Module:Skills/data')
local ShopData = mw.loadData('Module:Shop/data')

local Constants = require('Module:Constants')
local Shared = require('Module:Shared')
local Items = require('Module:Items')
local Icons = require('Module:Icons')

function p.getAxeTable(frame)
  local toolArray = {}
  for i, upgrade in Shared.skpairs(ShopData.Shop.SkillUpgrades) do
    if Shared.contains(upgrade.name, 'Axe') then
      table.insert(toolArray, upgrade)
    end
  end

  local result = '{| class="wikitable"'
  result = result..'\r\n!colspan="4"| !!colspan="2"|Cut Time Decrease'
  result = result..'\r\n|- class="headerRow-0"'
  result = result..'\r\n!colspan="2"|Name!!'..Icons.Icon({'Woodcutting', type='skill', notext=true})..' Level'
  result = result..'!!Cost!!This Axe!!Total'

  local total = 0

  for i, tool in Shared.skpairs(toolArray) do
    result = result..'\r\n|-'
    result = result..'\r\n|style="min-width:25px" data-sort-value="'..tool.name..'"|'..Icons.Icon({tool.name, type='upgrade', size='50', notext=true})
    result = result..'||'..tool.name
    local level = 1
    if tool.unlockRequirements ~= nil and tool.unlockRequirements.skillLevel ~= nil then
      --Gonna be lazy and assume there's only the one skill level and it's the one we care about
      level = tool.unlockRequirements.skillLevel[1][2]
    end
    result = result..'||style="text-align:right"|'..level
    result = result..'||style="text-align:right" data-sort-value="'..tool.cost.gp..'"|'..Icons.GP(tool.cost.gp)

    local cutTime = tool.contains.modifiers.decreasedSkillIntervalPercent[1][2]
    total = total + cutTime
    result = result..'||style="text-align:right"|-'..cutTime..'%'
    result = result..'||style="text-align:right"|-'..total..'%'
  end

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

function p.getPickaxeTable(frame)
  local toolArray = {}
  for i, upgrade in Shared.skpairs(ShopData.Shop.SkillUpgrades) do
    if Shared.contains(upgrade.name, 'Pickaxe') then
      table.insert(toolArray, upgrade)
    end
  end

  local result = '{| class="wikitable"'
  result = result..'\r\n!colspan="4"| !!colspan="2"|Mine Time Decrease!!colspan="2"|2x Ore Chance'
  result = result..'\r\n|- class="headerRow-0"'
  result = result..'\r\n!colspan="2"|Name!!'..Icons.Icon({'Mining', type='skill', notext=true})..' Level'
  result = result..'!!Cost!!This Pick!!Total!!This Pick!!Total'

  local total = 0
  local total2 = 0

  for i, tool in Shared.skpairs(toolArray) do
    result = result..'\r\n|-'
    result = result..'\r\n|style="min-width:25px" data-sort-value="'..tool.name..'"|'..Icons.Icon({tool.name, type='upgrade', size='50', notext=true})
    result = result..'||'..tool.name
    local level = 1
    if tool.unlockRequirements ~= nil and tool.unlockRequirements.skillLevel ~= nil then
      --Gonna be lazy and assume there's only the one skill level and it's the one we care about
      level = tool.unlockRequirements.skillLevel[1][2]
    end
    result = result..'||style="text-align:right"|'..level
    result = result..'||style="text-align:right" data-sort-value="'..tool.cost.gp..'"|'..Icons.GP(tool.cost.gp)

    local cutTime = tool.contains.modifiers.decreasedSkillIntervalPercent[1][2]
    total = total + cutTime

    result = result..'||style="text-align:right"|-'..cutTime..'%'
    result = result..'||style="text-align:right"|-'..total..'%'

    local OreDouble = tool.contains.modifiers.increasedChanceToDoubleOres
    total2 = total2 + OreDouble

    result = result..'||style="text-align:right"|+'..OreDouble..'%'
    result = result..'||style="text-align:right"|+'..total2..'%'
  end

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

function p.getRodTable(frame)
  local toolArray = {}
  for i, upgrade in Shared.skpairs(ShopData.Shop.SkillUpgrades) do
    if Shared.contains(upgrade.name, 'Fishing Rod') then
      table.insert(toolArray, upgrade)
    end
  end

  local result = '{| class="wikitable"'
  result = result..'\r\n!colspan="4"| !!colspan="2"|Catch Time Decrease'
  result = result..'\r\n|- class="headerRow-0"'
  result = result..'\r\n!colspan="2"|Name!!'..Icons.Icon({'Fishing', type='skill', notext=true})..' Level'
  result = result..'!!Cost!!This Rod!!Total'

  local total = 0

  for i, tool in Shared.skpairs(toolArray) do
    result = result..'\r\n|-'
    result = result..'\r\n|style="min-width:25px" data-sort-value="'..tool.name..'"|'..Icons.Icon({tool.name, type='upgrade', size='50', notext=true})
    result = result..'||'..tool.name
    local level = 1
    if tool.unlockRequirements ~= nil and tool.unlockRequirements.skillLevel ~= nil then
      --Gonna be lazy and assume there's only the one skill level and it's the one we care about
      level = tool.unlockRequirements.skillLevel[1][2]
    end
    result = result..'||style="text-align:right"|'..level
    result = result..'||style="text-align:right" data-sort-value="'..tool.cost.gp..'"|'..Icons.GP(tool.cost.gp)

    local cutTime = tool.contains.modifiers.decreasedSkillIntervalPercent[1][2]
    total = total + cutTime
    result = result..'||style="text-align:right"|-'..cutTime..'%'
    result = result..'||style="text-align:right"|-'..total..'%'
  end

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

function p.getTreesTable(frame)
  local result = '{| class="wikitable sortable"'
  result = result..'\r\n|- class="headerRow-0"'
  result = result..'\r\n!colspan="2"|Tree!!colspan="2"|Logs!!'..Icons.Icon({'Woodcutting', type='skill', notext=true})..' Level'
  result = result..'!!XP!!Cut Time!!XP/s!!GP/s'

  for i, tree in Shared.skpairs(SkillData.Woodcutting.Trees) do
    result = result..'\r\n|-'
    local treeName = Shared.titleCase(tree.type..' tree')
    local logName = Shared.titleCase(tree.type..' logs')
    result = result..'\r\n|style="min-width:25px" data-sort-value="'..treeName..'"|'..Icons.Icon({logName, img=treeName, type='tree', notext=true, size=50})
    result = result..'||'..treeName..''
    result = result..'||style="min-width:25px" data-sort-value="'..logName..'"|'..Icons.Icon({logName, type='item', notext=true, size=50})
    result = result..'||[['..logName..']]'
    result = result..'||style="text-align:right"|'..tree.level
    result = result..'||style="text-align:right"|'..tree.xp
    result = result..'||style="text-align:right" data-sort-value="'..tree.interval..'"|'..Shared.timeString(tree.interval/1000, true)
    local XPs = tree.xp / (tree.interval / 1000)
    local Log = Items.getItemByID(i - 1)
    local GPs = Log.sellsFor / (tree.interval / 1000)
    result = result..'||style="text-align:right"|'..Shared.round(XPs, 2, 2)
    result = result..'||style="text-align:right" data-sort-value="'..GPs..'"|'..Icons.GP(Shared.round(GPs, 2, 2))
  end

  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 stickyHeader"'
  result = result..'\r\n|- class="headerRow-0"'
  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.getFishingJunkTable(frame)
  local result = '{| class="wikitable sortable stickyHeader"'
  result = result..'\r\n|- class="headerRow-0"'
  result = result..'\r\n!colspan="2"|Item!!Value'
  
  local itemArray = Items.getItems(function(item) return item.type == "Junk" end)

  table.sort(itemArray, function(a, b) return a.name < b.name end)

  for i, item in Shared.skpairs(itemArray) do
    result = result..'\r\n|-'
    result = result..'\r\n|style="min-width:25px"|'..Icons.Icon({item.name, type='item', notext='true', size='50'})..'||[['..item.name..']]'
    result = result..'||style="text-align:right;" data-sort-value="'..item.sellsFor..'"|'..Icons.GP(item.sellsFor)
  end

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

  return result
end

function p.getMiningOresTable(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.Rocks)

  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|style="min-width:25px"|'..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.getMiningGemsTable(frame)
  local result = '{|class="wikitable sortable stickyHeader"'
  result = result..'\r\n|- class="headerRow-0"'
  result = result..'\r\n!colspan=2|Gem!!Gem Chance!!Gem Price'

  -- Sort gems by ID order
  for i, gemData in Shared.spairs(Items.GemTable, function(t,a,b) return t[a].id < t[b].id end) do
    local gem = Items.getItemByID(gemData.id)
    result = result..'\r\n|-\r\n|style="min-width:25px"|'
    result = result..Icons.Icon({gem.name, type='item', size='50', notext=true})..'||[['..gem.name..']]'
    result = result..'||style="text-align:right"|'..string.format("%.1f%%", gemData.chance)
    result = result..'||data-sort-value="'..gem.sellsFor..'"|'..Icons.GP(gem.sellsFor)
  end

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

function p.getFishTable(frame)
  local data = Items.getItems(function(item) return item.fishingID ~= nil end)

  table.sort(data, function(a, b) return a.fishingID < b.fishingID end)

  local result = '{| class="wikitable sortable stickyHeader"'
  result = result..'\r\n|- class="headerRow-0"'
  result = result..'\r\n!Fish\r\n!Name\r\n!'..Icons.Icon({'Fishing', type='skill', notext=true})..' Level\r\n!Catch Time'
  result = result..'\r\n!Experience\r\n!Fish Price\r\n!'..Icons.Icon({'Cooking', type='skill', notext=true})..' Level'

  for i, fish in Shared.skpairs(data) do
    result = result..'\r\n|-'
    result = result..'\r\n| style="text-align: left;" | '..Icons.Icon({fish.name, type='item', size='50', notext=true})
    result = result..'\r\n| style ="text-align: left;" |[['..fish.name..']]'
    result = result..'\r\n| style="text-align:right"|'..fish.fishingLevel

    local timeSortVal = (fish.minFishingInterval + fish.maxFishingInterval) / 2
    local timeStr = string.format("%.1fs-%.1fs", (fish.minFishingInterval/1000), (fish.maxFishingInterval/1000))
    result = result..'\r\n| style="text-align:right" data-sort-value="'..timeSortVal..'"|'..timeStr
    result = result..'\r\n| style="text-align:right"|'..fish.fishingXP
    result = result..'\r\n| style="text-align:right"|'..fish.sellsFor

    local cookStr = "N/A"
    if fish.cookingLevel ~= nil then 
      cookStr = fish.cookingLevel
    end
    result = result..'\r\n| style="text-align:right"|'..cookStr
  end

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

function p.getFishingAreasTable(frame)

  local result = '{| class="wikitable sortable stickyHeader"'
  result = result..'\r\n|- class="headerRow-0"'
  result = result..'\r\n!Name\r\n!Fish\r\n!Fish Chance'
  result = result..'\r\n!Junk Chance\r\n!Special Chance'

  for i, area in Shared.skpairs(SkillData.Fishing.Areas) do
    result = result..'\r\n|-'
    result = result..'\r\n| style ="text-align: left;" |'..area.name

    local fishArray = {}
    for j, fish in Shared.skpairs(area.fish) do
      local fishTable = Items.getItems(function(item) return item.fishingID == fish end)
      local fishItem = fishTable[0] or fishTable[1]
      table.insert(fishArray, Icons.Icon({fishItem.name, type='item'}))
    end
    result = result..'\r\n|'..table.concat(fishArray, '<br />')

    result = result..'\r\n| style="text-align:right"|'..area.fishChance..'%'
    result = result..'\r\n| style="text-align:right"|'..area.junkChance..'%'
    result = result..'\r\n| style="text-align:right"|'..area.specialChance..'%'
  end

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

return p