Formulas
thetowersdk/mechanics is the maths the game runs, as functions you can call: enemy scaling
by tier and wave, ultimate weapon timing, lab and workshop costs, Effective Paths planning, damage reduction,
resource drops and more. Each one takes plain values and returns a number, so they drop straight into
a calculator, a chart, or a bot command.
Enemy Scaling
Give a tier and a wave and get the base health and damage an enemy has there. This is the core of any "how far can I push" tool.
import { computeWaveBaseHealth, computeWaveBaseDamage } from 'thetowersdk/mechanics'
import { formatNumberForDisplay } from 'thetowersdk/formatting'
const hp = computeWaveBaseHealth({ tier: 10, wave: 4500 })
const dmg = computeWaveBaseDamage({ tier: 10, wave: 4500 })
console.log(formatNumberForDisplay(hp)) // '1.343S'
console.log(formatNumberForDisplay(dmg)) // '110.445T'Both scale continuously, so charting a tier is a loop over waves — every point comes from the same function the calculators use.
const series = []
for (let wave = 100; wave <= 5000; wave += 100) {
series.push({ wave, hp: computeWaveBaseHealth({ tier: 10, wave }) })
}Ultimate Weapon Uptime
computeUptimeRatio takes a duration and a cooldown, in that order, and returns the fraction
of the time the weapon is active. Pair it with the catalogs and you can compare any two weapons at any
level.
import { computeUptimeRatio } from 'thetowersdk/mechanics'
import { uwStoneChartData } from 'thetowersdk/data'
const seconds = (value) => Number(String(value).replace(/[^0-9.]/g, ''))
function uptime(weaponName, level) {
const weapon = Object.values(uwStoneChartData).find((w) => w.name === weaponName)
const at = (statName) =>
weapon.stats.find((s) => s.name === statName).levels.find((l) => l.level === level).value
return computeUptimeRatio(seconds(at('Duration')), seconds(at('Cooldown')))
}
console.log(uptime('Golden Tower', 8)) // 0.1045…
console.log(uptime('Black Hole', 8)) // 0.1917…Effective Paths Planning
The planner answers "what should I buy next" across health, damage, economy and regen, using the same maths as the community workbook.
import {
planEffectiveDamagePath,
ZERO_EFFECTIVE_DAMAGE_LEVELS,
zeroEffectiveDamageConfig,
} from 'thetowersdk/mechanics'
const plan = planEffectiveDamagePath({
config: zeroEffectiveDamageConfig(),
levels: ZERO_EFFECTIVE_DAMAGE_LEVELS,
variant: 'lab-time',
steps: 10,
})
plan.steps
plan.excludedStart With A Builder
There are 914 functions here. For the fifteen questions people ask most, a builder already wraps the right ones, declares the inputs they need with their units and limits, and hands back a full result. Reach for a raw function when you want one value inside something larger; reach for a builder when you want a working calculator.
import { findCalculatorBuilder } from 'thetowersdk/builders'
const wave = findCalculatorBuilder('enemy.wave')
console.log(wave.summary) // what it answers
console.log(wave.fields) // exactly what to ask the user for
console.log(wave.compute(wave.normalize(wave.defaults)))How The Names Are Organised
Every export is named after what it does, with a consistent prefix, so you can find a family without a list to hand.
| Prefix | Count | What it holds |
|---|---|---|
compute* | 125 | The top-level calculators — a question in, a number out. |
build* | 43 | Planners that assemble a whole result set, such as a buy order. |
apply* | 17 | Layer one effect onto a value — defense, rend, reductions. |
| the mechanic's name | — | Its own stats: blackHoleDuration, bounceShotChance, attackSpeed. |
Search The Module From Code
Everything is a named export on one object, so you can list what exists at runtime — handy in a REPL, and the fastest way to find the family you want.
import * as mechanics from 'thetowersdk/mechanics'
const named = (pattern) =>
Object.keys(mechanics).filter((key) => pattern.test(key) && typeof mechanics[key] === 'function')
named(/uptime/i) // every uptime helper
named(/^blackHole/) // Black Hole duration, cooldown, coin bonus, range
named(/coin/i) // 49 coin bonus and income helpers
named(/wave/i) // 111 wave and enemy-scaling functions
named(/^compute/) // the 125 top-level calculatorsWorked Example: A Survivability Table
A few of them together give a table a player can read at a glance — enemy health and damage across a tier, next to how many hits a given tower takes.
import { computeWaveBaseHealth, computeWaveBaseDamage } from 'thetowersdk/mechanics'
import { formatNumberForDisplay } from 'thetowersdk/formatting'
const towerHealth = 4.2e18
const rows = []
for (let wave = 1000; wave <= 6000; wave += 500) {
const hp = computeWaveBaseHealth({ tier: 10, wave })
const dmg = computeWaveBaseDamage({ tier: 10, wave })
rows.push({
wave,
enemyHealth: formatNumberForDisplay(hp),
enemyDamage: formatNumberForDisplay(dmg),
hitsSurvived: Math.floor(towerHealth / dmg)
})
}
console.table(rows)Put It On A Chart
Any series you compute goes straight into the chart renderer as an image, or into a spreadsheet as live formulas.