cuqueclicker_lib/game/golden.rs
1use rand::RngExt;
2use ratatui::layout::Rect;
3
4/// A Golden Cuque variant. The on-screen marker color + label differ per
5/// variant, but all are caught through the same path (mouse click on the
6/// marker, or the `g` hotkey). See `GameState::catch_golden` for effects.
7#[derive(Clone, Copy, Debug, PartialEq, Eq)]
8pub enum GoldenVariant {
9 /// Instant flat reward: `max(10, fps * 60s)` cuques. No buff, no duration.
10 Lucky,
11 /// 13-second `ClickFrenzy` buff: manual clicks produce x777 cuques.
12 Frenzy,
13 /// 60-second `FingererBoost` buff on a random owned fingerer: that
14 /// fingerer's passive FPS is multiplied x7.
15 Buff,
16}
17
18impl GoldenVariant {
19 pub fn random() -> Self {
20 let r: f64 = rand::rng().random();
21 if r < 0.6 {
22 Self::Lucky
23 } else if r < 0.8 {
24 Self::Frenzy
25 } else {
26 Self::Buff
27 }
28 }
29}
30
31/// Position is stored as a fraction of the biscuit rect ([0.0, 1.0] on each
32/// axis) so the marker stays anchored to its spot on the biscuit when the
33/// terminal resizes or the user zooms (`+`/`-`). The renderer resolves these
34/// fractions against the *current* biscuit rect every frame.
35#[derive(Clone)]
36pub struct GoldenCuque {
37 pub frac_x: f32,
38 pub frac_y: f32,
39 pub life_ticks: u32,
40 pub variant: GoldenVariant,
41}
42
43pub const GOLDEN_LIFE_TICKS: u32 = 220; // ~11s at 20Hz
44pub const GOLDEN_COOLDOWN_MIN: u32 = 400; // 20s
45pub const GOLDEN_COOLDOWN_MAX: u32 = 1600; // 80s
46// Inset (in fractional units) the spawn lottery away from the biscuit edges
47// so the 5x3 marker has room to render without bumping into the border.
48const SPAWN_INSET_X: f32 = 0.08;
49const SPAWN_INSET_Y: f32 = 0.10;
50
51pub fn next_cooldown() -> u32 {
52 rand::rng().random_range(GOLDEN_COOLDOWN_MIN..=GOLDEN_COOLDOWN_MAX)
53}
54
55/// Pick a random fractional position inside the biscuit, away from the edges.
56/// `_biscuit` is taken so the signature documents intent (the spawn area is
57/// "inside this rect"); the actual fractions are rect-independent.
58pub fn spawn_in(_biscuit: Rect) -> GoldenCuque {
59 let mut r = rand::rng();
60 let frac_x = r.random_range(SPAWN_INSET_X..=(1.0 - SPAWN_INSET_X));
61 let frac_y = r.random_range(SPAWN_INSET_Y..=(1.0 - SPAWN_INSET_Y));
62 GoldenCuque {
63 frac_x,
64 frac_y,
65 life_ticks: GOLDEN_LIFE_TICKS,
66 variant: GoldenVariant::random(),
67 }
68}