このモジュールについての説明文ページを モジュール:Void/doc に作成できます
--- '''Void''' retrieves drop table data of opening [[Void Relic]]s. Originally
-- built when the [[Void]] rewarded [[Prime]]d parts and blueprints.
--
-- On this Wiki, Void is used in:
-- * [[Module:Acquisition]]
--
--
-- @module void
-- @alias p
-- @author [[User:ChickenBar|ChickenBar]]
-- @attribution [[User:Flaicher|Flaicher]]
-- @attribution [[User:FINNER|FINNER]]
-- @attribution [[User:Falterfire|Falterfire]]
-- @attribution [[User:Gigamicro|Gigamicro]]
-- @attribution [[User:Synthtech|Synthtech]]
-- @image VoidProjectionsIronD.png
-- @require [[Module:Void/data]]
-- @require [[Module:Icon]]
-- @require [[Module:Shared]]
-- @require [[Module:String]]
-- @require [[Module:Math]]
-- @release stable
-- <nowiki>
-- TODO: Replace any mentions of string functions from M:Shared to those from M:String
local p = {}
local VoidData = mw.loadData [[Module:Void/data]]
local Icon = require [[Module:Icon]]
local Shared = require [[Module:Shared]]
local String = require [[Module:String]]
local Math = require [[Module:Math]]
local Version = require [[Module:Version]]
local TxtColors = {Common = '#9C7344', Uncommon = '#D3D3D3', Rare = '#D1B962'}
local tooltipStart = '<span class="tooltip" data-param="'
local tooltipCenter = '" data-param2="Void">'
local tooltipEnd = '</span>'
--- Checks if a relic is vaulted or not.
-- @function p.isVaulted
-- @param {string} relicName Relic name
-- @return {boolean} True if relic is vaulted, false otherwise
function p.isVaulted(relicName)
local itr = string.gmatch(relicName, '([^ ]+)')
local tier = itr[1]
local name = itr[2]
return p.getRelic(tier, name)['Vaulted'] ~= nil
end
--- Converts item names to their proper Prime names.
-- For example, 'LATRON' becomes 'Latron Prime'.
-- @function p.getItemName
-- @param {string} itemStr Item name
-- @return {string} Prime name
function p.getItemName(itemStr)
local caseItem = String.titleCase(itemStr)
if (itemStr ~= "FORMA") then
caseItem = caseItem.." Prime"
end
return caseItem
end
--- Converts Prime part names in data to proper casing.
-- @function p.getPartName
-- @param {string} partStr Item name
-- @param[opt] {boolean} keepBlueprint If true, adds 'blueprint' to end of result, false otherwise.
-- Default value is true.
-- @return {string} Name of Prime part
function p.getPartName(partStr, keepBlueprint)
--User:Falterfire 6/19/2018:
-- New parameter to remove ' Blueprint' if wanted
-- IE returns 'Neuroptics' instead of 'Neuroptics Blueprint'
if keepBlueprint == nil then keepBlueprint = true end
local result = String.titleCase(partStr)
if not keepBlueprint and String.contains(result, 'の設計図') then
result = string.gsub(result, 'の設計図', '')
end
return result
end
--- Gets the relic data
-- @function p.getRelic
-- @param {string} tier Relic tier (e.g. 'Axi')
-- @param {string} name Relic name (e.g. 'A1')
-- @return {table or nil} A table containing relic's drops and vaulted info. Returns nil if no data for that relic is found.
function p.getRelic(tier, name)
return VoidData['RelicNames'][('%s %s'):format(tier, name)]
end
--- Returns the rarity if a relic drops a part.
-- @function p.getRelicDropRarity
-- @param {table} relic Relic table entry
-- @param {string} item Name of item
-- @param {string} part Name of item part
-- @return {string or nil} The rarity of drop; returns nil if relic does not drop specified item
function p.getRelicDropRarity(relic, item, part)
for i, drop in pairs(relic['Drops']) do
if (drop['Item'] == item and drop['Part'] == part) then
return drop.Rarity
end
end
return nil
end
--- Returns the part icon for a drop.
-- For example, "Braton Prime Barrel" returns [[File:Primebarrel.png|38px]]
-- @function p.getPartIconForDrop
-- @param {string} drop Item name
-- @return {string} Icon in the form of a wikitext link
function p.getPartIconForDrop(drop)
local iName = p.getItemName(drop.Item)
local pName = p.getPartName(drop.Part)
local iconSize =''
local primeToggle = 'Prime '
if iName == 'Forma' then
iconSize = '43'
else
iconSize = '54'
end
if iName == 'Odonata Prime' then
if pName == 'Harness Blueprint' or pName == 'Systems Blueprint' or pName == 'Wings Blueprint' then
primeToggle = 'Archwing '
end
elseif pName == 'Carapace' or pName == 'Cerebrum' or pName == 'Systems' then
primeToggle = ''
end
local icon =''
if(pName == 'Blueprint') then
icon = Icon._Prime(String.titleCase(drop.Item), nil, iconSize)
elseif iName == 'Kavasa Prime' then
icon = Icon._Prime('Kavasa', nil,iconSize)
else
icon = Icon._Item(primeToggle..pName, "", iconSize)
end
return icon
end
--- Returns the item icon for a drop.
-- For example, "Braton Prime Barrel" returns [[File:PrimeBraton.png|38px]]
-- @function p.getItemIconForDrop
-- @param {string} drop Item name
-- @return {string} Icon in the form of a wikitext link
function p.getItemIconForDrop(drop)
local iName = p.getItemName(drop.Item)
local pName = p.getPartName(drop.Part)
local iconSize = '38'
return Icon._Prime(String.titleCase(drop.Item), nil, iconSize)
end
--- Returns the relics in which the item is dropped from.
-- @function p.item
-- @param {string} item_type
-- @param {string} item_part
-- @param {string} relic_tier
-- @return {string}
function p.item(frame)
local item_type = frame.args[1]
local item_part = frame.args[2]
local relic_tier = frame.args[3]
return p._item(item_type, item_part, relic_tier)
end
--- Returns the relics in which the item is dropped from.
-- @function p._item
-- @param {string} item_type
-- @param {string} item_part
-- @param {string} relic_tier
-- @return {string}
function p._item(item_type, item_part, relic_tier)
item_type = string.upper(item_type)
item_part = string.upper(item_part)
if (item_part == "HELMET BLUEPRINT") then
item_part = "NEUROPTICS BLUEPRINT"
end
local locations = {}
local vaultLocations = {}
local i
for i, relic in pairs(VoidData["Relics"]) do
if (relic_tier == nil or relic.Tier == relic_tier) then
local dropRarity = p.getRelicDropRarity(relic, item_type, item_part)
if(dropRarity ~= nil) then
local relicText = relic.Tier.." "..relic.Name
local relicString = tooltipStart..relicText..tooltipCenter.."[["..relicText.."]]"..tooltipEnd.." "..dropRarity
if(relic.Vaulted ~= nil) then
relicString = relicString.." ([[Prime Vault|V]])"
table.insert(vaultLocations, relicString)
else
if(relic.IsBaro == 1) then
relicString = relicString.." ([[Baro Ki%27Teer|B]])"
end
table.insert(locations, relicString)
end
end
end
end
for _, i in pairs(vaultLocations) do
table.insert(locations, i)
end
return table.concat(locations, "<br/>")
end
--- Gets the drop table of a relic.
-- @function p.getRelicDrop
-- @param {string} relicName
-- @param {string} rarity
-- @param {number} number
-- @return {string}
function p.getRelicDrop(frame)
local relicName = frame.args ~= nil and frame.args[1] or nil
local rarity = frame.args ~= nil and frame.args[2] or nil
local number = frame.args ~= nil and frame.args[3] or nil
-- The number of the drop defaults to 1 if not set
if number == nil then
number = 1
elseif type(number) == 'string' then
-- If the argument is a string, force it into being a number
number = tonumber(number)
end
-- Return an error if any arguments are missing
if relicName == nil or relicName == '' then
error("ERROR: Missing argument 'Relic Name'")
elseif rarity == nil or rarity == '' then
error("ERROR: Missing argument 'Rarity'")
end
local bits = String.split(relicName, '%s')
local theRelic = p.getRelic(bits[1], bits[2])
-- Return an error if the relic wasn't found
assert(theRelic ~= nil, "ERROR: Invalid relic "..relicName)
local count = 0
for i, drop in pairs(theRelic.Drops) do
-- Loop through the drops to find drops of the chosen rarity
if drop.Rarity == rarity then
count = count + 1
-- Once enough drops of the right kind have been found, return the icon + the item name
if count == number then
local iName = p.getItemName(drop.Item)
local pName = p.getPartName(drop.Part, false)
local icon = p.getItemIconForDrop(drop)
return icon..' [['..iName..'|'..iName..' '..pName..']]'
end
end
end
-- If we got to here, there weren't enough drops of that rarity for this relic.
error("ERROR: Only found "..count.." drops of "..rarity.." rarity for "..relicName)
end
--- Gets the total number of relics in the game.
-- @function p.getRelicTotal
-- @param[opt] {string} frame.args Options for what relic types to include are
-- "unvaulted", "vaulted", "baro", or nil
-- @return {number} The total count of all relics
function p.getRelicTotal(frame)
local total = 0
if (Shared.contains(frame.args, "unvaulted")) then
for _, relic in pairs(VoidData["Relics"]) do
if (relic.Vaulted == nil) then
total = total + 1
end
end
end
if (Shared.contains(frame.args, "vaulted")) then
for _, relic in pairs(VoidData["Relics"]) do
if (relic.Vaulted ~= nil) then
total = total + 1
end
end
end
if (Shared.contains(frame.args, "baro")) then
for _, relic in pairs(VoidData["Relics"]) do
if (relic.IsBaro == 1) then
total = total + 1
end
end
end
if (frame.args[1] == nil) then
total = Shared.tableCount(VoidData["Relics"])
end
return total
end
local function relicData()
--This is snatched from m:VoidByReward p.byReward
local data = {}
for _, relic in pairs(VoidData["Relics"]) do
for i, drop in pairs(relic.Drops) do
local newObj = {Tier = relic.Tier, Name = relic.Name, Rarity = drop.Rarity, IsVaulted = relic.Vaulted ~= nil, IsBaro = relic.IsBaro == 1}
if (data[drop.Item] == nil) then
data[drop.Item] = {}
end
if(data[drop.Item][drop.Part] == nil) then
data[drop.Item][drop.Part] = {}
end
table.insert(data[drop.Item][drop.Part], newObj)
end
end
return data
end
local function checkData(data)
if data == nil or type(data) ~= 'table' then
local data = relicData()
return data
elseif type(data) == 'table' then
return data
end
end
local function getItemRarities(itemName, partName, data)
local data = checkData(data)
local rarities = {}
itemName = string.upper(itemName)
partName = string.upper(partName)
for n, drop in Shared.skpairs(data[itemName][partName]) do
rarities[drop.Rarity] = true
end
local brarities = {}
for r in pairs(rarities) do table.insert(brarities,r) end
--[[for rar, n in pairs(rarities) do
mw.log(rar)
end--]]
return brarities
end
--- Gets the ducat value of a Prime part or blueprint.
-- @function p.getDucatValue
-- @param {string} itemName Prime item name
-- @param {string} partName Part name
-- @return {number} The ducat value of that Prime part/blueprint
function p.getDucatValue(frame)
--T his is just for invoking p._getDucatValue on article pages.
local itemName = frame.args ~= nil and frame.args[1] or nil
local partName = frame.args ~= nil and frame.args[2] or nil
if itemName == nil or itemName == '' then
return 'Item name missing'
elseif partName == nil or partName == '' then
return 'Part name missing'
end
return p._getDucatValue(itemName, partName)
end
--- Gets the ducat value of a Prime part or blueprint.
-- @function p._getDucatValue
-- @param {string} itemName Prime item name
-- @param {string} partName Part name
-- @param {table} data Relic data
-- @return {number} The ducat value of that Prime part/blueprint
function p._getDucatValue(itemName, partName, data)
local rarities = getItemRarities(itemName, partName, data)
local exceptions = {
akstiletto={receiver=45},
braton={stock=15,receiver=45},
rubico={stock=45},
saryn={['neuroptics blueprint']=45},
soma={blueprint=15},
--valkyr={['systems blueprint']=100},
};
if exceptions[string.lower(itemName)] ~= nil and exceptions[string.lower(itemName)][string.lower(partName)] ~= nil then
return exceptions[string.lower(itemName)][string.lower(partName)]
end
return not rarities and -1
or rarities[2] and (Shared.contains(rarities, 'Common') and 25 or Shared.contains(rarities, 'Rare') and 65 or rarities[3] and 25 )
or ({Common=15,Uncommon=45,Rare=100})[rarities[1]]
end
--- Gets the total ducat value of all Prime parts and blueprints.
-- @function p.getTotalDucats
-- @param[opt] {string} tierName Tier name if want to filter by a specific relic tier
-- @return {number} The total ducat value
function p.getTotalDucats(frame)
local tierName = frame.args ~= nil and frame.args[1]
local data = relicData()
local totalItemCount = 0 --counting all items
local withoutFormaCount = 0 --counting all items excluding forma
local totalDucats = 0 --all, including duplicates, itemDucats
local availableDucats = 0 --total ducats for items from available relics
local availableItems = 0 --available items
local availableItemsEF = 0 --available items excluding forma
local vaultedDucats = 0 --total ducats for items from vaulted relics
local vaultedItems = 0 --vaulted items
local vaultedItemsEF = 0 --vaulted items excluding forma
local result = ''
for item, parts in Shared.skpairs(data) do
for part, drops in Shared.skpairs(parts) do
for n, drop in Shared.skpairs(drops) do
if tierName == drop.Tier or tierName == nil then
if drop.Vaulted then
vaultedItems = vaultedItems + 1
else
availableItems = availableItems + 1
end
totalItemCount = totalItemCount + 1
if item ~= 'FORMA' then
local tempDucat =p._getDucatValue(item, part, data)
totalDucats = totalDucats + tempDucat
withoutFormaCount = withoutFormaCount + 1
if drop.Vaulted then
vaultedDucats = vaultedDucats + tempDucat
vaultedItemsEF = vaultedItemsEF + 1
else
availableDucats = availableDucats + tempDucat
availableItemsEF = availableItemsEF + 1
end
end
end
end
end
end
if tierName then
result = "'''Average Ducats Value''': "..Icon._Item('Ducats').."'''"..Math.round((totalDucats / totalItemCount), 0.01).."''' ("..totalItemCount..' rewards with '..withoutFormaCount..' parts)'
result = result.."<br>'''Available''': "..Icon._Item('Ducats').."'''"..Math.round((availableDucats/availableItems), 0.01).."''' ("..availableItems..' rewards with '..availableItemsEF..' parts)'
result = result.." | '''Vaulted''': "..Icon._Item('Ducats').."'''"..Math.round((vaultedDucats/vaultedItems), 0.01).."''' ("..vaultedItems..' rewards with '..vaultedItemsEF..' parts)'
else
result = "'''Total Ducats Value''': "..Icon._Item('Ducats').."'''"..Math.formatnum(totalDucats).."''' ("..totalItemCount..' rewards with '..withoutFormaCount..' parts)'
result = result.."<br>'''Available''': "..Icon._Item('Ducats').."'''"..Math.formatnum(availableDucats).."''' ("..availableItems..' rewards with '..availableItemsEF..' parts)'
result = result.." | '''Vaulted''': "..Icon._Item('Ducats').."'''"..Math.formatnum(vaultedDucats).."''' ("..vaultedItems..' rewards with '..vaultedItemsEF..' parts)'
end
return result
end
local function ducatPriceRow(itemName, partName, tierName, data)
local ducatValue = p._getDucatValue(itemName, partName, data)
local sortValue = ''
local function createRelicText(itemName, partName, tierName, data)
itemName = string.upper(itemName)
partName = string.upper(partName)
local locations = {}
local vaultLocations = {}
for n, drop in Shared.skpairs(data[itemName][partName]) do
if drop.Tier == tierName or tierName == nil then
local dropRarity = drop.Rarity
if dropRarity ~= nil then
local relicText = drop.Tier.." "..drop.Name
local relicString = tooltipStart..relicText..tooltipCenter.."[["..relicText.."]]"..tooltipEnd.." "..dropRarity
if drop.Vaulted then
relicString = relicString.." ([[Prime Vault|V]])"
table.insert(vaultLocations, relicString)
else
if drop.IsBaro then
relicString = relicString.." ([[Baro Ki%27Teer|B]])"
end
table.insert(locations, relicString)
end
end
end
end
for _, i in pairs(vaultLocations) do
table.insert(locations, i)
end
return table.concat(locations, "<br/>")
end
if itemName == nil or itemName == '' or partName == nil or partName == '' then
return 'Please enter item and part names'
end
--first cell
if partName == 'Blueprint' then
sortValue = itemName..' _'..partName
else
sortValue = itemName..' '..partName
end
local cell1 = '\n|data-sort-value="'..sortValue..'"|'..Icon._Prime(itemName,partName)
local cell2 = '\n|'..createRelicText(itemName, partName, tierName, data)
local cell3 = '\n|data-sort-value="'..ducatValue..'"|'..Icon._Item('Ducats').."'''"..ducatValue.."'''\n|-"
return cell1..cell2..cell3
end
--- Builds a table of all Prime parts, the relics they are in, and their ducat value
-- as seen https://warframe.fandom.com/wiki/Ducats/Prices/Lith
-- @function p.ducatRelicList
-- @param[opt] {string} tierName Tier name if want to filter by a specific relic tier
-- @param[opt] {string} listMode If nil, displays only unvaulted item; if "All", displays all items, including vaulted ones
-- @return {string} Wikitext of table
function p.ducatRelicList(frame)
local data = relicData()
local tierName = frame.args ~= nil and frame.args[1] or nil
-- Adding switch to choose only vaulted or unvaulted items to show
local listMode = frame.args ~= nil and frame.args[2] or 'ALL'
listMode = string.upper(listMode)
local itemList = {}
local result = {}
for item, parts in Shared.skpairs(data) do
if item ~= 'FORMA' then
for part, drops in Shared.skpairs(parts) do
for i, drop in pairs(drops) do
if drop.Tier == tierName or tierName == nil then
local tempName = ''
if part == 'BLUEPRINT' then
tempName = String.titleCase(item..'<> '..part)
else
tempName = String.titleCase(item..'<>'..part)
end
if not Shared.contains(itemList, tempName) then
if listMode == 'VAULTED' then
if drop.isBaro or drop.Vaulted then
table.insert(itemList, tempName)
end
elseif listMode == 'UNVAULTED' then
if not drop.IsBaro and not drop.Vaulted then
table.insert(itemList, tempName)
end
else
table.insert(itemList, tempName)
end
end
end
end
end
end
end
table.sort(itemList)
for num, itm in pairs(itemList) do
local item = String.split(itm, '<>')
item[1] = String.trim(item[1])
item[2] = String.trim(item[2])
table.insert(result, (ducatPriceRow(item[1], item[2], tierName, data)))
end
return table.concat(result)
end
--- Builds relic infobox.
-- TODO: Figure out errors with _getVersionLink() and String.trim()
-- @function p.buildRelicInfobox
-- @param {table} frame
-- @return {string} Wikitext of infobox
function p.buildRelicInfobox(frame)
assert(frame and frame.args ~= nil, 'p.buildRelicInfobox(frame): empty frame arguments')
local relicName = frame.args[1]
local Relic = VoidData['RelicNames'][relicName]
assert(Relic ~= nil, 'p.buildRelicInfobox(frame): "'..relicName..'" does not exist in [[Module:Void/data]]')
local imageMap = {
Lith = 'VoidProjectionsIronD.png',
Meso = 'VoidProjectionsBronzeD.png',
Neo = 'VoidProjectionsSilverD.png',
Axi = 'VoidProjectionsGoldD.png',
Requiem = 'RequiemR0.png'
}
local getRelicStatus = function(Relic)
if (Relic.isBaro == nil) then
if (Relic.Vaulted == nil) then
return '<div style="text-align:center;">{{text|green|Available}}</div>'
else
return '<div style="text-align:center;">{{text|red|Vaulted}}</div>[[Category:Vaulted]]'
end
else
return '<div style="text-align:center;">[[Baro Ki\'Teer|{{text|blue|Baro Ki\'Teer Exclusive}}]]</div>[[Category:Removed]]'
end
end
local infobox = [=[
<infobox>
<title source="name"><default><span><b>%s</b></span></default></title>
<image source="image"><default>%s</default></image>
<group>
<header>General</header>
<data source="release-date">
<label>Release date</label><default>%s</default>
</data>
<data source="vault-date">
<label>Vault date</label><default>%s</default>
</data>
<data source="baro"><default>%s</default></data>
</group>
</infobox>
]=]
infobox = infobox:format(
relicName,
imageMap[Relic.Tier],
Version._getVersionLink(Relic.Introduced),
Version._getVersionLink(Relic.Vaulted),
getRelicStatus(Relic)
)
mw.log(infobox)
return frame:preprocess(infobox)
end
p.relicTooltip = function(frame) mw.log'Remove Void.relicTooltip call' return require [[Module:Tooltips/tip]] .Void (frame.args and frame.args[1] or frame) end
return p