Module:Skills/Archaeology: Difference between revisions
From Melvor Idle
Falterfire (talk | contribs) (Added Archaeology level requirement) |
No edit summary |
||
(26 intermediate revisions by 5 users not shown) | |||
Line 6: | Line 6: | ||
local Shared = require('Module:Shared') | local Shared = require('Module:Shared') | ||
local | local Common = require('Module:Common') | ||
local GameData = require('Module:GameData') | local GameData = require('Module:GameData') | ||
local SkillData = GameData.skillData | local SkillData = GameData.skillData | ||
local Modifiers = require('Module:Modifiers') | |||
local Items = require('Module:Items') | local Items = require('Module:Items') | ||
local Icons = require('Module:Icons') | local Icons = require('Module:Icons') | ||
local Cartography = require('Module:Skills/Cartography') | local Cartography = require('Module:Skills/Cartography') | ||
local Num = require('Module:Number') | |||
local sizes = {'small', 'tiny', 'medium', 'large'} | local sizes = {'small', 'tiny', 'medium', 'large'} | ||
Line 33: | Line 35: | ||
end | end | ||
return nil | return nil | ||
end | |||
function p._getArtefactType(item) | |||
if item.isArtefact then | |||
if item.isGenericArtefact then | |||
return 'Generic' | |||
elseif item.validSlots ~= nil then | |||
local searchSlots = { 'Consumable', 'Gem' } | |||
for i, slotID in ipairs(searchSlots) do | |||
if Shared.contains(item.validSlots, slotID) then | |||
return Common.getEquipmentSlotLink(slotID) | |||
end | |||
end | |||
end | |||
return 'Other' | |||
end | |||
end | end | ||
Line 42: | Line 60: | ||
local result = {} | local result = {} | ||
table.insert(result, '{|class="wikitable sortable" id="itemdrops"') | table.insert(result, '{|class="wikitable sortable" id="itemdrops"') | ||
table.insert(result, '\r\n!Item!!Qty') | table.insert(result, '\r\n!Item!!Type!!Qty') | ||
table.insert(result, '!!Price!!colspan="2"|Chance') | table.insert(result, '!!Price!!colspan="2"|Chance') | ||
local lootTable = Shared.shallowClone(digSite.artefacts[string.lower(size)]) | local lootTable = Shared.shallowClone(digSite.artefacts[string.lower(size)]) | ||
local lootValue = 0 | |||
local plusOneMinimumRefinementValue = 0 | |||
local doubleConsumableRefinementValue = 0 | |||
local totalWt = 0 | local totalWt = 0 | ||
for i, row in ipairs(lootTable) do | for i, row in ipairs(lootTable) do | ||
Line 62: | Line 83: | ||
end | end | ||
end) | end) | ||
local lootValue, plusOneMinimumRefinementValue, doubleConsumableRefinementValue = {}, {}, {} | |||
for i, row in ipairs(lootTable) do | for i, row in ipairs(lootTable) do | ||
local thisItem = Items.getItemByID(row.itemID) | local thisItem = Items.getItemByID(row.itemID) | ||
if thisItem ~= nil then | if thisItem ~= nil then | ||
Line 70: | Line 93: | ||
table.insert(result, '\r\n|-\r\n|Unknown Item[[Category:Pages with script errors]]') | table.insert(result, '\r\n|-\r\n|Unknown Item[[Category:Pages with script errors]]') | ||
end | end | ||
table.insert(result, '||' .. p._getArtefactType(thisItem) .. '') | |||
table.insert(result, '||style="text-align:right" data-sort-value="'..row.maxQuantity..'"|') | table.insert(result, '||style="text-align:right" data-sort-value="'..row.maxQuantity..'"|') | ||
if row.maxQuantity > row.minQuantity then | if row.maxQuantity > row.minQuantity then | ||
table.insert(result, | table.insert(result, Num.formatnum(row.minQuantity) .. ' - ') | ||
end | end | ||
table.insert(result, | table.insert(result, Num.formatnum(row.maxQuantity)) | ||
--Adding price | local dropChance = row.weight / totalWt | ||
-- Adding price columnsR | |||
if thisItem == nil then | if thisItem == nil then | ||
table.insert(result, '||data-sort-value="0"|???') | table.insert(result, '||data-sort-value="0"|???') | ||
else | else | ||
table.insert(result, '||' .. Items.getValueText(thisItem, row.minQuantity, row.maxQuantity)) | |||
if | |||
-- Add to total loot value | |||
local sellAmount = thisItem.sellsFor or 0 | |||
local sellCurrency = thisItem.sellsForCurrency or 'melvorD:GP' | |||
if sellAmount ~= nil and sellCurrency ~= nil then | |||
if lootValue[sellCurrency] == nil then | |||
lootValue[sellCurrency] = 0 | |||
plusOneMinimumRefinementValue[sellCurrency] = 0 | |||
doubleConsumableRefinementValue[sellCurrency] = 0 | |||
end | |||
local artefactAvgValue = dropChance * sellAmount * ((row.minQuantity + row.maxQuantity) / 2) | |||
lootValue[sellCurrency] = lootValue[sellCurrency] + artefactAvgValue | |||
plusOneMinimumRefinementValue[sellCurrency] = plusOneMinimumRefinementValue[sellCurrency] + artefactAvgValue + (dropChance * sellAmount) | |||
-- Checking if item is a consumable, then adding its value a second time | |||
local doubleExtraVal = (Items._canItemUseSlot(thisItem, 'Consumable') and artefactAvgValue) or 0 | |||
doubleConsumableRefinementValue[sellCurrency] = doubleConsumableRefinementValue[sellCurrency] + artefactAvgValue + doubleExtraVal | |||
end | end | ||
end | end | ||
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 | ||
table.insert(result, '||style="text-align:right" data-sort-value="'..row.weight..'"') | table.insert(result, '||style="text-align:right" data-sort-value="'..row.weight..'"') | ||
table.insert(result, '|'.. | table.insert(result, '|'..Num.fraction(row.weight, totalWt)) | ||
table.insert(result, '||') | table.insert(result, '||') | ||
else | else | ||
Line 103: | Line 137: | ||
local fmt = (dropChance < 0.10 and '%.2g') or '%.2f' | local fmt = (dropChance < 0.10 and '%.2g') or '%.2f' | ||
table.insert(result, 'style="text-align:right"|'..string.format(fmt, dropChance * 100)..'%') | table.insert(result, 'style="text-align:right"|'..string.format(fmt, dropChance * 100)..'%') | ||
end | |||
local function lootValueText(lootValue) | |||
local returnPart = {} | |||
for _, currencyDefn in ipairs(GameData.rawData.currencies) do | |||
-- Guarantee order by iterating through currency game data definition | |||
local currID = currencyDefn.id | |||
local val = Num.round(lootValue[currID], 2, 2) | |||
if val ~= nil then | |||
table.insert(returnPart, Icons._Currency(currID, val)) | |||
end | |||
end | |||
return table.concat(returnPart, ', ') | |||
end | end | ||
table.insert(result, '\r\n|}') | table.insert(result, '\r\n|}') | ||
local lootText = lootValueText(lootValue) | |||
local plusOneLootText = lootValueText(plusOneMinimumRefinementValue) | |||
local doubleLootText = lootValueText(doubleConsumableRefinementValue) | |||
table.insert(result, '\r\nThe average value of one action is ' .. lootText .. ', ') | |||
table.insert(result, 'increasing to ' .. plusOneLootText .. ' when the +1 Minimum Items refinement is active.') | |||
if doubleLootText ~= lootText then | |||
table.insert(result, '\r\n\r\nThe average value of one action with the x2 Consumables refinement is ' .. doubleLootText .. '.') | |||
end | |||
return table.concat(result, '') | return table.concat(result, '') | ||
Line 135: | Line 190: | ||
end | end | ||
local poi = Cartography. | local poi = Cartography.getPointOfInterestForDigSite(digSite.id) | ||
local hex = Cartography.getHexByAxial(poi.coords.q, poi.coords.r) | local hex = Cartography.getHexByAxial(poi.coords.q, poi.coords.r) | ||
local coordX, coordY = Cartography.convertAxialToXY(poi.coords) | local coordX, coordY = Cartography.convertAxialToXY(poi.coords) | ||
Line 174: | Line 229: | ||
return table.concat(resultArray, '') | return table.concat(resultArray, '') | ||
end | |||
function p._getMuseumRewards(reward) | |||
local rewardTable = {} | |||
local equipment = nil | |||
if reward.gp ~= nil then | |||
table.insert(rewardTable, Icons._Currency('melvorD:GP', reward.gp)) | |||
end | |||
if reward.items ~= nil then | |||
for _, reward in ipairs(reward.items) do | |||
local item = Items.getItemByID(reward.id) | |||
table.insert(rewardTable, Icons.Icon({item.name, type='item', qty=reward.quantity})) | |||
if item.category == 'Archaeology' then | |||
equipment = item.name | |||
end | |||
end | |||
end | |||
if reward.modifiers ~= nil then | |||
table.insert(rewardTable, Modifiers.getModifiersText(reward.modifiers, true)) | |||
end | |||
if equipment ~= nil then | |||
table.insert(rewardTable, 'Unlocks the ability to purchase '..equipment..' from the '..Icons.Icon({'Shop'})) | |||
end | |||
return rewardTable | |||
end | |||
function p.getMuseumRewardsTable(frame) | |||
-- Build the table | |||
local resultTable = mw.html.create('table') | |||
resultTable:addClass('wikitable sortable lighttable') | |||
resultTable:tag('tr'):addClass('headerRow-0') | |||
:tag('th'):wikitext('Donations') | |||
:tag('th'):wikitext('Rewards') | |||
for _, reward in ipairs(SkillData.Archaeology.museumRewards) do | |||
local tr = mw.html.create('tr') | |||
tr:tag('td'):wikitext(reward.museumCount) | |||
tr:tag('td'):wikitext(table.concat(p._getMuseumRewards(reward), '<br/>')) | |||
resultTable:node(tr) | |||
end | |||
return tostring(resultTable) | |||
end | end | ||
return p | return p |
Latest revision as of 22:45, 29 June 2024
Documentation for this module may be created at Module:Skills/Archaeology/doc
--New module for Archaeology-related tables
--Unavoidably has some overlap with Module:Skills/Cartography
--Crucially, stuff that involves both MUST go here
--Because otherwise we get circular references, which are Not Fun.
local p = {}
local Shared = require('Module:Shared')
local Common = require('Module:Common')
local GameData = require('Module:GameData')
local SkillData = GameData.skillData
local Modifiers = require('Module:Modifiers')
local Items = require('Module:Items')
local Icons = require('Module:Icons')
local Cartography = require('Module:Skills/Cartography')
local Num = require('Module:Number')
local sizes = {'small', 'tiny', 'medium', 'large'}
function p.getDigSite(name)
name = string.gsub(name, "%%27", "'")
name = string.gsub(name, "'", "'")
for i, digSite in ipairs(SkillData.Archaeology.digSites) do
if digSite.name == name then
return digSite
end
end
return nil
end
function p.getDigSiteByID(id)
for i, digSite in ipairs(SkillData.Archaeology.digSites) do
if digSite.id == id then
return digSite
end
end
return nil
end
function p._getArtefactType(item)
if item.isArtefact then
if item.isGenericArtefact then
return 'Generic'
elseif item.validSlots ~= nil then
local searchSlots = { 'Consumable', 'Gem' }
for i, slotID in ipairs(searchSlots) do
if Shared.contains(item.validSlots, slotID) then
return Common.getEquipmentSlotLink(slotID)
end
end
end
return 'Other'
end
end
function p._getDigSiteArtefactTable(digSite, size)
if not Shared.contains(sizes, string.lower(size)) then
return Shared.printError(size..' is an invalid size for Archeology artefacts.')
end
local result = {}
table.insert(result, '{|class="wikitable sortable" id="itemdrops"')
table.insert(result, '\r\n!Item!!Type!!Qty')
table.insert(result, '!!Price!!colspan="2"|Chance')
local lootTable = Shared.shallowClone(digSite.artefacts[string.lower(size)])
local lootValue = 0
local plusOneMinimumRefinementValue = 0
local doubleConsumableRefinementValue = 0
local totalWt = 0
for i, row in ipairs(lootTable) do
totalWt = totalWt + row.weight
end
table.sort(lootTable, function(a, b)
if a.weight == b.weight then
local aItem, bItem = Items.getItemByID(a.itemID), Items.getItemByID(b.itemID)
if aItem ~= nil and bItem ~= nil then
return aItem.name < bItem.name
else
return a.itemID < b.itemID
end
else
return a.weight > b.weight
end
end)
local lootValue, plusOneMinimumRefinementValue, doubleConsumableRefinementValue = {}, {}, {}
for i, row in ipairs(lootTable) do
local thisItem = Items.getItemByID(row.itemID)
if thisItem ~= nil then
table.insert(result, '\r\n|-\r\n|'..Icons.Icon({thisItem.name, type='item'}))
else
table.insert(result, '\r\n|-\r\n|Unknown Item[[Category:Pages with script errors]]')
end
table.insert(result, '||' .. p._getArtefactType(thisItem) .. '')
table.insert(result, '||style="text-align:right" data-sort-value="'..row.maxQuantity..'"|')
if row.maxQuantity > row.minQuantity then
table.insert(result, Num.formatnum(row.minQuantity) .. ' - ')
end
table.insert(result, Num.formatnum(row.maxQuantity))
local dropChance = row.weight / totalWt
-- Adding price columnsR
if thisItem == nil then
table.insert(result, '||data-sort-value="0"|???')
else
table.insert(result, '||' .. Items.getValueText(thisItem, row.minQuantity, row.maxQuantity))
-- Add to total loot value
local sellAmount = thisItem.sellsFor or 0
local sellCurrency = thisItem.sellsForCurrency or 'melvorD:GP'
if sellAmount ~= nil and sellCurrency ~= nil then
if lootValue[sellCurrency] == nil then
lootValue[sellCurrency] = 0
plusOneMinimumRefinementValue[sellCurrency] = 0
doubleConsumableRefinementValue[sellCurrency] = 0
end
local artefactAvgValue = dropChance * sellAmount * ((row.minQuantity + row.maxQuantity) / 2)
lootValue[sellCurrency] = lootValue[sellCurrency] + artefactAvgValue
plusOneMinimumRefinementValue[sellCurrency] = plusOneMinimumRefinementValue[sellCurrency] + artefactAvgValue + (dropChance * sellAmount)
-- Checking if item is a consumable, then adding its value a second time
local doubleExtraVal = (Items._canItemUseSlot(thisItem, 'Consumable') and artefactAvgValue) or 0
doubleConsumableRefinementValue[sellCurrency] = doubleConsumableRefinementValue[sellCurrency] + artefactAvgValue + doubleExtraVal
end
end
if dropChance < 100 then
--Show fraction as long as it isn't going to be 1/1
table.insert(result, '||style="text-align:right" data-sort-value="'..row.weight..'"')
table.insert(result, '|'..Num.fraction(row.weight, totalWt))
table.insert(result, '||')
else
table.insert(result, '||colspan="2" data-sort-value="'..row.weight..'"')
end
-- 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'
table.insert(result, 'style="text-align:right"|'..string.format(fmt, dropChance * 100)..'%')
end
local function lootValueText(lootValue)
local returnPart = {}
for _, currencyDefn in ipairs(GameData.rawData.currencies) do
-- Guarantee order by iterating through currency game data definition
local currID = currencyDefn.id
local val = Num.round(lootValue[currID], 2, 2)
if val ~= nil then
table.insert(returnPart, Icons._Currency(currID, val))
end
end
return table.concat(returnPart, ', ')
end
table.insert(result, '\r\n|}')
local lootText = lootValueText(lootValue)
local plusOneLootText = lootValueText(plusOneMinimumRefinementValue)
local doubleLootText = lootValueText(doubleConsumableRefinementValue)
table.insert(result, '\r\nThe average value of one action is ' .. lootText .. ', ')
table.insert(result, 'increasing to ' .. plusOneLootText .. ' when the +1 Minimum Items refinement is active.')
if doubleLootText ~= lootText then
table.insert(result, '\r\n\r\nThe average value of one action with the x2 Consumables refinement is ' .. doubleLootText .. '.')
end
return table.concat(result, '')
end
function p.getDigSiteArtefactTable(frame)
local name = frame.args ~= nil and frame.args[1] or frame[1]
local size = frame.args ~= nil and frame.args[2] or frame[2]
local digSite = p.getDigSite(name)
if digSite == nil then
return Shared.printError('No Dig Site named '..name..' found')
end
return p._getDigSiteArtefactTable(digSite, size)
end
--Trying something new this time. Building the entire infobox in Lua and then passing it to the module.
function p.getDigSiteInfobox(frame)
local name = frame.args ~= nil and frame.args[1] or frame
name = string.gsub(name, "%%27", "'")
name = string.gsub(name, "'", "'")
local digSite = p.getDigSite(name)
if digSite == nil then
return Shared.printError('No Dig Site named '..name..' found')
end
local poi = Cartography.getPointOfInterestForDigSite(digSite.id)
local hex = Cartography.getHexByAxial(poi.coords.q, poi.coords.r)
local coordX, coordY = Cartography.convertAxialToXY(poi.coords)
local resultArray = {}
table.insert(resultArray, '{| class="wikitable infobox"')
--Expansion Symbol + Name
table.insert(resultArray, '\r\n!')
table.insert(resultArray, Icons.getExpansionIcon(digSite.id))
table.insert(resultArray, digSite.name)
--Image
table.insert(resultArray, '\r\n|-\r\n| style="text-align:center" |')
table.insert(resultArray, Icons.Icon({digSite.name, type='poi', size=250, notext='true'}))
--ID
table.insert(resultArray, "\r\n|-\r\n|'''ID:''' ")
table.insert(resultArray, digSite.id)
--Coordinates
table.insert(resultArray, "\r\n|-\r\n|'''Coordinates:''' ")
table.insert(resultArray, '('..coordX..', '..coordY..')')
--Requirements
table.insert(resultArray, "\r\n|-\r\n|'''Discovery Requirements:''' ")
local reqTable = Cartography._getPOIRequirements(poi)
if Shared.tableCount(reqTable) == 0 then
table.insert(resultArray, 'None')
else
table.insert(resultArray, '\r\n* '..table.concat(reqTable, '\r\n* '))
end
table.insert(resultArray, "\r\n|-\r\n|'''Archaeology Level:''' ")
table.insert(resultArray, Icons._SkillReq('Archaeology', digSite.level))
--Description
table.insert(resultArray, '\r\n|-\r\n| style="text-align:center" |')
table.insert(resultArray, "''"..poi.description.."''")
table.insert(resultArray, '\r\n|}')
table.insert(resultArray, '\n[[Category:Dig Sites]]')
return table.concat(resultArray, '')
end
function p._getMuseumRewards(reward)
local rewardTable = {}
local equipment = nil
if reward.gp ~= nil then
table.insert(rewardTable, Icons._Currency('melvorD:GP', reward.gp))
end
if reward.items ~= nil then
for _, reward in ipairs(reward.items) do
local item = Items.getItemByID(reward.id)
table.insert(rewardTable, Icons.Icon({item.name, type='item', qty=reward.quantity}))
if item.category == 'Archaeology' then
equipment = item.name
end
end
end
if reward.modifiers ~= nil then
table.insert(rewardTable, Modifiers.getModifiersText(reward.modifiers, true))
end
if equipment ~= nil then
table.insert(rewardTable, 'Unlocks the ability to purchase '..equipment..' from the '..Icons.Icon({'Shop'}))
end
return rewardTable
end
function p.getMuseumRewardsTable(frame)
-- Build the table
local resultTable = mw.html.create('table')
resultTable:addClass('wikitable sortable lighttable')
resultTable:tag('tr'):addClass('headerRow-0')
:tag('th'):wikitext('Donations')
:tag('th'):wikitext('Rewards')
for _, reward in ipairs(SkillData.Archaeology.museumRewards) do
local tr = mw.html.create('tr')
tr:tag('td'):wikitext(reward.museumCount)
tr:tag('td'):wikitext(table.concat(p._getMuseumRewards(reward), '<br/>'))
resultTable:node(tr)
end
return tostring(resultTable)
end
return p