Examples

Examples

Labs, cards, uptime, enemy stats, saves, modules, Effective Paths, and the package glossary.

Lab Costs

Coins and research time for the next levels.

Live

Coin cost (levels 0 → 10)
18.759K
Research time
15h 45m

10 levels · lab max 99

Code

import { LAB_CATALOG } from 'thetowersdk/data'
import { formatNumberForDisplay } from 'thetowersdk/formatting'

// Find the lab by its display name
const lab = LAB_CATALOG.find((l) => l.name === 'Attack Speed')

// Levels are 0-based in the array; level 10 → index 10
const from = 10
const steps = 10
const next = lab.levels.slice(from, from + steps)

// Each level has a coin cost
const coins = next.reduce((sum, level) => sum + level.cost, 0)

// Format like the game (1.1q, 2.3s, …)
console.log(formatNumberForDisplay(coins))

Death Wave × Golden Bot

DW duration comes from Quantity × 4s per wave; results match the Uptime Calculator columns.

Live

SourceCooldownDurationUptime
Death Wave220s16s (4 × 4s)7.3%
Golden Bot90s25s27.8%

Code

import { BOT_UPGRADES_DATA, estimateBotUptimeFraction, uwStoneChartData } from 'thetowersdk/data'

const dw = Object.values(uwStoneChartData).find((w) => w.name === 'Death Wave')
const dwCd = Number(String(dw.stats.find((s) => s.name === 'Cooldown').levels[8].value).replace(/s$/i, ''))
const dwWaves = Number(String(dw.stats.find((s) => s.name === 'Quantity').levels[3].value).replace(/^x/i, ''))
const dwDur = dwWaves * 4 // Uptime Calculator wave time

const gb = BOT_UPGRADES_DATA.find((b) => b.name === 'Golden Bot')
const gbCd = gb.stats.Cooldown.levels['10']
const gbDur = gb.stats.Duration.levels['10']
const gbUptime = estimateBotUptimeFraction(gbDur, gbCd)

console.log({ dwCd, dwDur, gbCd, gbDur, gbUptime })

Enemy Stats

Base health and damage for a farm tier or tournament league base.

Live

Base enemy health
1.343S
Base enemy damage
110.445T

Code

import {
  computeWaveBaseHealth,
  computeWaveBaseDamage,
} from 'thetowersdk/mechanics'
import { formatNumberForDisplay } from 'thetowersdk/formatting'

// Farm tier 10, or tournament Copper as tier 1 + tournament:true
const hp = computeWaveBaseHealth({ tier: 10, wave: 4500, tournament: false })
const dmg = computeWaveBaseDamage({ tier: 10, wave: 4500, tournament: false })

console.log(formatNumberForDisplay(hp))
console.log(formatNumberForDisplay(dmg))

Read A Save

Sample extractor shapes from a decoded playerInfo.dat (decode runs in Node).

Sample

Decode playerInfo.dat, then pull labs, modules, cards, ultimate weapons, bots, vault, relics, lifetime stats, and battle reports from the same root:

{
  "labs": {
    "researchedCount": 142,
    "maxedCount": 38,
    "bySlug": {
      "attack_speed": 45,
      "labs_speed": 99
    }
  },
  "modules": {
    "owned": 48,
    "equipped": {
      "cannon": "Dimension Core",
      "armor": "Anti-Cube Portal",
      "generator": "Galaxy Compressor",
      "core": "Sharp Fortitude"
    }
  },
  "cards": {
    "unlocked": 62,
    "masteriesStarted": 11
  },
  "ultimateWeapons": {
    "unlocked": [
      "Golden Tower",
      "Black Hole",
      "Death Wave",
      "Chrono Field"
    ],
    "stonesSpent": 18420
  },
  "bots": {
    "unlocked": [
      "Golden Bot",
      "Flame Bot",
      "Thunder Bot"
    ],
    "medalsSpent": 3200
  },
  "vault": {
    "harmonyNodes": 18,
    "powerNodes": 12
  },
  "relics": {
    "owned": 27
  },
  "lifetime": {
    "totalWaves": 2450000,
    "highestTier": {
      "farm": 18,
      "tournament": "Champion"
    }
  },
  "battleReports": {
    "recentRuns": 40
  },
  "warnings": [
    "cards extractor: save predates card mastery fields"
  ]
}

thetowersdk/node decodes the file; thetowersdk/save extractors return typed slices (plus warnings when a field is missing or legacy).

Code

import { readFile } from 'node:fs/promises'
import { decodePlayerInfoSaveBytes } from 'thetowersdk/node'
import {
  readLabsFromSaveRoot,
  readModulesFromSaveRoot,
  readCardsFromSaveRoot,
  readUltimateWeaponsFromSaveRoot,
  readBotsFromSaveRoot,
  readVaultFromSaveRoot,
} from 'thetowersdk/save'

const { parsedRoot } = decodePlayerInfoSaveBytes(
  await readFile('playerInfo.dat')
)

const labs = readLabsFromSaveRoot(parsedRoot)
const modules = readModulesFromSaveRoot(parsedRoot)
const cards = readCardsFromSaveRoot(parsedRoot)
const uws = readUltimateWeaponsFromSaveRoot(parsedRoot)
const bots = readBotsFromSaveRoot(parsedRoot)
const vault = readVaultFromSaveRoot(parsedRoot)

Generate A Cost Table

Level, value, cost and running total, generated from the catalog.

Live

Shards to level 161

5K

Code

import { uwStoneChartData } from 'thetowersdk/data'
import { formatNumberForDisplay } from 'thetowersdk/formatting'

const gt = Object.values(uwStoneChartData).find((w) => w.name === 'Golden Tower')
const multiplier = gt.stats.find((s) => s.name === 'Multiplier')

// Level, value, cost, running total — the table players actually want.
let running = 0
const rows = multiplier.levels.map((l) => {
  if (typeof l.cost === 'number') running += l.cost
  return [l.level, l.value, l.cost, formatNumberForDisplay(running)]
})

Module Shard Cost

Shards to take a module from one level to the next.

Live

Gem cost (range)

1.6K

LevelCopiesGems
0 → 1120
1 → 2240
2 → 35100
3 → 48160
4 → 512240
5 → 620400
6 → 732640

Code

import { getModuleShardUpgradeCost } from 'thetowersdk/data'
import { formatNumberForDisplay } from 'thetowersdk/formatting'

// Cost to reach level 161 from 160
const shards = getModuleShardUpgradeCost(161)
console.log(formatNumberForDisplay(shards))

Card Gem Cost

Gems to raise a card from one level to another (copies × 20).

Live

  • 1. Coins / Kill Bonus lv 1
  • 2. Coins / Kill Bonus lv 2
  • 3. Coins / Kill Bonus lv 3
  • 4. Coins / Kill Bonus lv 4
  • 5. Coins / Kill Bonus lv 5

21 candidates skipped (with reasons on the full object).

Code

import { cardLevelUpgradeGemCost } from 'thetowersdk/mechanics'
import { formatNumberForDisplay } from 'thetowersdk/formatting'

const gems = cardLevelUpgradeGemCost(0, 7)
console.log(formatNumberForDisplay(gems))

Effective Paths

Next economy buys from your starting levels, including what was skipped.

Live

  • CF — Chrono Field

    ultimate-weapon

    Chrono Field ultimate weapon.

Code

import {
  planEffectiveEconomyPath,
  ZERO_EFFECTIVE_ECONOMY_LEVELS,
  zeroEffectiveEconomyConfig,
} from 'thetowersdk/mechanics'

const levels = {
  ...ZERO_EFFECTIVE_ECONOMY_LEVELS,
  time: {
    ...ZERO_EFFECTIVE_ECONOMY_LEVELS.time,
    coinsPerKillBonus: 20,
  },
}

const plan = planEffectiveEconomyPath({
  config: zeroEffectiveEconomyConfig(),
  levels,
  variant: 'time',
  steps: 5,
})

console.log(plan.steps.map((s) => s.name))
console.log(plan.excluded.length, 'skipped')