Module:Potion price

Revision as of 21:22, 4 November 2021 by Admin (talk | contribs) (1 revision imported)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

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

-- todo modulise
local yn = require('Module:Yesno')
local round = require('Module:Number')._round
local var = mw.ext.VariablesLua
local GEPrices = mw.loadData('Module:GEPrices/data')
local data = mw.loadData('Module:Potion price/data')
local infoOrder = { 'scroll', 'mask', 'well', 'brooch', 'factory', 'amulet', 'noamuletcost', 'desert', 'improved', 'herb120' }
local improvedMap = {[0] = '', [1] = '_1', [2] = '_2'}
local info = {}
local amuletCostPerPotion = 0

local p = {}

function expr(x)
	local expr_good, expr_val = pcall(mw.ext.ParserFunctions.expr, x)
	if expr_good then
		return expr_val
	else
		return 1
	end
end

function gep(i)
    local pr = GEPrices[i]
    if pr then
        return pr
    end
    return 0
end

function calcPotion(pot, num)
	local variableKey = {}
    for i,v in ipairs(infoOrder) do
        if type(info[v]) == 'number' then
        	table.insert(variableKey, tostring(info[v]))
    	elseif info[v] then
            table.insert(variableKey, '1')
        else
            table.insert(variableKey, '0')
        end
    end
    variableKey = string.format('%s_%s', pot, table.concat(variableKey,''))
    if var.varexists(variableKey) then
    	return (tonumber(var.var(variableKey)) or 0) * num
    end
    local pdata = data[pot]
    if pdata.improvable then
    	pdata = data[pot..improvedMap[tonumber(info.improved) or 0]]
    end
    local total = 0
    local ingredNumber = 0
    local isBatch = pdata.herb120 and info.herb120
    for i,v in ipairs(pdata.ingredients) do
        local name, price, qty
        if type(v) == 'string' then
            name = v
            qty = 1
            price = gep(name)
        else
            name = v[1]
            qty = v.qty or 1
            if v.val then
                price = v.val
            elseif v.r then
                price = calcPotion(name,1)
            else
                price = gep(name)
            end
        end
        local add = qty * price
        if pdata.type == 'potion' and i == 2 and info.scroll then
        	-- standard potion - only secondary has a chance at being saved
        	add = add * 0.9
        end
        total = total + add
        ingredNumber = i
    end
    if pdata.type ~= 'potion' and info.scroll then
        -- overloads and crystal potions - saves any one of the ingredients with a reduced rate
        -- 10% for any saving, equally between all ingreds = overall (10/#ingreds)% saving
    	total = total * (1 - 0.1/ingredNumber)
    end
    local doublePotChance = 1
    if pdata.type == 'powerburst' then
    	total = total + gep('Powerburst vial')
    elseif pdata.type == 'bomb' then
    	total = total + gep('Bomb vial')
    elseif pdata.type == 'crystal' then
    	-- if it is crystal, add crystal flask price
    	total = total + gep('Crystal flask')
    elseif pdata.type == 'combination' and pdata.basepot then
    	total = total + calcPotion(pdata.basepot, 1)
    end
    if pdata.type ~= 'crystal' and pdata.type ~= 'combination' then
        -- these do not apply to crystal flasks
        if info.well then
        	local well_double_chance = 0.05
        	if info.brooch then
        		well_double_chance = 0.1
        	end
        	if isBatch then
        		-- when it procs on batches it gives +1 potion, not +5
        		-- effectively 1/5 the chance
        		doublePotChance = doublePotChance + well_double_chance/5
        	else	
            -- portable well duplication
    			doublePotChance = doublePotChance + well_double_chance
    		end
        end
        -- 4-instead-of-3-dose potions from factory outfit and botanist amulet
        -- we aren't considering morytania legs, as they're only used to make prayer renewals, which are tradeable
    	local doseMul = 0
    	if info.factory and not isBatch then
    		-- factory outfit
    		-- batches don't work
    		doseMul = doseMul + 0.1
    	end
    	if info.desert and pdata.desert then
    		-- desert amulet overriding botanist amulet
    		doseMul = doseMul + 0.2
    	elseif info.amulet and not isBatch then
    		-- botanist amulet
    		-- batches don't work
    		doseMul = doseMul + 0.05
    	end
    	-- X chance of making 4 dose
    	-- the 4 dose ones have a per-dose cost that is 3/4 of making a normal 3-dose
    	-- thus you have X that cost 3/4 and (1-X) that cost normal amount
    	-- = (1-X)*1 + 3/4*X
    	-- = 1 + (3/4-1)*X
    	-- = 1 - 1/4*X = 1-X/4
    	total = total * (1 - doseMul/4)
    	if not isBatch then
    		total = total + amuletCostPerPotion
    	end
    end
    if info.mask then
        -- modified botanist mask duplication
        if isBatch then
    		-- when it procs on batches it gives +1 potion, not +5
    		-- effectively 1/5 the chance
        	doublePotChance = doublePotChance + 0.01
        else
    		doublePotChance = doublePotChance + 0.05
    	end
    end
    if isBatch then
    	total = total * 4/5
    end
    total = total / doublePotChance
    var.vardefine(variableKey, total)
    return total * num
end


function p.main(frame)
    return p._main(frame:getParent().args)
end

function p._main(args)
    local potion = args[1]:lower():gsub('potion', ''):gsub('%(%d%)', '')
    potion = mw.text.trim(potion)
    if not data[potion] then
        return 'Invalid potion name: '..args[1]
    end
    for i,v in ipairs(infoOrder) do
        info[v] = yn(args[v], false) or false
    end
    if info.amulet then
    	if not info.noamuletcost then
    		amuletCostPerPotion = gep("Botanist's amulet") / 100
    	end
    end
    info.improved = tonumber(args.improved) or 0
    local pprice = calcPotion(potion, expr(args[2]) or 1)
    if tonumber(args.round) then
    	pprice = round(pprice, args.round)
    end
    return pprice
end

function p._list()
	local l = {}
	for k,v in pairs(data) do
		table.insert(l, k)
	end
	table.sort(l)
	return '* '..table.concat(l, '\n* ')
end

return p