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.excluded

Start 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.

PrefixCountWhat it holds
compute*125The top-level calculators — a question in, a number out.
build*43Planners that assemble a whole result set, such as a buy order.
apply*17Layer one effect onto a value — defense, rend, reductions.
the mechanic's nameIts 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 calculators

Worked 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.

Charts → · Builders → · Live Formula Examples →