Module:Item

From Hero Siege Wiki
Jump to navigation Jump to search

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

local p = {}
local cargo = mw.ext.cargo

local game = require('Module:Game')
local func = require('Module:Func')
local cfg = require('Module:Config')

function p.fetchItemDetails(itemName)
    local queryResult = cargo.query(
        "items",
        "Item_Name, Item_Type, Item_Rarity, Item_Lore, Item_Level_Requirement, Item_Tier, Item_Weapon_Class, Item_Restricted_Drop, Item_Craftable, Item_Set",
        { where = "Item_Name = '" .. func.encodeName(itemName) .. "'" }
    )
    return queryResult
end

function p.fetchFormatDetails()
    local cargo = mw.ext.cargo
    local query = cargo.query(
        "stat_format",
        "Stat_ID, Stat_Display, Stat_Color, Stat_Type",
        {Stat_ID = "Stat_ID IS NOT NULL AND Stat_ID <> ''"}
    )
    local formatDetails = {}
    for _, row in ipairs(query) do
        formatDetails[row.Stat_ID] = {Stat_Display = row.Stat_Display, Stat_Color = row.Stat_Color, Stat_Type = row.Stat_Type}
    end
    return formatDetails
end

function p.item(frame)
	local itemName = frame.args[1]
	--local itemName = "Gabriel's Broken Wings"
	local fetchItem = p.fetchItemDetails(itemName)
	local item = fetchItem[1]
	frame:callParserFunction("#vardefine", { "itemData", mw.text.jsonEncode(item) })
	local image = cfg.imageFormat(item.Item_Type, item.Item_Name)
	local itemBox = {}
	
	table.insert(itemBox, string.format('<div class="item-box %s">', item.Item_Rarity)) -- ADD RARITY TO DROPDOWN FOR COLOR HERE
	
	table.insert(itemBox, '<div class="item-header">')
	table.insert(itemBox, string.format('<p class="item-name">%s</p>', item.Item_Name or 'Item Name'))
	
    -- Determine what type information to include
    local itemDescription = item.Item_Type
    if game.isWeaponType(item.Item_Type) or game.isArmorType(item.Item_Type) then
        itemDescription = string.format('%s %s', item.Item_Rarity, item.Item_Type)
    end

    -- Insert rarity and type information
    table.insert(itemBox, string.format('<p class="item-rarity-type">%s</p>', itemDescription))
    if item.Item_Rarity == "Runeword" then
		table.insert(itemBox, p.formatRuneWord(item.Item_Name))
    end
	table.insert(itemBox, '</div>')
	
	
	table.insert(itemBox, string.format('<p class="item-image">[[File:%s]]</p>', image or 'Item Name'))
	
	table.insert(itemBox, p.formatItemStats(item.Item_Name))
	
	if item.Item_Set and item.Item_Set ~= "" then
		table.insert(itemBox, p.formatItemSet(item.Item_Name, item.Item_Set))
	end
	
	
	table.insert(itemBox, string.format('<div class="item-lore"><p>%s</p></div>', item.Item_Lore or ''))
	
	if game.isWeaponType(item.Item_Type) then
		table.insert(itemBox, string.format('<p class ="attributes"><span>[%s]</span><span>[%s]</span></p>', item.Item_Type or '', item.Item_Weapon_Class or ''))
	end
	
	
	table.insert(itemBox, string.format('<p class ="attributes"><span>Level Req. %s</span>',item.Item_Level_Requirement or ''))
	if not game.isMiscType(item.Item_Type) then
        -- Include the item tier if the item is not a miscellaneous type
        table.insert(itemBox, string.format('<span>Tier: <span class="tier-%s">%s</span></span>',item.Item_Tier, item.Item_Tier or 'Unknown'))
    end
	table.insert(itemBox, '</p>')
	
	table.insert(itemBox, '</div>')
	
	return table.concat(itemBox)
end

function p.formatItemStats(itemName)
    local cargo = mw.ext.cargo
	local where = string.format("Item_Name = '%s'", func.encodeName(itemName))
    local statsQuery, queryError = cargo.query(
        'item_stats',
        'Stat_ID, Spell_Name, Class_Name, Min_Value1, Max_Value1, Min_Value2, Max_Value2, Min_Value3, Max_Value3, Stat_Order',
        {
            where = where,
            orderBy = "Stat_Order"
        }
    )

    local formatDetails = p.fetchFormatDetails()
    local baseStats = {}
    local nonBaseStats = {}

	local defense, block, damage, aps = 'N/A', 'N/A', 'N/A', 'N/A'  -- Default values
    local minRangeAS, maxRangeAS, minRangeED, maxRangeED= 0, 0, 0, 0

	for _, stat in ipairs(statsQuery) do
    		if stat.Stat_ID == 'enhanced_defense_percent' or stat.Stat_ID == "enhanced_defense_based_on_level_percent" or stat.Stat_ID == 'enhanced_dmg_percent' or stat.Stat_ID == "enhanced_dmg_based_on_level_percent" then
        		minRangeED = tonumber(stat.Min_Value1) + minRangeED
        		maxRangeED = tonumber(stat.Max_Value1) or tonumber(stat.Min_Value1) + maxRangeED
    		elseif stat.Stat_ID == 'attack_speed_percent' then
    			minRangeAS = tonumber(stat.Min_Value1)
    			maxRangeAS = tonumber(stat.Max_Value1) or tonumber(stat.Min_Value1)
    		end
		end

        for _, stat in ipairs(statsQuery) do
            if stat.Stat_ID == 'attack_dmg_base' or stat.Stat_ID == 'attacks_per_second_base' or stat.Stat_ID == 'defense_base' or stat.Stat_ID == 'block_chance_base' then
                if stat.Stat_ID == 'defense_base' then
            		local minDefense = tonumber(stat.Min_Value1) * (1 + minRangeED/100)
            		local maxDefense = tonumber(stat.Max_Value1 or stat.Min_Value1) * (1 + maxRangeED/100)
                    table.insert(baseStats, string.format('<p class="base-stat">Defense: [%s-%s]</p>', math.ceil(minDefense), math.ceil(maxDefense)))
                elseif stat.Stat_ID == 'block_chance_base' then
                    table.insert(baseStats, string.format('<p class="base-stat">Block Chance: %s</p>', stat.Min_Value1))
                elseif stat.Stat_ID == 'attack_dmg_base' then
                    local minDamage = tonumber(stat.Min_Value1) * (1 + minRangeED/100)
            		local maxDamage = tonumber(stat.Max_Value1) * (1 + maxRangeED/100)
                    table.insert(baseStats, string.format('<p class="base-stat">Attack Damage: [%s-%s]</p>', math.ceil(minDamage), math.ceil(maxDamage)))
                elseif stat.Stat_ID == 'attacks_per_second_base' then
                    local minAttackSpeed = (tonumber(stat.Min_Value1) * (1 + minRangeAS/100)) * 100
                    minAttackSpeed = math.ceil(minAttackSpeed)
                    minAttackSpeed = minAttackSpeed / 100
            		local maxAttackSpeed = (tonumber(stat.Min_Value1) * (1 + maxRangeAS/100)) * 100
                    maxAttackSpeed = math.ceil(maxAttackSpeed)
                    maxAttackSpeed = maxAttackSpeed / 100
            		if minAttackSpeed == maxAttackSpeed then
            		table.insert(baseStats, string.format('<p class="base-stat">Attacks per Second: %s</p>', minAttackSpeed))
            		else
                    table.insert(baseStats, string.format('<p class="base-stat">Attacks per Second: [%s-%s]</p>', minAttackSpeed, maxAttackSpeed))
                    end
                end
            elseif stat.Stat_ID == 'socketed_flat' then
            	if stat.Max_Value1 and stat.Max_Value1 ~= "" then
	    			table.insert(nonBaseStats, string.format('<p class="stat-default">Socketed (%s-%s)</p>', stat.Min_Value1, stat.Max_Value1))            		
	    		else
	    			table.insert(nonBaseStats, string.format('<p class="stat-default">Socketed (%s)</p>', stat.Min_Value1))	    			
	    		end
        	else
                table.insert(nonBaseStats, p.formatStatLine(stat, formatDetails))
    	end
	end
    -- Combine formatted stats into sections
    return string.format(
        '<div class="item-basestats">%s</div><div class="item-stats">%s</div>',
        table.concat(baseStats, "\n"),
        table.concat(nonBaseStats, "\n")
    )
end

function p.formatStatLine(stat, formatDetails)
    local statDetail = formatDetails[stat.Stat_ID]
    local formattedStat = statDetail and statDetail.Stat_Display or stat.Stat_ID
    mw.logObject(statDetail)
    -- Replace placeholders for value1, value2, and value3
    if stat.Min_Value1 and stat.Min_Value1 ~= "" and tonumber(stat.Min_Value1) >= 0 then formattedStat = formattedStat:gsub("value1", p.formatRange(stat.Min_Value1, stat.Max_Value1)) end
	if stat.Min_Value1 and stat.Min_Value1 ~= "" and tonumber(stat.Min_Value1) < 0 then
	    local formattedRange = p.formatRange(stat.Min_Value1, stat.Max_Value1)
	    formattedStat = formattedStat:gsub("[+]?[vV]alue1", formattedRange)
	end
    if stat.Min_Value2 and stat.Min_Value2 ~= "" then formattedStat = formattedStat:gsub("value2", p.formatRange(stat.Min_Value2, stat.Max_Value2)) end
    if stat.Min_Value3 and stat.Min_Value3 ~= "" then formattedStat = formattedStat:gsub("value3", p.formatRange(stat.Min_Value3, stat.Max_Value3)) end
    if stat.Spell_Name and stat.Spell_Name ~= "" then formattedStat = formattedStat:gsub("spellvalue", string.format('<span class="item-stat-spell-link">[[%s|[%s]]]</span>', stat.Spell_Name, stat.Spell_Name)) end
    if stat.Class_Name and stat.Class_NAme ~= "" then formattedStat = formattedStat .. string.format(" (%s)", stat.Class_Name) end
    if statDetail and statDetail.Stat_Type == "none" then formattedStat = string.format("[[%s]]", formattedStat) end
    local class = "stat-" .. (statDetail and statDetail.Stat_Color or "default")
    return string.format('<p class="%s">%s</p>', class, formattedStat)
end

function p.formatItemSet(itemName, setName)
	local cargo = mw.ext.cargo
	local where = "Set_Name = '" .. func.encodeName(setName) .. "'"
    local query = cargo.query(
        "item_sets",
        "Set_Name, Set_Item_1, Set_Item_2, Set_Item_3, Set_Item_4, Set_Item_5, Set_Item_6, Set_Bonus_1, Set_Bonus_2, Set_Bonus_3, Set_Bonus_4, Set_Bonus_5",
        { where = where }
    )
    local setInfo = query[1]  -- Assuming there's only one set with this name
    -- Start building the display
    local output = {}
    table.insert(output, '<div class="item-stats">')
    for i = 1, 10 do
        local bonusField = "Set_Bonus_" .. i
        if setInfo[bonusField] and setInfo[bonusField] ~= '' then
            table.insert(output, string.format("<p>%s</p>", setInfo[bonusField]))
        end
    end
	table.insert(output, '</div>')
	
	table.insert(output, '<div class="item-stats">')
    table.insert(output, string.format('<p class="set-name">%s</p>', setInfo.Set_Name))

    -- Display set items
    for i = 1, 6 do
        local itemField = "Set_Item_" .. i
        if setInfo[itemField] and setInfo[itemField] ~= '' then
            table.insert(output, string.format('<p class="set-item">%s</p>', setInfo[itemField]))
        end
    end
	table.insert(output, '</div>')
    return table.concat(output)
end

function p.formatRuneWord(itemName)
    local where = "Runeword_Name = '" .. func.encodeName(itemName) .. "'"

    -- Query the runewords
    local query = cargo.query(
        "runewords",
        "Runeword_Name, Runeword_Item_Type, Rune_1, Rune_2, Rune_3, Rune_4, Rune_5, Rune_6, Sockets",
        { where = where }
    )

    -- Ensure the query returned results
    if #query == 0 then
        return "No runeword found."
    end

    -- Extract the runes from the query result
    local runeword = query[1]
    local runes = {}
    for i = 1, 6 do
        local rune = runeword["Rune_" .. i]
        if rune and rune ~= "" then
            table.insert(runes, rune)
        end
    end

    -- Construct the format string based on the number of runes
    local formatString = string.format("(%s)", string.rep("%s, ", #runes):sub(1, -3))

    -- Format the extracted runes
    local formattedRunes = string.format(formatString, unpack(runes))

    return formattedRunes
end

function p.formatRange(min, max)
    if max and max ~= '' and max ~= min then
        return "[" .. min .. "-" .. max .. "]"
    else
        return min
    end
end

function p.isWeaponType(itemType)
	local weaponTypes = {
    Sword = true,
    Dagger = true,
    Mace = true,
    Axe = true,
    Claw = true,
    Polearm = true,
    Chainsaw = true,
    Staff = true,
    Cane = true,
    Wand = true,
    Book = true,
    Spellblade = true,
    Bow = true,
    Gun = true,
    Flask = true,
    ["Throwing Weapon"] = true }
    
    return weaponTypes[itemType] or false
end

function p.isArmorType(itemType)
	local armorTypes = {
		Helmet = true,
		["Body Armor"] = true,
		Gloves = true,
		Belt = true,
		Amulet = true,
		Ring = true,
		Boots = true,
		Shield = true,
		Charm = true,
	}
	
	return armorTypes[itemType] or false
end

function p.isMiscType(itemType) 
	local miscTypes = {
	Consumable = true,
	Potion = true,
	Key = true,
	Material = true,
	Collectible = true
	}
	
	return miscTypes[itemType] or false
end

return p