Module:Township: Difference between revisions

Various amends to update for v1.1.2, still WIP
(getBiomeTable: Initial implementation; Re-arrange some functions & consistency of function naming with other modules)
(Various amends to update for v1.1.2, still WIP)
Line 1: Line 1:
local Shared = require('Module:Shared')
local Shared = require('Module:Shared')
local Icons = require('Module:Icons')
local Icons = require('Module:Icons')
local Shop = require('Module:Shop')
local GameData = require('Module:GameData')
local GameData = require('Module:GameData')
local Constants = require('Module:Constants')
local Constants = require('Module:Constants')
Line 19: Line 20:
return GameData.getEntityByID(Township.buildings, id)
return GameData.getEntityByID(Township.buildings, id)
end
end
end
-- Gets a resource from id
function p._getResourceByID(id)
return GameData.getEntityByID(Township.resources, id)
end
end


Line 27: Line 33:
end
end
return nil
return nil
end
-- Given a building and biome ID, returns the cost of constructing the building
-- within that biome as a human readable text string. Returns nil if the building
-- cannot be built within that biome.
function p._getBuildingCostText(building, biomeID, delimiter)
-- Basic validation of inputs
if type(building) == 'table' and building.cost ~= nil and biomeID ~= nil then
local delim = delimiter
if delim == nil then
delim = ', '
end
for i, costDef in ipairs(building.cost) do
if costDef.biomeID == biomeID then
local resultPart = {}
for j, cost in ipairs(costDef.cost) do
local resData = p._getResourceByID(cost.id)
if resData ~= nil then
table.insert(resultPart, Icons.Icon({resData.name, type='resource', notext=true, nolink=true, qty=cost.quantity}))
end
end
return table.concat(resultPart, delim)
end
end
end
end
-- Given a building and biome ID, returns a string displaying the building's benefits,
-- or nil if no benefits
function p._getBuildingBenefits(building, biomeID, includeModifiers, delimiter)
-- Basic validation of inputs
if type(building) == 'table' and building.provides ~= nil and biomeID ~= nil then
local delim = delimiter
if delim == nil then
delim = ', '
end
local includeMods = includeModifiers
if includeMods == nil then
includeMods = false
end
local providesData = nil
for i, provides in ipairs(building.provides) do
if provides.biomeID == biomeID then
providesData = provides
break
end
end
if providesData ~= nil then
local resultPart = {}
local stats = {
population = 'Population',
happiness = 'Happiness',
education = 'Education',
storage = 'Storage',
worship = 'Worship'
}
local resourceText = function(resName, resType, quantity)
local elemClass = (quantity < 0 and 'text-negative') or 'text-positive'
local resIcon = Icons.Icon({resName, type=resType, notext=true})
return resIcon .. '&nbsp;<span class="' .. elemClass .. '">' .. Shared.numStrWithSign(quantity) .. '</span>'
end
-- Resources
if providesData.resources ~= nil then
for i, resource in ipairs(providesData.resources) do
local resData = p._getResourceByID(resource.id)
if resData ~= nil and resource.quantity ~= 0 then
table.insert(resultPart, resourceText(resData.name, 'resource', resource.quantity))
end
end
end
-- Other stats
for key, stat in pairs(stats) do
-- TODO Fix always using first biome
local quantity = providesData[key]
if quantity ~= nil and quantity ~= 0 then
table.insert(resultPart, resourceText(stat, 'township', quantity))
end
end
if not Shared.tableIsEmpty(resultPart) then
return table.concat(resultPart, delim)
end
end
end
end
end


Line 42: Line 136:
function p._getTierRequirements(tier)
function p._getTierRequirements(tier)
return Township.populationForTier[tier]
return Township.populationForTier[tier]
end
-- Returns a string containing the Township level and population requirements for a tier
function p._getTierText(tier)
local tierData = p._getTierRequirements(tier)
if tierData ~= nil then
local tierText = Icons._SkillReq('Township', tierData.level, false)
if tierData.population > 0 then
tierText = tierText .. '<br/>' .. Icons.Icon({'Population', type='township', notext=true}) .. '&nbsp;' .. Shared.formatnum(tierData.population)
end
return tierText
end
end
end


Line 56: Line 162:


local resultPart = {}
local resultPart = {}
table.insert(resultPart, '{| class="wikitable sortable stickyHeaders"')
table.insert(resultPart, '{| class="wikitable sortable stickyHeader"')
table.insert(resultPart, '\n|- class="headerRow-0"')
table.insert(resultPart, '\n|- class="headerRow-0"')
table.insert(resultPart, '\n!colspan="2" | Season\n!Type\n!Modifiers')
table.insert(resultPart, '\n!colspan="2" | Season\n!Type\n!Modifiers')
Line 80: Line 186:
function p.getBiomeTable(frame)
function p.getBiomeTable(frame)
local resultPart = {}
local resultPart = {}
table.insert(resultPart, '{| class="wikitable sortable stickyHeaders"')
table.insert(resultPart, '{| class="wikitable sortable stickyHeader"')
table.insert(resultPart, '\n|- class="headerRow-0"')
table.insert(resultPart, '\n|- class="headerRow-0"')
table.insert(resultPart, '\n!rowspan="2" colspan="2"| Biome\n!colspan="2"| Requirements')
table.insert(resultPart, '\n!rowspan="2" colspan="2"| Biome\n!colspan="2"| Requirements')
Line 104: Line 210:
-- Setup the table
-- Setup the table
local ret = {}
local ret = {}
table.insert(ret, '{| class="wikitable sortable stickyHeaders" style="text-align:center"')
table.insert(ret, '{| class="wikitable sortable stickyHeader" style="text-align:center"')
table.insert(ret, '\n|- class="headerRow-0"')
table.insert(ret, '\n|- class="headerRow-0"')
table.insert(ret, '\n! Building')
table.insert(ret, '\n! Building')
Line 143: Line 249:
return table.concat(ret)
return table.concat(ret)
end
end
-- Generates a table contaning each building plus their relevant information
function p.getBuildingTable(frame)
local resultPart = {}
-- Change structure of biomes data for ease of use later
local biomesByID = {}
for i, biome in ipairs(Township.biomes) do
biomesByID[biome.id] = biome
end
-- Generate table header
table.insert(resultPart, '{| class="wikitable sortable stickyHeader"')
table.insert(resultPart, '\n|- class="headerRow-0"')
table.insert(resultPart, '\n!colspan="2"|Building\n!Requirements\n!Type\n!Max Built')
table.insert(resultPart, '\n!Biomes\n!Cost\n!Provides')
local buildings = p._sortedBuildings(false)
for i, building in ipairs(buildings) do
-- Number of rows per building is dictated by number of biomes
local buildingName = (building.id == 'melvorF:Statues' and 'Statue of Worship') or building.name
local firstRow = true
local rowCount = Shared.tableCount(building.biomes)
local rowSpan = (rowCount > 1 and ' rowspan="' .. rowCount .. '"') or ''
local rowSpanOnly = (rowCount > 1 and '|' .. rowSpan) or ''
for j, biomeID in ipairs(building.biomes) do
local biome = biomesByID[biomeID]
if firstRow then
table.insert(resultPart, '\n|-')
table.insert(resultPart, '\n|class="table-img"' .. rowSpan .. '| ' .. Icons.Icon({buildingName, type='building', notext=true, size=50}))
table.insert(resultPart, '\n' .. rowSpanOnly .. '| ' .. Icons.getExpansionIcon(building.id) .. Icons.Icon({buildingName, type='building', noicon=true}))
table.insert(resultPart, '\n|' .. 'data-sort-value="' .. building.tier .. '"' .. rowSpan .. '| ' .. (p._getTierText(building.tier) or ''))
table.insert(resultPart, '\n' .. rowSpanOnly .. '| ' .. building.type)
table.insert(resultPart, '\n|style="text-align:right"' .. rowSpan .. '| ' .. building.maxUpgrades)
firstRow = false
else
table.insert(resultPart, '\n|-')
end
-- This section generates by biome rows
table.insert(resultPart, '\n| ' .. Icons.Icon({biome.name, type='biome', nolink=true}))
table.insert(resultPart, '\n| ' .. p._getBuildingCostText(building, biomeID))
local providesText = p._getBuildingBenefits(building, biomeID)
if building.modifiers ~= nil then
local modText = Constants.getModifiersText(building.modifiers)
if providesText == nil then
providesText = modText
else
providesText = providesText .. '<br/>' .. modText
end
end
table.insert(resultPart, '\n| ' .. (providesText or ''))
end
end
table.insert(resultPart, '\n|}')
return table.concat(resultPart)
end
-- Builds the table of trader items
function p.getTraderTable(frame)
-- Get the resources data with associated trader data
-- Build the text
local ret = {}
for _, resource in ipairs(p.resources) do
if #resource.itemConversions ~= 0 then -- Skips GP
local ret_resource = {}
-- Header
table.insert(ret_resource, '\r\n==='..resource.name..'===')
table.insert(ret_resource, '\r\n{| class="wikitable sortable stickyHeader"')
table.insert(ret_resource, '\r\n|- class="headerRow-0"')
table.insert(ret_resource, '\r\n!Item')
table.insert(ret_resource, '\r\n!Name')
table.insert(ret_resource, '\r\n!Level')
table.insert(ret_resource, '\r\n!Give To')
table.insert(ret_resource, '\r\n!Take From')
table.insert(ret_resource, '\r\n!Value')
table.insert(ret_resource, '\r\n!Value/Resource')
if resource.id =='melvorF:Food' then
table.insert(ret_resource, '\r\n!Heals')
table.insert(ret_resource, '\r\n!Heals/Resource')
end
-- Each item
for _, item in ipairs(resource.itemConversions) do
-- To indicate the skill level, we need to find the recipe of the item in the target skill
-- Unfortunately Module:Items/SourceTables.getItemSources does not provide parseable data
local required_level = nil
local recipes = nil
-- Get the skill based on the item.id or else use the resource's default skill
local skill_overrides = {
['melvorD:Raw_Magic_Fish'] = 'melvorD:Fishing',
['melvorF:Apple'] = 'melvorD:Farming',
}
local skill = skill_overrides[item.id] or p._GetResourceSkill(resource.id)
local skill_namespace, skill_localid = GameData.getLocalID(skill or '')
-- Check for upgraded Crafting items and downgrade them so we can display the crafting level for the base item
-- e.g. converts Black_Dhide_Body_U -> Black_Dhide_Body for the purposes of the lookup
local lookup_id = item.id
if string.match(item.id, '_U$') then
lookup_id = string.sub(item.id, 1, #item.id - 2)
end
-- Find the recipe's level
local recipes = p._FindItemRecipes(lookup_id, skill)
if #recipes == 1 then
required_level = recipes[1].level
end
-- Alright, now that we've found the required recipe and level, we can draw the item's row entry
table.insert(ret_resource, '\r\n|-')
-- Icon
table.insert(ret_resource, '\r\n|style="text-align:center"|'..Icons.Icon({item.name, type='item', size='50', notext=true}))
-- Name
table.insert(ret_resource, '\r\n|style="text-align:left"|'..Icons.getExpansionIcon(item.id)..Icons.Icon({item.name, type='item', noicon=true}))
-- Level
if required_level == nil then
-- Recipe not found, or multiple recipes found
table.insert(ret_resource, '\r\n|style="text-align:center" data-sort-value="0"|N/A')
else
table.insert(ret_resource, '\r\n|style="text-align:center" data-sort-value="' .. required_level .. '"|'..Icons.Icon({skill_localid, type="skill", notext=true})..' '..required_level)
end
-- Give To
table.insert(ret_resource, '\r\n|style="text-align:center" data-sort-value="' .. item.toTownship .. '"|'..Icons.Icon({item.name, type='item', notext=true})..' '..Shared.formatnum(item.toTownship))
-- Take From
table.insert(ret_resource, '\r\n|style="text-align:center" data-sort-value="' .. item.fromTownship .. '"|'..Icons.Icon({resource.name, type='resource', notext=true})..' '..Shared.formatnum(item.fromTownship))
-- Value
table.insert(ret_resource, '\r\n|style="text-align:center" data-sort-value="' .. item.sellsFor .. '"|'..Icons.GP(item.sellsFor))
-- Value/Resource
table.insert(ret_resource, '\r\n|style="text-align:center" data-sort-value="' .. item.sellsFor/item.fromTownship .. '"|'..Icons.GP(Shared.round(item.sellsFor/item.fromTownship, 2, 2)))
if resource.id =='melvorF:Food' then
-- Heals
table.insert(ret_resource, '\r\n|style="text-align:center" data-sort-value="' .. item.healsFor*10 .. '"|'..Icons.Icon({"Hitpoints", type="skill", notext=true})..' '..Shared.formatnum(item.healsFor*10))
-- Heals/Resource
table.insert(ret_resource, '\r\n|style="text-align:center" data-sort-value="' .. item.healsFor*10/item.fromTownship .. '"|'..Icons.Icon({"Hitpoints", type="skill", notext=true})..' '..Shared.round(item.healsFor*10/item.fromTownship, 2, 2))
end
end
table.insert(ret_resource, '\r\n|}')
table.insert(ret, table.concat(ret_resource))
end
end
return table.concat(ret)
end
-- Generates a table showing all the worship options
function p.getWorshipTable()
local function getCheckpointCell(checkpoint)
return '\n|-\n!' .. checkpoint .. '%<br/>' .. Shared.formatnum(checkpoint * Township.maxWorship / 100) .. '/' .. Shared.formatnum(Township.maxWorship)
end
local worships = GameData.getEntities(Township.worships, function(w) return not w.isHidden end)
local ret = {}
table.insert(ret, '{| class="wikitable stickyHeader"')
table.insert(ret, '\n!' .. Icons.Icon({'Worship', type='township', nolink=true}))
-- Names
for _, worship in ipairs(worships) do
table.insert(ret, '\n!' .. Icons.Icon({worship.name, type='monster', size=50}) .. Icons.Icon({'Statue of ' .. worship.name, type='building', size=50, notext=true}))
end
-- Requirements
table.insert(ret, '\n|-\n!Requirements')
for _, worship in ipairs(worships) do
table.insert(ret, '\n|style="text-align:center"| ' .. Shop.getRequirementString(worship.unlockRequirements))
end
-- Base modifiers
table.insert(ret, getCheckpointCell(0))
for _, worship in ipairs(worships) do
table.insert(ret, '\n| ' .. Constants.getModifiersText(worship.modifiers))
end
-- Checkpoint modifiers
for i, checkpoint in ipairs(Township.worshipCheckpoints) do
table.insert(ret, getCheckpointCell(checkpoint))
for _, worship in ipairs(worships) do
table.insert(ret, '\n| ' .. Constants.getModifiersText(worship.checkpoints[i]))
end
end
-- Total sum
table.insert(ret, '\n|-\n!Total')
for _, worship in ipairs(worships) do
local modifiers = Shared.clone(worship.modifiers)
for _, checkpoint in ipairs(worship.checkpoints) do
for modifier, magnitude in pairs(checkpoint) do
local swappedModifier = string.sub(modifier, 1, string.len('increased')) == 'increased' and string.gsub(modifier, 'increased', 'decreased') or string.gsub(modifier, 'decreased', 'increased')
-- The modifier already exists, so we add the two modifiers together
if modifiers[modifier] ~= nil then
modifiers[modifier] = modifiers[modifier] + magnitude
-- The inverse modifier already exists, so we subtract the negative value of the new modifier
elseif modifiers[swappedModifier] ~= nil then
modifiers[swappedModifier] = modifiers[swappedModifier] - magnitude
-- The modifier does not exist, so create the modifier
else
modifiers[modifier] = magnitude
end
end
end
table.insert(ret, '\n|' .. Constants.getModifiersText(modifiers))
end
table.insert(ret, '\n|}')
return table.concat(ret)
end
-- TODO Check if functions below this line are still in use


-- Returns the recipe for the item of a desired skill.
-- Returns the recipe for the item of a desired skill.
Line 303: Line 622:
end
end
p.resources = p._TraderData()
p.resources = p._TraderData()
-- Builds the table of trader items
function p.GetTraderTable(frame)
-- Get the resources data with associated trader data
-- Build the text
local ret = {}
for _, resource in ipairs(p.resources) do
if #resource.itemConversions ~= 0 then -- Skips GP
local ret_resource = {}
-- Header
table.insert(ret_resource, '\r\n==='..resource.name..'===')
table.insert(ret_resource, '\r\n{| class="wikitable sortable stickyHeader"')
table.insert(ret_resource, '\r\n|- class="headerRow-0"')
table.insert(ret_resource, '\r\n!Item')
table.insert(ret_resource, '\r\n!Name')
table.insert(ret_resource, '\r\n!Level')
table.insert(ret_resource, '\r\n!Give To')
table.insert(ret_resource, '\r\n!Take From')
table.insert(ret_resource, '\r\n!Value')
table.insert(ret_resource, '\r\n!Value/Resource')
if resource.id =='melvorF:Food' then
table.insert(ret_resource, '\r\n!Heals')
table.insert(ret_resource, '\r\n!Heals/Resource')
end
-- Each item
for _, item in ipairs(resource.itemConversions) do
-- To indicate the skill level, we need to find the recipe of the item in the target skill
-- Unfortunately Module:Items/SourceTables.getItemSources does not provide parseable data
local required_level = nil
local recipes = nil
-- Get the skill based on the item.id or else use the resource's default skill
local skill_overrides = {
['melvorD:Raw_Magic_Fish'] = 'melvorD:Fishing',
['melvorF:Apple'] = 'melvorD:Farming',
}
local skill = skill_overrides[item.id] or p._GetResourceSkill(resource.id)
local skill_namespace, skill_localid = GameData.getLocalID(skill or '')
-- Check for upgraded Crafting items and downgrade them so we can display the crafting level for the base item
-- e.g. converts Black_Dhide_Body_U -> Black_Dhide_Body for the purposes of the lookup
local lookup_id = item.id
if string.match(item.id, '_U$') then
lookup_id = string.sub(item.id, 1, #item.id - 2)
end
-- Find the recipe's level
local recipes = p._FindItemRecipes(lookup_id, skill)
if #recipes == 1 then
required_level = recipes[1].level
end
-- Alright, now that we've found the required recipe and level, we can draw the item's row entry
table.insert(ret_resource, '\r\n|-')
-- Icon
table.insert(ret_resource, '\r\n|style="text-align:center"|'..Icons.Icon({item.name, type='item', size='50', notext=true}))
-- Name
table.insert(ret_resource, '\r\n|style="text-align:left"|'..Icons.getExpansionIcon(item.id)..Icons.Icon({item.name, type='item', noicon=true}))
-- Level
if required_level == nil then
-- Recipe not found, or multiple recipes found
table.insert(ret_resource, '\r\n|style="text-align:center" data-sort-value="0"|N/A')
else
table.insert(ret_resource, '\r\n|style="text-align:center" data-sort-value="' .. required_level .. '"|'..Icons.Icon({skill_localid, type="skill", notext=true})..' '..required_level)
end
-- Give To
table.insert(ret_resource, '\r\n|style="text-align:center" data-sort-value="' .. item.toTownship .. '"|'..Icons.Icon({item.name, type='item', notext=true})..' '..Shared.formatnum(item.toTownship))
-- Take From
table.insert(ret_resource, '\r\n|style="text-align:center" data-sort-value="' .. item.fromTownship .. '"|'..Icons.Icon({resource.name, type='resource', notext=true})..' '..Shared.formatnum(item.fromTownship))
-- Value
table.insert(ret_resource, '\r\n|style="text-align:center" data-sort-value="' .. item.sellsFor .. '"|'..Icons.GP(item.sellsFor))
-- Value/Resource
table.insert(ret_resource, '\r\n|style="text-align:center" data-sort-value="' .. item.sellsFor/item.fromTownship .. '"|'..Icons.GP(Shared.round(item.sellsFor/item.fromTownship, 2, 2)))
if resource.id =='melvorF:Food' then
-- Heals
table.insert(ret_resource, '\r\n|style="text-align:center" data-sort-value="' .. item.healsFor*10 .. '"|'..Icons.Icon({"Hitpoints", type="skill", notext=true})..' '..Shared.formatnum(item.healsFor*10))
-- Heals/Resource
table.insert(ret_resource, '\r\n|style="text-align:center" data-sort-value="' .. item.healsFor*10/item.fromTownship .. '"|'..Icons.Icon({"Hitpoints", type="skill", notext=true})..' '..Shared.round(item.healsFor*10/item.fromTownship, 2, 2))
end
end
table.insert(ret_resource, '\r\n|}')
table.insert(ret, table.concat(ret_resource))
end
end
return table.concat(ret)
end


-- Gets the associated skill of a resource by id
-- Gets the associated skill of a resource by id
Line 430: Line 658:
end
end
end
end
-- Returns a string containing the Township level and population requirements for a tier
function p._GetTierText(tierlevel)
local tier = p._getTierRequirements(tierlevel)
return Icons._SkillReq('Township', tier.level, false)..'<br>'..Icons.Icon({'Population', type='township', notext=true})..'&nbsp;'..tier.population
end


-- Gets a building and prepares all the relevant stats for the building
-- Gets a building and prepares all the relevant stats for the building
-- TODO Rename, getBuildingInfoBox or something of the sort
function p.GetBuildingTable(frame)
function p.GetBuildingTable(frame)
local name = frame.args ~= nil and frame.args[1] or frame
local name = frame.args ~= nil and frame.args[1] or frame
Line 455: Line 677:
table.insert(ret, '\r\n|-\r\n| <b>Type:</b> '..building.type)
table.insert(ret, '\r\n|-\r\n| <b>Type:</b> '..building.type)
-- Tier
-- Tier
local tier = p._GetTierText(building.tier)
local tier = p._getTierText(building.tier)
table.insert(ret, '\r\n|-\r\n| <b>Requirements:</b><br>'..tier)
table.insert(ret, '\r\n|-\r\n| <b>Requirements:</b><br>'..tier)


Line 478: Line 700:


-- Fixed benefits
-- Fixed benefits
local benefits = p._GetBuildingBenefits(building)
local benefits = p._getBuildingBenefits(building)
if benefits ~= nil then
if benefits ~= nil then
table.insert(ret, '\r\n|-\r\n| <b>Provides:</b> '..benefits)
table.insert(ret, '\r\n|-\r\n| <b>Provides:</b> '..benefits)
Line 505: Line 727:
table.insert(ret, '\r\n|}')
table.insert(ret, '\r\n|}')
return table.concat(ret)
return table.concat(ret)
end
-- Given a resource id, return the job id
-- e.g. melvorF:Bar -> melvorF:Blacksmith
function p._GetJobFromResource(resource_id)
local job = GameData.getEntityByProperty(Township.jobs, 'produces', resource_id)
return job.id
end
end


Line 529: Line 744:
local production = resource.quantity*100*(Township.tickLength/10)
local production = resource.quantity*100*(Township.tickLength/10)
local color = production < 0 and 'red' or 'green'
local color = production < 0 and 'red' or 'green'
local resource_data = p._GetResourceByID(resource.id)
local resource_data = p._getResourceByID(resource.id)
table.insert(retProduction, '<span style="color:'..color..'">'..Icons.Icon({resource_data.name, type='resource', notext=true})..'&nbsp;'..Shared.numStrWithSign(production)..'</span>')
table.insert(retProduction, '<span style="color:'..color..'">'..Icons.Icon({resource_data.name, type='resource', notext=true})..'&nbsp;'..Shared.numStrWithSign(production)..'</span>')
if resource_data.requires ~= nil and #resource_data.requires > 0 then
if resource_data.requires ~= nil and #resource_data.requires > 0 then
for _, required_resource in ipairs(resource_data.requires) do
for _, required_resource in ipairs(resource_data.requires) do
local demand = production*required_resource.quantity*100
local demand = production*required_resource.quantity*100
local required_resource_data = p._GetResourceByID(required_resource.id)
local required_resource_data = p._getResourceByID(required_resource.id)
table.insert(retProduction, '<span style="color:red">'..Icons.Icon({required_resource_data.name, type='resource', notext=true})..'&nbsp;-'..demand..'</span>')
table.insert(retProduction, '<span style="color:red">'..Icons.Icon({required_resource_data.name, type='resource', notext=true})..'&nbsp;-'..demand..'</span>')
end
end
Line 540: Line 755:
end
end
return table.concat(retResources, '<br>')
return table.concat(retResources, '<br>')
end
-- Gets a string displaying the building's benefits, or nil if no benefits
function p._GetBuildingBenefits(building)
local benefits = {}
local stats = {
population = 'Population',
happiness = 'Happiness',
education = 'Education',
storage = 'Storage',
deadStorage = 'Dead Storage',
worship = 'Worship'
}
for key, stat in pairs(stats) do
-- TODO Fix always using first biome
if building.provides[1][key] ~= nil and building.provides[1][key] ~= 0 then
local quantity = building.provides[1][key]
if quantity < 0 then
quantity = '<span style="color:red">'..quantity..'</span>'
else
quantity = Shared.numStrWithSign(quantity)
end
table.insert(benefits, Icons.Icon({stat, type='township', notext=true})..'&nbsp;'..quantity)
end
end
if #benefits > 0 then
return table.concat(benefits, ', ')
end
return nil
end
end


Line 590: Line 776:
-- always taking costs for the first biome
-- always taking costs for the first biome
for _, resource in ipairs(building.cost[1].cost) do
for _, resource in ipairs(building.cost[1].cost) do
local resource_data = p._GetResourceByID(resource.id)
local resource_data = p._getResourceByID(resource.id)
table.insert(cost, Icons.Icon({resource_data.name, type='resource', notext=true})..'&nbsp;'..resource.quantity)
table.insert(cost, Icons.Icon({resource_data.name, type='resource', notext=true})..'&nbsp;'..resource.quantity)
end
end
return table.concat(cost, join)
return table.concat(cost, join)
end
-- Gets a resource from id
function p._GetResourceByID(id)
return GameData.getEntityByID(p.resources, id)
end
-- Gets text for only the biomes that have a modifier for a building
function p._GetBiomeModifiers(building)
-- TODO Concept of biome modifiers doesn't exist anymore
return ''
--[==[
local biomeRet = {}
for _, biome in ipairs(building.biomeModifiers) do
local biomename = GameData.getEntityByID(Township.biomes, biome.biomeID).name
local color = biome.value < 0 and 'red' or 'green'
local biome_value = Shared.numStrWithSign(biome.value)
table.insert(biomeRet, Icons.Icon({biomename, type='biome', notext=true, nolink=true})..' <span style="color:'..color..'">'..biomename..' ('..biome_value..'%)</span>')
end
if #biomeRet == 0 then
return nil
end
return table.concat(biomeRet, '<br>')
--]==]
end
end


Line 664: Line 826:
table.insert(ret, '\r\n|-\r\n! Requirements')
table.insert(ret, '\r\n|-\r\n! Requirements')
for _, building in ipairs(buildingList) do
for _, building in ipairs(buildingList) do
local tier = p._GetTierText(building.tier)
local tier = p._getTierText(building.tier)
table.insert(ret, '\r\n|'..tier)
table.insert(ret, '\r\n|'..tier)
end
end
Line 693: Line 855:
end
end
end
end
BuildOptionalRow('\r\n|-\r\n! Benefits\r\n|', p._GetBuildingBenefits)
BuildOptionalRow('\r\n|-\r\n! Benefits\r\n|', p._getBuildingBenefits)
BuildOptionalRow('\r\n|-\r\n! Biome Production Modifiers\r\n|', p._GetBiomeModifiers)


-- End
-- End
Line 700: Line 861:
return table.concat(ret)
return table.concat(ret)
end
-- TODO Fix
local FREE_LAND = Township.sectionSize or 0
-- Gets the cost of the current price of land
-- Taken from township.js -> Township.getNextSectionCost
function p.GetLandCost(frame)
local nthland = tonumber(frame.args ~= nil and frame.args[1] or frame)
return p._GetLandCost(nthland)
end
function p._GetLandCost(nthland)
-- First FREE_LAND plots of land are free
if nthland <= FREE_LAND then
return 0
end
return math.floor(15^(0.0100661358978*(nthland/32) + (nthland/32)^0.42))
end
-- Gets the cost to buy land until you have X amount of available land
-- Currently the max is 2048 land
function p.GetCumulativeLandCost(frame)
local totalLand = tonumber(frame.args ~= nil and frame.args[1] or frame)
return p._GetCumulativeLandCost(totalLand)
end
function p._GetCumulativeLandCost(totalLand)
local cost = 0
while totalLand > FREE_LAND do
cost = cost + p._GetLandCost(totalLand)
totalLand = totalLand - 1
end
return cost
end
-- Returns a table showing the land cost of a town
function p.GetLandCostTable()
-- TODO Fix
return ''
--[[=[
local ret = {}
table.insert(ret, '\r\n{| class="wikitable"')
table.insert(ret, '\r\n|- style="text-align:center" \r\n! Total Land \r\n! Single Land Cost \r\n! Total Cost')
for i=FREE_LAND,Township.maxTownSize,FREE_LAND do
table.insert(ret, '\r\n|-\r\n|'..i..'\r\n|'..Icons.GP(p._GetLandCost(i))..'\r\n|'..Icons.GP(p._GetCumulativeLandCost(i)))
end
table.insert(ret, '\r\n|}')
return table.concat(ret)
--]=]]
end
end


Line 810: Line 921:
end
end
for _, townshipResource in ipairs(task.rewards.townshipResources) do
for _, townshipResource in ipairs(task.rewards.townshipResources) do
local resourcename = p._GetResourceByID(townshipResource.id).name
local resourcename = p._getResourceByID(townshipResource.id).name
table.insert(rewards, Shared.formatnum(townshipResource.quantity)..' '..Icons.Icon({resourcename, type='resource'}))
table.insert(rewards, Shared.formatnum(townshipResource.quantity)..' '..Icons.Icon({resourcename, type='resource'}))
end
end
Line 923: Line 1,034:
end
end


-- Generates a table showing all the worship options
-- TODO Temporary functions, these exist to enable renaming of functions
-- above without causing templates to break until they are migrated to these
-- newly-named functions
function p.GetWorshipTable()
function p.GetWorshipTable()
local function GetCheckpointCell(checkpoint)
return p.getWorshipTable()
return '\r\n|-\r\n!'..checkpoint..'%<br>'..(checkpoint*Township.maxWorship/100)..'/'..Township.maxWorship
end
local ret = {}
table.insert(ret, '\r\n{| class="wikitable" style="text-align:left"')
table.insert(ret, '\r\n!'..Icons.Icon({'Worship', type='township', nolink=true}))
-- Names
for _, worship in ipairs(Township.worships) do
if worship.isHidden == false then
table.insert(ret, '\r\n!'..Icons.Icon({worship.name, type='monster', size=50})..Icons.Icon({'Statue of '..worship.name, type='building', size=50, notext=true}))
end
end
-- Requirements
-- Hard-coded because there's only 1 requirement
table.insert(ret, '\r\n|-\r\n!Requirements')
local requirements = {
['melvorF:Bane'] = 'Completion of<br>'..Icons.Icon({'Impending Darkness Event', type='dungeon'})
}
for _, worship in ipairs(Township.worships) do
if worship.isHidden == false then
local requirement = requirements[worship.id] ~= nil and requirements[worship.id] or 'None'
table.insert(ret, '\r\n|style="text-align:center|'..requirement)
end
end
-- Base modifiers
table.insert(ret, GetCheckpointCell(0))
for _, worship in ipairs(Township.worships) do
if worship.isHidden == false then
table.insert(ret, '\r\n|'..Constants.getModifiersText(worship.modifiers))
end
end
-- Checkpoint modifiers
for i, checkpoint in ipairs(Township.worshipCheckpoints) do
table.insert(ret, GetCheckpointCell(checkpoint))
for _, worship in ipairs(Township.worships) do
if worship.isHidden == false then
table.insert(ret, '\r\n|'..Constants.getModifiersText(worship.checkpoints[i]))
end
end
end
 
-- Total sum
table.insert(ret, '\r\n|-\r\n!Total')
for _, worship in ipairs(Township.worships) do
if worship.isHidden == false then
local modifiers = Shared.clone(worship.modifiers)
for _, checkpoint in ipairs(worship.checkpoints) do
for modifier, magnitude in pairs(checkpoint) do
local swappedModifier = string.sub(modifier, 1, string.len('increased')) == 'increased' and string.gsub(modifier, 'increased', 'decreased') or string.gsub(modifier, 'decreased', 'increased')
-- The modifier already exists, so we add the two modifiers together
if modifiers[modifier] ~= nil then
modifiers[modifier] = modifiers[modifier] + magnitude
-- The inverse modifier already exists, so we subtract the negative value of the new modifier
elseif modifiers[swappedModifier] ~= nil then
modifiers[swappedModifier] = modifiers[swappedModifier] - magnitude
-- The modifier does not exist, so create the modifier
else
modifiers[modifier] = magnitude
end
end
end
table.insert(ret, '\r\n|'..Constants.getModifiersText(modifiers))
end
end
table.insert(ret, '\r\n|}')
return table.concat(ret)
end
end


return p
return p