Anonymous

Module:Items/SourceTables: Difference between revisions

From Melvor Idle
_getItemLootSourceTable: Add fraction alongside percentage for chance stat (Attempt 2)
m (split icon i think)
(_getItemLootSourceTable: Add fraction alongside percentage for chance stat (Attempt 2))
(17 intermediate revisions by 3 users not shown)
Line 11: Line 11:
local Icons = require('Module:Icons')
local Icons = require('Module:Icons')
local Items = require('Module:Items')
local Items = require('Module:Items')
local Shop = require('Module:Shop')


-- Implements overrides for sources which cannot be obtained from game data
-- Currently only overrides for dungeon sources are implemented here
local sourceOverrides = {
  ['Dungeon'] = {
    [361] = 'Volcanic Cave', -- Fire Cape
    [941] = 'Infernal Stronghold', -- Infernal Cape
    [950] = 'Volcanic Cave', -- A Tale of the Past, a future's prophecy
    [951] = 'Fire God Dungeon' -- The First Hero and an Unknown Evil
  }
}


function p._getCreationTable(item)
function p._getCreationTable(item)
Line 108: Line 119:
     table.insert(tables, p.buildCreationTable(skill, lvl, xp, req, qty, time, maxTime))
     table.insert(tables, p.buildCreationTable(skill, lvl, xp, req, qty, time, maxTime))
   end
   end
   if item.type == "Havest" or item.type == "Herb" or item.type == "Logs" then
   if item.type == "Harvest" or item.type == "Herb" or item.type == "Logs" then
     --Havest/Herb means farming
     --Harvest/Herb means farming
     --Logs might mean farming or might not. Depends on the logs
     --Logs might mean farming or might not. Depends on the logs
    --Yes, Havest. The typos are coming from inside the source code
     for i, item2 in pairs(ItemData.Items) do
     for i, item2 in pairs(ItemData.Items) do
       if item2.grownItemID == item.id then
       if item2.grownItemID == item.id then
Line 118: Line 128:
         xp = item2.farmingXP
         xp = item2.farmingXP
         time = item2.timeToGrow
         time = item2.timeToGrow
         qty = 5
         if item.type == 'Logs' then
          qty = 35
        else
          qty = 15
        end
         req = {{id = i - 1, qty = (item2.seedsRequired ~= nil and item2.seedsRequired or 1)}}
         req = {{id = i - 1, qty = (item2.seedsRequired ~= nil and item2.seedsRequired or 1)}}
         table.insert(tables, p.buildCreationTable(skill, lvl, xp, req, qty, time))
         table.insert(tables, p.buildCreationTable(skill, lvl, xp, req, qty, time))
Line 242: Line 256:
   local item = Items.getItem(itemName)
   local item = Items.getItem(itemName)
   if item == nil then
   if item == nil then
     return "ERROR: No item named "..itemName.." exists in the data module"
     return "ERROR: No item named "..itemName.." exists in the data module[[Category:Pages with script errors]]"
   end
   end
    
    
Line 285: Line 299:
         if string.len(killStr) > 0 then
         if string.len(killStr) > 0 then
           killStr = killStr..','
           killStr = killStr..','
           if count1 % 3 == 1 and count1 > 1 then killStr = killStr..'<br/>' end
           --if count1 % 3 == 1 and count1 > 1 then killStr = killStr..'<br/>' end
           killStr = killStr..Icons.Icon({monster.name, type="monster", notext="true"})
           killStr = killStr..Icons.Icon({monster.name, type="monster", notext="true"})
         else
         else
Line 293: Line 307:
     end
     end
   end
   end
   --Add the Fire Cape's special exception:
   -- Special exceptions for Fire/Infernal Cape and first two lore books
   if item.name == 'Fire Cape' then
   if sourceOverrides['Dungeon'][item.id] ~= nil then
    if string.len(dungeonStr) > 0 then
     if string.len(dungeonStr) > 0 then
      dungeonStr = dungeonStr..','
       dungeonStr = dungeonStr .. ','
    else
      dungeonStr = 'Completing: '
    end
    dungeonStr = dungeonStr..Icons.Icon({"Volcanic Cave", type="dungeon", notext=true})
  elseif item.name == 'Infernal Cape' then
     if string.len(dungeonStr) > 0 then  
       dungeonStr = dungeonStr..','
     else
     else
       dungeonStr = 'Completing: '
       dungeonStr = 'Completing: '
     end
     end
     dungeonStr = dungeonStr..Icons.Icon({"Infernal Stronghold", type="dungeon", notext=true})
     dungeonStr = dungeonStr .. Icons.Icon({sourceOverrides['Dungeon'][item.id], type='dungeon', notext=true})
   end
   end


Line 329: Line 336:
           if string.len(lootStr) > 0 then
           if string.len(lootStr) > 0 then
             lootStr = lootStr..','
             lootStr = lootStr..','
             if count1 % 3 == 1 and count1 > 1 then lootStr = lootStr..'<br/>' end
             --if count1 % 3 == 1 and count1 > 1 then lootStr = lootStr..'<br/>' end
             lootStr = lootStr..Icons.Icon({item2.name, type="item", notext="true"})
             lootStr = lootStr..Icons.Icon({item2.name, type="item", notext="true"})
           else
           else
Line 341: Line 348:
         if string.len(upgradeStr) > 0 then
         if string.len(upgradeStr) > 0 then
           upgradeStr = upgradeStr..','
           upgradeStr = upgradeStr..','
           if count2 % 3 == 1 and count2 > 1 then upgradeStr = upgradeStr..'<br/>' end
           --if count2 % 3 == 1 and count2 > 1 then upgradeStr = upgradeStr..'<br/>' end
           upgradeStr = upgradeStr..Icons.Icon({item2.name, type="item", notext="true"})
           upgradeStr = upgradeStr..Icons.Icon({item2.name, type="item", notext="true"})
         else
         else
Line 475: Line 482:
     local rhaStr = 'Any action in: '
     local rhaStr = 'Any action in: '
     rhaStr = rhaStr..Icons.Icon({'Woodcutting', type = 'skill', notext = true})..', '..Icons.Icon({'Fishing', type = 'skill', notext = true})..', '..Icons.Icon({'Mining', type = 'skill', notext = true})..',<br/>'
     rhaStr = rhaStr..Icons.Icon({'Woodcutting', type = 'skill', notext = true})..', '..Icons.Icon({'Fishing', type = 'skill', notext = true})..', '..Icons.Icon({'Mining', type = 'skill', notext = true})..',<br/>'
     rhaStr = rhaStr..Icons.Icon({'Thieving', type = 'skill', notext = true})..', '..Icons.Icon({'Farming', type = 'skill', notext = true})
     rhaStr = rhaStr..Icons.Icon({'Thieving', type = 'skill', notext = true})..', '..Icons.Icon({'Farming', type = 'skill', notext = true})..', '..Icons.Icon({'Agility', type = 'skill', notext = true})
     table.insert(lineArray, rhaStr)
     table.insert(lineArray, rhaStr)
   elseif item.name == 'Mysterious Stone' then
   elseif item.name == 'Mysterious Stone' then
Line 482: Line 489:
     rhaStr = rhaStr..Icons.Icon({'Fletching', type = 'skill', notext = true})..', '..Icons.Icon({'Crafting', type = 'skill', notext = true})..', '..Icons.Icon({'Runecrafting', type = 'skill', notext = true})..',<br/>'
     rhaStr = rhaStr..Icons.Icon({'Fletching', type = 'skill', notext = true})..', '..Icons.Icon({'Crafting', type = 'skill', notext = true})..', '..Icons.Icon({'Runecrafting', type = 'skill', notext = true})..',<br/>'
     rhaStr = rhaStr..Icons.Icon({'Herblore', type='skill', notext = true})..', '..Icons.Icon({'Woodcutting', type = 'skill', notext = true})..', '..Icons.Icon({'Fishing', type = 'skill', notext = true})..',<br/>'
     rhaStr = rhaStr..Icons.Icon({'Herblore', type='skill', notext = true})..', '..Icons.Icon({'Woodcutting', type = 'skill', notext = true})..', '..Icons.Icon({'Fishing', type = 'skill', notext = true})..',<br/>'
     rhaStr = rhaStr..Icons.Icon({'Mining', type = 'skill', notext = true})..', '..Icons.Icon({'Thieving', type = 'skill', notext = true})..', '..Icons.Icon({'Farming', type = 'skill', notext = true})
     rhaStr = rhaStr..Icons.Icon({'Mining', type = 'skill', notext = true})..', '..Icons.Icon({'Thieving', type = 'skill', notext = true})..', '..Icons.Icon({'Farming', type = 'skill', notext = true})..', '..Icons.Icon({'Agility', type = 'skill', notext = true})
     rhaStr = rhaStr..'<br/>after finding '..Icons.Icon({'Crown of Rhaelyx', type='item'})
     rhaStr = rhaStr..'<br/>after finding '..Icons.Icon({'Crown of Rhaelyx', type='item'})
     table.insert(lineArray, rhaStr)
     table.insert(lineArray, rhaStr)
Line 496: Line 503:


   --Shop items (including special items like gloves that aren't otherwise listed)
   --Shop items (including special items like gloves that aren't otherwise listed)
   if item.slayerCost ~= nil or item.buysFor ~= nil or Shared.contains(Items.OtherShopItems, item.name) then
   local shopSources = Shop.getItemSourceArray(item.id)
     table.insert(lineArray, '[[Shop]]')
  if Shared.tableCount(shopSources) > 0 then
     table.insert(lineArray, Icons.Icon({'Shop'}))
   end
   end


Line 526: Line 534:
   end
   end
   if item == nil then
   if item == nil then
     return "ERROR: No item named "..itemName.." exists in the data module"
     return "ERROR: No item named "..itemName.." exists in the data module[[Category:Pages with script errors]]"
   end
   end


Line 535: Line 543:
   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!Source!!Source Type!!Quantity!!Chance'
   result = result..'\r\n!Source!!Source Type!!Quantity!!colspan="2"|Chance'


   --Set up function for adding rows
   --Set up function for adding rows
   local buildRow = function(source, type, minqty, qty, chance)
   local buildRow = function(source, type, minqty, qty, weight, totalWeight)
     if minqty == nil then minqty = 1 end
     if minqty == nil then minqty = 1 end
     local rowTxt = '\r\n|-'
     local rowTxt = '\r\n|-'
     rowTxt = rowTxt..'\r\n|style ="text-align: left;"|'..source
     rowTxt = rowTxt..'\r\n|style="text-align: left;"|'..source
     rowTxt = rowTxt..'\r\n|style ="text-align: left;"|'..type
     rowTxt = rowTxt..'\r\n|style="text-align: left;"|'..type


     rowTxt = rowTxt..'\r\n|style ="text-align: right;" data-sort-value:"'..qty..'"|'..minqty
     rowTxt = rowTxt..'\r\n|style="text-align: right;" data-sort-value="'..qty..'"|'..minqty
     if qty ~= minqty then rowTxt = rowTxt..' - '..qty end
     if qty ~= minqty then rowTxt = rowTxt..' - '..qty end
     rowTxt = rowTxt..'\r\n|style ="text-align: right;"|'..Shared.round(chance, 2, 2)..'%'
     local chance = Shared.round(weight / totalWeight * 100, 2, 2)
    if weight >= totalWeight then
      -- Fraction would be 1/1, so only show the percentage
      chance = 100
      rowTxt = rowTxt .. '\r\n|colspan="2" '
    else
      rowTxt = rowTxt .. '\r\n|style="text-align: right;" data-sort-value="' .. chance .. '"| ' .. Shared.fraction(weight, totalWeight) .. '\r\n|'
    end
    rowTxt = rowTxt..'style="text-align: right;" data-sort-value="'.. chance .. '"|'..chance..'%'
     return rowTxt
     return rowTxt
   end
   end
   local dropRows = {}
   local dropRows = {}
 
 
   --Alright, time to go through a few ways to get the item
   --Alright, time to go through a few ways to get the item
   --First up: Can we kill somebody and take theirs?
   --First up: Can we kill somebody and take theirs?
Line 572: Line 588:
           qty = loot[3]
           qty = loot[3]
         end
         end
      end
      if wt > 0 then
        local lootChance = monster.lootChance ~= nil and monster.lootChance or 100
        chance = ((wt * lootChance) / (totalWt * 100)) * 100
       end
       end
     end
     end
     if chance > 0 then
    local lootChance = monster.lootChance ~= nil and monster.lootChance or 100
     if wt > 0 and lootChance > 0 then
      local sourceTxt = nil
      local typeTxt = nil
       --If we're dealing with a boss, this is a Dungeon row instead
       --If we're dealing with a boss, this is a Dungeon row instead
       if monster.isBoss and not Shared.contains(item.name, 'Shard') then
       if monster.isBoss and not Shared.contains(item.name, 'Shard') then
         local dung = Areas.getMonsterAreas(i - 1)[1]
         local dung = Areas.getMonsterAreas(i - 1)[1]
         local sourceTxt = Icons.Icon({dung.name, type="dungeon", notext=true})
         sourceTxt = Icons.Icon({dung.name, type='dungeon', notext=true})
         table.insert(dropRows, {source = sourceTxt, type = '[[Dungeon]]', minqty = minqty, qty = qty, chance = chance})
         typeTxt = '[[Dungeon]]'
       else
       else
         local sourceTxt = Icons.Icon({monster.name, type='monster'})
         sourceTxt = Icons.Icon({monster.name, type='monster'})
         table.insert(dropRows, {source = sourceTxt, type = '[[Monster]]', minqty = minqty, qty = qty, chance = chance})
         typeTxt = '[[Monster]]'
       end
       end
      table.insert(dropRows, {source = sourceTxt, type = typeTxt, minqty = minqty, qty = qty, weight = wt * lootChance, totalWeight = totalWt * 100})
     end
     end
   end
   end


   --Special exception for the Fire Cape as a bonus dungeon drop
   --Special exception for the Fire/Infernal Cape and first two lore books as bonus dungeon drops
   if item.name == 'Fire Cape' then
   if sourceOverrides['Dungeon'][item.id] ~= nil then
      local sourceTxt = Icons.Icon({"Volcanic Cave", type="dungeon", notext=true})
    local sourceTxt = Icons.Icon({sourceOverrides['Dungeon'][item.id], type='dungeon', notext=true})
      table.insert(dropRows, {source = sourceTxt, type = '[[Dungeon]]', minqty = 1, qty = 1, chance = 100})
    table.insert(dropRows, {source=sourceTxt, type='[[Dungeon]]', minqty=1, qty=1, weight = 1, totalWeight = 1})
  elseif item.name == 'Infernal Cape' then
      local sourceTxt = Icons.Icon({"Infernal Stronghold", type="dungeon", notext=true})
      table.insert(dropRows, {source = sourceTxt, type = '[[Dungeon]]', minqty = 1, qty = 1, chance = 100})
   end
   end


Line 616: Line 629:


       if wt > 0 then
       if wt > 0 then
        chance = (wt / totalWt) * 100
         local sourceTxt = Icons.Icon({item2.name, type='item'})
         local sourceTxt = Icons.Icon({item2.name, type='item'})
         table.insert(dropRows, {source = sourceTxt, type = '[[Chest]]', minqty = 1, qty = qty, chance = chance})
         table.insert(dropRows, {source = sourceTxt, type = '[[Chest]]', minqty = 1, qty = qty, weight = wt, totalWeight = totalWt})
       end
       end
     end
     end
Line 638: Line 650:
       end
       end
       if wt > 0 then
       if wt > 0 then
         chance = (wt / totalWt) * 75
         -- There is a constant 75% chance of gaining an item per successful steal attempt
         local sourceTxt = Icons.Icon({npc.name, type='thieving'})
         local sourceTxt = Icons.Icon({npc.name, type='thieving'})
         table.insert(dropRows, {source = sourceTxt, type = thiefType, minqty = 1, qty = qty, chance = chance})
         table.insert(dropRows, {source = sourceTxt, type = thiefType, minqty = 1, qty = qty, weight = wt * 75, totalWeight = totalWt * 100})
       end
       end
     end
     end
Line 648: Line 660:
   if item.type == 'Gem' then
   if item.type == 'Gem' then
     local mineType = Icons.Icon({'Mining', type='skill'})
     local mineType = Icons.Icon({'Mining', type='skill'})
     local thisGemChance = Items.GemTable[item.name].chance  
     local thisGemChance = Items.GemTable[item.name].chance
     table.insert(dropRows, {source = '[[Mining#Gems|Gem]]', type = mineType, minqty = 1, qty = 1, chance = thisGemChance})
    local totalGemChance = 0
    for i, gem in pairs(Items.GemTable) do
      totalGemChance = totalGemChance + gem.chance
    end
     table.insert(dropRows, {source = '[[Mining#Gems|Gem]]', type = mineType, minqty = 1, qty = 1, weight = thisGemChance, totalWeight = totalGemChance})
     local magicType = Icons.Icon({'Magic', type = 'skill'})
     local magicType = Icons.Icon({'Magic', type = 'skill'})
     table.insert(dropRows, {source = Icons.Icon({"Rags to Riches I", type="spell"}), type = magicType, minqty = 1, qty = 1, chance = thisGemChance})
     table.insert(dropRows, {source = Icons.Icon({"Rags to Riches I", type="spell"}), type = magicType, minqty = 1, qty = 1, weight = thisGemChance, totalWeight = totalGemChance})
     table.insert(dropRows, {source = Icons.Icon({"Rags to Riches II", type="spell"}), type = magicType, minqty = 1, qty = 1, chance = thisGemChance})
     table.insert(dropRows, {source = Icons.Icon({"Rags to Riches II", type="spell"}), type = magicType, minqty = 1, qty = 1, weight = thisGemChance, totalWeight = totalGemChance})
   end
   end


Line 658: Line 674:
     local fishSource = '[[Fishing#Special|Special]]'
     local fishSource = '[[Fishing#Special|Special]]'
     local fishType = Icons.Icon({'Fishing', type='skill'})
     local fishType = Icons.Icon({'Fishing', type='skill'})
    local thisChance = (item.fishingCatchWeight / Items.specialFishWt) * 100
     table.insert(dropRows, {source = fishSource, type = fishType, minqty = 1, qty = 1, weight = item.fishingCatchWeight, totalWeight = Items.specialFishWt})
     table.insert(dropRows, {source = fishSource, type = fishType, minqty = 1, qty = 1, chance = thisChance})
   end
   end


Line 665: Line 680:
     local fishSource = '[[Fishing#Junk|Junk]]'
     local fishSource = '[[Fishing#Junk|Junk]]'
     local fishType = Icons.Icon({'Fishing', type='skill'})
     local fishType = Icons.Icon({'Fishing', type='skill'})
    local thisChance = 100 / Items.junkCount
     table.insert(dropRows, {source = fishSource, type = fishType, minqty = 1, qty = 1, weight = 1, totalWeight = Items.junkCount})
     table.insert(dropRows, {source = fishSource, type = fishType, minqty = 1, qty = 1, chance = thisChance})
   end
   end


   --Make sure to return nothing if there are no drop sources
   --Make sure to return nothing if there are no drop sources
   if Shared.tableCount(dropRows) == 0 then return '' end
   if Shared.tableCount(dropRows) == 0 then return '' end


   table.sort(dropRows, function(a, b) return a.chance > b.chance end)
   table.sort(dropRows, function(a, b) return a.weight / a.totalWeight > b.weight / b.totalWeight end)
   for i, data in pairs(dropRows) do
   for i, data in pairs(dropRows) do
     result = result..buildRow(data.source, data.type, data.minqty, data.qty, data.chance)
     result = result..buildRow(data.source, data.type, data.minqty, data.qty, data.weight, data.totalWeight)
   end
   end


Line 685: Line 699:
   local item = Items.getItem(itemName)
   local item = Items.getItem(itemName)
   if item == nil then
   if item == nil then
     return "ERROR: No item named "..itemName.." exists in the data module"
     return "ERROR: No item named "..itemName.." exists in the data module[[Category:Pages with script errors]]"
   end
   end


   return p._getItemLootSourceTable(item)
   return p._getItemLootSourceTable(item)
end
function p._getItemShopTable(item)
  local result = '{| class="wikitable"\r\n|-\r\n!colspan="2"|[[Shop]] Purchase'
  result = result..'\r\n|-\r\n!style="text-align:right;"|Cost\r\n|'
  local cost = {}
  local qty = '1'
  if item.buysFor ~= nil then
    if item.buysFor > 0 then table.insert(cost, Icons.GP(item.buysFor)) end
  elseif item.slayerCost ~= nil then
    table.insert(cost, Icons.SC(item.slayerCost))
  elseif Items.GloveTable[item.name] ~= nil then
    table.insert(cost, Icons.GP(Items.GloveTable[item.name].cost))
    qty = ' +'..Shared.formatnum(Items.GloveTable[item.name].charges)..' Charges'
  end
  if item.buysForLeather ~= nil then
    table.insert(cost, Icons.Icon({'Leather', type='item', qty=item.buysForLeather}))
  end
  if item.buysForItems ~= nil then
    for i, row in pairs(item.buysForItems) do
      local mat = Items.getItemByID(row[1])
      table.insert(cost, Icons.Icon({mat.name, type='item', qty=row[2]}))
    end
  end
  if Shared.tableCount(cost) == 0 then
    --If no cost is set, return an empty string
    return ''
  else
    result = result..table.concat(cost, '<br/>')
  end
  --For right now, only have requirements on Skillcapes
  result = result..'\r\n|-\r\n!style="text-align:right;"|Requirements\r\n|'
  if item.name == 'Cape of Completion' then
    result = result..'100% Completion Log'
  elseif item.name == 'Max Skillcape' then
    result = result..'Level 99 in all [[Skills]]'
  elseif Shared.contains(item.name, 'Skillcape') then
    local skillName = Shared.splitString(item.name)[1]
    result = result..Icons._SkillReq(skillName, 99)
  else
    result = result..'None'
  end
  result = result..'\r\n|-\r\n!style="text-align:right;"|Quantity\r\n|'..qty
  result = result..'\r\n|}'
  return result
end
function p.getItemShopTable(frame)
  local itemName = frame.args ~= nil and frame.args[1] or frame
  local item = Items.getItem(itemName)
  if item == nil then
    return "ERROR: No item named "..itemName.." exists in the data module"
  end
  return p._getItemShopTable(item)
end
end


Line 779: Line 736:
   local item = Items.getItem(itemName)
   local item = Items.getItem(itemName)
   if item == nil then
   if item == nil then
     return "ERROR: No item named "..itemName.." exists in the data module"
     return "ERROR: No item named "..itemName.." exists in the data module[[Category:Pages with script errors]]"
   end
   end


Line 837: Line 794:
   local item = Items.getItem(itemName)
   local item = Items.getItem(itemName)
   if item == nil then
   if item == nil then
     return "ERROR: No item named "..itemName.." exists in the data module"
     return "ERROR: No item named "..itemName.." exists in the data module[[Category:Pages with script errors]]"
   end
   end


Line 845: Line 802:
function p._getItemSourceTables(item)
function p._getItemSourceTables(item)
   local result = ''
   local result = ''
   local shopTable = p._getItemShopTable(item)
   local shopTable = Shop._getItemShopTable(item)
   if string.len(shopTable) > 0 then
   if string.len(shopTable) > 0 then
     result = result..'===Shop===\r\n'..shopTable
     result = result..'===Shop===\r\n'..shopTable
Line 879: Line 836:
   local item = Items.getItem(itemName)
   local item = Items.getItem(itemName)
   if item == nil then
   if item == nil then
     return "ERROR: No item named "..itemName.." exists in the data module"
     return "ERROR: No item named "..itemName.." exists in the data module[[Category:Pages with script errors]]"
   end
   end


Line 890: Line 847:
   table = table..'!colspan="2"|Item\r\n! Passive\r\n'
   table = table..'!colspan="2"|Item\r\n! Passive\r\n'


   for i, item in pairs(ItemData.Items) do
  local itemArray = Items.getItems(function(item) return item.isPassiveItem and true or false end)
     if item.isPassiveItem then
 
      table = table..'|-\r\n'
   for i, item in Shared.skpairs(itemArray) do
      table = table..'! '..Icons.Icon({item.name, type='item', notext='true'})..'| '..item.name..'\r\n'
     table = table..'|-\r\n'
      table = table..'| '..item.description..'\r\n'
    table = table..'! '..Icons.Icon({item.name, type='item', notext='true'})..'\r\n! [['..item.name..']]\r\n'
    end
    table = table..'| '..item.description..'\r\n'
   end
   end