pub struct GameState {Show 42 fields
pub cuques: f64,
pub total_clicks: u64,
pub lifetime_cuques: f64,
pub best_fps: f64,
pub golden_caught: u64,
pub fingerers_owned: HashMap<String, u32>,
pub achievements_earned: HashSet<String>,
pub upgrades_earned: HashSet<String>,
pub prestige: u64,
pub total_play_ticks: u64,
pub buffs: Vec<Buff>,
pub clench_ticks: u32,
pub particles: Vec<Particle>,
pub misclick_particles: Vec<MisclickParticle>,
pub golden: Option<GoldenCuque>,
pub golden_cooldown: u32,
pub session_ticks: u64,
pub newly_unlocked: Vec<String>,
pub active_unlock_id: Option<String>,
pub active_unlock_ticks: u32,
pub visual_debt: f64,
pub lucky_flash_ticks: u32,
pub achievement_flash_ticks: u32,
pub border_phase: u32,
pub steady_phase: u32,
pub purchase_flash_ticks: u32,
pub purchase_flash_strength: f32,
pub fingerer_flash_ticks: Vec<u32>,
pub upgrade_flash_ticks: Vec<u32>,
pub fingerer_unaffordable_flash: Vec<u32>,
pub upgrade_unaffordable_flash: Vec<u32>,
pub fingerer_unlock_flash: Vec<u32>,
pub upgrade_unlock_flash: Vec<u32>,
pub prev_fingerer_affordable: Vec<bool>,
pub prev_upgrade_affordable: Vec<bool>,
pub space_pressed_this_tick: bool,
pub ticks_since_last_press: u32,
pub space_hold_ticks: u32,
pub displayed_cuques: f64,
pub displayed_fps: f64,
pub cuques_flash_ticks: u32,
pub cuques_spend_flash_ticks: u32,
}Expand description
Persistent game state. Catalog-addressed state (fingerers_owned,
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).
Fields§
§cuques: f64§total_clicks: u64§lifetime_cuques: f64§best_fps: f64§golden_caught: u64§fingerers_owned: HashMap<String, u32>Fingerer id → owned count.
achievements_earned: HashSet<String>Set of earned achievement ids.
upgrades_earned: HashSet<String>Set of earned upgrade ids.
prestige: u64§total_play_ticks: u64§buffs: Vec<Buff>§clench_ticks: u32§particles: Vec<Particle>§misclick_particles: Vec<MisclickParticle>Screen-anchored “misclick” tap particles — independent buffer because they don’t follow the biscuit (they’re feedback for clicks that MISSED the biscuit, including the dead zone at low zoom).
golden: Option<GoldenCuque>§golden_cooldown: u32§session_ticks: u64§newly_unlocked: Vec<String>Queue of achievement ids that unlocked but haven’t yet been shown as a
toast. Drained one-at-a-time by tick() into active_unlock_id.
active_unlock_id: Option<String>Currently-on-screen achievement toast (id) and its remaining life in
ticks. None means no toast right now; tick() pops the next pending
id off newly_unlocked when this clears.
active_unlock_ticks: u32§visual_debt: f64§lucky_flash_ticks: u32§achievement_flash_ticks: u32§border_phase: u32HUD title border phase clock. Advances by border_speed() each
tick, so the title border visibly speeds up under Frenzy / Lucky /
purchase events. INTENTIONALLY NOT shared with secondary shimmers
(panel borders, sidebar / upgrade rows) — they need a constant-rate
clock so a global speed-up on the HUD doesn’t drag them along.
steady_phase: u32Constant-rate phase clock for secondary shimmers — sidebar row,
upgrade row, and panel-border flashes. Advances by exactly 1 per
tick regardless of game state, so e.g. an Achievement / Frenzy
event accelerating border_phase doesn’t accelerate the
“can’t-buy” shimmer that happens to be running on a fingerer
row at the same time.
purchase_flash_ticks: u32§purchase_flash_strength: f32Strength multiplier (1.0..=3.0) for the most recent purchase flash, scaled by bulk-buy quantity. The border + panel borders read this so a max-buy lands harder than a single click.
fingerer_flash_ticks: Vec<u32>One slot per visible sidebar row; indexed by catalog position because it’s purely a render-time flash and doesn’t need to survive reorders.
upgrade_flash_ticks: Vec<u32>Mirror of fingerer_flash_ticks for the Upgrades panel. Sized to
UPGRADES.len() lazily by migrate().
fingerer_unaffordable_flash: Vec<u32>Negative-feedback flash: red row pulse when a click hit a row but
cuques < cost. One slot per fingerer / upgrade index.
upgrade_unaffordable_flash: Vec<u32>§fingerer_unlock_flash: Vec<u32>“Just became affordable” flash: a brief one-shot green shimmer
fired the tick a row’s affordability flips false → true. Distinct
from *_flash_ticks (purchase) — shorter duration, no panel
border bleed — so the player can tell “now buyable” apart from
“you just bought.”
upgrade_unlock_flash: Vec<u32>§prev_fingerer_affordable: Vec<bool>Previous-tick affordability per row, used to detect the
false→true edge that triggers *_unlock_flash. Sized to catalog
length by migrate() and seeded at init from the live state, so a
freshly-loaded save with rows already affordable doesn’t fire a
fake unlock flash on tick 1.
prev_upgrade_affordable: Vec<bool>§space_pressed_this_tick: boolHeld-spacebar tracking.
space_pressed_this_tick is set whenever Action::ClickCenter
arrives (terminal key-repeat fires Press events at ~30Hz, easily
hitting every 50ms tick when a key is genuinely held).
ticks_since_last_press is a small countdown that allows up to 3
missed ticks (~150ms) before declaring the key released — handles
real keyboard-repeat jitter so a 1-tick gap doesn’t kill the
streak. space_hold_ticks is the consecutive “active” tick streak;
space_held() is true once it crosses 1 second.
Net result: spamming spacebar at human speed (≥150ms between presses) never triggers held; actually holding the key climbs the streak past 20 ticks within ~1s.
ticks_since_last_press: u32§space_hold_ticks: u32§displayed_cuques: f64HUD count-up tween: rendered numbers smoothly chase the real ones. Initialized to the live values on load so the first frame doesn’t look like a count-up from zero.
displayed_fps: f64§cuques_flash_ticks: u32Brief green flash on the HUD digits when cuques jump UP — golden catch, frenzy click, F4 dev cheat, etc. (“money coming in”)
cuques_spend_flash_ticks: u32Brief red flash on the HUD digits when cuques drop — successful
purchase, prestige reset (the big -all event). Mirrors
cuques_flash_ticks and competes with it: whichever channel is
stronger this frame drives the HUD color sweep, so a buy that
happens during a still-decaying gain pulse correctly flips the
digits red instead of staying green.
Implementations§
Source§impl GameState
impl GameState
Sourcepub fn migrate(self) -> Self
pub fn migrate(self) -> Self
Initialize ephemeral runtime state that #[serde(skip)] left empty
after deserialization, and normalize any fields that need live values
rather than the serde default. Hook point for future shape
transforms — see CLAUDE.md on the stable-id save policy.
pub fn fingerer_count(&self, id: &str) -> u32
pub fn fingerer_count_idx(&self, idx: usize) -> u32
pub fn fingerers_owned_total(&self) -> u32
pub fn has_upgrade(&self, id: &str) -> bool
pub fn has_achievement(&self, id: &str) -> bool
pub fn has_achievement_idx(&self, idx: usize) -> bool
pub fn click(&mut self, origin: (u16, u16), biscuit: Rect)
Sourcepub fn spawn_misclick(&mut self, col: u16, row: u16)
pub fn spawn_misclick(&mut self, col: u16, row: u16)
Spawn a screen-anchored “·” particle at a click point that hit nothing (biscuit dead zone, blank panel area, etc). Acknowledges that the click registered without altering any game state.
Sourcepub fn spawn_confetti(&mut self, n: u32)
pub fn spawn_confetti(&mut self, n: u32)
Spawn n confetti particles scattered over the biscuit. Used for
bulk-buy juice — a max-buy of a fingerer pops a small burst.
pub fn click_power(&self) -> f64
pub fn fingerer_mult(&self, idx: usize) -> f64
Sourcepub fn dev_add_cuques(&mut self, amount: f64)
pub fn dev_add_cuques(&mut self, amount: f64)
Dev-build cheat. Bypasses normal flow; not reachable in release builds
because the F-key that triggers it is gated behind App::debug.
Sourcepub fn catch_golden(&mut self) -> f64
pub fn catch_golden(&mut self) -> f64
Catch whatever Golden Cuque is currently on screen (any variant:
Lucky, Frenzy, or Buff). Applies the variant-specific effect,
increments golden_caught, re-rolls the next spawn cooldown, and
returns the flat reward (0.0 for buff variants).
pub fn fps(&self) -> f64
pub fn border_speed(&self) -> u32
Sourcepub fn trigger_purchase_flash(&mut self, strength: f32)
pub fn trigger_purchase_flash(&mut self, strength: f32)
Trigger the green purchase flash on the global border + the panel
border. strength scales how loud the flash is (1.0 = single buy,
up to 3.0 = bulk max-buy) so a max-buy lands harder than a +1.
pub fn prestige_mult(&self) -> f64
pub fn prestige_earned_total(&self) -> u64
pub fn prestige_available(&self) -> u64
pub fn prestige_reset(&mut self) -> bool
pub fn tick(&mut self)
pub fn tick_achievements(&mut self)
pub fn tick_golden(&mut self)
pub fn trigger_clench(&mut self)
Sourcepub fn space_held(&self) -> bool
pub fn space_held(&self) -> bool
True when the spacebar has been held continuously for ≥ 1 second.
Driven by space_hold_ticks (a streak counter that increments on
every tick where at least one ClickCenter arrived, resets the
instant a tick passes without one). Switches the biscuit’s clench
animation from a burning * to the spin frames \ | / -.
Sourcepub fn spawn_auto_particle(&mut self, frac_x: f32, frac_y: f32)
pub fn spawn_auto_particle(&mut self, frac_x: f32, frac_y: f32)
Spawn a “+N” particle representing cuques earned since the last
auto-particle. Silently skips if there isn’t a whole cuque of accrued
income to show — at low FPS the caller is a rate-based timer that
fires faster than cuques arrive, and spawning a “+1” in that window
used to lie (particle flying up while the HUD counter didn’t move).
The shown amount is always real cuques that just accrued into
visual_debt.
pub fn cost(&self, idx: usize) -> f64
Sourcepub fn affordable_cuques(&self) -> f64
pub fn affordable_cuques(&self) -> f64
Cuques the player can ACTUALLY spend right now: the lesser of real
cuques and the displayed counter. Both bounds matter:
- Gating ONLY on
cuques(real) lets the row turn green and a click succeed before the counter visibly catches up — the “I have 8 but the row says I can buy a 17” lie. - Gating ONLY on
displayed_cuques.floor()lets a click DRAIN real cuques NEGATIVE during a spend’s tween-down: real already dropped, displayed hasn’t caught down yet, gate sees the high displayed value and lets the buy through against the depleted real. Oncecuquesgoes negative, the HUD floor() shows “0” for a long time while the slow income climbs back.
Taking min(real, displayed.floor()) makes both conditions
equally binding: row turns green only when the visible counter
AND the underlying balance both reach the cost; click succeeds
only when both still hold. No overspend, no visual lie.
pub fn can_buy(&self, idx: usize) -> bool
pub fn buy(&mut self, idx: usize) -> bool
pub fn buy_n(&mut self, idx: usize, n: u32) -> u32
pub fn buy_max(&mut self, idx: usize) -> u32
pub fn buy_upgrade(&mut self, idx: usize) -> bool
Trait Implementations§
Source§impl<'de> Deserialize<'de> for GameState
impl<'de> Deserialize<'de> for GameState
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
Auto Trait Implementations§
impl Freeze for GameState
impl RefUnwindSafe for GameState
impl Send for GameState
impl Sync for GameState
impl Unpin for GameState
impl UnsafeUnpin for GameState
impl UnwindSafe for GameState
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more