Module:StormforgedController: Difference between revisions

From Against the Storm Official Wiki
(Fixed duplication)
(Enabling upgrade_from column)
Line 1: Line 1:
---
---
--- Generated by EmmyLua(https://github.com/EmmyLua)
--- Serves the Stormforged Cornerstones template by capturing input and using it to control the display of data.
--- Created by onken.
--- DateTime: 4/29/2024 9:27 PM
---
---
---@module StormforgedController
---@module StormforgedController
Line 23: Line 21:
local ARG_NAME = "name"
local ARG_NAME = "name"
local ARG_DESCRIPTION = "description"
local ARG_DESCRIPTION = "description"
local ARG_UPGRADABLE_ID = "upgrade_from_id"
local ARG_UPGRADABLE_ID = "upgrades_from_id"
local ARGS_EXCLUDE_LIST = "exclude"
local ARGS_EXCLUDE_LIST = "exclude"
local ARG_CAPTION = "caption"
local ARG_CAPTION = "caption"
Line 38: Line 36:
local TEMPLATE_PARAMETER_DESC = "description"
local TEMPLATE_PARAMETER_DESC = "description"
local TEMPLATE_PARAMETER_PRICE_META = "price_in_meta_resources"
local TEMPLATE_PARAMETER_PRICE_META = "price_in_meta_resources"
local TEMPLATE_PARAMETER_PRICE_VILL = "price_in_villagers"
local TEMPLATE_PARAMETER_PRICE_VILLAGER = "price_in_villagers"
local TEMPLATE_PARAMETER_UPGRA_META = "price_for_upgrade_in_meta_resources"
local TEMPLATE_PARAMETER_UPGRADE_META = "price_for_upgrade_in_meta_resources"
local TEMPLATE_PARAMETER_UPGRA_VILL = "price_for_upgrade_in_villagers"
local TEMPLATE_PARAMETER_UPGRADE_VILLAGER = "price_for_upgrade_in_villagers"
local TEMPLATE_PARAMETER_SHOW_REGULAR = "show_regular"
local TEMPLATE_PARAMETER_UPGRADE_FROM = "upgrades_from"


local TEMPLATE_CONTAINER_START = "StormforgedCornerstonesTable"
local TEMPLATE_CONTAINER_START = "StormforgedCornerstonesTable"
Line 88: Line 88:
--- Runs through the list of perk IDs and checks that a name exists for each one. If not, it throws an error identifying the offending ID.
--- Runs through the list of perk IDs and checks that a name exists for each one. If not, it throws an error identifying the offending ID.
---
---
---@param list table the list of unique identifiers for which to look up names
--- Works from the member variable altarIDs
---
local function validateNamesFromIDs()
local function validateNamesFromIDs()


Line 101: Line 102:
end
end


--- Takes a list of possible IDs and only loads the valid ones (Stormforged ones) to the member variable altardIDs. Skips all ids present in the exclude list.
--- Takes a list of possible IDs and only loads the valid ones (Stormforged ones) to the member variable altarIDs. Skips all ids present in the exclude list.
---
---
---@param newIDs table a list of possible IDs to add to main list
---@param newIDs table a list of possible IDs to add to main list
Line 154: Line 155:
         if regularID and regularID ~= "" then
         if regularID and regularID ~= "" then
             loadStormforgedIDs({ AltarEffectsData.getUpgradeWhereRegularID(regularID) }, excludeList)
             loadStormforgedIDs({ AltarEffectsData.getUpgradeWhereRegularID(regularID) }, excludeList)
            attemptedSearch = true
         end
         end


Line 213: Line 215:
     end
     end
     if regularID and regularID ~= "" then
     if regularID and regularID ~= "" then
         return "Stormforged Cornerstones upgraded from '" .. regularID .. "'"
         return "Stormforged Cornerstone upgraded from '" .. regularID .. "'"
     end
     end


Line 251: Line 253:
---@param desiredCaption string the caption for the table, if any
---@param desiredCaption string the caption for the table, if any
---@param skippingPrice string the flag for skipping prices in the table, if any
---@param skippingPrice string the flag for skipping prices in the table, if any
---@param showingRegular string flag if columns should be added
---@return string the wiki markup to display, now longer
---@return string the wiki markup to display, now longer
local function makeMarkupForTableStart(desiredCaption, skippingPrice, showingRegular)
local function makeMarkupForTableStart(desiredCaption, skippingPrice, showingRegular)
Line 256: Line 259:
     local templateParameters = {
     local templateParameters = {
         [TEMPLATE_PARAMETER_CAPTION] = desiredCaption,
         [TEMPLATE_PARAMETER_CAPTION] = desiredCaption,
         [TEMPLATE_PARAMETER_SKIP_PRICES] = skippingPrice
         [TEMPLATE_PARAMETER_SKIP_PRICES] = skippingPrice,
        [TEMPLATE_PARAMETER_SHOW_REGULAR] = showingRegular
     }
     }


Line 264: Line 268:
--- Calls the view (other templates) to render a single row of the table with data based on the provided identifier.
--- Calls the view (other templates) to render a single row of the table with data based on the provided identifier.
---
---
---@param id string the unique identifier of a Stormforged Cornerstone to use to add data to a new table row
---@param skippingPrice string the flag for skipping prices in the table, if any
---@param skippingPrice string the flag for skipping prices in the table, if any
---@param id string the unique identifier of a Stormforged Cornerstone to use to add data to a new table row
---@param showingRegular string flag if columns should be added
---@return string the wiki markup to display, now longer
---@return string the wiki markup to display, now longer
local function makeMarkupPerRow(skippingPrice, id)
local function makeMarkupPerRow(id, skippingPrice, showingRegular)


     local templateParameters = {
     local templateParameters = {
         [TEMPLATE_PARAMETER_ID] = id,
         [TEMPLATE_PARAMETER_ID] = id,
         [TEMPLATE_PARAMETER_DESC] = PerksData.getDescriptionByID(id)
         [TEMPLATE_PARAMETER_DESC] = PerksData.getDescriptionByID(id),
        [TEMPLATE_PARAMETER_SHOW_REGULAR] = showingRegular
     }
     }
    -- If showing this column, we need this data for all rows, since the author may have searched for other names or descriptions.
    if showingRegular == ARG_SHOW_REGULAR_FLAG_VALUE then
        templateParameters[TEMPLATE_PARAMETER_UPGRADE_FROM] = AltarEffectsData.getRegularVersionEffectID(id)
    end


     if skippingPrice ~= ARG_SKIP_PRICES_FLAG_VALUE then
     if skippingPrice ~= ARG_SKIP_PRICES_FLAG_VALUE then
         templateParameters[TEMPLATE_PARAMETER_PRICE_META] = AltarEffectsData.getPriceInMetaResources(id)
         templateParameters[TEMPLATE_PARAMETER_PRICE_META] = AltarEffectsData.getPriceInMetaResources(id)
         templateParameters[TEMPLATE_PARAMETER_PRICE_VILL] = AltarEffectsData.getPriceInVillagers(id)
         templateParameters[TEMPLATE_PARAMETER_PRICE_VILLAGER] = AltarEffectsData.getPriceInVillagers(id)
         templateParameters[TEMPLATE_PARAMETER_UPGRA_META] = AltarEffectsData.getUpgradePriceInMetaResources(id)
         templateParameters[TEMPLATE_PARAMETER_UPGRADE_META] = AltarEffectsData.getUpgradePriceInMetaResources(id)
         templateParameters[TEMPLATE_PARAMETER_UPGRA_VILL] = AltarEffectsData.getUpgradePriceInVillagers(id)
         templateParameters[TEMPLATE_PARAMETER_UPGRADE_VILLAGER] = AltarEffectsData.getUpgradePriceInVillagers(id)
     end
     end


Line 287: Line 298:
---
---
---@param skippingPrice string the flag for skipping prices in the table, if any
---@param skippingPrice string the flag for skipping prices in the table, if any
---@param showingRegular string flag if columns should be added
---@return string the wiki markup to display, now longer
---@return string the wiki markup to display, now longer
local function makeMarkupForTableRows(skippingPrice)
local function makeMarkupForTableRows(skippingPrice, showingRegular)


     local markup = ""
     local markup = ""
     for _, id in ipairs(altarIDs) do
     for _, id in ipairs(altarIDs) do
         markup = markup .. makeMarkupPerRow(skippingPrice, id)
         markup = markup .. makeMarkupPerRow(id, skippingPrice, showingRegular)
     end
     end



Revision as of 23:52, 1 May 2024

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

---
--- Serves the Stormforged Cornerstones template by capturing input and using it to control the display of data.
---
---@module StormforgedController
local StormforgedController = {}



--region Dependencies

local AltarEffectsData = require("Module:AltarEffectsData")
local PerksData = require("Module:PerksData")

--endregion



--region Private constants

local ARG_ID = "id"
local ARG_NAME = "name"
local ARG_DESCRIPTION = "description"
local ARG_UPGRADABLE_ID = "upgrades_from_id"
local ARGS_EXCLUDE_LIST = "exclude"
local ARG_CAPTION = "caption"
local ARG_SKIP_PRICES = "skip_prices"
local ARG_SKIP_PRICES_FLAG_VALUE = "skip"
local ARG_SHOW_REGULAR = "show_regular"
local ARG_SHOW_REGULAR_FLAG_VALUE = "show"

--local DISPLAY_OPTION_TABLE = "table"

local TEMPLATE_PARAMETER_CAPTION = "caption"
local TEMPLATE_PARAMETER_SKIP_PRICES = "skip_prices"
local TEMPLATE_PARAMETER_ID = "id"
local TEMPLATE_PARAMETER_DESC = "description"
local TEMPLATE_PARAMETER_PRICE_META = "price_in_meta_resources"
local TEMPLATE_PARAMETER_PRICE_VILLAGER = "price_in_villagers"
local TEMPLATE_PARAMETER_UPGRADE_META = "price_for_upgrade_in_meta_resources"
local TEMPLATE_PARAMETER_UPGRADE_VILLAGER = "price_for_upgrade_in_villagers"
local TEMPLATE_PARAMETER_SHOW_REGULAR = "show_regular"
local TEMPLATE_PARAMETER_UPGRADE_FROM = "upgrades_from"

local TEMPLATE_CONTAINER_START = "StormforgedCornerstonesTable"
local TEMPLATE_CONTAINER_SUFFIX_ROW = "/row"
local TEMPLATE_CONTAINER_SUFFIX_END = "/end"
local TEMPLATE_CONTAINER_SKIP_PRICES_VARIANT = "/SkipPrices"

local ERROR_PREFIX_NAME_NOT_FOUND = "StormforgedController attempted to retrieve the display name of a Stormforged Cornerstones, but it was not found. Double-check that the data is up-to-date and loaded correctly:"

--endregion



--region Private member variables

local currentFrame = {}
local altarIDs = {}
local isIDAlreadyAdded = {}

--endregion



--region Private methods

--- Helper comparison function to give to table.sort to sort the perk names alphabetically that correspond to the identifiers of Stormforged Cornerstones.
---
---@param altarID1 string the identifier of a Stormforged Cornerstone
---@param altarID2 string the identifier of a Stormforged Cornerstone
---@return boolean to sort the corresponding display names alphabetically
local function compareNames(altarID1, altarID2)

    local name1 = PerksData.getNameByID(altarID1)
    local name2 = PerksData.getNameByID(altarID2)

    if not name1 then
        error(ERROR_PREFIX_NAME_NOT_FOUND .. " id=" .. altarID1 .. ".")
    end
    if not name2 then
        error(ERROR_PREFIX_NAME_NOT_FOUND .. " id=" .. altarID2 .. ".")

    end

    return name1 < name2
end

--- Runs through the list of perk IDs and checks that a name exists for each one. If not, it throws an error identifying the offending ID.
---
--- Works from the member variable altarIDs
---
local function validateNamesFromIDs()

    for _, id in ipairs(altarIDs) do

       --Validate the names. This should never happen, but this is here to save hours of troubleshooting.
        local name = PerksData.getNameByID(id)
        if not name then
            error(ERROR_PREFIX_NAME_NOT_FOUND .. "id=" .. id)
        end
    end
end

--- Takes a list of possible IDs and only loads the valid ones (Stormforged ones) to the member variable altarIDs. Skips all ids present in the exclude list.
---
---@param newIDs table a list of possible IDs to add to main list
---@param excludeList table where keys are ids to skip and the values are `true`
local function loadStormforgedIDs(newIDs, excludeList)

    for _, id in ipairs(newIDs) do
        if AltarEffectsData.isIDValid(id) and not excludeList[id] and not isIDAlreadyAdded[id] then

            table.insert(altarIDs, id)
            isIDAlreadyAdded[id] = true
        end
    end
end

--- Requests the lists of IDs from both AltarEffects and Perks data models, applies some post-processing, and stores them in the member variable.
---
---@param selectedID string the id of the cornerstone to include
---@param searchName string search term to look in cornerstone names
---@param searchDesc string search term to look in cornerstone descriptions
---@param regularID string the id of the cornerstone that gets upgraded to a Stormforged version
---@param excludeList table list of ids
local function loadIDs(selectedID, searchName, searchDesc, regularID, excludeList)

    if not altarIDs or #altarIDs < 1 then

        altarIDs = {}
        isIDAlreadyAdded = {}
        local attemptedSearch = false

        -- Load the selected ID
        if selectedID and selectedID ~= "" then
            loadStormforgedIDs( { selectedID }, excludeList )
            attemptedSearch = true
        end

        -- Add any name matches
        if searchName and searchName ~= "" then
            local newIDs = PerksData.getAllPerkIDsWhereName(searchName)
            loadStormforgedIDs(newIDs, excludeList)
            attemptedSearch = true
        end

        -- Add any description matches
        if searchDesc and searchDesc ~= "" then
            local newIDs = PerksData.getAllPerkIDsWhereDescription(searchDesc)
            loadStormforgedIDs(newIDs, excludeList)
            attemptedSearch = true
        end

        -- Add any upgrade matches
        if regularID and regularID ~= "" then
            loadStormforgedIDs({ AltarEffectsData.getUpgradeWhereRegularID(regularID) }, excludeList)
            attemptedSearch = true
        end

        -- Or, if no searching was even attempted (regardless of result), show them all
        if not attemptedSearch then
            local newIDs = AltarEffectsData.getAllAltarIDs()
            loadStormforgedIDs(newIDs, excludeList)
        end
    end

    if #altarIDs > 0 then
        -- Remove all IDs that aren't for Stormforged Cornerstones--there were probably extra pulled from PerksData if there were search terms.
        validateNamesFromIDs()
        --Alphabetize by name
        table.sort(altarIDs, compareNames)
    end
end


---expandExclusions
---@param exclusions string the list of ids, separated by commas
---@return table the ids now as keys in the table and each value is `true`
local function expandExclusions(exclusions)

    local excludeList = {}
    for idToExclude in string.gmatch(exclusions, "[^,]+") do
        excludeList[idToExclude] = true
    end

    return excludeList
end


--- Ensures that if a caption is not defined, there is a suitable fallback in case the author has specified an id, name, or search term to use, so readers know what they're looking at.
---
--- If no caption was specified and also none of those filtering parameters, then leave it up to the template by returning a blank caption.
---
---@param selectedID string the first search parameter, an id
---@param searchName string the second search parameter, a name
---@param searchDesc string the third search parameter, a term in a description
---@param regularID string the id of the cornerstone that gets upgraded to a Stormforged version
---@param desiredCaption string the caption requested, if any
---@return string an appropriate caption, or blank if it should be default
local function resolveCaption(selectedID, searchName, searchDesc, regularID, desiredCaption)

    if desiredCaption and desiredCaption ~= "" then
        return desiredCaption
    end

    if selectedID and selectedID ~= "" then
        return "Stormforged Cornerstone with id '" .. selectedID .. "'"
    end
    -- Do this first since mentioning could also imply name, but not the other way around.
    if searchDesc and searchDesc ~= "" then
        return "Stormforged Cornerstones mentioning '" .. searchDesc .. "'"
    end
    if searchName and searchName ~= "" then
        return "Stormforged Cornerstones named '" .. searchName .. "'"
    end
    if regularID and regularID ~= "" then
        return "Stormforged Cornerstone upgraded from '" .. regularID .. "'"
    end

    -- Delegate to the template for the default
    return ""
end

---resolveStartTemplate
---@param skippingPrice string the flag deciding whether to skip some columns
---@return string the template name to use
local function resolveStartTemplate(skippingPrice)

    local suffixIfSkipping = (skippingPrice == ARG_SKIP_PRICES_FLAG_VALUE and TEMPLATE_CONTAINER_SKIP_PRICES_VARIANT) or ""

    return TEMPLATE_CONTAINER_START .. suffixIfSkipping
end

---resolveRowTemplate
---@param skippingPrice string the flag deciding whether to skip some columns
---@return string the template name to use
local function resolveRowTemplate(skippingPrice)

    local suffixIfSkipping = (skippingPrice == ARG_SKIP_PRICES_FLAG_VALUE and TEMPLATE_CONTAINER_SKIP_PRICES_VARIANT) or ""

    return TEMPLATE_CONTAINER_START .. TEMPLATE_CONTAINER_SUFFIX_ROW .. suffixIfSkipping
end

---resolveEndTemplate
---@return string the template name to use
local function resolveEndTemplate()

    return TEMPLATE_CONTAINER_START .. TEMPLATE_CONTAINER_SUFFIX_END
end

--- Calls the view (other templates) to render the beginning of the table.
---
---@param desiredCaption string the caption for the table, if any
---@param skippingPrice string the flag for skipping prices in the table, if any
---@param showingRegular string flag if columns should be added
---@return string the wiki markup to display, now longer
local function makeMarkupForTableStart(desiredCaption, skippingPrice, showingRegular)

    local templateParameters = {
        [TEMPLATE_PARAMETER_CAPTION] = desiredCaption,
        [TEMPLATE_PARAMETER_SKIP_PRICES] = skippingPrice,
        [TEMPLATE_PARAMETER_SHOW_REGULAR] = showingRegular
    }

    return currentFrame:expandTemplate{ title = resolveStartTemplate(skippingPrice), args = templateParameters }
end

--- Calls the view (other templates) to render a single row of the table with data based on the provided identifier.
---
---@param id string the unique identifier of a Stormforged Cornerstone to use to add data to a new table row
---@param skippingPrice string the flag for skipping prices in the table, if any
---@param showingRegular string flag if columns should be added
---@return string the wiki markup to display, now longer
local function makeMarkupPerRow(id, skippingPrice, showingRegular)

    local templateParameters = {
        [TEMPLATE_PARAMETER_ID] = id,
        [TEMPLATE_PARAMETER_DESC] = PerksData.getDescriptionByID(id),
        [TEMPLATE_PARAMETER_SHOW_REGULAR] = showingRegular
    }

    -- If showing this column, we need this data for all rows, since the author may have searched for other names or descriptions.
    if showingRegular == ARG_SHOW_REGULAR_FLAG_VALUE then
        templateParameters[TEMPLATE_PARAMETER_UPGRADE_FROM] = AltarEffectsData.getRegularVersionEffectID(id)
    end

    if skippingPrice ~= ARG_SKIP_PRICES_FLAG_VALUE then
        templateParameters[TEMPLATE_PARAMETER_PRICE_META] = AltarEffectsData.getPriceInMetaResources(id)
        templateParameters[TEMPLATE_PARAMETER_PRICE_VILLAGER] = AltarEffectsData.getPriceInVillagers(id)
        templateParameters[TEMPLATE_PARAMETER_UPGRADE_META] = AltarEffectsData.getUpgradePriceInMetaResources(id)
        templateParameters[TEMPLATE_PARAMETER_UPGRADE_VILLAGER] = AltarEffectsData.getUpgradePriceInVillagers(id)
    end

    return currentFrame:expandTemplate{ title = resolveRowTemplate(skippingPrice), args = templateParameters }
end

--- Handles assembling the rows for all of the IDs in the member variable list altarIDs.
---
---@param skippingPrice string the flag for skipping prices in the table, if any
---@param showingRegular string flag if columns should be added
---@return string the wiki markup to display, now longer
local function makeMarkupForTableRows(skippingPrice, showingRegular)

    local markup = ""
    for _, id in ipairs(altarIDs) do
        markup = markup .. makeMarkupPerRow(id, skippingPrice, showingRegular)
    end

    return markup
end

--- Calls the view (other templates) to render the end of the table.
---
---@return string the wiki markup to display, now longer
local function makeMarkupForTableEnd()

    return currentFrame:expandTemplate{ title = resolveEndTemplate(), args = {} }
end

---Calls the view (other templates) to render the content and appends it to the wiki markup string that will replace this controller's template.
---
--- Calls several methods to build pieces of the table's markup based on the author's requests.
---
---@param selectedID string the id of the cornerstone to include
---@param searchName string search term to look in cornerstone names
---@param searchDesc string search term to look in cornerstone descriptions
---@param regularID string the id of the cornerstone that gets upgraded to a Stormforged version
---@param excludeList table list of ids
---@param desiredCaption string override the table caption
---@param skippingPrice string flag if some columns should be skipped
---@param showingRegular string flag if columns should be added
---@return string the wiki markup assembled by the view (other templates)
local function renderTable(selectedID, searchName, searchDesc, regularID, excludeList, desiredCaption, skippingPrice, showingRegular)

    loadIDs(selectedID, searchName, searchDesc, regularID, excludeList)

    if #altarIDs < 1 then
        return "No matching Stormforged Cornerstones found."
    end

    desiredCaption = resolveCaption(selectedID, searchName, searchDesc, regularID, desiredCaption)

    local startMarkup = makeMarkupForTableStart(desiredCaption, skippingPrice, showingRegular)
    local rowsMarkup =  makeMarkupForTableRows(skippingPrice, showingRegular)

    return startMarkup .. rowsMarkup .. makeMarkupForTableEnd()
end

--endregion



--region Public methods

---main
---@param frame table the MediaWiki frame provided by the template call
---@return string wiki markup to display
function StormforgedController.main(frame)

    -- Extract template parameters
    local selectedID = frame.args[ARG_ID]
    local searchName = frame.args[ARG_NAME]
    local searchDesc = frame.args[ARG_DESCRIPTION]
    local regularID = frame.args[ARG_UPGRADABLE_ID]
    local exclusions = frame.args[ARGS_EXCLUDE_LIST]
    local desiredCaption = frame.args[ARG_CAPTION]
    local skippingPrice = frame.args[ARG_SKIP_PRICES]
    local showingRegular = frame.args[ARG_SHOW_REGULAR]

    --TODO make displayOverride == DISPLAY_OPTION_LIST

    local excludeList = {}
    if exclusions and exclusions ~= "" then
        excludeList = expandExclusions(exclusions)
    end

    currentFrame = frame
    return renderTable(selectedID, searchName, searchDesc, regularID, excludeList, desiredCaption, skippingPrice, showingRegular)
end

--endregion

return StormforgedController