Module:Buildingbox2: Difference between revisions

From Against the Storm Official Wiki
(fixed rendering specializations private method)
 
(Updated to work with building interface, support for service buildings, farms, camps, and collectors)
 
(One intermediate revision by the same user not shown)
Line 9: Line 9:
--region Dependencies
--region Dependencies


--Some dependencies in this module are loaded lazily.
--Some dependencies in this module are loaded lazily, but we want them scoped to the entire module, not their local functions
 
local WorkshopsData
local RecipeController = require("Module:RecipeController")
local InstitutionsData
local FarmsData
local CampsData
local CollectorsData


local ViewTemplate = "Template:Infobox"
local ViewTemplate = "Template:Infobox"
Line 21: Line 24:
--region Private constants
--region Private constants


local ARG_ID = "id"
local ARG_NAME = "name"


local PARAM_TITLE = "title"
local PARAM_TITLE = "title"
local PARAM_SUBTITLE = "subtitle"
local PARAM_SUBTITLE = "subtitle"
local PARAM_DESCRIPTION = "description"
local PARAM_DESCRIPTION = "description"
local PARAM_SPECIALIZATION = "specialization"
local PARAM_ICON_FILENAME = "iconfilename"
local PARAM_MOVABLE = "movable"
local PARAM_WORKPLACES = "workplaces"
local PARAM_STORAGE = "storage"
local PARAM_RECIPES = "recipes"
local PARAM_CONSTRUCTION_COST = "construction"
local PARAM_CITY_SCORE = "cityscore"
local PARAM_CONSTRUCTION_TIME = "constructiontime"
local PARAM_CONSTRUCTION_SIZE = "constructionsize"
local PARAM_ID = "id"


--endregion
--endregion
Line 33: Line 47:
--region Private methods
--region Private methods


---renderSpecializations takes the ID of a building and looks up its specialization
---renderSpecializations takes the ID of a building and looks up its specializations, calls external view templates to convert those specializations into usable content strings for display, and returns those strings concatenated together for display by the calling scope.
---@param id table
---@param id string the unique ID of the building
function Buildingbox2.renderSpecializations(id)
---@return string a content string ready for display
local function renderSpecializations(id)


     local SpecializationsData = mw.loadData("Module:SpecializationsData")
     local SpecializationsData = mw.loadData("Module:SpecializationsData")
Line 47: Line 62:
     end
     end


     local listOfStringsToReturn = {}
     local concatenatedStrings = ""
     for i, specIndex in ipairs(listOfSpecializationsAtBuilding) do
     for _, specIndex in ipairs(listOfSpecializationsAtBuilding) do


        -- Specialization link first
         local specData = SpecializationsData.specializations[specIndex]
         local specData = SpecializationsData.specializations[specIndex]
         local specializationString = frame:expandTemplate{
         local specializationString = frame:expandTemplate{
             title = "Specialization",
             title = "Specialization",
Line 58: Line 73:
                 ["name"] = specData[SpecializationsData.NAME],
                 ["name"] = specData[SpecializationsData.NAME],
                 ["type"] = specData[SpecializationsData.IS_COMFORTABLE] and "Comfort" or "Proficiency",
                 ["type"] = specData[SpecializationsData.IS_COMFORTABLE] and "Comfort" or "Proficiency",
                 ["size"] = "medium",
                 ["size"] = "small",
             }, }
             }, }


        -- Species link second, but just the icon
         local species = specData[SpecializationsData.SPECIES]
         local species = specData[SpecializationsData.SPECIES]
         local speciesString = frame:expandTemplate{
         local speciesString = frame:expandTemplate{
             title = "Species",
             title = "Species",
Line 68: Line 83:
                 ["iconfilename"] = SpeciesData.species[species][SpeciesData.ICON_FILENAME] .. ".png",
                 ["iconfilename"] = SpeciesData.species[species][SpeciesData.ICON_FILENAME] .. ".png",
                 ["name"] = SpeciesData.species[species][SpeciesData.NAME],
                 ["name"] = SpeciesData.species[species][SpeciesData.NAME],
                 ["size"] = "medium",
                 ["size"] = "small",
                 [1] = "notext",
                 [1] = "notext",
             }, }
             }, }


         table.insert(listOfStringsToReturn, specializationString .. " " .. speciesString)
         -- Separate multiple entries with line break
        if #concatenatedStrings > 1 then
            concatenatedStrings = concatenatedStrings .. "<br />"
        end
 
        concatenatedStrings = concatenatedStrings .. specializationString .. "&nbsp;" .. speciesString
     end
     end


     if #listOfStringsToReturn < 1 then
     if #concatenatedStrings < 1 then
         return "None"
         return "None"
     end
     end


     return listOfStringsToReturn
     return concatenatedStrings
end
 
 
 
-- Building interface:
-- getCategory
-- getCityScore
-- getConstructionCosts (as [goodName] = stack size)
-- getConstructionTime
-- getDescription
-- getIcon
-- isMovable
-- getName
-- getNumberOfWorkplaces
-- getSize (as "X x Y")
-- getStorage
local function buildViewParameters(id, buildingInterface, subtitlePrefix)
 
    local frame = mw.getCurrentFrame()
 
    local viewParameters = {}
    viewParameters[PARAM_TITLE] = buildingInterface.getName(id)
    viewParameters[PARAM_SUBTITLE] = subtitlePrefix .. " (" .. buildingInterface.getCategory(id) .. ")"
    viewParameters[PARAM_DESCRIPTION] = buildingInterface.getDescription(id)
    viewParameters[PARAM_SPECIALIZATION] = renderSpecializations(id)
    viewParameters[PARAM_ICON_FILENAME] = buildingInterface.getIcon(id)
    viewParameters[PARAM_MOVABLE] = buildingInterface.isMovable(id) and "true"
    viewParameters[PARAM_WORKPLACES] = buildingInterface.getNumberOfWorkplaces(id)
    viewParameters[PARAM_RECIPES] = frame:expandTemplate{ title = "Recipe", args = { ["building"] = buildingInterface.getName(id), ["display"] = "list", }, }
    viewParameters[PARAM_STORAGE] = buildingInterface.getStorage(id)
    viewParameters[PARAM_CONSTRUCTION_COST] = frame:expandTemplate{ title = "Construction", args = buildingInterface.getConstructionCosts(id) }
    viewParameters[PARAM_CITY_SCORE] = buildingInterface.getCityScore(id)
    viewParameters[PARAM_CONSTRUCTION_TIME] = buildingInterface.getConstructionTime(id)
    viewParameters[PARAM_CONSTRUCTION_SIZE] = buildingInterface.getSize(id)
    viewParameters[PARAM_ID] = id
 
    return viewParameters
end
end






function Buildingbox2.tryWorkshopsData(id)
local function tryWorkshopsData(name)
 
    WorkshopsData = require("Module:WorkshopsData")
 
    local id = WorkshopsData.getWorkshopID(name)
    if not id then
        return false
    else
        return buildViewParameters(id, WorkshopsData, "Production Building")
    end
end
 
local function tryInstitutionsData(name)


     local WorkshopsData = require("Module:WorkshopsData")
     InstitutionsData = require("Module:InstitutionsData")


     local name = WorkshopsData.getWorkshopNameByID(id)
     local id = InstitutionsData.getInstitutionID(name)
     if not name then
     if not id then
         return false
         return false
    else
        return buildViewParameters(id, InstitutionsData, "Service Building")
     end
     end
end


    local viewParameters = {}
local function tryFarmsData(name)
    viewParameters[PARAM_TITLE] = name
 
     viewParameters[PARAM_SUBTITLE] = "Production Building (" .. WorkshopsData.getWorkshopCategory(name) .. ")"
     FarmsData = require("Module:FarmsData")
     viewParameters[PARAM_DESCRIPTION] = WorkshopsData.getWorkshopDescription(name)
 
     viewParameters[PARAM_SPECIALIZATION] = renderSpecializations(id)
     local id = FarmsData.getFarmID(name)
     if not id then
        return false
    else
        return buildViewParameters(id, FarmsData, "Farm")
    end
end


local function tryCampsData(name)


     viewParameters = {
     CampsData = require("Module:CampsData")
        ["title"] = "Furnace",
        ["subtitle"] = "Production Building",
        ["description"] = "Can produce: Pie (**), Skewers (**), Copper Bars (**). Can use: Drizzle Water.",
        ["specialization"] = "Warmth",
        ["iconfilename"] = "Furnace_icon.png",
        ["workplaces"] = 3,
        ["recipes"] = "Recipe content goes here",
        ["construction"] = "Construction content goes here",
        ["cityscore"] = 10,
        ["constructiontime"] = "00:40",
        ["constructionsize"] = "3 × 2",
        ["id"] = "Furnace",
    }


     return viewParameters
     local id = CampsData.getCampID(name)
    if not id then
        return false
    else
        return buildViewParameters(id, CampsData, "Gathering Camp")
    end
end
end


--endregion
local function tryCollectorsData(name)


    CollectorsData = require("Module:CollectorsData")


    local id = CollectorsData.getCollectorID(name)
    if not id then
        return false
    else
        return buildViewParameters(id, CollectorsData, "Extraction Building")
    end
end


--region Public methods


--- For calling from another template, like Infobox. Handles data only, does not interface with the Buildingbox view.
--- For calling from another template, like Infobox. Handles data only, does not interface with the Buildingbox view.
---@param id string the id of the building about which to retrieve data
---@param name string the name of the building about which to retrieve data
---@return table the essential data about the building extracted
---@return table the essential data about the building extracted
function Buildingbox2.compileBoxContents(id)
local function findBoxType(name)


     -- Lazy-load of external data, since it's expensive. Start with the most likely so that most pages load as fast as possible.
     -- Lazy-load of external data, since it's expensive. Start with the most likely so that most pages load as fast as possible.
     local viewParameters = tryWorkshopsData(id)
     local viewParameters = tryWorkshopsData(name)
     if not viewParameters then
     if not viewParameters then
         viewParameters = tryInstitutionsData(id)
         viewParameters = tryInstitutionsData(name)
         if not viewParameters then
         if not viewParameters then
             viewParameters = tryFarmsData(id)
             viewParameters = tryFarmsData(name)
             if not viewParameters then
             if not viewParameters then
                 viewParameters = tryCollectorsData(id)
                 viewParameters = tryCollectorsData(name)
                 if not viewParameters then
                 if not viewParameters then
                     viewParameters = tryCampsData(id)
                     viewParameters = tryCampsData(name)
                     if not viewParameters then
                     if not viewParameters then
                         return("No building found with id: " .. id .. ".")
                         return("No building found with name: " .. name .. ".")
                     end
                     end
                 end
                 end
             end
             end
         end
         end
    end
    -- Make sure something exists in the data before returning it; the ID should always exist.
    if not viewParameters["id"] then
        error("Specified ID resulted in no data.")
     end
     end


Line 155: Line 229:
end
end


--endregion


--region Public methods


--- For calling from Template:Buildingbox. After handling the frame, forwards control to the primary method, compileBoxData, then calls the view template with the compiled box data. Does not interface with any data modules.
--- For calling from Template:Buildingbox. After handling the frame, forwards control to the primary method, compileBoxData, then calls the view template with the compiled box data. Does not interface with any data modules.
Line 163: Line 241:
function Buildingbox2.main(frame)
function Buildingbox2.main(frame)


     local id = frame.args[ARG_ID]
     local name = frame.args[ARG_NAME]
     if not id then
     if not name then
         error("You must specify the id of the building. Please see the template documentation for how to use the parameters.")
         error("You must specify the name of the building. Please see the template documentation for how to use the parameters.")
     end
     end


     local viewParameters = Buildingbox2.compileBoxContents(id)
     local viewParameters = findBoxType(name)
 
    -- Return the message if it's a string, otherwise proceed because it's a table.
    if type(viewParameters) == "string" then
        return viewParameters
    end


     return frame:expandTemplate{ title = ViewTemplate, args = viewParameters }
     return frame:expandTemplate{ title = ViewTemplate, args = viewParameters }

Latest revision as of 02:50, 9 October 2024

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

---
--- Retrieves data for the specified building, resource, perk, etc. and sends the data over to the view, another template.
---
--- @module Buildingbox2
local Buildingbox2 = {}



--region Dependencies

--Some dependencies in this module are loaded lazily, but we want them scoped to the entire module, not their local functions
local WorkshopsData
local InstitutionsData
local FarmsData
local CampsData
local CollectorsData

local ViewTemplate = "Template:Infobox"

--endregion



--region Private constants

local ARG_NAME = "name"

local PARAM_TITLE = "title"
local PARAM_SUBTITLE = "subtitle"
local PARAM_DESCRIPTION = "description"
local PARAM_SPECIALIZATION = "specialization"
local PARAM_ICON_FILENAME = "iconfilename"
local PARAM_MOVABLE = "movable"
local PARAM_WORKPLACES = "workplaces"
local PARAM_STORAGE = "storage"
local PARAM_RECIPES = "recipes"
local PARAM_CONSTRUCTION_COST = "construction"
local PARAM_CITY_SCORE = "cityscore"
local PARAM_CONSTRUCTION_TIME = "constructiontime"
local PARAM_CONSTRUCTION_SIZE = "constructionsize"
local PARAM_ID = "id"

--endregion



--region Private methods

---renderSpecializations takes the ID of a building and looks up its specializations, calls external view templates to convert those specializations into usable content strings for display, and returns those strings concatenated together for display by the calling scope.
---@param id string the unique ID of the building
---@return string a content string ready for display
local function renderSpecializations(id)

    local SpecializationsData = mw.loadData("Module:SpecializationsData")
    local SpeciesData = mw.loadData("Module:SpeciesData")
    local frame = mw.getCurrentFrame()

    local listOfSpecializationsAtBuilding = SpecializationsData.buildingSpecializations[id]

    if not listOfSpecializationsAtBuilding then
        return nil
    end

    local concatenatedStrings = ""
    for _, specIndex in ipairs(listOfSpecializationsAtBuilding) do

        -- Specialization link first
        local specData = SpecializationsData.specializations[specIndex]
        local specializationString = frame:expandTemplate{
            title = "Specialization",
            args = {
                ["iconfilename"] = specData[SpecializationsData.ICON_FILENAME],
                ["name"] = specData[SpecializationsData.NAME],
                ["type"] = specData[SpecializationsData.IS_COMFORTABLE] and "Comfort" or "Proficiency",
                ["size"] = "small",
            }, }

        -- Species link second, but just the icon
        local species = specData[SpecializationsData.SPECIES]
        local speciesString = frame:expandTemplate{
            title = "Species",
            args = {
                ["iconfilename"] = SpeciesData.species[species][SpeciesData.ICON_FILENAME] .. ".png",
                ["name"] = SpeciesData.species[species][SpeciesData.NAME],
                ["size"] = "small",
                [1] = "notext",
            }, }

        -- Separate multiple entries with line break
        if #concatenatedStrings > 1 then
            concatenatedStrings = concatenatedStrings .. "<br />"
        end

        concatenatedStrings = concatenatedStrings .. specializationString .. "&nbsp;" .. speciesString
    end

    if #concatenatedStrings < 1 then
        return "None"
    end

    return concatenatedStrings
end



-- Building interface:
-- getCategory
-- getCityScore
-- getConstructionCosts (as [goodName] = stack size)
-- getConstructionTime
-- getDescription
-- getIcon
-- isMovable
-- getName
-- getNumberOfWorkplaces
-- getSize (as "X x Y")
-- getStorage
local function buildViewParameters(id, buildingInterface, subtitlePrefix)

    local frame = mw.getCurrentFrame()

    local viewParameters = {}
    viewParameters[PARAM_TITLE] = buildingInterface.getName(id)
    viewParameters[PARAM_SUBTITLE] = subtitlePrefix .. " (" .. buildingInterface.getCategory(id) .. ")"
    viewParameters[PARAM_DESCRIPTION] = buildingInterface.getDescription(id)
    viewParameters[PARAM_SPECIALIZATION] = renderSpecializations(id)
    viewParameters[PARAM_ICON_FILENAME] = buildingInterface.getIcon(id)
    viewParameters[PARAM_MOVABLE] = buildingInterface.isMovable(id) and "true"
    viewParameters[PARAM_WORKPLACES] = buildingInterface.getNumberOfWorkplaces(id)
    viewParameters[PARAM_RECIPES] = frame:expandTemplate{ title = "Recipe", args = { ["building"] = buildingInterface.getName(id), ["display"] = "list", }, }
    viewParameters[PARAM_STORAGE] = buildingInterface.getStorage(id)
    viewParameters[PARAM_CONSTRUCTION_COST] = frame:expandTemplate{ title = "Construction", args = buildingInterface.getConstructionCosts(id) }
    viewParameters[PARAM_CITY_SCORE] = buildingInterface.getCityScore(id)
    viewParameters[PARAM_CONSTRUCTION_TIME] = buildingInterface.getConstructionTime(id)
    viewParameters[PARAM_CONSTRUCTION_SIZE] = buildingInterface.getSize(id)
    viewParameters[PARAM_ID] = id

    return viewParameters
end



local function tryWorkshopsData(name)

    WorkshopsData = require("Module:WorkshopsData")

    local id = WorkshopsData.getWorkshopID(name)
    if not id then
        return false
    else
        return buildViewParameters(id, WorkshopsData, "Production Building")
    end
end

local function tryInstitutionsData(name)

    InstitutionsData = require("Module:InstitutionsData")

    local id = InstitutionsData.getInstitutionID(name)
    if not id then
        return false
    else
        return buildViewParameters(id, InstitutionsData, "Service Building")
    end
end

local function tryFarmsData(name)

    FarmsData = require("Module:FarmsData")

    local id = FarmsData.getFarmID(name)
    if not id then
        return false
    else
        return buildViewParameters(id, FarmsData, "Farm")
    end
end

local function tryCampsData(name)

    CampsData = require("Module:CampsData")

    local id = CampsData.getCampID(name)
    if not id then
        return false
    else
        return buildViewParameters(id, CampsData, "Gathering Camp")
    end
end

local function tryCollectorsData(name)

    CollectorsData = require("Module:CollectorsData")

    local id = CollectorsData.getCollectorID(name)
    if not id then
        return false
    else
        return buildViewParameters(id, CollectorsData, "Extraction Building")
    end

end


--- For calling from another template, like Infobox. Handles data only, does not interface with the Buildingbox view.
---@param name string the name of the building about which to retrieve data
---@return table the essential data about the building extracted
local function findBoxType(name)

    -- Lazy-load of external data, since it's expensive. Start with the most likely so that most pages load as fast as possible.
    local viewParameters = tryWorkshopsData(name)
    if not viewParameters then
        viewParameters = tryInstitutionsData(name)
        if not viewParameters then
            viewParameters = tryFarmsData(name)
            if not viewParameters then
                viewParameters = tryCollectorsData(name)
                if not viewParameters then
                    viewParameters = tryCampsData(name)
                    if not viewParameters then
                        return("No building found with name: " .. name .. ".")
                    end
                end
            end
        end
    end

    return viewParameters
end

--endregion



--region Public methods

--- For calling from Template:Buildingbox. After handling the frame, forwards control to the primary method, compileBoxData, then calls the view template with the compiled box data. Does not interface with any data modules.
---
---@param frame table the calling template's context
---@return string wiki markup, constructed with the template view
function Buildingbox2.main(frame)

    local name = frame.args[ARG_NAME]
    if not name then
        error("You must specify the name of the building. Please see the template documentation for how to use the parameters.")
    end

    local viewParameters = findBoxType(name)

    -- Return the message if it's a string, otherwise proceed because it's a table.
    if type(viewParameters) == "string" then
        return viewParameters
    end

    return frame:expandTemplate{ title = ViewTemplate, args = viewParameters }
end

--endregion

return Buildingbox2