Persistent game state. Catalog-addressed state (fingerers_state,
upgrades_earned, achievements_earned) is keyed by STABLE STRING IDS,
not positional indices, so reordering / inserting / removing entries in
FINGERERS, UPGRADES, or ACHIEVEMENTS never corrupts an old save.
Unknown ids in a save are ignored (forward-compat); missing ids default
to zero / absent (backward-compat).
Screen-anchored particle (raw col/row, not biscuit-fractional). Used for
misclick acknowledgement: a small grey “·” at the exact dead-zone click
point so the player knows the click registered but missed every target.
Position is stored as a fraction of the biscuit rect ([0.0, 1.0] on each
axis), matching Powerup. The renderer resolves these fractions
against the current biscuit rect every frame, so particles travel with
the biscuit when the terminal resizes or the user zooms.
Global, click-side buffs. Per-fingerer multipliers (the old
Buff::FingererBoost) live on the modifier system in
crate::game::modifier; only buffs that affect global click power
belong here.
First CLENCH_SQUASH_TICKS of a clench draw the biscuit one row shorter
(top blank dropped, art shifted) so each finger reads as a real squish
before springing back. Strict subset of CLENCH_TICKS.
How long the biscuit stays “clenched” (eye→*, color shifts pink, art
vertically squashes by one row). Bumped from 3 to 6 so a single click is
actually visible — at 20Hz, 3 ticks (~150ms) was hard to perceive.
Cells the edge-unlock wavefront advances per tick. At TICK_HZ = 20
a value of 2 = 40 cells / sec — a typical 8-cell straight edge fully
energizes in ~0.2 s, a longer diagonal in ~0.4 s. Bumping this is
the right knob when the user says “make it faster”; going below 1
(e.g. tick / 2 cells/tick = slower) needs a different mechanism
since we sample integer cells per tick.
Green Coin catch pulse — slightly shorter than Lucky’s so the celebratory
blip lands without lingering for so long it competes with whatever might
be running on top (Frenzy, Buff, Lucky).
Per-row gold shimmer on the targeted fingerer’s sidebar row when a
Green Coin catch lands on it. ~2 seconds — long enough for the eye
to track from the floating +10% {fingerer} particle over to the
row, short enough that it doesn’t outlive the catch event.
Fraction of a tree node’s original cost returned on refund. The
remaining fraction is the “exploration tax” — without this gap,
buy/refund is a zero-cost move and the player can spam every
combination for free. 0.70 = 30% loss on each refund, enough to make
reckless paths expensive without punishing genuine course corrections.
“You can afford this now!” row flash — fires the moment a fingerer or
upgrade transitions from unaffordable to affordable. Brief on purpose:
short enough that it’s clearly an “announcement,” not the longer
purchase flash that fires on actual buy.
Convert an absolute (col, row) screen point into biscuit-fractional
coordinates, clamped to [0.0, 1.0]. Used at click/spawn sites that come
from screen-space input (mouse clicks, RNG within the biscuit rect).