Module:StormforgedController: Difference between revisions

From Against the Storm Official Wiki
(Allowing a display override to a list format instead)
(finished refactoring for list and inline display versions)
 
(8 intermediate revisions by the same user not shown)
Line 11: Line 11:
local AltarEffectsData = require("Module:AltarEffectsData")
local AltarEffectsData = require("Module:AltarEffectsData")
local PerksData = require("Module:PerksData")
local PerksData = require("Module:PerksData")
local ControllerUtilities = require("Module:ControllerUtilities")


--endregion
--endregion
Line 18: Line 20:
--region Private constants
--region Private constants


local ARG_ID = "id"
local ARG_ID_LIST = "id"
local ARG_NAME = "name"
local ARG_NAME = "name"
local ARG_DESCRIPTION = "description"
local ARG_DESCRIPTION = "description"
Line 25: Line 27:
local ARG_CAPTION = "caption"
local ARG_CAPTION = "caption"
local ARG_SKIP_PRICES = "skip_prices"
local ARG_SKIP_PRICES = "skip_prices"
local ARG_SKIP_PRICES_FLAG_VALUE = "skip"
local ARG_SKIP_FLAG_VALUE = "skip"
local ARG_SHOW_ID = "show_id"
local ARG_SHOW_DESCRIPTION = "show_description"
local ARG_SHOW_REGULAR = "show_regular"
local ARG_SHOW_REGULAR = "show_regular"
local ARG_SHOW_REGULAR_FLAG_VALUE = "show"
local ARG_SHOW_FLAG_VALUE = "show"
local ARG_DISPLAY_OVERRIDE = "display"
local ARG_DISPLAY_OVERRIDE = "display"
local ARG_DISPLAY_OVERRIDE_OPTION_LIST = "list"
local ARG_DISPLAY_OVERRIDE_OPTION_LIST = "list"
local ARG_DISPLAY_OVERRIDE_OPTION_INLINE = "inline"
local ARG_LIST_TYPE = "list_type"
local ARG_LIST_TYPE = "list_type"


--local DISPLAY_OPTION_TABLE = "table"
local TEMPLATE_PARAMETER_CAPTION = ARG_CAPTION
 
local TEMPLATE_PARAMETER_ID = ARG_ID_LIST
local TEMPLATE_PARAMETER_CAPTION = "caption"
local TEMPLATE_PARAMETER_DESC = ARG_DESCRIPTION
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_META = "price_in_meta_resources"
local TEMPLATE_PARAMETER_PRICE_VILLAGER = "price_in_villagers"
local TEMPLATE_PARAMETER_PRICE_VILLAGER = "price_in_villagers"
local TEMPLATE_PARAMETER_UPGRADE_META = "price_for_upgrade_in_meta_resources"
local TEMPLATE_PARAMETER_UPGRADE_META = "price_for_upgrade_in_meta_resources"
local TEMPLATE_PARAMETER_UPGRADE_VILLAGER = "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_SHOW_ID = ARG_SHOW_ID
local TEMPLATE_PARAMETER_UPGRADE_FROM = "upgrades_from"
local TEMPLATE_PARAMETER_UPGRADE_FROM = "upgrades_from"
local TEMPLATE_PARAMETER_LIST_TYPE = "list_type"
local TEMPLATE_PARAMETER_LIST_TYPE = ARG_LIST_TYPE
local TEMPLATE_PARAMETER_ICON_SIZE = "icon_size"
local TEMPLATE_PARAMETER_ICON_SIZE_DEFAULT = "none"


local TEMPLATE_TABLE_BASE = "StormforgedCornerstonesTable"
local TEMPLATE_TABLE_BASE = "StormforgedCornerstonesTable"
Line 51: Line 55:
local TEMPLATE_TABLE_SKIP_PRICES_VARIANT = "/SkipPrices"
local TEMPLATE_TABLE_SKIP_PRICES_VARIANT = "/SkipPrices"
local TEMPLATE_LIST_ITEM = "StormforgedCornerstonesList/item"
local TEMPLATE_LIST_ITEM = "StormforgedCornerstonesList/item"
 
local TEMPLATE_INLINE_LINK = "pl"
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
--endregion
Line 61: Line 64:


local currentFrame = {}
local currentFrame = {}
local altarIDs = {}
local altarIDs = {}
local isIDAlreadyAdded = {}
local isIDAlreadyAdded = {}
Line 69: Line 73:


--region Private methods
--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.
--- 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.
Line 122: Line 105:
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.
--- Requests the desired lists of IDs from both AltarEffects and Perks data models, applies some post-processing, and stores them in the member variable altarIDs.
---
---
---@param selectedID string the id of the cornerstone to include
---@param selectList table list of ids of the cornerstone to include
---@param searchName string search term to look in cornerstone names
---@param searchName string search term to look in cornerstone names
---@param searchDesc string search term to look in cornerstone descriptions
---@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 regularID string the id of the cornerstone that gets upgraded to a Stormforged version
---@param excludeList table list of ids
---@param excludeList table list of ids
local function loadIDs(selectedID, searchName, searchDesc, regularID, excludeList)
local function loadIDs(selectList, searchName, searchDesc, regularID, excludeList)
 
    if not altarIDs or #altarIDs < 1 then


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


        -- Load the selected ID
    -- Load the selected IDs
        if selectedID and selectedID ~= "" then
    if selectList then
            loadStormforgedIDs( { selectedID }, excludeList )
        loadStormforgedIDs(selectList, excludeList)
        -- It should always be true, but it can be blank.
        if #selectList > 0 then
             attemptedSearch = true
             attemptedSearch = true
         end
         end
    end


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


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


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


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


     if #altarIDs > 0 then
     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.
         -- Remove all IDs that aren't for Stormforged Cornerstones--there will be extra regular Perks pulled from PerksData whenever there are search terms.
         validateNamesFromIDs()
         validateNamesFromIDs()
         --Alphabetize by name
         -- Alphabetize by name.
         table.sort(altarIDs, compareNames)
         table.sort(altarIDs, PerksData.compareNames)
     end
     end
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.
--- 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.
Line 197: Line 165:
--- If no caption was specified and also none of those filtering parameters, then leave it up to the template by returning a blank caption.
--- 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 desiredCaption string the caption requested, if any
---@param selectList table list of ids of the cornerstone to include
---@param searchName string the second search parameter, a name
---@param searchName string the second search parameter, a name
---@param searchDesc string the third search parameter, a term in a description
---@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 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
---@return string an appropriate caption, or blank if it should be default
local function resolveCaption(selectedID, searchName, searchDesc, regularID, desiredCaption)
local function resolveCaption(desiredCaption, selectList, searchName, searchDesc, regularID)


    -- No matter what, if the author provided a caption, use that.
     if desiredCaption and desiredCaption ~= "" then
     if desiredCaption and desiredCaption ~= "" then
         return desiredCaption
         return desiredCaption
     end
     end


     if selectedID and selectedID ~= "" then
    -- If no selection, delegate to template.
         return "Stormforged Cornerstone with id '" .. selectedID .. "'"
    local addedToText = false
 
    desiredCaption = "" .. #altarIDs .. " Stormforged Cornerstones"
 
     if selectList and #selectList > 0 then
        if #selectList == 1 then
            desiredCaption = desiredCaption .. " with ID '" .. selectList[1] .. "'"
        else
            desiredCaption = desiredCaption .. " with selected IDs"
        end
        addedToText = true
    end
 
    if searchName and searchName ~= "" then
         if addedToText then
            desiredCaption = desiredCaption .. " and"
        end
        desiredCaption = desiredCaption .. " named '" .. searchName .. "'"
        addedToText = true
     end
     end
    -- Do this first since mentioning could also imply name, but not the other way around.
 
     if searchDesc and searchDesc ~= "" then
     if searchDesc and searchDesc ~= "" then
         return "Stormforged Cornerstones mentioning '" .. searchDesc .. "'"
         if addedToText then
            desiredCaption = desiredCaption .. " and"
        end
        desiredCaption = desiredCaption .. " mentioning '" .. searchDesc .. "'"
        addedToText = true
     end
     end
     if searchName and searchName ~= "" then
 
         return "Stormforged Cornerstones named '" .. searchName .. "'"
     if regularID and regularID ~= "" then
         if addedToText then
            desiredCaption = desiredCaption .. " and"
        end
        desiredCaption = desiredCaption .. " upgraded from '" .. regularID .. "'"
        addedToText = true
     end
     end
     if regularID and regularID ~= "" then
 
         return "Stormforged Cornerstone upgraded from '" .. regularID .. "'"
     if excludeList and #excludeList > 0 then
         desiredCaption = desiredCaption .. " (with exclusions)"
        addedToText = true
     end
     end


     -- Delegate to the template for the default
     if addedToText then
    return ""
        return desiredCaption
    else
        -- Delegate to the template for the default
        return ""
    end
end
end


---resolveStartTemplate
---resolveStartTemplate
---@param skippingPrice string the flag deciding whether to skip some columns
---@param isSkippingPrices boolean true if skipping variant should be used
---@return string the template name to use
---@return string the template name to use
local function resolveTableStartTemplate(skippingPrice)
local function resolveTableStartTemplate(isSkippingPrices)


     local suffixIfSkipping = (skippingPrice == ARG_SKIP_PRICES_FLAG_VALUE and TEMPLATE_TABLE_SKIP_PRICES_VARIANT) or ""
     local suffixIfSkipping = (isSkippingPrices and TEMPLATE_TABLE_SKIP_PRICES_VARIANT) or ""


     return TEMPLATE_TABLE_BASE .. suffixIfSkipping
     return TEMPLATE_TABLE_BASE .. suffixIfSkipping
Line 238: Line 240:


---resolveRowTemplate
---resolveRowTemplate
---@param skippingPrice string the flag deciding whether to skip some columns
---@param isSkippingPrices boolean true if skipping variant should be used
---@return string the template name to use
---@return string the template name to use
local function resolveTableRowTemplate(skippingPrice)
local function resolveTableRowTemplate(isSkippingPrices)


     local suffixIfSkipping = (skippingPrice == ARG_SKIP_PRICES_FLAG_VALUE and TEMPLATE_TABLE_SKIP_PRICES_VARIANT) or ""
     local suffixIfSkipping = (isSkippingPrices and TEMPLATE_TABLE_SKIP_PRICES_VARIANT) or ""


     return TEMPLATE_TABLE_BASE .. TEMPLATE_TABLE_SUFFIX_ROW .. suffixIfSkipping
     return TEMPLATE_TABLE_BASE .. TEMPLATE_TABLE_SUFFIX_ROW .. suffixIfSkipping
Line 257: Line 259:
---
---
---@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 isSkippingPrices boolean true if skipping variant should be used
---@param showingRegular string flag if columns should be added
---@param argsForTableTemplate table a set of arguments ready to pass through to the called template
---@return string the wiki markup assembled by the view (other templates)
---@return string the wiki markup assembled by the view (other templates)
local function makeMarkupForTableStart(desiredCaption, skippingPrice, showingRegular)
local function makeMarkupForTableStart(desiredCaption, isSkippingPrices, argsForTableTemplate)


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


     return currentFrame:expandTemplate{ title = resolveTableStartTemplate(skippingPrice), args = templateParameters }
     return currentFrame:expandTemplate{ title = resolveTableStartTemplate(isSkippingPrices), args = argsForTableTemplate }
end
end


Line 274: Line 272:
---
---
---@param id string the unique identifier of a Stormforged Cornerstone to use to add data to a new table row
---@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 isSkippingPrices boolean true if skipping variant should be used
---@param showingRegular string flag if columns should be added
---@param argsForTableTemplate table a set of arguments ready to pass through to the called template
---@return string the wiki markup assembled by the view (other templates)
---@return string the wiki markup assembled by the view (other templates)
local function makeMarkupPerRow(id, skippingPrice, showingRegular)
local function makeMarkupPerRow(id, isSkippingPrices, argsForTableTemplate)


     local templateParameters = {
     argsForTableTemplate[TEMPLATE_PARAMETER_ID] = id
        [TEMPLATE_PARAMETER_ID] = id,
    argsForTableTemplate[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.
     argsForTableTemplate[TEMPLATE_PARAMETER_UPGRADE_FROM] = AltarEffectsData.getRegularVersionEffectID(id)
    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
     -- This is default, but adds a lot of extra template overhead if it's not needed, so only add it if necessary.
         templateParameters[TEMPLATE_PARAMETER_PRICE_META] = AltarEffectsData.getPriceInMetaResources(id)
    if not isSkippingPrices then
         templateParameters[TEMPLATE_PARAMETER_PRICE_VILLAGER] = AltarEffectsData.getPriceInVillagers(id)
         argsForTableTemplate[TEMPLATE_PARAMETER_PRICE_META] = AltarEffectsData.getPriceInMetaResources(id)
         templateParameters[TEMPLATE_PARAMETER_UPGRADE_META] = AltarEffectsData.getUpgradePriceInMetaResources(id)
         argsForTableTemplate[TEMPLATE_PARAMETER_PRICE_VILLAGER] = AltarEffectsData.getPriceInVillagers(id)
         templateParameters[TEMPLATE_PARAMETER_UPGRADE_VILLAGER] = AltarEffectsData.getUpgradePriceInVillagers(id)
         argsForTableTemplate[TEMPLATE_PARAMETER_UPGRADE_META] = AltarEffectsData.getUpgradePriceInMetaResources(id)
         argsForTableTemplate[TEMPLATE_PARAMETER_UPGRADE_VILLAGER] = AltarEffectsData.getUpgradePriceInVillagers(id)
     end
     end


     return currentFrame:expandTemplate{ title = resolveTableRowTemplate(skippingPrice), args = templateParameters }
     return currentFrame:expandTemplate{ title = resolveTableRowTemplate(isSkippingPrices), args = argsForTableTemplate }
end
end


--- Handles assembling the rows for all of the IDs in the member variable list altarIDs.
--- 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 isSkippingPrices boolean true if skipping variant should be used
---@param showingRegular string flag if columns should be added
---@param argsForTableTemplate table a set of arguments ready to pass through to the called template
---@return string the wiki markup assembled by the view (other templates)
---@return string the wiki markup assembled by the view (other templates)
local function makeMarkupForTableRows(skippingPrice, showingRegular)
local function makeMarkupForTableRows(isSkippingPrices, argsForTableTemplate)


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


Line 327: Line 320:
--- Calls several methods to build pieces of the table's markup based on the author's requests.
--- 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 desiredCaption string override the table caption
---@param skippingPrice string flag if some columns should be skipped
---@param isSkippingPrices boolean true if skipping variant should be used
---@param showingRegular string flag if columns should be added
---@param argsForTableTemplate table a set of arguments ready to pass through to the called template
---@return string the wiki markup assembled by the view (other templates)
---@return string the wiki markup assembled by the view (other templates)
local function renderTable(selectedID, searchName, searchDesc, regularID, excludeList, desiredCaption, skippingPrice, showingRegular)
local function renderTable(desiredCaption, isSkippingPrices, argsForTableTemplate)
 
    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 startMarkup = makeMarkupForTableStart(desiredCaption, isSkippingPrices, argsForTableTemplate)
     local rowsMarkup =  makeMarkupForTableRows(skippingPrice, showingRegular)
     local rowsMarkup =  makeMarkupForTableRows(isSkippingPrices, argsForTableTemplate)


     return startMarkup .. rowsMarkup .. makeMarkupForTableEnd()
     return startMarkup .. rowsMarkup .. makeMarkupForTableEnd()
Line 354: Line 335:
---@param id string the id of the cornerstone to display
---@param id string the id of the cornerstone to display
---@param listType string the type of list to create
---@param listType string the type of list to create
---@param isShowingID boolean true when needing to show the ID column
---@return string the wiki markup assembled by the view (other templates)
---@return string the wiki markup assembled by the view (other templates)
local function makeMarkupPerListItem(id, listType)
local function makeMarkupPerListItem(id, listType, isShowingID)


     local templateParameters = {
     local templateParameters = {
         [TEMPLATE_PARAMETER_ID] = id,
         [TEMPLATE_PARAMETER_ID] = id,
         [TEMPLATE_PARAMETER_LIST_TYPE] = listType
         [TEMPLATE_PARAMETER_LIST_TYPE] = listType,
        [TEMPLATE_PARAMETER_SHOW_ID] = isShowingID and ARG_SHOW_FLAG_VALUE
     }
     }


Line 367: Line 350:
---makeMarkupForListItems
---makeMarkupForListItems
---@param listType string the type of list to create
---@param listType string the type of list to create
---@param isShowingID boolean true when needing to show the ID column
---@return string the wiki markup assembled by the view (other templates)
---@return string the wiki markup assembled by the view (other templates)
local function makeMarkupForListItems(listType)
local function makeMarkupForListItems(listType, isShowingID)


     local markup = ""
     local markup = ""
     for _, id in ipairs(altarIDs) do
     for _, id in ipairs(altarIDs) do
         markup = markup .. makeMarkupPerListItem(id, listType)
         markup = markup .. makeMarkupPerListItem(id, listType, isShowingID)
     end
     end


Line 379: Line 363:


---renderList
---renderList
---@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 listType string the type of list to create
---@param listType string the type of list to create
---@param isShowingID boolean true when needing to show the ID column
---@return string the wiki markup assembled by the view (other templates)
local function renderList(listType, isShowingID)
    return makeMarkupForListItems(listType, isShowingID)
end
---makeMarkupPerLink
---@param id string the id of the cornerstone to display
---@param isShowingID boolean true when needing to show the ID column
---@return string the wiki markup assembled by the view (other templates)
local function makeMarkupPerLink(id, isShowingID)
    local templateParameters = {
        [TEMPLATE_PARAMETER_ID] = id,
        [TEMPLATE_PARAMETER_ICON_SIZE] = TEMPLATE_PARAMETER_ICON_SIZE_DEFAULT,
    }
    local link = currentFrame:expandTemplate{ title = TEMPLATE_INLINE_LINK, args = templateParameters }
    if isShowingID then
        return link .. " ('" .. id .. "')"
    else
        return link
    end
end
---makeMarkupForInlineLinks
---@param isShowingID boolean true when needing to show the ID column
---@return string the wiki markup assembled by the view (other templates)
---@return string the wiki markup assembled by the view (other templates)
local function renderList(selectedID, searchName, searchDesc, regularID, excludeList, listType)
local function makeMarkupForInlineLinks(isShowingID)


     loadIDs(selectedID, searchName, searchDesc, regularID, excludeList)
     local markup = ""
    if #altarIDs < 1 then
    for i, id in ipairs(altarIDs) do
         return "No matching Stormforged Cornerstones found."
        if i > 1 then
            markup = markup .. ", "
         end
        markup = markup .. makeMarkupPerLink(id, isShowingID)
     end
     end


     return makeMarkupForListItems(listType)
     return markup
end
 
---renderInline
---@param isShowingID boolean true when needing to show the ID column
---@return string the wiki markup assembled by the view (other templates)
local function renderInlineLinks(isShowingID)
 
    return makeMarkupForInlineLinks(isShowingID)
end
end


Line 408: Line 427:


     -- Selection parameters
     -- Selection parameters
     local selectedID = frame.args[ARG_ID]
     local selectList = ControllerUtilities.expandCommaSeparatedStringsIntoTable(frame.args[ARG_ID_LIST], false)
    local excludeList = ControllerUtilities.expandCommaSeparatedStringsIntoTable(frame.args[ARGS_EXCLUDE_LIST], true)
     local searchName = frame.args[ARG_NAME]
     local searchName = frame.args[ARG_NAME]
     local searchDesc = frame.args[ARG_DESCRIPTION]
     local searchDesc = frame.args[ARG_DESCRIPTION]
     local regularID = frame.args[ARG_UPGRADABLE_ID]
     local regularID = frame.args[ARG_UPGRADABLE_ID]
    local exclusions = frame.args[ARGS_EXCLUDE_LIST]


     -- Display parameters
     -- Display parameters
    local desiredCaption = frame.args[ARG_CAPTION]
     local displayOverride = frame.args[ARG_DISPLAY_OVERRIDE]
     local displayOverride = frame.args[ARG_DISPLAY_OVERRIDE]
    local desiredCaption = frame.args[ARG_CAPTION]
    local skippingPrice = frame.args[ARG_SKIP_PRICES]
    local showingRegular = frame.args[ARG_SHOW_REGULAR]
     local listType = frame.args[ARG_LIST_TYPE]
     local listType = frame.args[ARG_LIST_TYPE]
    local isSkippingPrices = ARG_SKIP_FLAG_VALUE == frame.args[ARG_SKIP_PRICES]
    local isShowingID = ARG_SHOW_FLAG_VALUE == frame.args[ARG_SHOW_ID]


     local excludeList = {}
    -- For clarity, copy each value instead of reusing the whole args table.
    if exclusions and exclusions ~= "" then
     local argumentsToPassThroughToTable = {
         excludeList = expandExclusions(exclusions)
        [ARG_SKIP_PRICES] = frame.args[ARG_SKIP_PRICES],
     end
        [ARG_SHOW_ID] = frame.args[ARG_SHOW_ID],
        [ARG_SHOW_DESCRIPTION] = frame.args[ARG_SHOW_DESCRIPTION],
         [ARG_SHOW_REGULAR] = frame.args[ARG_SHOW_REGULAR]
     }


     currentFrame = frame
     currentFrame = frame
    loadIDs(selectList, searchName, searchDesc, regularID, excludeList)
    if #altarIDs < 1 then
        return "No matching Stormforged Cornerstones found."
    end


     if displayOverride == ARG_DISPLAY_OVERRIDE_OPTION_LIST then
     if displayOverride == ARG_DISPLAY_OVERRIDE_OPTION_LIST then
         return renderList(selectedID, searchName, searchDesc, regularID, excludeList, listType)
         return renderList(listType, isShowingID)
     else
     end
         return renderTable(selectedID, searchName, searchDesc, regularID, excludeList, desiredCaption, skippingPrice, showingRegular)
    if displayOverride == ARG_DISPLAY_OVERRIDE_OPTION_INLINE then
         return renderInlineLinks(isShowingID)
    end
 
    -- Default display is table.
    desiredCaption = resolveCaption(desiredCaption, selectList, searchName, searchDesc, regularID)


     end
     return renderTable(desiredCaption, isSkippingPrices, argumentsToPassThroughToTable)
end
end



Latest revision as of 03:38, 5 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")

local ControllerUtilities = require("Module:ControllerUtilities")

--endregion



--region Private constants

local ARG_ID_LIST = "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_FLAG_VALUE = "skip"
local ARG_SHOW_ID = "show_id"
local ARG_SHOW_DESCRIPTION = "show_description"
local ARG_SHOW_REGULAR = "show_regular"
local ARG_SHOW_FLAG_VALUE = "show"
local ARG_DISPLAY_OVERRIDE = "display"
local ARG_DISPLAY_OVERRIDE_OPTION_LIST = "list"
local ARG_DISPLAY_OVERRIDE_OPTION_INLINE = "inline"
local ARG_LIST_TYPE = "list_type"

local TEMPLATE_PARAMETER_CAPTION = ARG_CAPTION
local TEMPLATE_PARAMETER_ID = ARG_ID_LIST
local TEMPLATE_PARAMETER_DESC = ARG_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_ID = ARG_SHOW_ID
local TEMPLATE_PARAMETER_UPGRADE_FROM = "upgrades_from"
local TEMPLATE_PARAMETER_LIST_TYPE = ARG_LIST_TYPE
local TEMPLATE_PARAMETER_ICON_SIZE = "icon_size"
local TEMPLATE_PARAMETER_ICON_SIZE_DEFAULT = "none"

local TEMPLATE_TABLE_BASE = "StormforgedCornerstonesTable"
local TEMPLATE_TABLE_SUFFIX_ROW = "/row"
local TEMPLATE_TABLE_SUFFIX_END = "/end"
local TEMPLATE_TABLE_SKIP_PRICES_VARIANT = "/SkipPrices"
local TEMPLATE_LIST_ITEM = "StormforgedCornerstonesList/item"
local TEMPLATE_INLINE_LINK = "pl"

--endregion



--region Private member variables

local currentFrame = {}

local altarIDs = {}
local isIDAlreadyAdded = {}

--endregion



--region Private methods

--- 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 desired lists of IDs from both AltarEffects and Perks data models, applies some post-processing, and stores them in the member variable altarIDs.
---
---@param selectList table list of ids 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(selectList, searchName, searchDesc, regularID, excludeList)

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

    -- Load the selected IDs
    if selectList then
        loadStormforgedIDs(selectList, excludeList)
        -- It should always be true, but it can be blank.
        if #selectList > 0 then
            attemptedSearch = true
        end
    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

    if #altarIDs > 0 then
        -- Remove all IDs that aren't for Stormforged Cornerstones--there will be extra regular Perks pulled from PerksData whenever there are search terms.
        validateNamesFromIDs()
        -- Alphabetize by name.
        table.sort(altarIDs, PerksData.compareNames)
    end
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 desiredCaption string the caption requested, if any
---@param selectList table list of ids of the cornerstone to include
---@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
---@return string an appropriate caption, or blank if it should be default
local function resolveCaption(desiredCaption, selectList, searchName, searchDesc, regularID)

    -- No matter what, if the author provided a caption, use that.
    if desiredCaption and desiredCaption ~= "" then
        return desiredCaption
    end

    -- If no selection, delegate to template.
    local addedToText = false

    desiredCaption = "" .. #altarIDs .. " Stormforged Cornerstones"

    if selectList and #selectList > 0 then
        if #selectList == 1 then
            desiredCaption = desiredCaption .. " with ID '" .. selectList[1] .. "'"
        else
            desiredCaption = desiredCaption .. " with selected IDs"
        end
        addedToText = true
    end

    if searchName and searchName ~= "" then
        if addedToText then
            desiredCaption = desiredCaption .. " and"
        end
        desiredCaption = desiredCaption .. " named '" .. searchName .. "'"
        addedToText = true
    end

    if searchDesc and searchDesc ~= "" then
        if addedToText then
            desiredCaption = desiredCaption .. " and"
        end
        desiredCaption = desiredCaption .. " mentioning '" .. searchDesc .. "'"
        addedToText = true
    end

    if regularID and regularID ~= "" then
        if addedToText then
            desiredCaption = desiredCaption .. " and"
        end
        desiredCaption = desiredCaption .. " upgraded from '" .. regularID .. "'"
        addedToText = true
    end

    if excludeList and #excludeList > 0 then
        desiredCaption = desiredCaption .. " (with exclusions)"
        addedToText = true
    end

    if addedToText then
        return desiredCaption
    else
        -- Delegate to the template for the default
        return ""
    end
end

---resolveStartTemplate
---@param isSkippingPrices boolean true if skipping variant should be used
---@return string the template name to use
local function resolveTableStartTemplate(isSkippingPrices)

    local suffixIfSkipping = (isSkippingPrices and TEMPLATE_TABLE_SKIP_PRICES_VARIANT) or ""

    return TEMPLATE_TABLE_BASE .. suffixIfSkipping
end

---resolveRowTemplate
---@param isSkippingPrices boolean true if skipping variant should be used
---@return string the template name to use
local function resolveTableRowTemplate(isSkippingPrices)

    local suffixIfSkipping = (isSkippingPrices and TEMPLATE_TABLE_SKIP_PRICES_VARIANT) or ""

    return TEMPLATE_TABLE_BASE .. TEMPLATE_TABLE_SUFFIX_ROW .. suffixIfSkipping
end

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

    return TEMPLATE_TABLE_BASE .. TEMPLATE_TABLE_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 isSkippingPrices boolean true if skipping variant should be used
---@param argsForTableTemplate table a set of arguments ready to pass through to the called template
---@return string the wiki markup assembled by the view (other templates)
local function makeMarkupForTableStart(desiredCaption, isSkippingPrices, argsForTableTemplate)

    argsForTableTemplate[TEMPLATE_PARAMETER_CAPTION] = desiredCaption

    return currentFrame:expandTemplate{ title = resolveTableStartTemplate(isSkippingPrices), args = argsForTableTemplate }
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 isSkippingPrices boolean true if skipping variant should be used
---@param argsForTableTemplate table a set of arguments ready to pass through to the called template
---@return string the wiki markup assembled by the view (other templates)
local function makeMarkupPerRow(id, isSkippingPrices, argsForTableTemplate)

    argsForTableTemplate[TEMPLATE_PARAMETER_ID] = id
    argsForTableTemplate[TEMPLATE_PARAMETER_DESC] = PerksData.getDescriptionByID(id)

    argsForTableTemplate[TEMPLATE_PARAMETER_UPGRADE_FROM] = AltarEffectsData.getRegularVersionEffectID(id)

    -- This is default, but adds a lot of extra template overhead if it's not needed, so only add it if necessary.
    if not isSkippingPrices then
        argsForTableTemplate[TEMPLATE_PARAMETER_PRICE_META] = AltarEffectsData.getPriceInMetaResources(id)
        argsForTableTemplate[TEMPLATE_PARAMETER_PRICE_VILLAGER] = AltarEffectsData.getPriceInVillagers(id)
        argsForTableTemplate[TEMPLATE_PARAMETER_UPGRADE_META] = AltarEffectsData.getUpgradePriceInMetaResources(id)
        argsForTableTemplate[TEMPLATE_PARAMETER_UPGRADE_VILLAGER] = AltarEffectsData.getUpgradePriceInVillagers(id)
    end

    return currentFrame:expandTemplate{ title = resolveTableRowTemplate(isSkippingPrices), args = argsForTableTemplate }
end

--- Handles assembling the rows for all of the IDs in the member variable list altarIDs.
---
---@param isSkippingPrices boolean true if skipping variant should be used
---@param argsForTableTemplate table a set of arguments ready to pass through to the called template
---@return string the wiki markup assembled by the view (other templates)
local function makeMarkupForTableRows(isSkippingPrices, argsForTableTemplate)

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

    return markup
end

--- Calls the view (other templates) to render the end of the table.
---
---@return string the wiki markup assembled by the view (other templates)
local function makeMarkupForTableEnd()

    return currentFrame:expandTemplate{ title = resolveTableEndTemplate(), 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 desiredCaption string override the table caption
---@param isSkippingPrices boolean true if skipping variant should be used
---@param argsForTableTemplate table a set of arguments ready to pass through to the called template
---@return string the wiki markup assembled by the view (other templates)
local function renderTable(desiredCaption, isSkippingPrices, argsForTableTemplate)

    local startMarkup = makeMarkupForTableStart(desiredCaption, isSkippingPrices, argsForTableTemplate)
    local rowsMarkup =  makeMarkupForTableRows(isSkippingPrices, argsForTableTemplate)

    return startMarkup .. rowsMarkup .. makeMarkupForTableEnd()
end

---makeMarkupPerListITem
---@param id string the id of the cornerstone to display
---@param listType string the type of list to create
---@param isShowingID boolean true when needing to show the ID column
---@return string the wiki markup assembled by the view (other templates)
local function makeMarkupPerListItem(id, listType, isShowingID)

    local templateParameters = {
        [TEMPLATE_PARAMETER_ID] = id,
        [TEMPLATE_PARAMETER_LIST_TYPE] = listType,
        [TEMPLATE_PARAMETER_SHOW_ID] = isShowingID and ARG_SHOW_FLAG_VALUE
    }

    return currentFrame:expandTemplate{ title = TEMPLATE_LIST_ITEM, args = templateParameters }
end

---makeMarkupForListItems
---@param listType string the type of list to create
---@param isShowingID boolean true when needing to show the ID column
---@return string the wiki markup assembled by the view (other templates)
local function makeMarkupForListItems(listType, isShowingID)

    local markup = ""
    for _, id in ipairs(altarIDs) do
        markup = markup .. makeMarkupPerListItem(id, listType, isShowingID)
    end

    return markup
end

---renderList
---@param listType string the type of list to create
---@param isShowingID boolean true when needing to show the ID column
---@return string the wiki markup assembled by the view (other templates)
local function renderList(listType, isShowingID)

    return makeMarkupForListItems(listType, isShowingID)
end

---makeMarkupPerLink
---@param id string the id of the cornerstone to display
---@param isShowingID boolean true when needing to show the ID column
---@return string the wiki markup assembled by the view (other templates)
local function makeMarkupPerLink(id, isShowingID)

    local templateParameters = {
        [TEMPLATE_PARAMETER_ID] = id,
        [TEMPLATE_PARAMETER_ICON_SIZE] = TEMPLATE_PARAMETER_ICON_SIZE_DEFAULT,
    }

    local link = currentFrame:expandTemplate{ title = TEMPLATE_INLINE_LINK, args = templateParameters }

    if isShowingID then
        return link .. " ('" .. id .. "')"
    else
        return link
    end
end

---makeMarkupForInlineLinks
---@param isShowingID boolean true when needing to show the ID column
---@return string the wiki markup assembled by the view (other templates)
local function makeMarkupForInlineLinks(isShowingID)

    local markup = ""
    for i, id in ipairs(altarIDs) do
        if i > 1 then
            markup = markup .. ", "
        end
        markup = markup .. makeMarkupPerLink(id, isShowingID)
    end

    return markup
end

---renderInline
---@param isShowingID boolean true when needing to show the ID column
---@return string the wiki markup assembled by the view (other templates)
local function renderInlineLinks(isShowingID)

    return makeMarkupForInlineLinks(isShowingID)
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)

    -- Selection parameters
    local selectList = ControllerUtilities.expandCommaSeparatedStringsIntoTable(frame.args[ARG_ID_LIST], false)
    local excludeList = ControllerUtilities.expandCommaSeparatedStringsIntoTable(frame.args[ARGS_EXCLUDE_LIST], true)
    local searchName = frame.args[ARG_NAME]
    local searchDesc = frame.args[ARG_DESCRIPTION]
    local regularID = frame.args[ARG_UPGRADABLE_ID]

    -- Display parameters
    local desiredCaption = frame.args[ARG_CAPTION]
    local displayOverride = frame.args[ARG_DISPLAY_OVERRIDE]
    local listType = frame.args[ARG_LIST_TYPE]
    local isSkippingPrices = ARG_SKIP_FLAG_VALUE == frame.args[ARG_SKIP_PRICES]
    local isShowingID = ARG_SHOW_FLAG_VALUE == frame.args[ARG_SHOW_ID]

    -- For clarity, copy each value instead of reusing the whole args table.
    local argumentsToPassThroughToTable = {
        [ARG_SKIP_PRICES] = frame.args[ARG_SKIP_PRICES],
        [ARG_SHOW_ID] = frame.args[ARG_SHOW_ID],
        [ARG_SHOW_DESCRIPTION] = frame.args[ARG_SHOW_DESCRIPTION],
        [ARG_SHOW_REGULAR] = frame.args[ARG_SHOW_REGULAR]
    }

    currentFrame = frame

    loadIDs(selectList, searchName, searchDesc, regularID, excludeList)
    if #altarIDs < 1 then
        return "No matching Stormforged Cornerstones found."
    end

    if displayOverride == ARG_DISPLAY_OVERRIDE_OPTION_LIST then
        return renderList(listType, isShowingID)
    end
    if displayOverride == ARG_DISPLAY_OVERRIDE_OPTION_INLINE then
        return renderInlineLinks(isShowingID)
    end

    -- Default display is table.
    desiredCaption = resolveCaption(desiredCaption, selectList, searchName, searchDesc, regularID)

    return renderTable(desiredCaption, isSkippingPrices, argumentsToPassThroughToTable)
end

--endregion

return StormforgedController