Skip to main content

tengu_api/state/
prestige.rs

1//! Prestige account: per-prestige fodder counts for SSR/UR. Enables prestiging fodder shoguns.
2//! When absent, all fodder is treated as prestige 1 (legacy). Created lazily on first use.
3
4use super::DojosAccount;
5use steel::*;
6
7/// Counts per (collection_index, prestige_level). collection_index = element×5+rarity (0–24).
8/// prestige_level 1–6. Index = ci * PRESTIGE_LEVELS + (prestige - 1).
9/// Split into [128; 22] for bytemuck Pod (max 128 per array).
10const COUNTS_LEN: usize = 25 * 6;
11
12#[repr(C)]
13#[derive(Clone, Copy, Debug, PartialEq, bytemuck::Pod, bytemuck::Zeroable)]
14pub struct Prestige {
15    pub dojo: Pubkey,
16    /// Fodder counts by (collection_index * PRESTIGE_LEVELS + prestige_minus_1). Prestige 1 = index 0.
17    pub counts_a: [u64; 128],
18    pub counts_b: [u64; 22],
19    /// Reserved for future extension (e.g. more prestige levels, metadata).
20    pub buffer1: [u64; 8],
21    pub buffer2: [u64; 8],
22    pub buffer3: [u64; 8],
23}
24
25account!(DojosAccount, Prestige);
26
27impl Prestige {
28    #[inline]
29    fn counts(&self) -> &[u64] {
30        unsafe { std::slice::from_raw_parts(self.counts_a.as_ptr(), COUNTS_LEN) }
31    }
32
33    #[inline]
34    fn counts_mut(&mut self) -> &mut [u64] {
35        unsafe { std::slice::from_raw_parts_mut(self.counts_a.as_mut_ptr(), COUNTS_LEN) }
36    }
37
38    /// Index for collection (element×5+rarity) at prestige level (1–6).
39    #[inline]
40    pub fn index(collection_index: usize, prestige: u64) -> usize {
41        let p = prestige.max(1).min(crate::consts::PRESTIGE_LEVELS as u64);
42        collection_index * crate::consts::PRESTIGE_LEVELS + (p - 1) as usize
43    }
44
45    /// Get count at (collection_index, prestige).
46    #[inline]
47    pub fn get(&self, collection_index: usize, prestige: u64) -> u64 {
48        if collection_index >= 25 {
49            return 0;
50        }
51        let i = Self::index(collection_index, prestige);
52        self.counts().get(i).copied().unwrap_or(0)
53    }
54
55    /// Add to count at (collection_index, prestige).
56    #[inline]
57    pub fn add(&mut self, collection_index: usize, prestige: u64, amount: u64) {
58        if collection_index < 25 {
59            let i = Self::index(collection_index, prestige);
60            if let Some(c) = self.counts_mut().get_mut(i) {
61                *c = c.saturating_add(amount);
62            }
63        }
64    }
65
66    /// Subtract from count. Returns false if insufficient.
67    #[inline]
68    pub fn sub(&mut self, collection_index: usize, prestige: u64, amount: u64) -> bool {
69        if collection_index >= 25 {
70            return false;
71        }
72        let i = Self::index(collection_index, prestige);
73        if let Some(c) = self.counts_mut().get_mut(i) {
74            if *c >= amount {
75                *c -= amount;
76                return true;
77            }
78        }
79        false
80    }
81
82    /// Total count for collection across all prestige levels.
83    #[inline]
84    pub fn total_for_collection(&self, collection_index: usize) -> u64 {
85        if collection_index >= 25 {
86            return 0;
87        }
88        let base = collection_index * crate::consts::PRESTIGE_LEVELS;
89        (0..crate::consts::PRESTIGE_LEVELS)
90            .map(|p| self.counts().get(base + p).copied().unwrap_or(0))
91            .sum()
92    }
93}