Module:ItemTables: Difference between revisions

From Deadlock Wiki
Jump to navigation Jump to search
Sylphoid (talk | contribs)
add fire rate and stamina, include inclusions of different stat names, cleanup. WORKS NOW BUT ALSO BREAKS, invocations need to be reversed from internal to friendly, to friendly to internal
Cypress (talk | contribs)
m ...also add % suffix to Spirit Lifesteal
 
(57 intermediate revisions by 2 users not shown)
Line 3: Line 3:
local get_cost = require("Module:ItemData")._get_cost
local get_cost = require("Module:ItemData")._get_cost
local get_type = require("Module:ItemData")._get_type
local get_type = require("Module:ItemData")._get_type
local commas = require("Module:Addcommas")


-- Adds commas delimiter to the thousands place
-- Returns an array of item tables that have the same properties
function Format(amount)
-- @function  get_similar_items_array
    local formatted = amount
-- @param      {array}
    while true do
-- @return    {array of tables}
        formatted, k = string.gsub(formatted, "^(-?%d+)(%d%d%d)", '%1,%2')
local function get_similar_items_array(property)
        if (k == 0) then
local similarItems = {}
            break
local hash = {}
        end
local noDuplicates = {}
    end
for _, v in pairs(data) do
    return formatted
for _, value in ipairs(property) do
if (v[value] ~= nil and v["Disabled"] == false and v["Name"] ~= nil and v[value] ~= "0" and v[value] ~= "0m") then
table.insert(similarItems, v)
end
end
end
-- remove duplicate items if that item contains multiple keys of the same stat increase (eg. Fleetfoot has both "BonusMoveSpeed", "ActiveBonusMoveSpeed" in move speed).
-- there might be a more efficient way to prevent adding duplicate items in the first place in the above for loop
for _, v in pairs(similarItems) do
if (not hash[v]) then
noDuplicates[#noDuplicates+1] = v
hash[v] = true
end
end
return noDuplicates
end
end


Line 33: Line 49:
     return copy
     return copy
end
end


-- local link_patterns = {}
-- local link_patterns = {}
Line 55: Line 70:
-- end
-- end


local internal_to_friendly = {}
local friendly_to_internal = {}
internal_to_friendly["ammo"] = { "BonusClipSizePercent", "BonusClipSize" }
friendly_to_internal["ammo"] = { "BonusClipSizePercent", "BonusClipSize", "ActiveReloadPercent" }
internal_to_friendly["weapon damage"] = { "BaseAttackDamagePercent" }
friendly_to_internal["weapon damage"] = { "BaseAttackDamagePercent", "CloseRangeBonusWeaponPower", "LongRangeBonusWeaponPower", "AttackDamageWhenShielded" }
internal_to_friendly["health"] = { "BonusHealth" }
friendly_to_internal["spirit damage"] = { "ProcBonusMagicDamage" }
internal_to_friendly["health regen"] = { "BonusHealthRegen" }
friendly_to_internal["bullet shield health"] = { "BulletShieldMaxHealth", "BulletShieldOnCast", "SaviorBulletShieldHealth", "FlyingBulletShield", "VexBarrierBulletMaxHealth" }
internal_to_friendly["fire rate"] = { "BonusFireRate" }
friendly_to_internal["spirit shield health"] = { "TechShieldMaxHealth", "TechShieldOnCast", "SaviorMagicShieldHealth", "FlyingTechShield", "VexBarrierTechMaxHealth" }
internal_to_friendly["stamina"] = { "Stamina" }
friendly_to_internal["bullet resist"] = { "BulletResist", "LocalBulletArmorReduction", "ReturnFireBulletResist", "BulletResistPerStack" }
friendly_to_internal["bullet resist reduction"] = { "BulletArmorReduction", "BulletResistReduction" }
friendly_to_internal["spirit resist"] = { "TechResist" }
friendly_to_internal["spirit resist reduction"] = { "TechArmorDamageReduction", "MagicResistReduction" }
friendly_to_internal["bonus health"] = { "BonusHealth" }
friendly_to_internal["health regen"] = { "BonusHealthRegen" }
friendly_to_internal["max health regen"] = { "HealLifePercentOutOfCombat" }
friendly_to_internal["fire rate"] = { "BonusFireRate", "FireRateWhenShielded", "FireRateBonus", "FervorFireRate", "AmbushBonusFireRate", "ActiveBonusFireRate" }
friendly_to_internal["fire rate slow"] = { "FireRateSlow" }
friendly_to_internal["bullet velocity"] = { "BonusBulletSpeedPercent" }
friendly_to_internal["spirit power"] = { "TechPower", "BonusSpirit", "SpiritPower", "BonusSpiritWithMagicShield", "ImbuedTechPower", "AmbushBonusTechPower" }
friendly_to_internal["bullet lifesteal"] = { "BulletLifestealPercent", "ActiveBonusLifesteal" }
friendly_to_internal["spirit lifesteal"] = { "AbilityLifestealPercentHero" }
friendly_to_internal["move speed"] = { "BonusMoveSpeed", "ActiveBonusMoveSpeed" }
friendly_to_internal["sprint speed"] = { "BonusSprintSpeed" }
friendly_to_internal["movement slow"] = { "SlowPercent", "MovementSpeedSlow" }
friendly_to_internal["reload time"] = { "ReloadSpeedMultipler" }
friendly_to_internal["heavy melee distance"] = { "MeleeDistanceScale" }
friendly_to_internal["bonus heavy damage"] = { "BonusHeavyMeleeDamage" }
friendly_to_internal["melee resist"] = { "MeleeResistPercent" }
friendly_to_internal["stamina"] = { "Stamina" }
friendly_to_internal["slide distance"] = { "SlideScale" }
friendly_to_internal["stamina recovery"] = { "StaminaCooldownReduction" }
friendly_to_internal["healing reduction"] = { "HealAmpRegenPenaltyPercent" }


function amicableNames(desc)
-- Returns a table of internal properties
-- @function   friendlyNames
-- @param      {string}
-- @return    {table}
local function friendlyNames(desc)
local keysTable = {}
local keysTable = {}
desc = string.lower(desc or "")
desc = string.lower(desc or "")
for link, patterns in pairs(internal_to_friendly) do
for link, patterns in pairs(friendly_to_internal) do
if (desc == link) then keysTable = patterns end
end
return keysTable
end


if (desc == link) then keysTable = patterns end
local unitSuffix = {
["%"] = { "BonusClipSizePercent", "ActiveReloadPercent",
"BaseAttackDamagePercent", "CloseRangeBonusWeaponPower", "LongRangeBonusWeaponPower", "AttackDamageWhenShielded",
"TechResist", "BulletResist",
"BonusFireRate", "FireRateWhenShielded", "FervorFireRate", "FireRateBonus", "AmbushBonusFireRate", "ActiveBonusFireRate", "FireRateSlow",
"LocalBulletArmorReduction", "ReturnFireBulletResist", "BulletArmorReduction", "BulletResistReduction", "BulletResistPerStack",
"TechArmorDamageReduction", "MagicResistReduction",
"BonusBulletSpeedPercent",
"BulletLifestealPercent", "ActiveBonusLifesteal", "AbilityLifestealPercentHero",
"HealLifePercentOutOfCombat",
"ReloadSpeedMultipler",
"MeleeDistanceScale", "BonusHeavyMeleeDamage", "MeleeResistPercent",
"SlideScale",
"StaminaCooldownReduction",
"SlowPercent", "MovementSpeedSlow",
"HealAmpRegenPenaltyPercent" },
["m/s"] = { "BonusMoveSpeed", "ActiveBonusMoveSpeed", "BonusSprintSpeed" }
}


local function appendSuffix(internal)
local unitName = ""
for key, s in pairs(unitSuffix) do
for _, pattern in pairs(s) do
if (internal == pattern) then return key end
end
end
return unitName
end
local sortByWeapon = {}
sortByWeapon["Weapon"] = 1
sortByWeapon["Armor"] = 10000
sortByWeapon["Tech"] = 100000000
-- Sort the order of items in a preset as it appears when no filtered ordering is applied.
-- Ordered first by slot and cost increasing, then alphabetical within same slot and cost.
function defaultSort()
    return function(a, b)
    if (get_cost(a["Name"]) == get_cost(b["Name"]) and sortByWeapon[a["Slot"]] == sortByWeapon[b["Slot"]]) then return a["Name"] < b["Name"] end
        return get_cost(a["Name"]) * sortByWeapon[a["Slot"]] < get_cost(b["Name"]) * sortByWeapon[b["Slot"]]
    end
end
-- Formats the value of the stat with a + or -
-- @function  signPrefix
-- @param      {string}
-- @return    {string}
local function signPrefix(value)
local signString = ""
value = value:gsub( "m", "" )
value = tonumber(value)
if (value >= 0) then
return "+<b>" .. value .. "</b>"
elseif (value < 0) then
value = math.abs(value)
return "-<b>" .. value .. "</b>"
end
end
return keysTable
end
end


-- Outputs a wikitable of items that increase a specified stat. Invoked by {{Item stat table}}
-- @function  p.itemPropTable
-- @param      {string}
-- @return    {string}
p.itemPropTable = function(frame)
p.itemPropTable = function(frame)
local TableValues = {}
local requirements = {}
local requirements = {}
local listofKeysTable = {}
local listofKeysTable = {}
local listofItems = ""
local listofItems = ""
local property = frame.args[1] or mw.title.getCurrentTitle().text
local property = frame:getParent().args[1] or mw.title.getCurrentTitle().text
local copyVar = property
local copyVar = property
listofKeysTable = amicableNames(property) -- need to switch this around from value to key, to key to values
listofKeysTable = friendlyNames(property)  
local filteredData = {}
filteredData = get_similar_items_array(listofKeysTable)
table.sort(filteredData, defaultSort())
local createTable = mw.html.create('table')
local createTable = mw.html.create('table')
:addClass('wikitable sortable')
:addClass('wikitable sortable')
:tag('caption'):wikitext("List of Items"):done()
:tag('caption'):wikitext("List of items"):done()
local createTableRow = mw.html.create('tr')
local soulIcon = frame:expandTemplate{ title = 'Souls' }
createTableRow
local createTableHeader = mw.html.create('tr')
createTableHeader
:tag('th'):wikitext('Name'):done()
:tag('th'):wikitext('Name'):done()
:tag('th'):wikitext('Cost'):done()
:tag('th'):wikitext(soulIcon .. 'Cost'):done()
:tag('th'):wikitext('Category'):done()
:tag('th'):wikitext('Category'):done()
:tag('th'):wikitext('Stat change'):done()
:tag('th'):wikitext('Stat change'):done()
createTable:node(createTableRow)
createTable:node(createTableHeader)
-- query all items
-- query all the filtered items. itemName is the item table.
for internalName, itemName in pairs(data) do --itemName is the key. go through whole table. in this case itemName is the item table
for internalName, itemName in ipairs(filteredData) do  


local display = frame:expandTemplate{
local display = frame:expandTemplate{
Line 105: Line 212:
}
}
}
}
for _, t in pairs(listofKeysTable) do
-- filter out items that: don't have the property, don't have names (have 'null' names), and aren't disabled --//and itemName["Disabled"] == nil
for k, t in pairs(listofKeysTable) do
if(itemName[t] ~= nil and itemName["Name"] ~= nil) then --  and itemName["Disabled"] == false --// the data field is not setup to filter this yet
-- filter out items that: don't have the property and the value isn't zero
if(itemName[t] ~= nil and itemName[t] ~= "0" ) then
listofItems = listofItems .. itemName["Name"] .. "<br/>"
listofItems = listofItems .. itemName["Name"] .. "<br/>"
copyVar = copyVar:gsub("^%l", string.upper)
local tableData = mw.html.create('tr')
local tableData = mw.html.create('tr')
tableData
tableData
:tag('td'):wikitext(display):done()
:tag('td'):wikitext(display):done()
:tag('td'):wikitext(get_cost(itemName["Name"])):done()
:tag('td'):wikitext(commas._add(get_cost(itemName["Name"]))):done()
:tag('td'):wikitext(get_type(itemName["Name"])):done()
:tag('td'):wikitext(get_type(itemName["Name"])):done()
:tag('td'):wikitext("+<b>" .. itemName[t].. "</b> " .. copyVar):done()
if (t == "LocalBulletArmorReduction") then
tableData
:tag('td'):wikitext("<span style=\"color:red;\">" .. signPrefix(itemName[t]) .. appendSuffix(t) .. "</span> " .. copyVar):done()
else
tableData
:tag('td'):wikitext(signPrefix(itemName[t]) .. appendSuffix(t) .. "</span> " .. copyVar):done()
end
table.insert(requirements, tableData)
table.insert(requirements, tableData)
-- TableValues = table.insert(TableValues, itemName["Name"]) -- i may want to make a table first, so it includes weapon and cost to make it sortable.
end
end
end
end
Line 124: Line 239:
for _, row in ipairs(requirements) do
for _, row in ipairs(requirements) do
createTableRow:node(row)
createTableHeader:node(row)
end
end
--createTable:node(createTableRow)
return tostring(createTable)
return tostring(createTable) --, listofItems -- this is just a string list, same thing as createTable. delete this when line when finished
--return listofItems -- this is just a string list, same thing as createTable. delete this when line when finished
--return table.concat(TableValues, ", ")


end
end


return p
return p

Latest revision as of 20:49, 12 November 2024

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

local p = {};
local data = mw.loadJsonData("Data:ItemData.json")
local get_cost = require("Module:ItemData")._get_cost
local get_type = require("Module:ItemData")._get_type
local commas = require("Module:Addcommas")

-- Returns an array of item tables that have the same properties
-- @function   get_similar_items_array
-- @param      {array}
-- @return     {array of tables}
local function get_similar_items_array(property)
	local similarItems = {}
	local hash = {}
	local noDuplicates = {}
	for _, v in pairs(data) do
		for _, value in ipairs(property) do
			if (v[value] ~= nil and v["Disabled"] == false and v["Name"] ~= nil and v[value] ~= "0" and v[value] ~= "0m") then
				table.insert(similarItems, v)
			end
		end
	end
	
	-- remove duplicate items if that item contains multiple keys of the same stat increase (eg. Fleetfoot has both "BonusMoveSpeed", "ActiveBonusMoveSpeed" in move speed).
	-- there might be a more efficient way to prevent adding duplicate items in the first place in the above for loop
	for _, v in pairs(similarItems) do
		if (not hash[v]) then
			noDuplicates[#noDuplicates+1] = v
			hash[v] = true
		end
	end
	return noDuplicates
end

--- Copies original table with its children as deep as possible. Does not handle metatables. (Copy is needed because Lua passes by reference, not value)
-- @function   Deepcopy
-- @param      {n-D table}
-- @return     {n-D table}
function Deepcopy(orig)
    local orig_type = type(orig)
    local copy
    if orig_type == 'table' then
        copy = {}
        for orig_key, orig_value in next, orig, nil do
            copy[Deepcopy(orig_key)] = Deepcopy(orig_value)
        end
    else
        copy = orig
    end
    return copy
end

--	local link_patterns = {}
--	link_patterns["BonusClipSizePercent"] = { "[Aa]mmo" }
--	link_patterns["CloseRangeBonusWeaponPower"] = { "[Cc]lose [Ww]eapon [Dd]amage" }
--	link_patterns["BaseAttackDamagePercent"] = { "[Ww]eapon [Dd]amage" }
--	link_patterns["BulletLifestealPercent"] = { "[Bb]ullet [Ll]ifesteal" }
--	link_patterns["BonusHealthRegen"] = { "[Hh]ealth [Rr]egen" }
--	link_patterns["BonusHealth"] = { "[Hh]ealth" }
--	link_patterns["BonusFireRate"] = { "[Ff]ire [Rr]ate" }
--	
--	function FriendlyNames(desc)
--		for link, patterns in pairs(link_patterns) do
--			for i, v in ipairs(patterns) do
--	    		local a = string.find(desc, v)
--					if a then desc = link break
--	    		end
--	    	end
--		end
--		return desc
--	end

local friendly_to_internal = {}
friendly_to_internal["ammo"] = { "BonusClipSizePercent", "BonusClipSize", "ActiveReloadPercent" }
friendly_to_internal["weapon damage"] = { "BaseAttackDamagePercent", "CloseRangeBonusWeaponPower", "LongRangeBonusWeaponPower", "AttackDamageWhenShielded" }
friendly_to_internal["spirit damage"] = { "ProcBonusMagicDamage" }
friendly_to_internal["bullet shield health"] = { "BulletShieldMaxHealth", "BulletShieldOnCast", "SaviorBulletShieldHealth", "FlyingBulletShield", "VexBarrierBulletMaxHealth" }
friendly_to_internal["spirit shield health"] = { "TechShieldMaxHealth", "TechShieldOnCast", "SaviorMagicShieldHealth", "FlyingTechShield", "VexBarrierTechMaxHealth" }
friendly_to_internal["bullet resist"] = { "BulletResist", "LocalBulletArmorReduction", "ReturnFireBulletResist", "BulletResistPerStack" }
friendly_to_internal["bullet resist reduction"] = { "BulletArmorReduction", "BulletResistReduction" }
friendly_to_internal["spirit resist"] = { "TechResist" }
friendly_to_internal["spirit resist reduction"] = { "TechArmorDamageReduction", "MagicResistReduction" }
friendly_to_internal["bonus health"] = { "BonusHealth" }
friendly_to_internal["health regen"] = { "BonusHealthRegen" }
friendly_to_internal["max health regen"] = { "HealLifePercentOutOfCombat" }
friendly_to_internal["fire rate"] = { "BonusFireRate", "FireRateWhenShielded", "FireRateBonus", "FervorFireRate", "AmbushBonusFireRate", "ActiveBonusFireRate" }
friendly_to_internal["fire rate slow"] = { "FireRateSlow" }
friendly_to_internal["bullet velocity"] = { "BonusBulletSpeedPercent" }
friendly_to_internal["spirit power"] = { "TechPower", "BonusSpirit", "SpiritPower", "BonusSpiritWithMagicShield", "ImbuedTechPower", "AmbushBonusTechPower" }
friendly_to_internal["bullet lifesteal"] = { "BulletLifestealPercent", "ActiveBonusLifesteal" }
friendly_to_internal["spirit lifesteal"] = { "AbilityLifestealPercentHero" }
friendly_to_internal["move speed"] = { "BonusMoveSpeed", "ActiveBonusMoveSpeed" }
friendly_to_internal["sprint speed"] = { "BonusSprintSpeed" }
friendly_to_internal["movement slow"] = { "SlowPercent", "MovementSpeedSlow" }
friendly_to_internal["reload time"] = { "ReloadSpeedMultipler" }
friendly_to_internal["heavy melee distance"] = { "MeleeDistanceScale" }
friendly_to_internal["bonus heavy damage"] = { "BonusHeavyMeleeDamage" }
friendly_to_internal["melee resist"] = { "MeleeResistPercent" }
friendly_to_internal["stamina"] = { "Stamina" }
friendly_to_internal["slide distance"] = { "SlideScale" }
friendly_to_internal["stamina recovery"] = { "StaminaCooldownReduction" }
friendly_to_internal["healing reduction"] = { "HealAmpRegenPenaltyPercent" }

-- Returns a table of internal properties 
-- @function   friendlyNames
-- @param      {string}
-- @return     {table}
local function friendlyNames(desc)
	local keysTable = {}
	desc = string.lower(desc or "")
	for link, patterns in pairs(friendly_to_internal) do
		if (desc == link) then keysTable = patterns end 
	end
	return keysTable
end

local unitSuffix = {
	["%"] = { "BonusClipSizePercent", "ActiveReloadPercent", 
		"BaseAttackDamagePercent", "CloseRangeBonusWeaponPower", "LongRangeBonusWeaponPower", "AttackDamageWhenShielded",
		"TechResist", "BulletResist",
		"BonusFireRate", "FireRateWhenShielded", "FervorFireRate", "FireRateBonus", "AmbushBonusFireRate", "ActiveBonusFireRate", "FireRateSlow",
		"LocalBulletArmorReduction", "ReturnFireBulletResist", "BulletArmorReduction", "BulletResistReduction", "BulletResistPerStack",
		"TechArmorDamageReduction", "MagicResistReduction",
		"BonusBulletSpeedPercent",
		"BulletLifestealPercent", "ActiveBonusLifesteal", "AbilityLifestealPercentHero",
		"HealLifePercentOutOfCombat",
		"ReloadSpeedMultipler",
		"MeleeDistanceScale", "BonusHeavyMeleeDamage", "MeleeResistPercent",
		"SlideScale",
		"StaminaCooldownReduction",
		"SlowPercent", "MovementSpeedSlow",
		"HealAmpRegenPenaltyPercent" },
	["m/s"] = { "BonusMoveSpeed", "ActiveBonusMoveSpeed", "BonusSprintSpeed" }
}

local function appendSuffix(internal)
	local unitName = ""
	for key, s in pairs(unitSuffix) do
		for _, pattern in pairs(s) do
			if (internal == pattern) then return key end
		end
	end
	return unitName
end

local sortByWeapon = {}
sortByWeapon["Weapon"] = 1
sortByWeapon["Armor"] = 10000
sortByWeapon["Tech"] = 100000000

-- Sort the order of items in a preset as it appears when no filtered ordering is applied. 
-- Ordered first by slot and cost increasing, then alphabetical within same slot and cost.
function defaultSort()
    return function(a, b)
    	if (get_cost(a["Name"]) == get_cost(b["Name"]) and sortByWeapon[a["Slot"]] == sortByWeapon[b["Slot"]]) then return a["Name"] < b["Name"] end
        return get_cost(a["Name"]) * sortByWeapon[a["Slot"]] < get_cost(b["Name"]) * sortByWeapon[b["Slot"]]
    end
end

-- Formats the value of the stat with a + or -
-- @function   signPrefix
-- @param      {string}
-- @return     {string}
local function signPrefix(value)
	local signString = ""
	value = value:gsub( "m", "" )
	value = tonumber(value)
	if (value >= 0) then
		return "+<b>" .. value .. "</b>"
	elseif (value < 0) then
		value = math.abs(value)
		return "-<b>" .. value .. "</b>"
	end
end

-- Outputs a wikitable of items that increase a specified stat. Invoked by {{Item stat table}}
-- @function   p.itemPropTable
-- @param      {string}
-- @return     {string}
p.itemPropTable = function(frame)
	local requirements = {}
	local listofKeysTable = {}
	local listofItems = ""
	local property = frame:getParent().args[1] or mw.title.getCurrentTitle().text
	local copyVar = property
	listofKeysTable = friendlyNames(property) 
	local filteredData = {}
	filteredData = get_similar_items_array(listofKeysTable)
	table.sort(filteredData, defaultSort())
	
	local createTable = mw.html.create('table')
			:addClass('wikitable sortable')
			:tag('caption'):wikitext("List of items"):done()
	
	local soulIcon = frame:expandTemplate{ title = 'Souls' }
		
	local createTableHeader = mw.html.create('tr')
	createTableHeader
		:tag('th'):wikitext('Name'):done()
		:tag('th'):wikitext(soulIcon .. 'Cost'):done()
		:tag('th'):wikitext('Category'):done()
		:tag('th'):wikitext('Stat change'):done()
		
	createTable:node(createTableHeader)
	
	-- query all the filtered items. itemName is the item table.
	for internalName, itemName in ipairs(filteredData) do 

		local display = frame:expandTemplate{
		title = 'ItemIcon',
		args = {
			itemName["Name"]
			}
		}
		
		for k, t in pairs(listofKeysTable) do
			-- filter out items that: don't have the property and the value isn't zero
			if(itemName[t] ~= nil and itemName[t] ~= "0" ) then
				listofItems = listofItems .. itemName["Name"] .. "<br/>"
				copyVar = copyVar:gsub("^%l", string.upper)
				
				local tableData = mw.html.create('tr')
				tableData
					:tag('td'):wikitext(display):done()
					:tag('td'):wikitext(commas._add(get_cost(itemName["Name"]))):done()
					:tag('td'):wikitext(get_type(itemName["Name"])):done()
					
					if (t == "LocalBulletArmorReduction") then 
					tableData
						:tag('td'):wikitext("<span style=\"color:red;\">" .. signPrefix(itemName[t]) .. appendSuffix(t) .. "</span> " .. copyVar):done()
					else
					tableData
						:tag('td'):wikitext(signPrefix(itemName[t]) .. appendSuffix(t) .. "</span> " .. copyVar):done()
					end
					
				table.insert(requirements, tableData)
			end
		end
	end	
	
	for _, row in ipairs(requirements) do
		createTableHeader:node(row)
	end
	
	return tostring(createTable) --, listofItems -- this is just a string list, same thing as createTable. delete this when line when finished

end

return p