StatForge

Live ratio panel for Torn gym stats with rep-counter automation and per-stat gym switching, plus a styled floating drug-cooldown alarm shown on all Torn pages via the Torn API (requires your own API key). Also reads your gym-gain perks (Steadfast, education, property, books) from the Torn API to weight training gains by your real multipliers and protect your special-gym access ratios. Inspired by ClasixTV's original Torn ratio helper. TornPDA users should set injection time to END.

A continuación se muestran las versiones de este script en las que se actualizó el código. Ver todas las versiones.

  • v1.15.0 22/6/2026

    feat: Steadfast-aware Train Next — ride the boosted stat toward the ratio

    Train Next now recommends the highest-yield below-target stat this month (best-gym dots x its gym-gain multiplier) instead of just the worst ratio gap. This rides whichever stat Steadfast boosts most (more gains for the same energy) while still heading for the aec3 ratio: a below-target stat is also below the x1.25 gym limit, so it always has headroom; secondaries are pursued to their ratio target (not the limit), and once every secondary is on target the high stat is trained to raise the bar and open new headroom. Over months each secondary reaches the same ratio %, but the boosted one is advanced first.

    Adds a one-line reason under the recommendation explaining the pick.

    Co-Authored-By: Claude Opus 4.8 (1M context) [email protected] Claude-Session: https://claude.ai/code/session_01LZLpdWB5L4FhhD8DBpJoM5

  • v1.14.0 22/6/2026

    refactor: drive headroom purely from the ratio, drop gain estimation

    The gym access limit IS the stat ratio, and we read real stats, so estimating per-train gains was unnecessary and imprecise above 50M. Removed estGainPerTrain, readPageHappy, computeAccessCaps (rep-based) and the now-unused readGymEnergyCost.

    computeAccessHeadroom returns headroom in stat POINTS straight from current stats (high/1.25 - each other stat, combo gym respected while held). The train counter is always 999 (Torn trains only what energy allows); a stat already at its limit returns 0 so it isn't trained past the x1.25 limit. The Headroom panel now shows points-to-limit per stat, read directly from your stats — no formula, no 50M assumption, no calibration.

    Co-Authored-By: Claude Opus 4.8 (1M context) [email protected] Claude-Session: https://claude.ai/code/session_01LZLpdWB5L4FhhD8DBpJoM5

  • v1.13.0 22/6/2026

    feat: fill counter to all available energy, capped by gym headroom

    Drop the per-stat rep distribution (computeRepPlan removed). The train counter now fills to 999 so Torn trains as many reps as the player's energy allows (Torn caps the count to available energy), limited only by the stat's special- gym access headroom so a large energy dump can't cross the x1.25 limit. The high stat is uncapped, so it always fills 999.

    The "Rep Plan" panel becomes "Headroom to gym limit", showing how many trains each stat has left before it would lose special-gym access (high stat: no limit). Shares computeAccessCaps with the fill logic so display and action agree. Collapse state key preserved.

    Co-Authored-By: Claude Opus 4.8 (1M context) [email protected] Claude-Session: https://claude.ai/code/session_01LZLpdWB5L4FhhD8DBpJoM5

  • v1.12.3 22/6/2026

    fix: calibrate gym-gain estimate to real trains, keep safety only in caps

    Removed the blanket 1.3x inflation from estGainPerTrain. Verified against a real train (1 rep at George's, 68M dex, 7.3 dots, 10 energy = 30,390.70 gained; formula now returns ~30,100 at happy 4000, ~30,470 at happy 5000 — within ~1%). The estimate is now honest, so the rep-plan distribution reflects real gains.

    The safety bias now lives only where it matters: computeAccessCaps multiplies gain by 1.5x so training at higher happy than we read can't make us under-count reps and overshoot the x1.25 access limit. Rep-plan sim uses the honest value.

    Co-Authored-By: Claude Opus 4.8 (1M context) [email protected] Claude-Session: https://claude.ai/code/session_01LZLpdWB5L4FhhD8DBpJoM5

  • v1.12.2 22/6/2026

    fix: clamp gym-gain estimate at 50M and use real gain in rep plan

    The Vladar gain estimate used the linear stat term unclamped, so above ~50M (where Torn dampens gym gains) it returned ~50x too high — e.g. ~2.3M/train at 500M defense. That corrupted both the access caps (far too few reps allowed) and, once the rep plan started using the estimate, made the high stat appear to balloon, cascading hundreds of reps onto the dump stat.

    Clamp the stat input at 50M (gains saturate there) and advance the rep-plan sim with the real per-train estimate instead of the raw dots proxy. Now a stat already at its ratio target stops there (a def build's 13.5% dex no longer gets flooded), str/spd fill their headroom toward the access limit, and surplus energy flows to the high stat to grow the whole build. Verified against real 500M-range stats and a 1M-range account; the clamp only affects stats >50M.

    Co-Authored-By: Claude Opus 4.8 (1M context) [email protected] Claude-Session: https://claude.ai/code/session_01LZLpdWB5L4FhhD8DBpJoM5

  • v1.12.1 22/6/2026

    fix: only protect special-gym combo ratio when the gym is actually held

    The access guard derived the combo gym from the build's high stat and always enforced it. For builds that can never satisfy that combo (e.g. aec3 Defense-high can't reach Balboa's def+dex >= 1.25*(str+spd), since str+spd are each ~78% of def), this permanently capped the secondary pair to 0 trains, freezing str/spd and training the dump stat first.

    Gate the combo rule on comboHeld = primarySum >= 1.25 * secondarySum so an unreachable/already-lost combo gym no longer blocks training. The single-stat rule (high >= 1.25 * second-highest) is always kept — it aligns with the build and is restorable by training the high stat.

    Also name gym id 32 "Fight Club" (was null -> "Gym #32").

    Co-Authored-By: Claude Opus 4.8 (1M context) [email protected] Claude-Session: https://claude.ai/code/session_01LZLpdWB5L4FhhD8DBpJoM5

  • v1.12.0 22/6/2026

    feat: weight rep plan by gym-gain perks and protect special-gym access

    Read the player's gym-gain perks (Steadfast, education, property, books) from api.torn.com user?selections=perks, combine them multiplicatively per stat (matching Torn's gym formula), and feed them into the rep plan so each stat's projected gains reflect the player's real multipliers.

    Add a P1 hard guard that keeps special-gym access: caps how many trains each non-high stat may take before crossing the x1.25 access ratio (single-stat Hank's rule + combo Frontline/Balboa rule), derived automatically from the build's high stat. The high stat is uncapped so surplus energy raises the ceiling. Guard activates only for special-gym-compatible builds (baldr/hank/aec3); balanced builds are unchanged. Without an API key, multipliers default to 1.0 and caps to Infinity, so existing behavior is preserved.

    Reuses the existing API key and fetch path (drug-cooldown feature); adds a Settings section disclosing the multipliers and access-protection status.

    Co-Authored-By: Claude Opus 4.8 (1M context) [email protected] Claude-Session: https://claude.ai/code/session_01LZLpdWB5L4FhhD8DBpJoM5

  • v1.11.8 14/6/2026

    feat: alarm shows only in final 5 min, doubled size, blink on ready

    Hide the floating drug-cooldown pill until the cooldown has <=5 min left (DRUG_ALARM_SEC=300) or is ready; set-key/error states stay visible so it can still be configured. Double the pill size (font 13->26px, padding /dot/border doubled). Blink (sf-drug-blink) only in the ready state; the final-5-min countdown (sf-alarm) is steady. Bump to v1.11.8.

    Co-Authored-By: Claude Opus 4.8 (1M context) [email protected]

  • v1.11.6 14/6/2026

    feat: redesign drug cooldown alarm as styled floating pill

    Replace the sidebar status-icons indicator (which inherited Torn's icon styling and looked out of place) with a fully self-contained floating pill appended to document.body: own id #sf-drug-alarm, namespaced .sf-* classes, injected CSS with idle/countdown/ready(green+pulse)/error states. No Torn class is read or written, so nothing bleeds in. API polling, active-view gating, item.php click and bad-key auto-prompt are unchanged. Fixed bottom-left. Bump to v1.11.6.

    Co-Authored-By: Claude Opus 4.8 (1M context) [email protected]

  • v1.11.4 14/6/2026

    fix: neutralise inherited status-icon background on drug badge

    Torn styles every status-icons

  • as a fixed-size icon with a background sprite/colour, which bled through behind the drug-cooldown pill (a green sprite corner). Inject a #sf-drug-badge-scoped style that resets background, sizing, box-shadow and ::before/::after with !important. Bump to v1.11.4.

    Co-Authored-By: Claude Opus 4.8 (1M context) [email protected]

  • v1.11.3 14/6/2026

    feat: move drug cooldown to status-icons row + key UX

    Relocate the drug-cooldown indicator from the Energy bar to the first item of the sidebar status-icons row (li#sf-drug-badge inserted via insertBefore, hardened ul[class*="status-icons___"] selector, verified dump). Click with a working key opens item.php; no key / bad key opens the key prompt, and a code-2 'incorrect key' auto-prompts once. Bump to v1.11.3.

    Co-Authored-By: Claude Opus 4.8 (1M context) [email protected]

  • v1.11.1 14/6/2026

    feat: render drug cooldown inline in sidebar Energy bar

    Replace the floating fixed badge with an inline span inserted right after the Energy bar-value in Torn's left sidebar (verified DOM dump). Locate the Energy row via hash-safe [class*="bar-name_"] + /energy/i, insert after [class*="bar-value_"], and re-attach on sidebar re-render. Colored text instead of a pill: amber countdown, green "ready". Bump to v1.11.1.

    Co-Authored-By: Claude Opus 4.8 (1M context) [email protected]

  • v1.11.0 14/6/2026

    feat: drug cooldown badge on all Torn pages via API

    Widen @match to https://www.torn.com/* and add an all-pages drug cooldown badge driven by api.torn.com (selections=cooldowns). Polls every 60s only while the tab is actively viewed, shows a live local countdown, and turns green ("Drug ready") when the cooldown expires. API key entered via prompt() and stored locally. Gym ratio panel is still gated to gym.php via isGymPage(). Bump to v1.11.0.

    Co-Authored-By: Claude Opus 4.8 (1M context) [email protected]

  • v1.10.10 1/6/2026

    chore: remove internal TORN_DOM.md references from public comments

    The 5 comments referencing the private DOM-dump doc name leaked an internal artifact name into the public repo. Reworded to 'verified against gym.php DOM dump' — same meaning, nothing internal exposed.

    Co-Authored-By: Claude Opus 4.8 (1M context) [email protected]

  • v1.10.9 30/5/2026

    fix: abbreviate numbers in history table to fit mobile screen

    Co-Authored-By: Claude Sonnet 4.6 [email protected]

  • v1.10.8 13/5/2026

    feat: gate DOM-reading auto-paths on actively-viewed tab

    Adds isActivelyViewed() (visibilityState + hasFocus) and gates the four auto-paths that read the gym page: waitAndInject, backgroundStatWatch, syncEnergyBaseline, and the trainObserver callback. Adds visibilitychange

    • focus listeners to resume work and resync the energy baseline when the tab becomes actively viewed again.

    Bumps to v1.10.8. Aligns with Torn's 2026-05-13 scripting-rule clarification that scripts may only read from pages the user is actively viewing (foreground tab + focused window).

    Co-Authored-By: Claude Opus 4.7 (1M context) [email protected]

  • v1.10.7 30/4/2026

    chore: bump v1.10.7

  • v1.10.6 30/4/2026

    chore: drop dead initial assignment in clear-history confirm

    ESLint v9.13's no-useless-assignment caught let confirmed = false; — the value is never read because both try and catch branches assign before the next read. Cleanup; behavior unchanged.

    Bumps version to 1.10.6.

    Co-Authored-By: Claude Opus 4.7 (1M context) [email protected]

  • v1.10.5 29/4/2026

    fix(ratio): drop forcedDump from isStatDumped — multipliers drive skipping

    1.10.4 over-corrected by treating RATIOS[ratioKey].forcedDump as a "skip this stat" signal. That was wrong:

    • forcedDump is the recommended default for the user's dump-stat picker UI (so selecting Aec3 auto-picks DEX in the dump dropdown), not a directive to exclude the stat from training.
    • Aec3's DEX has multiplier 0.1351 (13.51%). The ratio's intent is to KEEP DEX at that ratio, not zero it. Treating forcedDump as a skip caused the planner to ignore DEX entirely — directly violating the ratio the user wants respected.

    Strip the forcedDump check from isStatDumped. The remaining rule is: the ratio's multiplier for whichever role this stat occupies must be exactly 0 to count as a dump.

    Concrete behaviour after this:

    • Hank: tert2 multiplier is 0 → that role's stat is skipped (unchanged from the original hardcoded check).
    • Aec3: DEX has multiplier 0.1351 → DEX is trained up to its 13.51% target like any other ratio stat.
    • Custom ratios with one or more 0 multipliers → those stats skipped. Two-stat or three-stat builds still work without code changes.

    Co-Authored-By: Claude Opus 4.7 (1M context) [email protected]

  • v1.10.4 29/4/2026

    fix(ratio): respect any ratio's dump intent, not just Hank's

    Six sites hardcoded the dump-stat check as ratioKey === 'hank' && roles.tert2 === key which meant the rep allocator and grade ignored every other ratio's dump declaration:

    • Aec3 declares forcedDump: 'dex' but the planner queued reps for DEX when it was below its 13.51% target.
    • Custom ratios with one or more 0-multiplier slots were trained anyway, since only tert2 was checked.
    • "Only train 2 stats" / "only train 3 stats" builds had no clean declarative way to be honoured.

    Replace all six sites with a single helper:

    isStatDumped(key, ratioKey, roles)

    That returns true when:

    1. RATIOS[ratioKey].forcedDump matches key (Aec3 → DEX), OR
    2. The ratio's multiplier for whichever role key occupies is 0 (Hank's tert2; or any Custom slot zeroed out — this is what makes 2/3-stat builds work without further code changes).

    Sites updated: computeRepPlan (rep allocator) overallGrade (overall ratio grade) getDriftWarnings (per-stat drift detection) buildExportText (export panel display) renderOverview x2 (recommended stat picker + per-stat status)

    Effect for Aec3 + DEX dump (the user's loadout): DEX is now skipped in the rep planner, the grade, drift warnings, recommended stat, status row, and exported text. Reps redistribute to STR/SPD/DEF based on whichever is most behind its ratio target. Hank behaviour is preserved (its tert2 multiplier of 0 still triggers the skip).

    Custom ratios automatically get the same treatment for any 0-multiplier slot — including 2-stat or 3-stat training plans without further code.

    Co-Authored-By: Claude Opus 4.7 (1M context) [email protected]

  • v1.10.3 29/4/2026

    feat: serialise train-button clicks behind Torn's UI-ready signal

    Spamming the train button could race Torn's mid-transition UI. Each click fired executeTrainStep synchronously, so a second click might land on a stale button reference, miss the freshly-rendered confirm button, or send the rep-counter to the wrong gym.

    Two changes:

    1. New sfWaitForCondition(predicate, maxMs) — same shape as TSA's qtWaitForCondition. Resolves true when the predicate becomes truthy under any DOM mutation, false on timeout.

    2. executeTrainStep → executeTrainStepAsync. After each click, await Torn reaching the expected next state:

      switch → wait for membership-confirm to appear OR active gym to match step.target (free switches don't show confirm). confirm → wait for membership-confirm to disappear. fill → wait for the input value to reflect the requested reps. train → wait for the train button to re-enable OR energy to drop.

    Each wait has a 3 s ceiling (500 ms for fill); on timeout the step resolves anyway so the user can manually retry.

    1. Click handler at #trh-train-now now sets a module-level trainStepInFlight flag while the async step runs. Spam clicks while the flag is set are silently dropped — once the previous step resolves, the next legitimate click is processed against the already-stable Torn UI.

    Net effect: clicking faster than Torn can render no longer breaks the flow; the script processes one click at a time, waiting for Torn's UI to settle between each.

    Co-Authored-By: Claude Opus 4.7 (1M context) [email protected]

  • v1.10.2 25/4/2026 Imported from URL
  • v1.10.1 22/4/2026

    Sync scripts from Claude repo

  • v1.10.0 22/4/2026

    Sync scripts from Claude repo

  • v1.9.10 22/4/2026

    Sync scripts from Claude repo

  • v1.9.9 22/4/2026

    Sync scripts from Claude repo

  • v1.9.8 22/4/2026

    Sync scripts from Claude repo

  • v1.9.7 22/4/2026 Imported from URL
  • v1.9.7 22/4/2026