Module:BTD6 stats: Difference between revisions
Jump to navigation
Jump to search
mNo edit summary |
added paragon stat tables (hopefully this doesn't break everything) |
||
| Line 21: | Line 21: | ||
} | } | ||
function parse_tower(frame, new_data, prev_data, header) | function parse_paragon_table(data) | ||
local ret = {"\n{|class='wikitable mw-collapsible mw-collapsed'\n|+style='white-space:nowrap'|Degree-dependent stats"} | |||
local attack_labels = data["attacks"]["_order"] | |||
-- local functions to improve performance | |||
local tinsert = table.insert | |||
local tconcat = table.concat | |||
local sformat = string.format | |||
local msqrt = math.sqrt | |||
local mfloor = math.floor | |||
local degree_requirements = { | |||
0, 2000, 2324, 2666, 3027, 3408, 3808, 4228, 4669, 5131, | |||
5615, 6121, 6650, 7203, 7779, 8379, 9004, 9654, 10330, 11032, | |||
11761, 12518, 13302, 14114, 14955, 15825, 16725, 17655, 18616, 19609, | |||
20633, 21689, 22778, 23900, 25056, 26246, 27471, 28732, 30028, 31360, | |||
32729, 34135, 35579, 37061, 38582, 40143, 41743, 43383, 45064, 46786, | |||
48550, 50356, 52205, 54098, 56034, 58014, 60039, 62109, 64225, 66387, | |||
68596, 70853, 73157, 75509, 77910, 80360, 82860, 85410, 88011, 90664, | |||
93368, 96124, 98933, 101795, 104711, 107681, 110706, 113787, 116923, 120115, | |||
123364, 126670, 130034, 133456, 136937, 140478, 144078, 147738, 151459, 155241, | |||
159085, 162991, 166960, 170993, 175089, 179249, 183474, 187764, 192120, 200000 | |||
} | |||
-- -- -- -- -- -- | |||
-- CREATE HEADING | |||
-- -- -- -- -- -- | |||
local heading_upper = {} | |||
local upper_colspans = {} | |||
local heading_lower = {} | |||
local heading_effects = function(effects) | |||
for i, v in ipairs(effects["_order"]) do | |||
local effect = effects[v] | |||
local amount = 0 | |||
if effect["damage"]~=nil then tinsert(heading_lower, "Damage") amount = amount + 1 end | |||
if effect["damageModifierForBoss"]~=nil then tinsert(heading_lower, "Damage to bosses") amount = amount + 1 end | |||
if effect["damageModifierForMoabs"]~=nil then tinsert(heading_lower, "Damage to MOAB-Class") amount = amount + 1 end | |||
if effect["damageModifierForCeramic"]~=nil then tinsert(heading_lower, "Damage to Ceramic") amount = amount + 1 end | |||
if effect["damageModifierForCamo"]~=nil then tinsert(heading_lower, "Damage to Camo") amount = amount + 1 end | |||
if effect["damageModifierForStunned"]~=nil then tinsert(heading_lower, "Damage to stunned") amount = amount + 1 end | |||
if effect["damageModifierForStickied"]~=nil then tinsert(heading_lower, "Damage to stickied") amount = amount + 1 end | |||
tinsert(heading_upper, v) | |||
tinsert(upper_colspans, amount) | |||
end | |||
end | |||
local heading_projectiles = function(projectiles) | |||
for i, v in ipairs(projectiles["_order"]) do | |||
local projectile = projectiles[v] | |||
local amount = 0 | |||
if projectile["maxPierce"]~=nil then tinsert(heading_lower, "Cooldown") amount = amount + 1 end | |||
if projectile["damage"]~=nil then tinsert(heading_lower, "Damage") amount = amount + 1 end | |||
if projectile["damageModifierForBoss"]~=nil then tinsert(heading_lower, "Damage to bosses") amount = amount + 1 end | |||
if projectile["damageModifierForMoabs"]~=nil then tinsert(heading_lower, "Damage to MOAB-Class") amount = amount + 1 end | |||
if projectile["damageModifierForCeramic"]~=nil then tinsert(heading_lower, "Damage to Ceramic") amount = amount + 1 end | |||
if projectile["damageModifierForCamo"]~=nil then tinsert(heading_lower, "Damage to Camo") amount = amount + 1 end | |||
if projectile["damageModifierForStunned"]~=nil then tinsert(heading_lower, "Damage to stunned") amount = amount + 1 end | |||
if projectile["damageModifierForStickied"]~=nil then tinsert(heading_lower, "Damage to stickied") amount = amount + 1 end | |||
tinsert(heading_upper, v) | |||
tinsert(upper_colspans, amount) | |||
if projectile["effects"] ~= nil then heading_effects(projectile["effects"]) end | |||
end | |||
end | |||
local heading_attacks = function(attacks) | |||
for i, v in ipairs(attacks["_order"]) do | |||
local attack = attacks[v] | |||
-- rate | |||
tinsert(heading_lower, "Cooldown") | |||
tinsert(heading_upper, v) | |||
tinsert(upper_colspans, 1) | |||
-- projectiles | |||
if attack["projectiles"] ~= nil then heading_projectiles(attack["projectiles"]) end | |||
end | |||
end | |||
local heading_abilities = function(abils) | |||
for i, v in ipairs(abils["_order"]) do | |||
local abil = abils[v] | |||
-- rate | |||
tinsert(heading_lower, "Cooldown") | |||
tinsert(heading_upper, v) | |||
tinsert(upper_colspans, 1) | |||
if abil["projectiles"] ~= nil then heading_projectiles(abil["projectiles"]) end | |||
if abil["attacks"] ~= nil then heading_attacks(abil["attacks"]) end | |||
end | |||
end | |||
-- insert headings | |||
if data["projectiles"] ~= nil then heading_attacks(data["projectiles"]) end | |||
if data["attacks"] ~= nil then heading_attacks(data["attacks"]) end | |||
if data["abilities"] ~= nil then heading_abilities(data["abilities"]) end | |||
tinsert(ret, "!rowspan=2|Degree\n!rowspan=2|Power\n!rowspan=2|Boss multiplier") | |||
for i, v in ipairs(heading_upper) do | |||
tinsert(ret, sformat("!colspan=%i|%s", upper_colspans[i], v)) | |||
end | |||
tinsert(ret, "|-\n!" .. table.concat(heading_lower, "!!")) | |||
-- -- -- -- -- -- -- | |||
-- CALCULATE STATS | |||
-- -- -- -- -- -- -- | |||
-- current degree | |||
local d = 1 | |||
-- attack cooldowns and ability cooldowns | |||
local insert_rate = function(amt) | |||
tinsert(ret, sformat("|%gs", amt / (1 + (0.01 * msqrt((d-1)*50))))) | |||
end | |||
-- damage and pierce use the same formula | |||
local insert_damage_or_pierce = function(amt) | |||
if d == 100 then tinsert(ret, sformat("|%g", amt * 2 + 10)) | |||
else tinsert(ret, sformat("|%g", amt * (1 + (d-1) * 0.01) + mfloor((d-1)/10))) end | |||
end | |||
-- damage modifiers | |||
local insert_damage_mod = function(amt) | |||
if d == 100 then tinsert(ret, sformat("| +%g", amt * 2 + 10)) | |||
else tinsert(ret, sformat("| +%g", amt * (1 + (d-1) * 0.01))) end | |||
end | |||
local parse_effects = function(effects) | |||
for i, v in ipairs(effects["_order"]) do | |||
local effect = effects[v] | |||
if effect["damage"]~=nil then insert_damage_or_pierce(effect["damage"]) end | |||
if effect["damageModifierForBoss"]~=nil then insert_damage_mod(effect["damageModifierForBoss"]) end | |||
if effect["damageModifierForMoabs"]~=nil then insert_damage_mod(effect["damageModifierForMoabs"]) end | |||
if effect["damageModifierForCeramic"]~=nil then insert_damage_mod(effect["damageModifierForCeramic"]) end | |||
if effect["damageModifierForCamo"]~=nil then insert_damage_mod(effect["damageModifierForCamo"]) end | |||
if effect["damageModifierForStunned"]~=nil then insert_damage_mod(effect["damageModifierForStunned"]) end | |||
if effect["damageModifierForStickied"]~=nil then insert_damage_mod(effect["damageModifierForStickied"]) end | |||
end | |||
end | |||
local parse_projectiles = function(projectiles) | |||
for i, v in ipairs(projectiles["_order"]) do | |||
local projectile = projectiles[v] | |||
if projectile["maxPierce"]~=nil then insert_damage_or_pierce(projectile["pierce"]) end | |||
if projectile["damage"]~=nil then insert_damage_mod(projectile["damage"]) end | |||
if projectile["damageModifierForBoss"]~=nil then insert_damage_mod(projectile["damageModifierForBoss"]) end | |||
if projectile["damageModifierForMoabs"]~=nil then insert_damage_mod(projectile["damageModifierForMoabs"]) end | |||
if projectile["damageModifierForCeramic"]~=nil then insert_damage_mod(projectile["damageModifierForCeramic"]) end | |||
if projectile["damageModifierForCamo"]~=nil then insert_damage_mod(projectile["damageModifierForCamo"]) end | |||
if projectile["damageModifierForStunned"]~=nil then insert_damage_mod(projectile["damageModifierForStunned"]) end | |||
if projectile["damageModifierForStickied"]~=nil then insert_damage_mod(projectile["damageModifierForStickied"]) end | |||
if projectile["effects"] ~= nil then parse_effects(projectile["effects"]) end | |||
end | |||
end | |||
local parse_attacks = function(attacks) | |||
for i, v in ipairs(attacks["_order"]) do | |||
local attack = attacks[v] | |||
-- rate | |||
insert_rate(attack["rate"]) | |||
-- projectiles | |||
if attack["projectiles"] ~= nil then parse_projectiles(attack["projectiles"]) end | |||
end | |||
end | |||
local parse_abilities = function(abils) | |||
for i, v in ipairs(abils["_order"]) do | |||
local abil = abils[v] | |||
-- rate | |||
insert_rate(abil["rate"]) | |||
if abil["projectiles"] ~= nil then parse_projectiles(abil["projectiles"]) end | |||
if abil["attacks"] ~= nil then parse_attacks(abil["attacks"]) end | |||
end | |||
end | |||
-- degree loop | |||
while d <= 100 do | |||
-- new row | |||
tinsert(ret, sformat("|-\n!%i\n|%i", d, degree_requirements[d])) | |||
-- boss damage mult | |||
if d < 20 then tinsert(ret, "|×1.0") | |||
elseif d < 40 then tinsert(ret, "|×1.25") | |||
elseif d < 60 then tinsert(ret, "|×1.5") | |||
elseif d < 80 then tinsert(ret, "|×1.75") | |||
elseif d ~= 100 then tinsert(ret, "|×2.0") | |||
else tinsert(ret, "|×2.25") end | |||
-- calculations | |||
if data["projectiles"] ~= nil then parse_attacks(data["projectiles"]) end | |||
if data["attacks"] ~= nil then parse_attacks(data["attacks"]) end | |||
if data["abilities"] ~= nil then parse_abilities(data["abilities"]) end | |||
d = d + 1 | |||
end | |||
tinsert(ret, "|}") | |||
return table.concat(ret, "\n") | |||
end | |||
function parse_tower(frame, new_data, prev_data, header, paragon) | |||
local template = {} | local template = {} | ||
| Line 60: | Line 274: | ||
end | end | ||
local out = frame:expandTemplate{title = "BTD6 tower", args = template} | |||
if paragon then out = out .. parse_paragon_table(new_data) end | |||
return out | |||
end | end | ||
| Line 224: | Line 441: | ||
if frame.args[2] == nil then | if frame.args[2] == nil then | ||
if data["_000"] ~= nil then | if data["_000"] ~= nil then | ||
return parse_tower(frame, data["_000"], my_data, header) | return parse_tower(frame, data["_000"], my_data, header, false) | ||
else | else | ||
return parse_tower(frame, data, my_data, header) | return parse_tower(frame, data, my_data, header, false) | ||
end | end | ||
else | else | ||
return parse_tower(frame, data["_" .. frame.args[2]], my_data, header) | return parse_tower(frame, data["_" .. frame.args[2]], my_data, header, false) | ||
end | end | ||
end | end | ||
| Line 236: | Line 453: | ||
function p.paragon(frame) | function p.paragon(frame) | ||
local data = mw.loadJsonData(string.format("Module:BTD6 stats/%s/new", frame.args[1])) | local data = mw.loadJsonData(string.format("Module:BTD6 stats/%s/new", frame.args[1])) | ||
local out = parse_tower(frame, data, my_data, "<h3>%s</h3>") | local out = parse_tower(frame, data, my_data, "<h3>%s</h3>", true) | ||
return string.format("<div class='hatnote'>This data was last updated for: [[Bloons TD 6 v%s|version %s]]</div>", data["_last_updated"], data["_last_updated"]) .. out | return string.format("<div class='hatnote'>This data was last updated for: [[Bloons TD 6 v%s|version %s]]</div>", data["_last_updated"], data["_last_updated"]) .. out | ||
end | end | ||
| Line 277: | Line 494: | ||
for i, v in ipairs(upgrade_crosspaths[frame.args[2]]) do | for i, v in ipairs(upgrade_crosspaths[frame.args[2]]) do | ||
local result = parse_tower(frame, base_data, my_data, "<h3>%s</h3>") | local result = parse_tower(frame, base_data, my_data, "<h3>%s</h3>", false) | ||
if i == 1 then tinsert(ret, result) end | if i == 1 then tinsert(ret, result) end | ||
for ii, vv in ipairs(v) do | for ii, vv in ipairs(v) do | ||
if base_data[vv] ~= nil then | if base_data[vv] ~= nil then | ||
tinsert(ret, sformat("<h3>%s-%s-%s</h3>", ssub(vv, 2, 2), ssub(vv, 3, 3), ssub(vv, 4, 4))) | tinsert(ret, sformat("<h3>%s-%s-%s</h3>", ssub(vv, 2, 2), ssub(vv, 3, 3), ssub(vv, 4, 4))) | ||
tinsert(ret, parse_tower(frame, base_data[vv], my_data, "<h4>%s</h4>")) | tinsert(ret, parse_tower(frame, base_data[vv], my_data, "<h4>%s</h4>", false)) | ||
end | end | ||
end | end | ||
| Line 301: | Line 518: | ||
-- calculate base tower stats for later comparison | -- calculate base tower stats for later comparison | ||
parse_tower(frame, data, my_data, "<h3>%s</h3>") | parse_tower(frame, data, my_data, "<h3>%s</h3>", false) | ||
for i = 2, 20 do | for i = 2, 20 do | ||
tinsert(ret, sformat("===Level %i===", i)) | tinsert(ret, sformat("===Level %i===", i)) | ||
tinsert(ret, parse_tower(frame, data["_" .. i], my_data, "<h4>%s</h4>")) | tinsert(ret, parse_tower(frame, data["_" .. i], my_data, "<h4>%s</h4>", false)) | ||
end | end | ||
| Line 322: | Line 539: | ||
-- calculate base tower stats for later comparison | -- calculate base tower stats for later comparison | ||
parse_tower(frame, data, my_data, "<h3>%s</h3>") | parse_tower(frame, data, my_data, "<h3>%s</h3>", false) | ||
for i = 2, 20 do | for i = 2, 20 do | ||
tinsert(ret, sformat("===Level %i===", i)) | tinsert(ret, sformat("===Level %i===", i)) | ||
tinsert(ret, parse_tower_full(frame, data["_" .. i], my_data, "<h4>%s</h4>")) | tinsert(ret, parse_tower_full(frame, data["_" .. i], my_data, "<h4>%s</h4>", false)) | ||
end | end | ||
Revision as of 03:12, 26 February 2025
Documentation for this module may be created at Module:BTD6 stats/doc
-- This code is copyrighted and licensed under the Creative Commons Attribution-NonCommercial-ShareAlike International license, version 4.0. You may reuse and adapt this code for other purposes if:
-- * You give appropriate credit
-- * You are not using this material for commercial purposes
-- * You are releasing it under the same license
-- The subpages of this page are adapted from internal data in Bloons TD 6, which is copyrighted by Ninja Kiwi Limited. Its usage on Blooncyclopedia is believed to be fair use.
-- Further information: https://www.bloonswiki.com/Blooncyclopedia:Copyrights
-- By editing this code, you agree to release your changes under the same terms.
local p = {}
local my_data = {}
local template_names = {
attacks ="BTD6 attack",
projectiles ="BTD6 projectile",
collectables="BTD6 collectable",
abilities ="BTD6 ability",
effects ="BTD6 effect",
buffs ="BTD6 buff",
zones ="BTD6 zone",
subtowers ="BTD6 tower"
}
function parse_paragon_table(data)
local ret = {"\n{|class='wikitable mw-collapsible mw-collapsed'\n|+style='white-space:nowrap'|Degree-dependent stats"}
local attack_labels = data["attacks"]["_order"]
-- local functions to improve performance
local tinsert = table.insert
local tconcat = table.concat
local sformat = string.format
local msqrt = math.sqrt
local mfloor = math.floor
local degree_requirements = {
0, 2000, 2324, 2666, 3027, 3408, 3808, 4228, 4669, 5131,
5615, 6121, 6650, 7203, 7779, 8379, 9004, 9654, 10330, 11032,
11761, 12518, 13302, 14114, 14955, 15825, 16725, 17655, 18616, 19609,
20633, 21689, 22778, 23900, 25056, 26246, 27471, 28732, 30028, 31360,
32729, 34135, 35579, 37061, 38582, 40143, 41743, 43383, 45064, 46786,
48550, 50356, 52205, 54098, 56034, 58014, 60039, 62109, 64225, 66387,
68596, 70853, 73157, 75509, 77910, 80360, 82860, 85410, 88011, 90664,
93368, 96124, 98933, 101795, 104711, 107681, 110706, 113787, 116923, 120115,
123364, 126670, 130034, 133456, 136937, 140478, 144078, 147738, 151459, 155241,
159085, 162991, 166960, 170993, 175089, 179249, 183474, 187764, 192120, 200000
}
-- -- -- -- -- --
-- CREATE HEADING
-- -- -- -- -- --
local heading_upper = {}
local upper_colspans = {}
local heading_lower = {}
local heading_effects = function(effects)
for i, v in ipairs(effects["_order"]) do
local effect = effects[v]
local amount = 0
if effect["damage"]~=nil then tinsert(heading_lower, "Damage") amount = amount + 1 end
if effect["damageModifierForBoss"]~=nil then tinsert(heading_lower, "Damage to bosses") amount = amount + 1 end
if effect["damageModifierForMoabs"]~=nil then tinsert(heading_lower, "Damage to MOAB-Class") amount = amount + 1 end
if effect["damageModifierForCeramic"]~=nil then tinsert(heading_lower, "Damage to Ceramic") amount = amount + 1 end
if effect["damageModifierForCamo"]~=nil then tinsert(heading_lower, "Damage to Camo") amount = amount + 1 end
if effect["damageModifierForStunned"]~=nil then tinsert(heading_lower, "Damage to stunned") amount = amount + 1 end
if effect["damageModifierForStickied"]~=nil then tinsert(heading_lower, "Damage to stickied") amount = amount + 1 end
tinsert(heading_upper, v)
tinsert(upper_colspans, amount)
end
end
local heading_projectiles = function(projectiles)
for i, v in ipairs(projectiles["_order"]) do
local projectile = projectiles[v]
local amount = 0
if projectile["maxPierce"]~=nil then tinsert(heading_lower, "Cooldown") amount = amount + 1 end
if projectile["damage"]~=nil then tinsert(heading_lower, "Damage") amount = amount + 1 end
if projectile["damageModifierForBoss"]~=nil then tinsert(heading_lower, "Damage to bosses") amount = amount + 1 end
if projectile["damageModifierForMoabs"]~=nil then tinsert(heading_lower, "Damage to MOAB-Class") amount = amount + 1 end
if projectile["damageModifierForCeramic"]~=nil then tinsert(heading_lower, "Damage to Ceramic") amount = amount + 1 end
if projectile["damageModifierForCamo"]~=nil then tinsert(heading_lower, "Damage to Camo") amount = amount + 1 end
if projectile["damageModifierForStunned"]~=nil then tinsert(heading_lower, "Damage to stunned") amount = amount + 1 end
if projectile["damageModifierForStickied"]~=nil then tinsert(heading_lower, "Damage to stickied") amount = amount + 1 end
tinsert(heading_upper, v)
tinsert(upper_colspans, amount)
if projectile["effects"] ~= nil then heading_effects(projectile["effects"]) end
end
end
local heading_attacks = function(attacks)
for i, v in ipairs(attacks["_order"]) do
local attack = attacks[v]
-- rate
tinsert(heading_lower, "Cooldown")
tinsert(heading_upper, v)
tinsert(upper_colspans, 1)
-- projectiles
if attack["projectiles"] ~= nil then heading_projectiles(attack["projectiles"]) end
end
end
local heading_abilities = function(abils)
for i, v in ipairs(abils["_order"]) do
local abil = abils[v]
-- rate
tinsert(heading_lower, "Cooldown")
tinsert(heading_upper, v)
tinsert(upper_colspans, 1)
if abil["projectiles"] ~= nil then heading_projectiles(abil["projectiles"]) end
if abil["attacks"] ~= nil then heading_attacks(abil["attacks"]) end
end
end
-- insert headings
if data["projectiles"] ~= nil then heading_attacks(data["projectiles"]) end
if data["attacks"] ~= nil then heading_attacks(data["attacks"]) end
if data["abilities"] ~= nil then heading_abilities(data["abilities"]) end
tinsert(ret, "!rowspan=2|Degree\n!rowspan=2|Power\n!rowspan=2|Boss multiplier")
for i, v in ipairs(heading_upper) do
tinsert(ret, sformat("!colspan=%i|%s", upper_colspans[i], v))
end
tinsert(ret, "|-\n!" .. table.concat(heading_lower, "!!"))
-- -- -- -- -- -- --
-- CALCULATE STATS
-- -- -- -- -- -- --
-- current degree
local d = 1
-- attack cooldowns and ability cooldowns
local insert_rate = function(amt)
tinsert(ret, sformat("|%gs", amt / (1 + (0.01 * msqrt((d-1)*50)))))
end
-- damage and pierce use the same formula
local insert_damage_or_pierce = function(amt)
if d == 100 then tinsert(ret, sformat("|%g", amt * 2 + 10))
else tinsert(ret, sformat("|%g", amt * (1 + (d-1) * 0.01) + mfloor((d-1)/10))) end
end
-- damage modifiers
local insert_damage_mod = function(amt)
if d == 100 then tinsert(ret, sformat("| +%g", amt * 2 + 10))
else tinsert(ret, sformat("| +%g", amt * (1 + (d-1) * 0.01))) end
end
local parse_effects = function(effects)
for i, v in ipairs(effects["_order"]) do
local effect = effects[v]
if effect["damage"]~=nil then insert_damage_or_pierce(effect["damage"]) end
if effect["damageModifierForBoss"]~=nil then insert_damage_mod(effect["damageModifierForBoss"]) end
if effect["damageModifierForMoabs"]~=nil then insert_damage_mod(effect["damageModifierForMoabs"]) end
if effect["damageModifierForCeramic"]~=nil then insert_damage_mod(effect["damageModifierForCeramic"]) end
if effect["damageModifierForCamo"]~=nil then insert_damage_mod(effect["damageModifierForCamo"]) end
if effect["damageModifierForStunned"]~=nil then insert_damage_mod(effect["damageModifierForStunned"]) end
if effect["damageModifierForStickied"]~=nil then insert_damage_mod(effect["damageModifierForStickied"]) end
end
end
local parse_projectiles = function(projectiles)
for i, v in ipairs(projectiles["_order"]) do
local projectile = projectiles[v]
if projectile["maxPierce"]~=nil then insert_damage_or_pierce(projectile["pierce"]) end
if projectile["damage"]~=nil then insert_damage_mod(projectile["damage"]) end
if projectile["damageModifierForBoss"]~=nil then insert_damage_mod(projectile["damageModifierForBoss"]) end
if projectile["damageModifierForMoabs"]~=nil then insert_damage_mod(projectile["damageModifierForMoabs"]) end
if projectile["damageModifierForCeramic"]~=nil then insert_damage_mod(projectile["damageModifierForCeramic"]) end
if projectile["damageModifierForCamo"]~=nil then insert_damage_mod(projectile["damageModifierForCamo"]) end
if projectile["damageModifierForStunned"]~=nil then insert_damage_mod(projectile["damageModifierForStunned"]) end
if projectile["damageModifierForStickied"]~=nil then insert_damage_mod(projectile["damageModifierForStickied"]) end
if projectile["effects"] ~= nil then parse_effects(projectile["effects"]) end
end
end
local parse_attacks = function(attacks)
for i, v in ipairs(attacks["_order"]) do
local attack = attacks[v]
-- rate
insert_rate(attack["rate"])
-- projectiles
if attack["projectiles"] ~= nil then parse_projectiles(attack["projectiles"]) end
end
end
local parse_abilities = function(abils)
for i, v in ipairs(abils["_order"]) do
local abil = abils[v]
-- rate
insert_rate(abil["rate"])
if abil["projectiles"] ~= nil then parse_projectiles(abil["projectiles"]) end
if abil["attacks"] ~= nil then parse_attacks(abil["attacks"]) end
end
end
-- degree loop
while d <= 100 do
-- new row
tinsert(ret, sformat("|-\n!%i\n|%i", d, degree_requirements[d]))
-- boss damage mult
if d < 20 then tinsert(ret, "|×1.0")
elseif d < 40 then tinsert(ret, "|×1.25")
elseif d < 60 then tinsert(ret, "|×1.5")
elseif d < 80 then tinsert(ret, "|×1.75")
elseif d ~= 100 then tinsert(ret, "|×2.0")
else tinsert(ret, "|×2.25") end
-- calculations
if data["projectiles"] ~= nil then parse_attacks(data["projectiles"]) end
if data["attacks"] ~= nil then parse_attacks(data["attacks"]) end
if data["abilities"] ~= nil then parse_abilities(data["abilities"]) end
d = d + 1
end
tinsert(ret, "|}")
return table.concat(ret, "\n")
end
function parse_tower(frame, new_data, prev_data, header, paragon)
local template = {}
-- local functions to improve performance
local tinsert = table.insert
local tconcat = table.concat
local sformat = string.format
local ssub = string.sub
-- search through tables
for k, v in pairs(new_data) do
if type(v) == "table" and ssub(k, 1, 1) ~= "_" then
template[k] = {}
if prev_data[k] == nil then prev_data[k] = {} end
-- iterate through attacks/abilities/subtowers
for _, i in ipairs(v["_order"]) do
if k == "subtowers" then tinsert(template[k], sformat(header, i)) end
if prev_data[k][i] == nil then prev_data[k][i] = {} end
-- parse sub-table of table
tinsert(template[k], parse_stats(frame, i, v[i], prev_data[k][i], template_names[k]))
end
template[k] = tconcat(template[k])
elseif type(v) ~= "table" then
-- if previous value exists, make it a comparison
if prev_data[k] ~= nil then
template[k] = prev_data[k]
template[k .. " after"] = v
else
template[k] = v
end
-- update previous value
prev_data[k] = v
end
end
local out = frame:expandTemplate{title = "BTD6 tower", args = template}
if paragon then out = out .. parse_paragon_table(new_data) end
return out
end
function parse_stats(frame, name, new_data, prev_data, template_name)
local template = {name = name}
-- local functions to improve performance
local tinsert = table.insert
local tconcat = table.concat
-- search through tables
for k, v in pairs(new_data) do
if type(v) == "table" then
template[k] = {}
if prev_data[k] == nil then prev_data[k] = {} end
-- iterate through attacks/abilities/subtowers
for _, i in ipairs(v["_order"]) do
if prev_data[k][i] == nil then prev_data[k][i] = {} end
-- parse sub-table of table
tinsert(template[k], parse_stats(frame, i, v[i], prev_data[k][i], template_names[k]))
end
template[k] = tconcat(template[k])
else
-- if previous value exists, make it a comparison
if prev_data[k] ~= nil then
template[k] = prev_data[k]
template[k .. " after"] = v
else
template[k] = v
end
-- update previous value
prev_data[k] = v
end
end
return frame:expandTemplate{title = template_name, args = template}
end
function parse_tower_full(frame, new_data, prev_data, header)
local template = {}
-- local functions to improve performance
local tinsert = table.insert
local tconcat = table.concat
local sformat = string.format
local ssub = string.sub
-- search through tables
for k, v in pairs(new_data) do
if type(v) == "table" and ssub(k, 1, 1) ~= "_" then
if template[k] == nil then template[k] = {} end
if prev_data[k] == nil then prev_data[k] = {} end
if prev_data[k]["_order"] == nil then
prev_data[k]["_order"] = {}
prev_data[k]["_keys"] = {}
end
-- iterate through attacks/abilities/subtowers
for _, i in ipairs(v["_order"]) do
if prev_data[k][i] == nil then prev_data[k][i] = {} end
if prev_data[k]["_keys"][i] == nil then
tinsert(prev_data[k]["_order"], i)
prev_data[k]["_keys"][i] = true
end
-- parse sub-table of table
parse_stats_full(frame, i, v[i], prev_data[k][i], template_names[k])
end
elseif type(v) ~= "table" then
-- update previous value
prev_data[k] = v
end
end
-- update prev_data first
for k, v in pairs(prev_data) do
if k == "attacks" or k == "abilities" or k == "subtowers" or k == "zones" then
template[k] = {}
-- iterate through attacks/abilities/subtowers
for _, i in ipairs(v["_order"]) do
if k == "subtowers" then tinsert(template[k], sformat(header, i)) end
tinsert(template[k], parse_stats_full(frame, i, nil, v[i], template_names[k]))
end
template[k] = tconcat(template[k])
elseif type(v) ~= "table" then
-- update previous value
template[k] = v
end
end
return frame:expandTemplate{title = "BTD6 tower", args = template}
end
function parse_stats_full(frame, name, new_data, prev_data, template_name)
local template = {name = name}
-- local functions to improve performance
local tinsert = table.insert
local tconcat = table.concat
-- update prev_data first
if new_data ~= nil then
for k, v in pairs(new_data) do
if type(v) == "table" then
if prev_data[k] == nil then prev_data[k] = {} end
if prev_data[k]["_order"] == nil then
prev_data[k]["_order"] = {}
prev_data[k]["_keys"] = {}
end
-- iterate through attacks/abilities/subtowers
for _, i in ipairs(v["_order"]) do
if prev_data[k][i] == nil then prev_data[k][i] = {} end
if prev_data[k]["_keys"][i] == nil then
tinsert(prev_data[k]["_order"], i)
prev_data[k]["_keys"][i] = true
end
-- parse sub-table of table
parse_stats_full(frame, i, v[i], prev_data[k][i], template_names[k])
end
else
prev_data[k] = v
end
end
end
for k, v in pairs(prev_data) do
if type(v) == "table" then
template[k] = {}
-- iterate through attacks/abilities/subtowers
for _, i in ipairs(v["_order"]) do
if prev_data[k][i] == nil then prev_data[k][i] = {} end
-- parse sub-table of table
tinsert(template[k], parse_stats_full(frame, i, nil, v[i], template_names[k]))
end
template[k] = tconcat(template[k])
else
template[k] = v
end
end
return frame:expandTemplate{title = template_name, args = template}
end
-- stats of a single tower
function p.base_stats(frame)
local data = mw.loadJsonData(string.format("Module:BTD6 stats/%s/new", frame.args[1]))
local header_level = frame.args["header level"] ~= nil and frame.args["header level"] or "3"
local header = "<h" .. header_level .. ">%s</h" .. header_level .. ">"
if frame.args[2] == nil then
if data["_000"] ~= nil then
return parse_tower(frame, data["_000"], my_data, header, false)
else
return parse_tower(frame, data, my_data, header, false)
end
else
return parse_tower(frame, data["_" .. frame.args[2]], my_data, header, false)
end
end
-- stats of a paragon
function p.paragon(frame)
local data = mw.loadJsonData(string.format("Module:BTD6 stats/%s/new", frame.args[1]))
local out = parse_tower(frame, data, my_data, "<h3>%s</h3>", true)
return string.format("<div class='hatnote'>This data was last updated for: [[Bloons TD 6 v%s|version %s]]</div>", data["_last_updated"], data["_last_updated"]) .. out
end
-- stat changes of a tower
function p.tower_upgrade_stats(frame)
local data = mw.loadJsonData(string.format("Module:BTD6 stats/%s/new", frame.args[1]))
local ret = {}
-- local functions to improve performance
local tinsert = table.insert
local sformat = string.format
local ssub = string.sub
local base_data = data[frame.args[2]]
local upgrade_crosspaths = {
["_000"] = {{}},
["_100"] = {{"_110"}, {"_101"}},
["_200"] = {{"_210", "_220"}, {"_201", "_202"}},
["_010"] = {{"_110"}, {"_011"}},
["_020"] = {{"_120", "_220"}, {"_021", "_022"}},
["_001"] = {{"_101"}, {"_011"}},
["_002"] = {{"_102", "_202"}, {"_012", "_022"}},
["_300"] = {{"_310", "_320"}, {"_301", "_302"}},
["_400"] = {{"_410", "_420"}, {"_401", "_402"}},
["_500"] = {{"_510", "_520"}, {"_501", "_502"}},
["_030"] = {{"_130", "_230"}, {"_031", "_032"}},
["_040"] = {{"_140", "_240"}, {"_041", "_042"}},
["_050"] = {{"_150", "_250"}, {"_051", "_052"}},
["_003"] = {{"_103", "_203"}, {"_013", "_023"}},
["_004"] = {{"_104", "_204"}, {"_014", "_024"}},
["_005"] = {{"_105", "_205"}, {"_015", "_025"}}
}
tinsert(ret, sformat("<div class='hatnote'>This data was last updated for: [[Bloons TD 6 v%s|version %s]]</div>", data["_last_updated"], data["_last_updated"]))
for i, v in ipairs(upgrade_crosspaths[frame.args[2]]) do
local result = parse_tower(frame, base_data, my_data, "<h3>%s</h3>", false)
if i == 1 then tinsert(ret, result) end
for ii, vv in ipairs(v) do
if base_data[vv] ~= nil then
tinsert(ret, sformat("<h3>%s-%s-%s</h3>", ssub(vv, 2, 2), ssub(vv, 3, 3), ssub(vv, 4, 4)))
tinsert(ret, parse_tower(frame, base_data[vv], my_data, "<h4>%s</h4>", false))
end
end
end
return table.concat(ret, "\n")
end
-- stat changes of a hero
function p.hero_level_changes(frame)
local data = mw.loadJsonData(string.format("Module:BTD6 stats/%s/new", frame.args[1]))
local ret = {}
-- local functions to improve performance
local tinsert = table.insert
local sformat = string.format
-- calculate base tower stats for later comparison
parse_tower(frame, data, my_data, "<h3>%s</h3>", false)
for i = 2, 20 do
tinsert(ret, sformat("===Level %i===", i))
tinsert(ret, parse_tower(frame, data["_" .. i], my_data, "<h4>%s</h4>", false))
end
return table.concat(ret, "\n")
end
-- stat changes of a hero
function p.hero_level_stats(frame)
local data = mw.loadJsonData(string.format("Module:BTD6 stats/%s/new", frame.args[1]))
local ret = {}
-- local functions to improve performance
local tinsert = table.insert
local sformat = string.format
-- calculate base tower stats for later comparison
parse_tower(frame, data, my_data, "<h3>%s</h3>", false)
for i = 2, 20 do
tinsert(ret, sformat("===Level %i===", i))
tinsert(ret, parse_tower_full(frame, data["_" .. i], my_data, "<h4>%s</h4>", false))
end
return table.concat(ret, "\n")
end
function p.last_updated(frame)
local data = mw.loadJsonData(string.format("Module:BTD6 stats/%s/new", frame.args[1]))
return string.format("<div class='hatnote'>This data was last updated for: [[Bloons TD 6 v%s|version %s]]</div>", data["_last_updated"], data["_last_updated"])
end
return p