572
edits
(Blanked the page) Tag: Blanking |
(Modifiers) |
||
Line 1: | Line 1: | ||
local Shared = require('Module:Shared') | |||
local Icons = require('Module:Icons') | |||
local GameData = require('Module:GameData') | |||
local Constants = require('Module:Constants') | |||
local p = {} | |||
local Township = GameData.getSkillData('melvorD:Township') | |||
p.Township = Township | |||
-- Returns the namespace name (eventually we should use an icon) | |||
function p.PLACEHOLDER_NAMESPACE_ICON(namespace) | |||
local namespaces = { | |||
melvorD = 'Demo', | |||
melvorF = 'Full', | |||
melvorTotH = 'TotH' | |||
} | |||
return namespaces[namespace] | |||
end | |||
-- Returns the recipe for the item of a desired skill. | |||
-- Unfortunately Module:Items/SourceTables.getItemSources does not provide parseable data so we instead use this quick function | |||
function p._FindItemRecipes(itemid, skill) | |||
-- No skill? No recipes | |||
if skill == nil then | |||
return {} | |||
end | |||
-- the key name for each skill in the json file | |||
local skill_recipe_keys = { | |||
['melvorD:Woodcutting'] = {recipes='trees', productID='productId'}, -- lowercase "d" | |||
['melvorD:Fishing'] = {recipes='fish', productID='productId'}, -- lowercase "d" | |||
['melvorD:Cooking'] = {recipes='recipes', productID='productID'}, | |||
['melvorD:Mining'] = {recipes='rockData', productID='productId'}, -- lowercase "d" | |||
['melvorD:Smithing'] = {recipes='recipes', productID='productID'}, | |||
['melvorD:Farming'] = {recipes='recipes', productID='productId'}, -- lowercase "d" | |||
['melvorD:Summoning'] = {recipes='recipes', productID='productID'}, | |||
['melvorD:Fletching'] = {recipes='recipes', productID='productID'}, | |||
['melvorD:Crafting'] = {recipes='recipes', productID='productID'}, | |||
['melvorD:Runecrafting'] = {recipes='recipes', productID='productID'}, | |||
['melvorD:Herblore'] = {recipes='recipes', productID='potionIDs'} -- Special case potions I-IV | |||
--[[ Excluded skills: | |||
Attack, Strength, Defence, Magic, Ranged, Prayer, Slayer | |||
Thieving, Agility, Astrology, Firemaking, Township (not items)]] | |||
} | |||
local results = {} | |||
local SkillData = GameData.getSkillData(skill) | |||
local recipes = skill_recipe_keys[skill].recipes | |||
local productID = skill_recipe_keys[skill].productID | |||
if SkillData[recipes] ~= nil then | |||
for _, recipe in ipairs(SkillData[recipes]) do | |||
-- Special case for Herblore | |||
if skill == 'melvorD:Herblore' then | |||
-- Iterate over the 4 potion tiers | |||
for _, potionid in ipairs(recipe[productID]) do | |||
if itemid == potionid then | |||
table.insert(results, Shared.clone(recipe)) | |||
end | |||
end | |||
-- Base case | |||
else | |||
if itemid == recipe[productID] then | |||
table.insert(results, Shared.clone(recipe)) | |||
end | |||
end | |||
end | |||
end | |||
return results | |||
end | |||
-- Returns a list of all the Township resources | |||
function p._ResourcesData() | |||
-- Get a sorted list of all the resources | |||
local resources = GameData.sortByOrderTable(Township.resources, Township.resourceDisplayOrder[1].ids) | |||
resources = Shared.clone(resources) | |||
return resources | |||
end | |||
-- Returns a list of all the Township resources along with the Trader's trade ratios | |||
function p._TraderData() | |||
-- Get the list of resources. We get a copy instead of directly using p.resources because we are going to modify the table | |||
local resources = p._ResourcesData() | |||
-- Get the list of tradeable items | |||
-- See township.js -> TownshipResource.buildResourceItemConversions for the calculation of valid items | |||
local function matchNone(item) | |||
return false | |||
end | |||
local function matchFood(item) | |||
return item.type == 'Food' and (not string.match(item.id, '_Perfect')) and item.category ~= 'Farming' and (not item.ignoreCompletion) | |||
end | |||
local function matchLogs(item) | |||
return item.type == 'Logs' | |||
end | |||
local function matchOre(item) | |||
return item.type == 'Ore' and item.id ~= 'melvorTotH:Meteorite_Ore' | |||
end | |||
local function matchCoal(item) | |||
return item.id == 'melvorD:Coal_Ore' | |||
end | |||
local function matchBar(item) | |||
return item.type == 'Bar' and item.id ~= 'melvorTotH:Meteorite_Bar' | |||
end | |||
local function matchHerb(item) | |||
return item.type == 'Herb' | |||
end | |||
local function matchEssence(item) | |||
return item.id == 'melvorD:Rune_Essence' or item.id == 'melvorTotH:Pure_Essence' | |||
end | |||
local function matchLeather(item) | |||
return item.id == 'melvorD:Leather' | |||
end | |||
local function matchPotion(item) | |||
return item.type == 'Potion' and string.match(item.id, '_IV') | |||
end | |||
local function matchClothing(item) | |||
local valid_tiers = {'Leather', 'Hard Leather', 'Dragonhide', 'Elderwood', 'Revenant', 'Carrion'} | |||
for _, tier in ipairs(valid_tiers) do | |||
if item.tier == tier then | |||
return true | |||
end | |||
end | |||
return false | |||
end | |||
local traderMatchesList = { | |||
['melvorF:GP'] = {traderMatches = matchNone}, | |||
['melvorF:Food'] = {traderMatches = matchFood}, | |||
['melvorF:Wood'] = {traderMatches = matchLogs}, | |||
['melvorF:Stone'] = {traderMatches = matchOre}, | |||
['melvorF:Ore'] = {traderMatches = matchOre}, | |||
['melvorF:Coal'] = {traderMatches = matchCoal}, | |||
['melvorF:Bar'] = {traderMatches = matchBar}, | |||
['melvorF:Herbs'] = {traderMatches = matchHerb}, | |||
['melvorF:Rune_Essence'] = {traderMatches = matchEssence}, | |||
['melvorF:Leather'] = {traderMatches = matchLeather}, | |||
['melvorF:Potions'] = {traderMatches = matchPotion}, | |||
['melvorF:Planks'] = {traderMatches = matchLogs}, | |||
['melvorF:Clothing'] = {traderMatches = matchClothing} | |||
} | |||
for _, resource in ipairs(resources) do | |||
resource.itemConversions = Shared.clone(GameData.getEntities('items', traderMatchesList[resource.id].traderMatches)) | |||
end | |||
-- Calculate the trader's conversion ratios | |||
-- See township.js TownshipResource.getBaseConvertToTownshipRatio and TownshipResource.getBaseConvertFromTownshipRatio for the conversion prices | |||
for _, resource in ipairs(resources) do | |||
if resource.id == 'melvorF:Food' then | |||
for _, item in ipairs(resource.itemConversions) do | |||
item.toTownship = math.max(math.floor(1000/(item.healsFor*10)), 2) | |||
item.fromTownship = item.healsFor*5*6 | |||
end | |||
elseif resource.id == 'melvorF:Planks' then | |||
for _, item in ipairs(resource.itemConversions) do | |||
item.toTownship = math.max(math.floor(3000/math.max(item.sellsFor, 1)), 2) | |||
item.fromTownship = math.max(math.ceil(item.sellsFor/2)*6, 1); | |||
end | |||
elseif resource.id == 'melvorF:Rune_Essence' then | |||
for _, item in ipairs(resource.itemConversions) do | |||
item.toTownship = 5 | |||
item.fromTownship = (item.sellsFor+1)*10*6 | |||
end | |||
elseif resource.id == 'melvorF:Leather' then | |||
for _, item in ipairs(resource.itemConversions) do | |||
item.toTownship = 20 | |||
item.fromTownship = 20*6 | |||
end | |||
else | |||
for _, item in ipairs(resource.itemConversions) do | |||
item.toTownship = math.max(math.floor(1000/math.max(item.sellsFor, 1)), 2) | |||
item.fromTownship = math.max(item.sellsFor*6, 1) | |||
end | |||
end | |||
end | |||
return resources | |||
end | |||
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!DLC') | |||
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.Icon({item.name, type='item', noicon=true})) | |||
-- DLC | |||
local item_namespace, item_localid = GameData.getLocalID(item.id) | |||
table.insert(ret_resource, '\r\n|style="text-align:center"|'..p.PLACEHOLDER_NAMESPACE_ICON(item_namespace)) | |||
-- 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 | |||
-- modifiers associated with specific biomes | |||
local biome_data = { | |||
['melvorF:Grasslands'] = {modifiers = {'increasedTownshipGrasslandsProduction', 'decreasedTownshipGrasslandsProduction'}}, | |||
['melvorF:Forest'] = {modifiers = {'increasedTownshipForestProduction', 'decreasedTownshipForestProduction'}}, | |||
['melvorF:Desert'] = {modifiers = {'increasedTownshipDesertProduction', 'decreasedTownshipDesertProduction'}}, | |||
['melvorF:Water'] = {modifiers = {'increasedTownshipWaterProduction', 'decreasedTownshipWaterProduction'}}, | |||
['melvorF:Swamp'] = {modifiers = {'increasedTownshipSwampProduction', 'decreasedTownshipSwampProduction'}}, | |||
['melvorF:Arid_Plains'] = {modifiers = {'increasedTownshipAridPlainsProduction', 'decreasedTownshipAridPlainsProduction'}}, | |||
['melvorF:Mountains'] = {modifiers = {'increasedTownshipMountainsProduction', 'decreasedTownshipMountainsProduction'}}, | |||
['melvorF:Valley'] = {modifiers = {'increasedTownshipValleyProduction', 'decreasedTownshipValleyProduction'}}, | |||
['melvorF:Jungle'] = {modifiers = {'increasedTownshipJungleProduction', 'decreasedTownshipJungleProduction'}}, | |||
['melvorF:Snowlands'] = {modifiers = {'increasedTownshipSnowlandsProduction', 'decreasedTownshipSnowlandsProduction', 'increasedTownshipCoalUsage', 'decreasedTownshipCoalUsage'}}, | |||
} | |||
-- modifiers associated with specific buildings or resources | |||
local unique_modifiers = { | |||
['melvorF:Fishermans_Dock'] = {modifiers = {'increasedTownshipFishingDockProduction', 'decreasedTownshipFishingDockProduction'}}, | |||
['melvorF:Fishermans_Pier'] = {modifiers = {'increasedTownshipFishingDockProduction', 'decreasedTownshipFishingDockProduction'}}, | |||
['melvorF:Fishermans_Port'] = {modifiers = {'increasedTownshipFishingDockProduction', 'decreasedTownshipFishingDockProduction'}}, | |||
['melvorTotH:Fishermans_Estate'] = {modifiers = {'increasedTownshipFishingDockProduction', 'decreasedTownshipFishingDockProduction'}}, | |||
['melvorF:Magic_Emporium'] = {modifiers = {'increasedTownshipMagicEmporiumProduction', 'decreasedTownshipMagicEmporiumProduction'}}, | |||
['melvorF:Orchard'] = {modifiers = {'increasedTownshipOrchardProduction', 'decreasedTownshipOrchardProduction'}}, | |||
['melvorF:Farmland'] = {modifiers = {'increasedTownshipFarmProduction', 'decreasedTownshipFarmProduction'}}, | |||
['melvorF:Mill'] = {modifiers = {'increasedTownshipFarmProduction', 'decreasedTownshipFarmProduction'}}, | |||
['melvorF:Plantation'] = {modifiers = {'increasedTownshipFarmProduction', 'decreasedTownshipFarmProduction'}}, | |||
['melvorTotH:Farming_Estate'] = {modifiers = {'increasedTownshipFarmProduction', 'decreasedTownshipFarmProduction'}}, | |||
['melvorF:Woodcutters_Camp'] = {modifiers = {'increasedTownshipWoodcuttingProduction', 'decreasedTownshipWoodcuttingProduction'}}, | |||
['melvorF:Logging_Camp'] = {modifiers = {'increasedTownshipWoodcuttingProduction', 'decreasedTownshipWoodcuttingProduction'}}, | |||
['melvorF:Forestry_Camp'] = {modifiers = {'increasedTownshipWoodcuttingProduction', 'decreasedTownshipWoodcuttingProduction'}}, | |||
['melvorTotH:Forestry_Estate'] = {modifiers = {'increasedTownshipWoodcuttingProduction', 'decreasedTownshipWoodcuttingProduction'}}, | |||
['melvorF:Blacksmiths_Smithy'] = {modifiers = {'increasedTownshipBlacksmithProduction', 'decreasedTownshipBlacksmithProduction'}}, | |||
['melvorF:Blacksmiths_Forge'] = {modifiers = {'increasedTownshipBlacksmithProduction', 'decreasedTownshipBlacksmithProduction'}}, | |||
['melvorF:Blacksmiths_Workshop'] = {modifiers = {'increasedTownshipBlacksmithProduction', 'decreasedTownshipBlacksmithProduction'}}, | |||
['melvorTotH:Blacksmiths_Estate'] = {modifiers = {'increasedTownshipBlacksmithProduction', 'decreasedTownshipBlacksmithProduction'}}, | |||
['melvorF:Food'] = {modifiers = {'increasedTownshipFoodUsage', 'decreasedTownshipFoodUsage'}}, | |||
-- Absolute delta so doesn't apply to buildings | |||
population = {modifiers = {'increasedTownshipPopulationCap', 'decreasedTownshipPopulationCap'}}, | |||
} | |||
p.stats = { | |||
happiness = {name='Happiness', modifiers = {'increasedTownshipHappiness', 'decreasedTownshipHappiness', 'increasedTownshipBuildingHappinessPenalties', 'decreasedTownshipBuildingHappinessPenalties'}}, | |||
education = {name='Education', modifiers = {'increasedTownshipEducation', 'decreasedTownshipEducation'}}, | |||
health = {name='Health', modifiers = {'increasedTownshipHealth', 'decreasedTownshipHealth'}}, | |||
storage = {name='Storage', modifiers = {'increasedTownshipMaxStorage', 'decreasedTownshipMaxStorage'}}, | |||
deadStorage = {name='Dead Storage', modifiers = {'increasedTownshipDeadStorage', 'decreasedTownshipDeadStorage'}}, | |||
population = {name='Population', modifiers = {}}, -- see unique_modifiers | |||
} | |||
-- Special modifiers | |||
local special_modifiers = { | |||
['all_buildings'] = {modifiers={'increasedTownshipBuildingCost', 'decreasedTownshipBuildingCost'}}, | |||
['all_production'] = {modifiers={'increasedTownshipResourceProduction', 'decreasedTownshipResourceProduction'}}, --Includes GP production as well | |||
['unused'] = {modifiers = {'townshipDisableHunting'}}, | |||
} | |||
-- skill -> The Skill used to produce the Trader's tradeable items | |||
-- modifiers -> For buildings that produce this resource, the modifiers to search for. | |||
local resource_info = { | |||
['melvorF:GP'] = {skill = nil, modifiers={'increasedTownshipGPProduction', 'decreasedTownshipGPProduction', 'increasedTownshipTaxPerCitizen', 'decreasedTownshipTaxPerCitizen'}}, | |||
['melvorF:Food'] = {skill = 'melvorD:Cooking', modifiers={'increasedTownshipFoodProduction', 'decreasedTownshipFoodProduction'}}, | |||
['melvorF:Wood'] = {skill = 'melvorD:Woodcutting', modifiers={'increasedTownshipWoodProduction', 'decreasedTownshipWoodProduction'}}, | |||
['melvorF:Stone'] = {skill = 'melvorD:Mining', modifiers={'increasedTownshipStoneProduction', 'decreasedTownshipStoneProduction'}}, | |||
['melvorF:Ore'] = {skill = 'melvorD:Mining', modifiers={'increasedTownshipOreProduction', 'decreasedTownshipOreProduction'}}, | |||
['melvorF:Coal'] = {skill = 'melvorD:Mining', modifiers={'increasedTownshipCoalProduction', 'decreasedTownshipCoalProduction', 'TownshipCoalUsage'}}, | |||
['melvorF:Bar'] = {skill = 'melvorD:Smithing', modifiers={'increasedTownshipBarProduction', 'decreasedTownshipBarProduction'}}, | |||
['melvorF:Herbs'] = {skill = 'melvorD:Farming', modifiers={'increasedTownshipHerbProduction', 'decreasedTownshipHerbProduction'}}, | |||
['melvorF:Rune_Essence'] = {skill = 'melvorD:Mining', modifiers={'increasedTownshipRuneEssenceProduction', 'decreasedTownshipRuneEssenceProduction'}}, | |||
['melvorF:Leather'] = {skill = nil, modifiers={'increasedTownshipLeatherProduction', 'decreasedTownshipLeatherProduction'}}, | |||
['melvorF:Potions'] = {skill = 'melvorD:Herblore', modifiers={'increasedTownshipPotionProduction', 'decreasedTownshipPotionProduction'}}, | |||
['melvorF:Planks'] = {skill = 'melvorD:Woodcutting', modifiers={'increasedTownshipPlankProduction', 'decreasedTownshipPlankProduction'}}, | |||
['melvorF:Clothing'] = {skill = 'melvorD:Crafting', modifiers={'increasedTownshipClothingProduction', 'decreasedTownshipClothingProduction'}}, | |||
} | |||
-- Gets a list of target modifiers based on the building name | |||
function p._GetBuildingModifiers(building) | |||
local modifiers = {} | |||
local newModifiers = nil | |||
local function addModifiers(_newModifiers) | |||
if newModifiers ~= nil then | |||
for _, newModifier in pairs(_newModifiers.modifiers) do | |||
table.insert(modifiers, newModifier) | |||
end | |||
end | |||
end | |||
-- Unique ID modifiers | |||
newModifiers = unique_modifiers[building.id] | |||
addModifiers(newModifiers) | |||
-- Building modifiers | |||
newModifiers = special_modifiers.all_buildings | |||
addModifiers(newModifiers) | |||
-- Production modifiers | |||
local anyProduction = false | |||
for _, resource in ipairs(building.provides.resources) do | |||
anyProduction = true | |||
newModifiers = resource_info[resource.id] | |||
addModifiers(newModifiers) | |||
end | |||
if anyProduction == true then | |||
newModifiers = special_modifiers.all_production | |||
addModifiers(newModifiers) | |||
end | |||
-- Benefit modifiers | |||
for statid, stat in pairs(p.stats) do | |||
if building.provides[statid] ~= nil and building.provides[statid] ~= 0 then | |||
addModifiers(stat) | |||
end | |||
end | |||
return modifiers | |||
end | |||
-- Gets a list of target modifiers based on a resource id | |||
function p._GetResourceModifiers(resource_id) | |||
local modifiers = {} | |||
local newModifiers = nil | |||
local function addModifiers(_newModifiers) | |||
if newModifiers ~= nil then | |||
for _, newModifier in pairs(_newModifiers.modifiers) do | |||
table.insert(modifiers, newModifier) | |||
end | |||
end | |||
end | |||
-- Unique ID modifiers | |||
newModifiers = unique_modifiers[resource_id] | |||
addModifiers(newModifiers) | |||
-- Production | |||
newModifiers = special_modifiers.all_production | |||
addModifiers(newModifiers) | |||
-- Resource modifiers | |||
newModifiers = resource_info[resource_id] | |||
addModifiers(newModifiers) | |||
return modifiers | |||
end | |||
-- Gets a list of target modifiers based on a stat id | |||
function p._GetStatModifiers(stat_id) | |||
local modifiers = {} | |||
local newModifiers = nil | |||
local function addModifiers(_newModifiers) | |||
if newModifiers ~= nil then | |||
for _, newModifier in pairs(_newModifiers.modifiers) do | |||
table.insert(modifiers, newModifier) | |||
end | |||
end | |||
end | |||
-- Unique ID modifiers | |||
newModifiers = unique_modifiers[stat_id] | |||
addModifiers(newModifiers) | |||
-- Production | |||
newModifiers = p.stats[stat_id] | |||
addModifiers(newModifiers) | |||
return modifiers | |||
end | |||
-- Gets a list of target modifiers based on a biome id. Does not include buildings' biomeModifiers | |||
function p._GetBiomeModifiers(biome_id) | |||
local modifiers = {} | |||
local newModifiers = nil | |||
local function addModifiers(_newModifiers) | |||
if newModifiers ~= nil then | |||
for _, newModifier in pairs(_newModifiers.modifiers) do | |||
table.insert(modifiers, newModifier) | |||
end | |||
end | |||
end | |||
-- Unique ID modifiers | |||
newModifiers = biome_data[biome_id] | |||
addModifiers(newModifiers) | |||
return modifiers | |||
end | |||
function p._GetResourceSkill(id) | |||
return resource_info[id].skill | |||
end | |||
-- Gets a Township building by ID, e.g. melvorF:Hunters_Cabin | |||
function p._GetBuildingByID(id) | |||
return GameData.getEntityByID(Township.buildings, id) | |||
end | |||
-- Gets a Township building by name, e.g. Hunters Cabin | |||
function p._GetBuildingByName(name) | |||
return GameData.getEntityByName(Township.buildings, name) | |||
end | |||
-- Gets the Township level and population requirements for a tier | |||
-- Returns {population=X, level=X} | |||
function p._GetTierRequirements(tier) | |||
return Township.populationForTier[tier] | |||
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})..' '..tier.population | |||
end | |||
-- Gets a building and prepares all the relevant stats for the building | |||
function p.GetBuildingTable(frame) | |||
local name = frame.args ~= nil and frame.args[1] or frame | |||
local building = Shared.clone(p._GetBuildingByName(name)) | |||
local ret = {} | |||
-- Header | |||
table.insert(ret, '\r\n{| class="wikitable infobox"') | |||
-- Name | |||
table.insert(ret, '\r\n|-\r\n!'..building.name) | |||
-- Icon | |||
table.insert(ret, '\r\n|-\r\n|style="text-align:center"|'..Icons.Icon({building.name, type='building', size='250', notext=true})) | |||
-- ID | |||
table.insert(ret, '\r\n|-\r\n| <b>Building ID:</b> '..building.id) | |||
-- Type | |||
table.insert(ret, '\r\n|-\r\n| <b>Type:</b> '..building.type) | |||
-- Tier | |||
local tier = p._GetTierText(building.tier) | |||
table.insert(ret, '\r\n|-\r\n| <b>Requirements:</b><br>'..tier) | |||
-- Upgrades From | |||
table.insert(ret, '\r\n|-\r\n| <b>Base Cost:</b>') | |||
local upgradesFrom = p._GetBuildingDowngrade(building) | |||
if upgradesFrom ~= nil then | |||
table.insert(ret, '<br>'..Icons.Icon({upgradesFrom.name, type='building'})) | |||
end | |||
-- Cost | |||
local cost = p._GetBuildingBaseCost(building) | |||
table.insert(ret, '<br>'..cost) | |||
-- Upgrades To | |||
local upgradesTo = p._GetBuildingIDUpgrade(building.id) | |||
if upgradesTo ~= nil then | |||
table.insert(ret, '\r\n|-\r\n| <b>Upgrades To:</b>') | |||
table.insert(ret, '<br>'..Icons.Icon({upgradesTo.name, type='building'})) | |||
local upgrade_cost = p._GetBuildingBaseCost(upgradesTo) | |||
table.insert(ret, '<br>'..upgrade_cost) | |||
end | |||
-- Fixed benefits | |||
local benefits = p._GetBuildingBenefits(building) | |||
if benefits ~= nil then | |||
table.insert(ret, '\r\n|-\r\n| <b>Provides:</b> '..benefits) | |||
end | |||
-- Production | |||
local production = p._GetBuildingBaseProduction(building) | |||
if production ~= nil then | |||
table.insert(ret, '\r\n|-\r\n| <b>Base Production per '..Icons.Icon({'Workers', type='township', notext=true})..':</b><br>') | |||
table.insert(ret, production) | |||
end | |||
-- Modifiers | |||
if building.modifiers ~= nil and not Shared.tableIsEmpty(building.modifiers) then | |||
table.insert(ret, '\r\n|-\r\n| <b>Modifiers:</b>\r\n'..Constants.getModifiersText(building.modifiers, true)) | |||
end | |||
-- Biomes | |||
table.insert(ret, '\r\n|-\r\n| <b>Biomes:</b><br><ul>') | |||
for _, biomeid in ipairs(building.biomes) do | |||
local biomename = GameData.getEntityByID(Township.biomes, biomeid).name | |||
-- Optional hidden bonus/penalty for building | |||
local modifier = nil | |||
if #building.biomeModifiers > 0 then | |||
modifier = GameData.getEntityByProperty(building.biomeModifiers, 'biomeID', biomeid) | |||
end | |||
if modifier ~= nil then | |||
local color = modifier.value < 0 and 'red' or 'green' | |||
local modifier_value = Shared.numStrWithSign(modifier.value) | |||
table.insert(ret, '<li style="color:'..color..'"><b>'..biomename..' ('..modifier_value..'%)</b></li>') | |||
else | |||
table.insert(ret, '<li>'..biomename..'</li>') | |||
end | |||
end | |||
-- End | |||
table.insert(ret, '\r\n|}') | |||
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 | |||
-- Gets a string displaying the base production of a building, or nil if no production | |||
function p._GetBuildingBaseProduction(building) | |||
local production = Shared.clone(building.provides.resources) | |||
if #production == 0 then | |||
return nil | |||
end | |||
local retResources = {} | |||
for _, resource in ipairs(production) do | |||
local retProduction = {} | |||
local job = p._GetJobFromResource(resource.id) | |||
local workers = GameData.getEntityByID(building.provides.workers, job).quantity | |||
-- Sourced from township.js -> Township.computeTownResourceGain() | |||
local production = resource.quantity*100*(Township.tickLength/10) | |||
local color = production < 0 and 'red' or 'green' | |||
local resource_data = p._GetResourceByID(resource.id) | |||
table.insert(retProduction, '<span style="color:'..color..'">'..Icons.Icon({resource_data.name, type='resource', notext=true})..' '..Shared.numStrWithSign(production)..'</span>') | |||
if resource_data.requires ~= nil and #resource_data.requires > 0 then | |||
for _, required_resource in ipairs(resource_data.requires) do | |||
local demand = production*required_resource.quantity*100 | |||
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})..' -'..demand..'</span>') | |||
end | |||
end | |||
retProduction = table.concat(retProduction, ', ')..'/t ('..Icons.Icon({'Workers', type='township', notext=true})..' '..workers..')' | |||
table.insert(retResources, retProduction) | |||
end | |||
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 = {} | |||
for statid, stat in pairs(p.stats) do | |||
if building.provides[statid] ~= nil and building.provides[statid] ~= 0 then | |||
local quantity = building.provides[statid] | |||
if quantity < 0 then | |||
quantity = '<span style="color:red">'..quantity..'</span>' | |||
else | |||
quantity = Shared.numStrWithSign(quantity) | |||
end | |||
table.insert(benefits, Icons.Icon({stat.name, type='township', notext=true})..' '..quantity) | |||
end | |||
end | |||
if #benefits > 0 then | |||
return table.concat(benefits, ', ') | |||
end | |||
return nil | |||
end | |||
-- Given a building id, find the next building upgrade | |||
function p._GetBuildingIDUpgrade(buildingid) | |||
local function checkFunc(entity) | |||
return entity.upgradesFrom ~= nil and entity.upgradesFrom == buildingid | |||
end | |||
local upgradesTo = GameData.getEntities(Township.buildings, checkFunc) | |||
if #upgradesTo > 0 then | |||
return upgradesTo[1] | |||
end | |||
return nil | |||
end | |||
-- Given a building, find the building's downgrade | |||
function p._GetBuildingDowngrade(building) | |||
if building.upgradesFrom ~= nil then | |||
return p._GetBuildingByID(building.upgradesFrom) | |||
end | |||
return nil | |||
end | |||
-- Given a building, find the base resource cost | |||
function p._GetBuildingBaseCost(building, _join) | |||
local join = _join ~= nil and _join or ', ' | |||
local cost = {} | |||
for _, resource in ipairs(building.cost) do | |||
local resource_data = p._GetResourceByID(resource.id) | |||
table.insert(cost, Icons.Icon({resource_data.name, type='resource', notext=true})..' '..resource.quantity) | |||
end | |||
return table.concat(cost, join) | |||
end | |||
-- Gets a resource from id | |||
function p._GetResourceByID(id) | |||
return GameData.getEntityByID(p.resources, id) | |||
end | |||
-- Gets a resource from name | |||
function p._GetResourceByName(name) | |||
return GameData.getEntityByName(p.resources, name) | |||
end | |||
-- Gets text for only the biomes that have a modifier for a building | |||
function p._GetBuildingBiomeModifiers(biome) | |||
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, '<li style="color:'..color..'">'..biomename..' ('..biome_value..'%)</li>') | |||
end | |||
if #biomeRet == 0 then | |||
return nil | |||
end | |||
return '<ul>'..table.concat(biomeRet)..'</ul>' | |||
end | |||
-- Returns an upgrade table of a building | |||
function p.GetBuildingUpgradeTable(frame) | |||
local buildingname = frame.args ~= nil and frame.args[1] or frame | |||
local building = p._GetBuildingByName(buildingname) | |||
-- Let's find the base building | |||
local baseBuilding = building | |||
while true do | |||
local previousBuilding = p._GetBuildingDowngrade(baseBuilding) | |||
if previousBuilding ~= nil then | |||
baseBuilding = previousBuilding | |||
else | |||
break | |||
end | |||
end | |||
-- Let's make a list of all the buildings | |||
-- Return empty string if there is only 1 building in the upgrade chain (i.e. no upgrades/downgrades) | |||
local buildingList = {} | |||
local _curBuilding = baseBuilding | |||
while true do | |||
table.insert(buildingList, _curBuilding) | |||
_curBuilding = p._GetBuildingIDUpgrade(_curBuilding.id) | |||
if _curBuilding == nil then | |||
break | |||
end | |||
end | |||
if #buildingList == 1 then | |||
return '' | |||
end | |||
local ret = {} | |||
table.insert(ret, '\r\n== Upgrade Chart ==') | |||
table.insert(ret, '\r\n{| class="wikitable"') | |||
-- Name | |||
table.insert(ret, '\r\n|- style="text-align:center" \r\n! Name') | |||
for _, building in ipairs(buildingList) do | |||
table.insert(ret, '\r\n!'..Icons.Icon({building.name, type='building'})) | |||
end | |||
-- Tier | |||
table.insert(ret, '\r\n|-\r\n! Requirements') | |||
for _, building in ipairs(buildingList) do | |||
local tier = p._GetTierText(building.tier) | |||
table.insert(ret, '\r\n|'..tier) | |||
end | |||
-- Cost | |||
table.insert(ret, '\r\n|-\r\n! Cost') | |||
for _, building in ipairs(buildingList) do | |||
local cost = p._GetBuildingBaseCost(building) | |||
table.insert(ret, '\r\n|'..cost) | |||
end | |||
-- Optional params | |||
-- Generate a row | |||
-- textFunc: returns nil if no data for a building, or else returns a string | |||
local function BuildOptionalRow(header, textFunc) | |||
local texts = {} | |||
local hasTexts = false | |||
for _, building in ipairs(buildingList) do | |||
local text = textFunc(building) | |||
hasTexts = hasTexts == true or text ~= nil | |||
texts = texts ~= nil and texts or '' | |||
table.insert(texts, text) | |||
end | |||
if hasTexts == true then | |||
texts = table.concat(texts, '\r\n|') | |||
table.insert(ret, header..texts) | |||
end | |||
end | |||
BuildOptionalRow('\r\n|-\r\n! Benefits\r\n|', p._GetBuildingBenefits) | |||
BuildOptionalRow('\r\n|-\r\n! Base Production per '..Icons.Icon({'Workers', type='township', notext=true})..'\r\n|', p._GetBuildingBaseProduction) | |||
BuildOptionalRow('\r\n|-\r\n! Biome Production Modifiers\r\n|', p._GetBuildingBiomeModifiers) | |||
-- End | |||
table.insert(ret, '\r\n|}') | |||
return table.concat(ret) | |||
end | |||
local FREE_LAND = Township.sectionSize | |||
-- 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() | |||
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 | |||
return p |
edits