Documentation for this module may be created at Module:FFVIII enemy stats/doc

p = {}

local getArgs = require('Dev:Arguments').getArgs

local enemystats = {
    { name = "Lv",  formula = 5, width = 10 },
    { name = "HP",  formula = 1, width = 20 },
    { name = "STR", formula = 2, width = 10 },
    { name = "MAG", formula = 2, width = 10 },
    { name = "VIT", formula = 3, width = 10 },
    { name = "SPR", formula = 3, width = 10 },
    { name = "SPD", formula = 3, width = 10 },
    { name = "EVA", formula = 3, width = 10 },
    { name = "EXP", formula = 4, width = 10 }
}

local characterstats = {
    { name = "LV", formula = 5, width = 12.5 },
    { name = "HP", formula = 7, width = 12.5 },
    { name = "Str", formula = 2, width = 12.5 },
    { name = "Vit", formula = 2, width = 12.5 },
    { name = "Mag", formula = 2, width = 12.5 },
    { name = "Spr", formula = 2, width = 12.5 },
    { name = "Spd", formula = 3, width = 12.5 },
    { name = "Luck", formula = 3, width = 12.5 }
}

function p.collapsiblestattable(frame)
    local data = {}
    local stats = enemystats
    for k,v in pairs(frame.args) do
        data[k] = tonumber(v)
    end
    return onetohundredtable(data, stats)
end

function p.charactercollapsiblestattable(frame)
    local data = {}
    local stats = characterstats
    local fargs = getArgs(frame)
    for k,v in pairs(fargs) do
        data[k] = tonumber(v)
    end
    return onetohundredtable(data, stats)
end


--function to get defaults and fill in missing variables
function setDefaults(defaults, a, b, c, d)
    return
        a or defaults[1],
        b or defaults[2],
        c or defaults[3],
        d or defaults[4]
end

local formulas = {
    {
        func = function(lv, a, b, c)
            a, b, c = setDefaults({ 0, 0, 0 }, a, b, c)
            return math.floor((lv^2*a) + (lv*b) + c)
        end,
        formula = function(a, b, c)
            a, b, c = setDefaults({ 0, 0, 0 }, a, b, c)
            local formula = ""
            if a ~= 0 then
                formula = (a==1 and "" or a) .. "(Lv)²";
            end
            if b ~= 0 then
                if formula ~= "" then formula = formula .. " + " end
                formula = formula .. (b==1 and "" or b) .."(Lv)"
            end
            if c ~= 0 then
                if formula ~= "" then formula = formula .. " + " end
                formula = formula .. c
            end
            return formula
        end
    },
    {
        func = function(lv, a, b, c, d)
            a, b, c, d = setDefaults({ 10, 1, 4, 1 }, a, b, c, d)
            
            local calc = math.floor((math.floor(lv*a/10)+math.floor(lv/b)-math.floor(math.floor(lv^2/d)/2)+c)/4)
            return math.min(calc, 255)
        end,
        formula = function(a, b, c, d)
            a, b, c, d = setDefaults({ 10, 1, 4, 1 }, a, b, c, d)

            local formula = "("
            local aCalc = a/10
            if b==1 then
                aCalc = aCalc + 1
            end
            formula = formula .. "[" .. (aCalc ~= 1 and aCalc or "") .. "(Lv)]"
            if b ~= 1 then
                formula = formula .. " + [(Lv) / " .. b .. "]"
            end
            formula = formula .. " - " .. "[(Lv)² / " .. (2*d) .. "]"
            if c ~=0 then
                formula = formula .. " + " .. c
            end
            formula = formula .. ") / 4"
            return formula
        end
    },
    {
        func = function(lv, a, b, c, d)
            a, b, c, d = setDefaults({ 0, 1, 0, 1 }, a, b, c, d)

            local calc = math.floor(lv/b)-math.floor(lv/d)+(lv*a)+c
            return math.min(calc, 255)
        end,
        formula = function(a, b, c, d)
            a, b, c, d = setDefaults({ 0, 1, 0, 1 }, a, b, c, d)
            local formula = ""

            local disone = false

            if b ~= d then
                formula = "(Lv)"
                if b ~= 1 then
                    formula = "(" .. formula .. " / " .. b .. ")"
                end
                if d == 1 then
                    disone = true
                else
                    formula = formula .. " - [(Lv) / " .. d .. "]"
                end
            end
            if a == 1 and disone then
                
            else
                if disone then
                    formula = formula .. " - (Lv)"
                end
                if a ~= 0 then
                    if formula ~= "" then
                        formula = formula .. " + "
                    end
                    formula = formula .. (a==1 and "" or a) .. "(Lv)"
                end
            end
            if c ~= 0 then
                if formula ~= "" then
                    formula = formula .. " + "
                end
                formula = formula .. c
            end
            if formula == "" then formula = "0" end
            return formula
        end
    },
    {
        func = function(lv, a, b)
            a, b = setDefaults({ 0, 0 }, a, b)

            return (a*lv)+b
        end,
        formula = function(a, b)
            a, b = setDefaults({ 0, 0 }, a, b)

            local formula = ""
            if a ~= 0 then
                formula = (a==1 and "" or a) .. "(Lv)²"
            end
            if b ~= 0 then
                if formula ~= "" then formula = formula .. " + " end
                formula = formula .. b
            end
            if formula == "" then formula = "0" end
            return formula
        end
    },
    {
        func = function()end,
        formula = function()end,
    },
    {--formula[1] is a refactored HP formula the wiki uses. this formula[6] is the true inputs
        func = function(lv, a, b, c, d)
            a, b, c, d = setDefaults({ 0, 0, 0, 0 }, a, b, c, d)
            return formulas[1].func(lv, a/20, a+(c*100), d*1000 + b*10)
        end,
        formula = function(a, b, c, d)
            a, b, c = setDefaults({ 0, 0, 0, 0 }, a, b, c, d)
            return formulas[1].formula(lv, a/20, a+(c*100), d*1000 + b*10)
        end
    },
    {--formula[7] - character HP
        func = function(lv, a, b, c)
            a, b, c = setDefaults({ 0, 255, 0 }, a, b, c)

            return a*lv - math.floor(lv*lv*10/b) + c
        end,
        formula = function(a, b, c)
            a, b, c = setDefaults({ 0, 255, 0 }, a, b, c)
            local formula = ""
            local btxt = "[(Lv)² * 10 / " .. b .. "]"
            if a ~= 0 then
                formula = a .. "(Lv) - " .. btxt
                if c ~= 0 then
                    formula = formula .. " + " .. c
                end
            else
                formula = c - btxt
            end
            return formula
        end
    },
    {--formula[8] - character EXP (for completion. every char's the same and the formula goes to waste)
        func = function(lv, a, b)
            a, b = setDefaults({ 100, 0 }, a, b)

            return ((lv-1)*(lv-1)*b)/256 + (lv-1)*a*10
        end,
        formula = function(a, b)
            a, b = setDefaults({ 100, 0 }, a, b)
            local formula = ""
            local atxt
            if a then atxt = "((Lv)-1) * " .. (a*10) end
            if b then
                formula = "[((Lv)-1)² * " .. b .. " / 256]"
                if atxt then
                    formula = formula  .. " + " .. atxt
                end
            elseif atxt then
                formula = atxt
            else
                formula = 0
            end
            return formula
        end
    }
}


--
--Calculates a given stat (e.g. "STR") at a given level,
--with the given variables. parameters in that order
--
function p.statcalc(frame)
    gargs = getArgs(frame.args)
    local stats = enemystats
    local args = {}
    for k,v in pairs(gargs) do
        args[k] = tonumber(gargs[k])
    end
    args[1] = gargs[1]

    for i = 2, #stats do
        if stats[i].name==args[1] then return formulas[stats[i].formula].func(args[2], args[3], args[4], args[5], args[6]) end
    end
end

--
--Generates the formula for a given stat (e.g. "STR")
--with the given variables. parameters go stat then parameters in order
--
function p.statformula(frame)
    gargs = getArgs(frame.args)
    local stats = enemystats
    local args = {}
    for k,v in pairs(gargs) do
        args[k] = tonumber(gargs[k])
    end
    args[1] = gargs[1]

    for i = 2, #stats do
        if stats[i].name==args[1] then return formulas[stats[i].formula].formula(args[2], args[3], args[4], args[5]) end
    end
end

--
--One to hundred table
--
function onetohundredtable(data, stats)
    --
    --i need to set a default so i need a variable for at least these
    --
    local lvMin = data["lv min"] or 1--I think this is only for Ifrit
    local lvMax = data["lv max"] or 100

    local currenttable = mw.html.create("table")
        :addClass("FFVIII")
        :css("text-align", "center")

    local minimize = data["minimize"] == true

    if minimize then
        currenttable
        :cssText("font-size", "8pt")
        :css("width", "270px")
    else
        currenttable:addClass("article-table")

    end

    local tr = currenttable:tag("tr")
        :addClass("a")

    for i=1, #stats do
        local thisstat = stats[i]
        local th = tr:tag("th")
            :wikitext(thisstat.name)
            
        if not minimize then
            th:css("width", thisstat.width .. "%")
        end
    end

    
    
    local collapsibletr = {
        [1] = true,
        [10] = true,
        [20] = true,
        [30] = true,
        [40] = true,
        [50] = true,
        [60] = true,
        [70] = true,
        [80] = true,
        [90] = true,
    }
    
    local uncollapsible = {
        [lvMax] = true
    }
    
    --this here is to stop, e.g. 10 from being set to collapsible when the max is 11
    if collapsibletr[lvMax-1] then
        uncollapsible[lvMax-1] = true
    end

    -- i is for LEVEL
    for i = lvMin, lvMax do
        --
        -- EVERY LEVEL
        --
        local tr = currenttable:tag("tr")
            :tag("th")
            :addClass("b")
            :wikitext(i)
            :done()

        local collapsiblerow

        if uncollapsible[i] then
            tr:addClass("uncollapsible")
        elseif collapsibletr[i] then
            collapsiblerow = true
            tr
                :addClass("collapsibletr")
                :addClass("collapsed")
        end

        --
        -- EACH STAT EVERY LEVEL
        --
        for j=2, #stats do
            local thisstat = stats[j]
            local statname = thisstat.name
            local statformula = formulas[thisstat.formula].func 
            tr:tag("td")
                :wikitext(statformula(
                    i, --level
                    data[(statname:lower() .. " a")],
                    data[(statname:lower() .. " b")],
                    data[(statname:lower() .. " c")],
                    data[(statname:lower() .. " d")]
                ))
        end
    end

    return currenttable
end

function consolidateRates(chance, ...)
  local items = require "Module:Table".pack(...)
  local itemList = {}
  local total = 0
  for i=1, #chance do
    if i~=4 and items[i]==items[i+1] then
      chance[i+1] = chance[i+1] + chance[i]
    else
      table.insert(itemList, { items[i], chance[i] })
      total = total + chance[i]
    end
  end
  local output = ""
  for i=1, #itemList do
    local dp = 2
    local percent = math.floor((10^(dp+2)/total)*itemList[i][2])/10^dp
    local element = mw.html.create("abbr")
     :attr("title", itemList[i][2] .. "/" .. total)
     :wikitext(percent .. "%")
    output = output .. itemList[i][1] .. " (" .. tostring(element) .. ")"
    if i ~= #itemList then
      output = output .. "<br/>"
    end
  end
  return output
end

function p.mug(frame)
    local args = getArgs(frame.args)
    local emptytext = args[5] or "Nothing"
    if not args[1] and not args[2] and not args[3] and not args[4] then return emptytext end
    if not args[1] then args[1] = emptytext end
    if not args[2] then args[2] = emptytext end
    if not args[3] then args[3] = emptytext end
    if not args[4] then args[4] = emptytext end
    local chance = { 178, 51, 15, 12 }
    return consolidateRates(chance, args[1], args[2], args[3], args[4])
end

function p.drop(frame)
    local args = getArgs(frame.args)
    local emptytext = args[5] or "Nothing"
    if not args[1] and not args[2] and not args[3] and not args[4] then return emptytext end
    if not args[1] then args[1] = emptytext end
    if not args[2] then args[2] = emptytext end
    if not args[3] then args[3] = emptytext end
    if not args[4] then args[4] = emptytext end
    local chance = { 178, 51, 15, 12 }
    local normalrates = consolidateRates(chance, args[1], args[2], args[3], args[4])
    local chance = { 128, 114, 14 }
    local rareitemrates = consolidateRates(chance, args[1], args[2], args[3])
    if normalrates == rareitemrates then
        return normalrates
    else
        return "<div class='mw-collapsible mw-collapsed'>'''Normal rates:'''<div class='mw-collapsible-content'>" .. normalrates .. "</div></div>" .. "<div class='mw-collapsible mw-collapsed'>'''Rare Item equipped:'''<div class='mw-collapsible-content'>"  .. rareitemrates  .. "</div></div>"
    end
end

return p
Community content is available under CC-BY-SA unless otherwise noted.