Module:Attributes

From Fractured Wiki
Jump to navigation Jump to search
Documentation

This module is responsible for the output of race attribute tables.


-- Build racial attribute tables
local Utils = require("Module:Utils")
local mw = mw

local sprintf = Utils.sprintf
local upper = Utils.upper
local flatten = Utils.flatten

--[[------------------------------------------------]]
--[[----------------- MODULE DATA ------------------]]
--[[------------------------------------------------]]
--
-- indexes to race family table
local HUMANS = 1
local IRIDRA = 2
local HUMAN_IDXS = {HUMANS, IRIDRA}

local CHADRA = 3
local UDOADRA = 4
local NHEEDRA = 5
local ERWYDRA = 6
local BEASTMEN_IDXS = {CHADRA, UDOADRA, NHEEDRA, ERWYDRA}

local BLOOD = 7
local SHADOW = 8
local HELLFIRE = 9
local DEMON_IDXS = {BLOOD, SHADOW, HELLFIRE}

local race_idxs = flatten({HUMAN_IDXS, BEASTMEN_IDXS, DEMON_IDXS})

local valid_args = {
    ["HUMANS"] = HUMAN_IDXS,
    ["HUMAN"] = HUMAN_IDXS,
    ["BEASTMEN"] = BEASTMEN_IDXS,
    ["BEASTMEN"] = BEASTMEN_IDXS,
    ["DEMONS"] = DEMON_IDXS,
    ["DEMON"] = DEMON_IDXS,
    ["CHADRA"] = CHADRA,
    ["UDOADRA"] = UDOADRA,
    ["NHEEDRA"] = NHEEDRA,
    ["ERWYDRA"] = ERWYDRA,
    ["BLOOD"] = BLOOD,
    ["SHADOW"] = SHADOW,
    ["HELLFIRE"] = HELLFIRE,
    ["IRIDRA"] = IRIDRA
}

-- indexes to race attribute data
local STR = 1
local DEX = 2
local INT = 3
local CON = 4
local PER = 5
local CHA = 6
local CPS = 7 -- creation points
local AFF = 8 -- affinity

local attributes = {"STR", "DEX", "INT", "CON", "PER", "WIS", "POINTS"}

local race_attributes = {
    -- HUMANS
    {2, 2, 2, 2, 2, 2, 12, nil}, -- all
    {1, 2, 2, 1, 2, 2, 10, nil}, -- Iridra    
    -- BEASTMEN
    {2, 4, 0, 2, 2, 0, 10, nil}, -- chadra
    {0, 0, 0, 0, 0, 0, 0, nil}, -- udoadra
    {0, 0, 0, 0, 0, 0, 0, nil}, -- nheedra
    {0, 2, 4, 0, 2, 2, 10, nil}, -- erwydra
    -- DEMONS
    {0, 0, 0, 0, 0, 0, 0, nil}, -- blood
    {0, 0, 0, 0, 0, 0, 0, nil}, -- shadow
    {0, 0, 0, 0, 0, 0, 0, nil} -- hellfire
}

local MAX_ATTRIBUTE_VALUE = 21
local MIN_ATTRIBUTE_VALUE = 6

-- indexes to attribute table
local COST_NORMAL = 1
local COST_AFFINITY = 2

-- regular attribute cost and affinity attribute cost per level
local attribute_costs = {
    nil, nil, nil, nil, nil,
    {0, 0},
    {3, 2}, {3, 2},
    {2, 1}, {2, 1}, {2, 1}, {2, 1}, {2, 1}, {2, 1}, {2, 1},
    {3, 2}, {3, 2},
    {4, 3}, {4, 3}, {4, 3}, {4, 3}
}

-- table colors
local affinity_color = "lightblue"
local penalty_color = "red"
local bonus_color = "lightgreen"
local fmt_attr_td_style = "background-color:%s;color:black"

local family_tbl_headers = {
    "[[Human|HUMANS]]",
    "[[Human|IRIDRA]]",
    "[[Chadra|CHADRA]]",
    "[[Udoadra|UDOADRA]]",
    "[[Nheedra|NHEEDRA]]",
    "[[Erwydra|ERWYDRA]]",
    "[[Blood Demon|BLOOD]]",
    "[[Shadow Demon|SHADOW]]",
    "[[Hellfire Demon|HELLFIRE]]",
}

--[[------------------------------------------------]]
--[[--------------- MODULE FUNCTIONS ---------------]]
--[[------------------------------------------------]]
local p = require("Module:BaseModule"):newModule()

local main_args = {
    parentFirst = true,
    wrappers = {
        "Template/Attributes"
    }
}

p.main = p:makeInvokeFunc("_main", main_args)

--[[------------------------------------------------]]
--[[-------------- INTERNAL FUNCTIONS --------------]]
--[[------------------------------------------------]]
--
-- Table with all races and families
local function attribute_tbl()
    -- Build table depending on contents of race_idxs and race_attributes. As these are
    -- declared outside this function, they can be manipulated by the race and family
    -- functions. It's done this way to create the same table design regardless of what
    -- content is requested.
    local have_humans_header = false
    local have_beastman_header = false
    local have_demons_header = false

    local tbl = mw.html.create("table")
        :addClass("wikitable")
        :cssText("text-align: center")

    -- Build race header row
    local race_header = tbl
        :tag("tr")
        :cssText("font-size: 115%")
            :tag("th"):done()

    for _, idx in ipairs(race_idxs) do
        if have_humans_header == false and idx >= HUMANS and idx <= IRIDRA then
            race_header:tag("th")
            	:attr("colspan", #HUMAN_IDXS)
                :wikitext("[[Humans]]")
            :done()
            have_humans_header = true

        elseif have_beastman_header == false and idx >= CHADRA and idx <= ERWYDRA then
            race_header
            :tag("th")
                :attr("colspan", #BEASTMEN_IDXS)
                :wikitext("[[Wildfolk]]")
            :done()

            have_beastman_header = true

        elseif have_demons_header == false and idx >= BLOOD and idx <= HELLFIRE then
            race_header
            :tag("th")
                :attr("colspan", #DEMON_IDXS)
                :wikitext("[[Demon]]s")
            :done()

            have_demons_header = true
        end
    end
    race_header:done()

    -- Build family header row
    local family_header = tbl
        :tag("tr")
            :cssText("font-size: 90%")
            :tag("th"):done()

    for _, idx in ipairs(race_idxs) do
        family_header:tag("th")
            :cssText("padding: 2px 8px")
            :wikitext(family_tbl_headers[idx])
        :done()
    end
    family_header:done()

    -- Build attributes for table body
    local tr
    for idx, attr in ipairs(attributes) do
        tr = tbl
            :tag("tr")
                --:tag("td")
                :tag("th")
                    :wikitext(sprintf("'''%s'''", attr))
                :done()

        for ra_idx, race_attrs in ipairs(race_attributes) do
            local td = tr:tag("td")

            if race_attrs[idx] == 0 then
                td:wikitext("-")
            else
                if race_attrs[idx] < 0 then
                    td
                        :cssText(sprintf(fmt_attr_td_style, penalty_color))
                        :wikitext(race_attrs[idx])
                else
                    if race_attrs[AFF] == idx then
                        td
                            :cssText(sprintf(fmt_attr_td_style, affinity_color))
                            :wikitext("+" .. race_attrs[idx])
                    else
                        if CPS == idx then
                            -- only highlight first points if the table has humans in it as
                            -- they're the only ones who get the bonus
                            if have_humans_header == true and ra_idx == 1 then
                                td
                                :cssText(sprintf(fmt_attr_td_style, bonus_color))
                                :wikitext(race_attrs[idx])
                            else
                                td:wikitext(race_attrs[idx])
                            end
                        else
                            td
                                :cssText(sprintf(fmt_attr_td_style, bonus_color))
                                :wikitext("+" .. race_attrs[idx])
                        end
                    end
                end
            end
            
            td:done()
        end

        tr:done()
    end

    return tbl:allDone()
end

-- Table with race and all race families
-- Called as {{attributes|RACE}}
local function race_tbl(race)  --luacheck: ignore
    local attr_tbl = {}
    race_idxs = race

    for idx, ra_idx in ipairs(race_idxs) do
        attr_tbl[idx] = race_attributes[ra_idx]
    end

    race_attributes = attr_tbl

    return attribute_tbl()
end

-- Table with specific race family
-- Called as {{attributes|RACE|FAMILY}}
local function family_tbl(race, family)  --luacheck: ignore
    local attr_tbl = {}

    if race == HUMAN_IDXS then
        race_idxs = race
    else
        race_idxs = {family}
    end

    for idx, ra_idx in ipairs(race_idxs) do
        attr_tbl[idx] = race_attributes[ra_idx]
    end

    race_attributes = attr_tbl

    return attribute_tbl()

end

--[[------------------------------------------------]]
--[[---------------- PAGE FUNCTIONS ----------------]]
--[[------------------------------------------------]]
function p._main(args, frame)  --luacheck: ignore
    local race
    local family
    local tbl

    if args ~= nil then
        race = valid_args[upper(args[1])]
        family = valid_args[upper(args[2])]
    end

	if race == nil then
		tbl = attribute_tbl()
	else
		if family == nil then
			tbl = race_tbl(race)
		else
			tbl = family_tbl(race, family)
		end
	end

    return tostring(tbl)
end

-- Build table depicting attribute points cost when creating characters
function p.cost_table(frame)  -- luacheck: ignore
    local normal_cumulative_cost = 0
    local affinity_cumulative_cost = 0

    local tbl = mw.html.create("table")
        :addClass("wikitable")
        :cssText("text-align: center")
        :tag("tr")
            :tag("th")
                :wikitext("ATTRIBUTE SCORE")
            :done()
            :tag("th")
                :wikitext("ATTRIBUTE COST")
            :done()
            :tag("th")
                :wikitext("CUMULATIVE COST")
            :done()
            :tag("th")
                :wikitext("AFFINITY COST")
            :done()
            :tag("th")
                :wikitext("CUMULATIVE COST WITH AFFINITY")
            :done()
            :tag("th")
                :wikitext("POINTS SAVED WITH AFFINITY")
            :done()
        :done()
    
    local trs = {nil, nil, nil, nil, nil}
    local attr_cost, aff_cost, affinity_saved

    for score = MIN_ATTRIBUTE_VALUE, MAX_ATTRIBUTE_VALUE do
        attr_cost = attribute_costs[score][COST_NORMAL]
        aff_cost = attribute_costs[score][COST_AFFINITY]

        normal_cumulative_cost = normal_cumulative_cost + attr_cost
        affinity_cumulative_cost = affinity_cumulative_cost + aff_cost
        affinity_saved = normal_cumulative_cost - affinity_cumulative_cost

        local tr = mw.html.create("tr")

        if score == 10 or score == 18 then
            tr:cssText("background-color:orange; font-weight:bold")
        end

        tr
            :tag("td")
                :wikitext(score)
            :done()
            :tag("td")
                :wikitext(attr_cost)
            :done()
            :tag("td")
                :wikitext(normal_cumulative_cost)
            :done()
            :tag("td")
                :wikitext(aff_cost)
            :done()
            :tag("td")
                :wikitext(affinity_cumulative_cost)
            :done()
            :tag("td")
                :wikitext(affinity_saved)
            :done()
        :done()

        trs[score] = tr
    end

    for i = MAX_ATTRIBUTE_VALUE, MIN_ATTRIBUTE_VALUE, -1 do
        tbl:node(trs[i])
    end

    return tostring(tbl:allDone())
end

return p