Module:Equipment

From Roat Pkz
Revision as of 13:57, 3 May 2024 by Hefner (talk | contribs)
Jump to navigation Jump to search

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

-- Current module being tested: Module:Equipment

local p = {}

local hasc = require('Module:Paramtest').has_content
local itemstats = require('Module:FetchItemStats')
local yesno = require('Module:Yesno')
local lang = mw.language.getContentLanguage()
local GEPrice = require('Module:Exchange')._price

-- Parse item string and check if GIF icons are allowed
local function parseItem(ret, itemString, equipSlot, stats, quantity)
    local itemString = itemString
    local allowGif = false
    local itemName = ""

    -- Look for a ;g at the end of the string and separate them
    if hasc(itemString) then
        allowGif = itemString:sub(-2) == ";g"
        if allowGif then
        	itemName = itemString:sub(0, -3)
        else
        	itemName = itemString or ""
        end
    end
    
    return ret, itemName, allowGif, equipSlot, stats, quantity
end

-- formats a number to thousands/millions
function formatAmount(_x)
    local x = tonumber(_x) or 1
    if x < 100000 then
        return x, 'qty-1'
    elseif x < 10000000 then
        return tostring(math.floor(x/1000))..'K', 'qty-100k'
    else
        return tostring(math.floor(x/1000000))..'M', 'qty-10m'
    end
end


-- Formats a <div> element for items
local function makeDiv(ret, itemName, allowGif, equipSlot, stats, quantity)
    local itemName = itemName
    local allowGif = allowGif
    local topDivClass = "equipment-" .. equipSlot

	local names = mw.text.split(itemName, ";")
	if #names <= 1 or names[2] == 'g' then
		names[2] = itemstats.defaultVersion(names[1]) or names[1]
	end

    local imgType = allowGif == true and "gif" or "png"

    -- Use proper item icon/link and background, if item is present or not
    if itemName == '' then
        equipSlotText = ""
    else
        equipSlotText = string.format("[[File:%s.%s|link=%s]]", names[1], imgType, names[2])
    end

    -- Create the divs
    local topDiv = ret
        :tag("div")
        :addClass(topDivClass)

    local nestedDiv = topDiv
        :tag("div")
        :addClass("equipment-plinkp")
        :wikitext(equipSlotText)

    if quantity then
    	local amt, quantclass = formatAmount(quantity)
	    nestedDiv:tag('span')
	    		:addClass('inv-quantity-text')
	    		:addClass(quantclass)
	    		:wikitext(amt)
	end

    if stats and itemName ~= '' then
	    local GEP = GEPrice(names[1], nil, nil, nil, -1)
    	local value = itemstats.value(names[2])
    	local name = names[1]
    	if allowGif then
    		-- restore ;g flag in order to be able to show a gif in the IKOD interface
    		name = name .. ';g'
    	end
		if GEP == -1 then
			table.insert(stats.ikods, {name, value})
		else
			table.insert(stats.ikods, {name, GEP})
		end
        local statstr = ''
        local statstbl = itemstats.equipmentStats({names[2]})[1]
        for stat, bonus in pairs(stats) do
        	if not statstbl then
        		-- do nothing, this item doesn't seem to exist
        	elseif statstbl[stat] then
	        	-- Note: technically not 100% true since two types of ammo don't combine to increase rstr
	        	-- but things like craw's bow or hvy ballista also give rstr in the weapon slot so this is
	        	-- not trivial to correct for. Just doing it this way works for almost all legit situations.
	        	stats[stat] = bonus + tonumber(statstbl[stat])
	        	if statstr == '' then
	        		statstr = bonus
	        	else
	        		statstr = statstr .. ',' .. bonus
	        	end
	        elseif stat ~= "ikods" then
	        	mw.log('Not found: ', itemName, equipSlot, stat)
	        	mw.logObject(statstbl)
	        end
        end
        nestedDiv:attr("data-gemw", GEP)
        	:attr("data-value", value)
        	:attr("data-bonuses", statstr)
    end

    if itemName ~= '' then
        topDiv:addClass("equipment-blank")
    end
end

function statsdata(ret, txt, val)
	if val >= 0 then
		if txt == "Magic damage" then
			val = string.format(": +%.1f%%", val)
		elseif string.find(txt, "Weight") then
			val = string.format(" %.1f kg", val)
		else
			val = ": +"..tostring(val)
		end
	else
		val = ": "..tostring(val)
	end
	ret:tag('data'):wikitext(txt..val):attr('value', val)
end

function statslist(ret, stats)
	local td = ret:tag("td"):addClass("equipment-stats"):tag("div")
	td:tag("b"):wikitext("Attack bonus")
	statsdata(td, 'Stab', stats['astab'])
	statsdata(td, 'Slash', stats['aslash'])
	statsdata(td, 'Crush', stats['acrush'])
	statsdata(td, 'Magic', stats['amagic'])
	statsdata(td, 'Range', stats['arange'])
	td:tag('b'):wikitext("Defence bonus")
	statsdata(td, 'Stab', stats['dstab'])
	statsdata(td, 'Slash', stats['dslash'])
	statsdata(td, 'Crush', stats['dcrush'])
	statsdata(td, 'Magic', stats['dmagic'])
	statsdata(td, 'Range', stats['drange'])
	td:tag('b'):wikitext("Other bonuses")
	statsdata(td, 'Melee strength', stats['str'])
	statsdata(td, 'Ranged strength', stats['rstr'])
	statsdata(td, 'Magic damage', stats['mdmg'])
	statsdata(td, 'Prayer', stats['prayer'])
	statsdata(td, '[[File:Weight icon.png|link=]]', stats['weight'])
end

function ikod(ret, stats)
	table.sort(stats.ikods, function(left, right)
		return left[2] > right[2]
	end)
	
	local risk = 0
	local smite = 0
	-- hidden td by default; will be shown when the IKOD button is pressed.
	local td = ret:tag("td"):addClass("equipment-ikod"):css("display", "none"):tag("div")
	td:tag("em"):wikitext("Items <b>KEPT</b> if not <strong>SKULLED</strong>:")
	local ul = td:tag("ul")
	for i, ikod in pairs(stats.ikods) do
		if i > 4 then
			-- Finish previous <ul> and insert a header that items will be lost.
		end
		it = ikod[1]
		val = ikod[2]
		local ftype = 'png'
		if it:sub(-2) == ';g' then
			ftype = 'gif'
			it = it:sub(0, -3)
		end
		if i == 4 then
			-- 4th item is only kept with protect item; create new header
			td:tag("hr")
			td:tag("em"):wikitext("Items <b>KEPT</b> if using <b>[[Protect Item|PROTECT ITEM]]</b>:")
			ul = td:tag("ul")
			ul:tag("li"):wikitext(string.format("[[File:%s.%s|link=|Kept-on-death value: %s]]", it, ftype, lang:formatNum(val)))
			smite = smite + tonumber(val)
			-- the rest of the items will be lost regardless; create a new header for that
			td:tag("hr")
			td:tag("em"):wikitext("Items sent to your <b>GRAVESTONE</b> or <strong>LOST</strong> to the player who killed you:")
			-- change currently active ul to a new one
			ul = td:tag("ul")
		else
			ul:tag("li"):wikitext(string.format("[[File:%s.%s|link=|Kept-on-death value: %s]]", it, ftype, lang:formatNum(val)))
			if i > 4 then
				risk = risk + tonumber(val)
				smite = smite + tonumber(val)
			end
		end
		i = i + 1
	end
	-- add an informative notice at the end
	td:tag("hr")
	td:tag("em"):wikitext("Data in this list is based purely on exchange or item value. " ..
		"See <b>[[Items Kept on Death]]</b> for info. " ..
		"The interface and items kept on death may vary in-game; [[RuneScape:General disclaimer|general disclaimer]]s apply.")
	return risk, smite
end

function p.main(frame)
    local args = frame:getParent().args
    local buttons = yesno(args.buttons, false)
    local stats = yesno(args.stats, false)

    local align
    if args.align == "right" then
        align = "equipment-right"
    elseif args.align == "center" then
        align = "equipment-center"
    else
        align = "equipment-left"
    end
    -- general 'equipment' class for the whole thing
    align = "equipment " .. align

	local tbl = mw.html.create("table"):addClass(align):tag("tr")
	local ret = tbl:tag("td"):tag("div")
	if stats then
		stats = {
			astab = 0,
			aslash = 0,
			acrush = 0,
			amagic = 0,
			arange = 0,
			dstab = 0,
			dslash = 0,
			dcrush = 0,
			dmagic = 0,
			drange = 0,
			str = 0,
			rstr = 0,
			mdmg = 0,
			prayer = 0,
			weight = 0,
			ikods = {},
		}
	end

    if buttons then
        ret:addClass("equipment-div-buttons")
    else
        ret:addClass("equipment-div")
    end

    -- Fetch equipment and create divs
    

	return tbl:done()
end

return p