Module:PerksController
From Against the Storm Official Wiki
Documentation for this module may be created at Module:PerksController/doc
--- --- Serves the Perks searching template by capturing input and using it to control the display of data. --- ---@module PerksController local PerksController = {} --region Dependencies local PerksData = require("Module:PerksData") local ControllerUtilities = require("Module:ControllerUtilities") --endregion --region Private constants local ARG_ID_LIST = "id" local ARG_NAME_LIST = "name" local ARG_DESCRIPTION_LIST = "description" local ARG_RARITY = "rarity" local ARG_SOURCE = "source" local ARGS_EXCLUDE_LIST = "exclude" local ARG_CAPTION = "caption" local ARG_SKIP_SOURCES = "skip_sources" local ARG_SKIP_FLAG_VALUE = "skip" local ARG_SHOW_ID = "show_id" local ARG_SHOW_RARITY = "show_rarity" local ARG_SHOW_DESCRIPTION = "show_description" local ARG_SHOW_SOURCE_ALTAR = "show_source_altar" local ARG_SHOW_SOURCE_CORNERSTONE = "show_source_cornerstone" local ARG_SHOW_SOURCE_ORDER = "show_source_order" local ARG_SHOW_SOURCE_RELIC = "show_source_relic" local ARG_SHOW_SOURCE_TRADER = "show_source_trader" local ARG_SHOW_PRICE = "show_price" 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_RARITY = ARG_RARITY local TEMPLATE_PARAMETER_DESC = ARG_DESCRIPTION_LIST local TEMPLATE_PARAMETER_SOURCE_ALTAR = "is_from_altar" local TEMPLATE_PARAMETER_SOURCE_CORNERSTONE = "is_from_cornerstone" local TEMPLATE_PARAMETER_SOURCE_ORDER = "is_from_order" local TEMPLATE_PARAMETER_SOURCE_RELIC = "is_from_relic" local TEMPLATE_PARAMETER_SOURCE_TRADER = "is_from_trader" local TEMPLATE_PARAMETER_NUM_SOURCES = "num_sources_shown" local TEMPLATE_PARAMETER_PRICE = "price" local TEMPLATE_PARAMETER_SHOW_ID = ARG_SHOW_ID 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 = "PerksCornerstonesTable" local TEMPLATE_TABLE_SUFFIX_ROW = "/row" local TEMPLATE_TABLE_SUFFIX_END = "/end" local TEMPLATE_TABLE_SKIP_SOURCES_VARIANT = "/SkipSources" local TEMPLATE_LIST_ITEM = "PerksCornerstonesList/item" local TEMPLATE_INLINE_LINK = "pl" local DISPLAY_YES = "true" --endregion --region Private member variables local currentFrame = {} local perkIDs = {} local isIDAlreadyAdded = {} --endregion --region Private methods --- Takes a list of possible IDs and only loads the valid ones of the specified rarity or source to the member variable perkIDs. Skips all ids present in the exclude list. --- ---@param newIDs table an array of possible IDs to check before adding ---@param rarityToCheck string a rarity to filter to, needs to be normalized ---@param sourceToCheck string a source to filter to, needs to be normalized ---@param excludeList table an array of IDs that should not be added local function loadPerkIDs(newIDs, rarityToCheck, sourceToCheck, excludeList) for _, id in ipairs(newIDs) do if PerksData.isPerkIDValid(id) and not excludeList[id] and not isIDAlreadyAdded[id] then -- In this situation, nil values mean to skip the filter. local isRarityMatch = not rarityToCheck or "" == rarityToCheck or PerksData.isRarityMatchByID(id, rarityToCheck) local isSourceMatch = not sourceToCheck or "" == sourceToCheck or PerksData.isAnySource(id, sourceToCheck) if isRarityMatch and isSourceMatch then table.insert(perkIDs, id) isIDAlreadyAdded[id] = true end end end end --- Requests the desired lists of IDs from Perks data models, applies some post-processing, and stores them in the member variable perkIDs. --- ---@param selectList table array of ids of the cornerstone to include ---@param searchNameList table array of search criteria for names ---@param searchDescriptionsList table array of search criteria for descriptions ---@param rarity string the rarity of the cornerstones ---@param source string the source of cornerstones ---@param excludeList table list of ids function PerksController.loadIDs(selectList, searchNameList, searchDescriptionsList, rarity, source, excludeList) perkIDs = {} isIDAlreadyAdded = {} local attemptedSearch = false -- Load the selected IDs if selectList then loadPerkIDs(selectList, rarity, source, excludeList) -- It should always be true, but it can be blank. if #selectList > 0 then attemptedSearch = true end end -- Add any name matches if searchNameList and #searchNameList > 0 then for _, searchName in ipairs(searchNameList) do local newIDs = PerksData.getAllPerkIDsWhereName(searchName) loadPerkIDs(newIDs, rarity, source, excludeList) attemptedSearch = true end end -- Add any description matches if searchDescriptionsList and #searchDescriptionsList > 0 then for _, searchDescription in ipairs(searchDescriptionsList) do local newIDs = PerksData.getAllPerkIDsWhereDescription(searchDescription) loadPerkIDs(newIDs, rarity, source, excludeList) attemptedSearch = true end end -- Or, if no searching was attempted (regardless of result), show all from the selected rarities and sources. if not attemptedSearch then local newIDs = PerksData.getAllPerkIDsFilteredByRarityAndSource(rarity, source) loadPerkIDs(newIDs, rarity, source, excludeList) attemptedSearch = true end -- Or, if no searching was even attempted (regardless of result), show them all. if not attemptedSearch then local newIDs = PerksData.getAllPerkIDs() loadStormforgedIDs(newIDs, excludeList) end if #perkIDs > 0 then -- Alphabetize by name. table.sort(perkIDs, PerksData.compareNames) end return perkIDs 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 array of ids of the cornerstone to include ---@param searchNameList table array of search criteria for names ---@param searchDescriptionList table array of search criteria for descriptions ---@param rarity string the rarity of the cornerstones ---@param source string the source of cornerstones ---@return string an appropriate caption, or blank if it should be default local function resolveCaption(desiredCaption, selectList, searchNameList, searchDescriptionList, rarity, source, excludeList) -- 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 = "" .. #perkIDs if rarity and rarity ~= "" then desiredCaption = desiredCaption .. " " .. rarity .. " Perk" addedToText = true else desiredCaption = desiredCaption .. " Perk" -- did not addedToText, this is just default end if #perkIDs > 1 then desiredCaption = desiredCaption .. "s" end if source and source ~= "" then desiredCaption = desiredCaption .. " from " .. source .. "s" addedToText = true end 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 searchNameList and #searchNameList > 0 then if addedToText then desiredCaption = desiredCaption .. " and" end if #searchNameList == 1 and searchNameList[1] then desiredCaption = desiredCaption .. " named '" .. searchNameList[1] .. "'" else desiredCaption = desiredCaption .. " with specific names" end addedToText = true end if searchDescriptionList and #searchDescriptionList > 0 then if addedToText then desiredCaption = desiredCaption .. " and" end if #searchDescriptionList == 1 and searchDescriptionList[1] then desiredCaption = desiredCaption .. " mentioning '" .. searchDescriptionList[1] .. "'" else desiredCaption = desiredCaption .. " by searching descriptions" end 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 ---resolveTableStartTemplate ---@param isSkippingSources boolean true if skipping variant should be used ---@return string the full title of the template, for expandTemplate local function resolveTableStartTemplate(isSkippingSources) local suffixIfSkipping = (isSkippingSources and TEMPLATE_TABLE_SKIP_SOURCES_VARIANT) or "" return TEMPLATE_TABLE_BASE .. suffixIfSkipping end ---resolveTableRowTemplate ---@param isSkippingSources boolean true if skipping variant should be used ---@return string the full title of the template, for expandTemplate local function resolveTableRowTemplate(isSkippingSources) local suffixIfSkipping = (isSkippingSources and TEMPLATE_TABLE_SKIP_SOURCES_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 isSkippingSources 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, isSkippingSources, argsForTableTemplate) argsForTableTemplate[TEMPLATE_PARAMETER_CAPTION] = desiredCaption -- Count how many source columns should be shown. local sources = { ARG_SHOW_SOURCE_ALTAR, ARG_SHOW_SOURCE_CORNERSTONE, ARG_SHOW_SOURCE_ORDER, ARG_SHOW_SOURCE_RELIC, ARG_SHOW_SOURCE_TRADER } local numSourcesShown = 0 for _, index in ipairs(sources) do if ARG_SHOW_FLAG_VALUE == argsForTableTemplate[index] then numSourcesShown = numSourcesShown + 1 end end argsForTableTemplate[TEMPLATE_PARAMETER_NUM_SOURCES] = numSourcesShown return currentFrame:expandTemplate{ title = resolveTableStartTemplate(isSkippingSources), 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 Perk or Cornerstone to use to add data to a new table row ---@param isSkippingSources 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, isSkippingSources, argsForTableTemplate) argsForTableTemplate[TEMPLATE_PARAMETER_ID] = id argsForTableTemplate[TEMPLATE_PARAMETER_RARITY] = PerksData.getRarityByID(id) argsForTableTemplate[TEMPLATE_PARAMETER_DESC] = ControllerUtilities.findAndReplaceSpriteTagsWithFiles(PerksData.getDescriptionByID(id), currentFrame) argsForTableTemplate[TEMPLATE_PARAMETER_PRICE] = PerksData.getPriceByID(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 isSkippingSources then argsForTableTemplate[TEMPLATE_PARAMETER_SOURCE_ALTAR] = PerksData.isFromAltarByID(id) and DISPLAY_YES argsForTableTemplate[TEMPLATE_PARAMETER_SOURCE_CORNERSTONE] = PerksData.isFromCornerstoneByID(id) and DISPLAY_YES argsForTableTemplate[TEMPLATE_PARAMETER_SOURCE_ORDER] = PerksData.isFromOrderByID(id) and DISPLAY_YES argsForTableTemplate[TEMPLATE_PARAMETER_SOURCE_RELIC] = PerksData.isFromEventByID(id) and DISPLAY_YES argsForTableTemplate[TEMPLATE_PARAMETER_SOURCE_TRADER] = PerksData.isFromTraderByID(id) and DISPLAY_YES end return currentFrame:expandTemplate{ title = resolveTableRowTemplate(isSkippingSources), args = argsForTableTemplate } end --- Handles assembling the rows for all of the IDs in the member variable list altarIDs. --- ---@param isSkippingSources boolean true if skipping sources columns ---@param argsForTableTemplate table a table of arguments to pass through to the view templates ---@return string the wiki markup assembled by the view (other templates) local function makeMarkupForTableRows(isSkippingSources, argsForTableTemplate) local markup = "" for _, id in ipairs(perkIDs) do markup = markup .. makeMarkupPerRow(id, isSkippingSources, 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 the caption for the table ---@param isSkippingSources boolean true if skipping sources columns ---@param argsForTableTemplate table a table of arguments to pass through to the view templates ---@return string the wiki markup assembled by the view (other templates) local function renderTable(desiredCaption, isSkippingSources, argsForTableTemplate) local startMarkup = makeMarkupForTableStart(desiredCaption, isSkippingSources, argsForTableTemplate) local rowsMarkup = makeMarkupForTableRows(isSkippingSources, 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(perkIDs) 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(perkIDs) 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 function PerksController.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 searchNameList = ControllerUtilities.expandCommaSeparatedStringsIntoTable(frame.args[ARG_NAME_LIST], false) local searchDescriptionList = ControllerUtilities.expandCommaSeparatedStringsIntoTable(frame.args[ARG_DESCRIPTION_LIST], false) local rarityFilter = PerksData.normalizeRarityText(frame.args[ARG_RARITY]) local sourceFilter = PerksData.normalizeSourceText(frame.args[ARG_SOURCE]) -- Display parameters local desiredCaption = frame.args[ARG_CAPTION] local displayOverride = frame.args[ARG_DISPLAY_OVERRIDE] local listType = frame.args[ARG_LIST_TYPE] local isShowingID = ARG_SHOW_FLAG_VALUE == frame.args[ARG_SHOW_ID] local isSkippingSources = ARG_SKIP_FLAG_VALUE == frame.args[ARG_SKIP_SOURCES] -- For clarity, copy each value instead of reusing the whole args table. local argumentsToPassThroughToTable = { [ARG_SKIP_SOURCES] = frame.args[ARG_SKIP_SOURCES], [ARG_SHOW_ID] = frame.args[ARG_SHOW_ID], [ARG_SHOW_RARITY] = frame.args[ARG_SHOW_RARITY], [ARG_SHOW_DESCRIPTION] = frame.args[ARG_SHOW_DESCRIPTION], [ARG_SHOW_SOURCE_ALTAR] = frame.args[ARG_SHOW_SOURCE_ALTAR], [ARG_SHOW_SOURCE_CORNERSTONE] = frame.args[ARG_SHOW_SOURCE_CORNERSTONE], [ARG_SHOW_SOURCE_ORDER] = frame.args[ARG_SHOW_SOURCE_ORDER], [ARG_SHOW_SOURCE_RELIC] = frame.args[ARG_SHOW_SOURCE_RELIC], [ARG_SHOW_SOURCE_TRADER] = frame.args[ARG_SHOW_SOURCE_TRADER], [ARG_SHOW_PRICE] = frame.args[ARG_SHOW_PRICE] } currentFrame = frame PerksController.loadIDs(selectList, searchNameList, searchDescriptionList, rarityFilter, sourceFilter, excludeList) if #perkIDs < 1 then return "No matching Perks 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, searchNameList, searchDescriptionList, rarityFilter, sourceFilter, excludeList) return renderTable(desiredCaption, isSkippingSources, argumentsToPassThroughToTable) end --endregion return PerksController