Module:StormforgedController: Difference between revisions

From Against the Storm Official Wiki
(fixing no parameters working again)
(finished refactoring for list and inline display versions)
 
(One intermediate revision 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_ID = "show_id"
local ARG_SHOW_DESCRIPTION = "show_description"
local ARG_SHOW_DESCRIPTION = "show_description"
Line 35: Line 37:
local ARG_LIST_TYPE = "list_type"
local ARG_LIST_TYPE = "list_type"


local TEMPLATE_PARAMETER_CAPTION = "caption"
local TEMPLATE_PARAMETER_CAPTION = ARG_CAPTION
local TEMPLATE_PARAMETER_SKIP_PRICES = "skip_prices"
local TEMPLATE_PARAMETER_ID = ARG_ID_LIST
local TEMPLATE_PARAMETER_ID = "id"
local TEMPLATE_PARAMETER_DESC = ARG_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_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_ID = "show_id"
local TEMPLATE_PARAMETER_SHOW_ID = ARG_SHOW_ID
local TEMPLATE_PARAMETER_SHOW_DESCRIPTION = "show_description"
local TEMPLATE_PARAMETER_SHOW_REGULAR = "show_regular"
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 = "icon_size"
local TEMPLATE_PARAMETER_ICON_SIZE_DEFAULT = "none"
local TEMPLATE_PARAMETER_ICON_SIZE_DEFAULT = "none"
Line 57: Line 56:
local TEMPLATE_LIST_ITEM = "StormforgedCornerstonesList/item"
local TEMPLATE_LIST_ITEM = "StormforgedCornerstonesList/item"
local TEMPLATE_INLINE_LINK = "pl"
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 76: 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 129: 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 selectList table list of ids of the cornerstone to include
---@param selectList table list of ids of the cornerstone to include
Line 145: Line 121:
     if selectList then
     if selectList then
         loadStormforgedIDs(selectList, excludeList)
         loadStormforgedIDs(selectList, excludeList)
         -- It's actually always true, but it can be blank.
         -- It should always be true, but it can be blank.
         if #selectList > 0 then
         if #selectList > 0 then
             attemptedSearch = true
             attemptedSearch = true
Line 171: Line 147:
     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()
Line 180: Line 156:
         -- Remove all IDs that aren't for Stormforged Cornerstones--there will be extra regular Perks pulled from PerksData whenever there are 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
 
---expandIDList
---@param stringOfIDs string the list of ids, separated by commas
---@param isFlags boolean true if the list should be made of keys and values of true, false if the list should be an array
---@return table the ids now as a table
local function expandIDList(stringOfIDs, isFlags)
 
    local list = {}
    for id in string.gmatch(stringOfIDs, "[^%s,][^,]+[^%s,]") do
        if isFlags then
            list[id] = true
        else
            table.insert(list, id)
        end
     end
     end
    return list
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.
--- 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 208: 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 desiredCaption string the caption requested, if any
---@param selectList table list of ids of the cornerstone to include
---@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(selectList, 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 no selection, delegate to template.
    local addedToText = false
    desiredCaption = "" .. #altarIDs .. " Stormforged Cornerstones"


     if selectList and #selectList > 0 then
     if selectList and #selectList > 0 then
         if #selectList == 1 then
         if #selectList == 1 then
             return "Stormforged Cornerstone with id '" .. selectList[1] .. "'"
             desiredCaption = desiredCaption .. " with ID '" .. selectList[1] .. "'"
         else
         else
             return #selectList .. " selected Stormforged Cornerstones"
             desiredCaption = desiredCaption .. " with selected IDs"
         end
         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 mentioning '" .. 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 254: 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 273: 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 showingID string flag when needing to show the ID as well
---@param argsForTableTemplate table a set of arguments ready to pass through to the called template
---@param showingDescription string flag when needing to show the description as well
---@param showingRegular string flag if columns should be added
---@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, showingID, showingDescription, 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_ID] = showingID,
        [TEMPLATE_PARAMETER_SHOW_DESCRIPTION] = showingDescription,
        [TEMPLATE_PARAMETER_SHOW_REGULAR] = showingRegular
    }


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


Line 294: 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 showingID string flag when needing to show the ID as well
---@param argsForTableTemplate table a set of arguments ready to pass through to the called template
---@param showingDescription string flag when needing to show the description as well
---@param showingRegular string flag if columns should be added
---@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, showingID, showingDescription, 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_ID] = showingID,
        [TEMPLATE_PARAMETER_SHOW_DESCRIPTION] = showingDescription,
        [TEMPLATE_PARAMETER_SHOW_REGULAR] = showingRegular
    }


     -- This is not default, so don't get the data unless necessary.
     argsForTableTemplate[TEMPLATE_PARAMETER_UPGRADE_FROM] = AltarEffectsData.getRegularVersionEffectID(id)
    if showingRegular == ARG_SHOW_FLAG_VALUE then
        templateParameters[TEMPLATE_PARAMETER_UPGRADE_FROM] = AltarEffectsData.getRegularVersionEffectID(id)
    end


     -- This is default, but adds a lot of extra template overhead if it's not needed, so only add it if necessary.
     -- This is default, but adds a lot of extra template overhead if it's not needed, so only add it if necessary.
     if skippingPrice ~= ARG_SKIP_PRICES_FLAG_VALUE then
     if not isSkippingPrices then
         templateParameters[TEMPLATE_PARAMETER_PRICE_META] = AltarEffectsData.getPriceInMetaResources(id)
         argsForTableTemplate[TEMPLATE_PARAMETER_PRICE_META] = AltarEffectsData.getPriceInMetaResources(id)
         templateParameters[TEMPLATE_PARAMETER_PRICE_VILLAGER] = AltarEffectsData.getPriceInVillagers(id)
         argsForTableTemplate[TEMPLATE_PARAMETER_PRICE_VILLAGER] = AltarEffectsData.getPriceInVillagers(id)
         templateParameters[TEMPLATE_PARAMETER_UPGRADE_META] = AltarEffectsData.getUpgradePriceInMetaResources(id)
         argsForTableTemplate[TEMPLATE_PARAMETER_UPGRADE_META] = AltarEffectsData.getUpgradePriceInMetaResources(id)
         templateParameters[TEMPLATE_PARAMETER_UPGRADE_VILLAGER] = AltarEffectsData.getUpgradePriceInVillagers(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 showingID string flag when needing to show the ID as well
---@param argsForTableTemplate table a set of arguments ready to pass through to the called template
---@param showingDescription string flag when needing to show the description as well
---@param showingRegular string flag if columns should be added
---@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, showingID, showingDescription, 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, showingID, showingDescription, showingRegular)
         markup = markup .. makeMarkupPerRow(id, isSkippingPrices, argsForTableTemplate)
     end
     end


Line 355: Line 321:
---
---
---@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 showingID string flag when needing to show the ID as well
---@param argsForTableTemplate table a set of arguments ready to pass through to the called template
---@param showingDescription string flag when needing to show the description as well
---@param showingRegular string flag if columns should be added
---@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(desiredCaption, skippingPrice, showingID, showingDescription, showingRegular)
local function renderTable(desiredCaption, isSkippingPrices, argsForTableTemplate)


     local startMarkup = makeMarkupForTableStart(desiredCaption, skippingPrice, showingID, showingDescription, showingRegular)
     local startMarkup = makeMarkupForTableStart(desiredCaption, isSkippingPrices, argsForTableTemplate)
     local rowsMarkup =  makeMarkupForTableRows(skippingPrice, showingID, showingDescription, showingRegular)
     local rowsMarkup =  makeMarkupForTableRows(isSkippingPrices, argsForTableTemplate)


     return startMarkup .. rowsMarkup .. makeMarkupForTableEnd()
     return startMarkup .. rowsMarkup .. makeMarkupForTableEnd()
Line 371: 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 showingID string flag when needing to show the ID as well
---@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, showingID)
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] = showingID
         [TEMPLATE_PARAMETER_SHOW_ID] = isShowingID and ARG_SHOW_FLAG_VALUE
     }
     }


Line 386: Line 350:
---makeMarkupForListItems
---makeMarkupForListItems
---@param listType string the type of list to create
---@param listType string the type of list to create
---@param showingID string flag when needing to show the ID as well
---@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, showingID)
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, showingID)
         markup = markup .. makeMarkupPerListItem(id, listType, isShowingID)
     end
     end


Line 400: Line 364:
---renderList
---renderList
---@param listType string the type of list to create
---@param listType string the type of list to create
---@param showingID string flag when needing to show the ID as well
---@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(listType, showingID)
local function renderList(listType, isShowingID)


     return makeMarkupForListItems(listType, showingID)
     return makeMarkupForListItems(listType, isShowingID)
end
end


---makeMarkupPerLink
---makeMarkupPerLink
---@param id string the id of the cornerstone to display
---@param id string the id of the cornerstone to display
---@param showingID string flag when needing to show the ID as well
---@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 makeMarkupPerLink(id, showingID)
local function makeMarkupPerLink(id, isShowingID)


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


     if showingID == ARG_SHOW_FLAG_VALUE then
     if isShowingID then
         return link .. " ('" .. id .. "')"
         return link .. " ('" .. id .. "')"
     else
     else
Line 428: Line 392:


---makeMarkupForInlineLinks
---makeMarkupForInlineLinks
---@param showingID string flag when needing to show the ID as well
---@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 makeMarkupForInlineLinks(showingID)
local function makeMarkupForInlineLinks(isShowingID)


     local markup = ""
     local markup = ""
Line 437: Line 401:
             markup = markup .. ", "
             markup = markup .. ", "
         end
         end
         markup = markup .. makeMarkupPerLink(id, showingID)
         markup = markup .. makeMarkupPerLink(id, isShowingID)
     end
     end


Line 444: Line 408:


---renderInline
---renderInline
---@param showingID string flag when needing to show the ID as well
---@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 renderInlineLinks(showingID)
local function renderInlineLinks(isShowingID)


     return makeMarkupForInlineLinks(showingID)
     return makeMarkupForInlineLinks(isShowingID)
end
end


Line 463: Line 427:


     -- Selection parameters
     -- Selection parameters
     local inclusions = 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 showingID = frame.args[ARG_SHOW_ID]
    local showingDescription = frame.args[ARG_SHOW_DESCRIPTION]
    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]
    -- 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
     currentFrame = frame
    local selectList = {}
    if inclusions and inclusions ~= "" then
        selectList = expandIDList(inclusions, false)
    end
    local excludeList = {}
    if exclusions and exclusions ~= "" then
        excludeList = expandIDList(exclusions, true)
    end
    desiredCaption = resolveCaption(selectList, searchName, searchDesc, regularID, desiredCaption)


     loadIDs(selectList, searchName, searchDesc, regularID, excludeList)
     loadIDs(selectList, searchName, searchDesc, regularID, excludeList)
Line 497: Line 456:


     if displayOverride == ARG_DISPLAY_OVERRIDE_OPTION_LIST then
     if displayOverride == ARG_DISPLAY_OVERRIDE_OPTION_LIST then
         return renderList(listType, showingID)
         return renderList(listType, isShowingID)
     end
     end
     if displayOverride == ARG_DISPLAY_OVERRIDE_OPTION_INLINE then
     if displayOverride == ARG_DISPLAY_OVERRIDE_OPTION_INLINE then
         return renderInlineLinks(showingID)
         return renderInlineLinks(isShowingID)
     end
     end
    return renderTable(desiredCaption, skippingPrice, showingID, showingDescription, showingRegular)


    -- Default display is table.
    desiredCaption = resolveCaption(desiredCaption, selectList, searchName, searchDesc, regularID)
    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