Skip to main content

tengu_api/state/
shogun.rs

1use super::DojosAccount;
2use steel::*;
3
4/// Empty slot sentinel. Barracks uses u64::MAX for empty slots.
5pub const BARRACKS_SLOT_EMPTY: u64 = u64::MAX;
6
7/// Shogun data. Stored in ShogunAccount; Barracks.slots hold pool indices.
8#[repr(C)]
9#[derive(Clone, Copy, Debug, PartialEq, bytemuck::Pod, bytemuck::Zeroable)]
10pub struct Shogun {
11    pub dojo: Pubkey,
12    pub index: u64,
13    pub rarity: u64,
14    pub element: u64,
15    pub spirit_power: u64,
16    pub prestige: u64,
17    pub chakra_max: u64,
18    pub chakra_remaining: u64,
19    pub assigned_barracks_slot: u64,
20    pub last_used_slot: u64,
21    pub level: u64,
22    pub buffer1: u64,
23    pub buffer2: u64,
24    pub buffer3: u64,
25    pub buffer4: u64,
26}
27
28account!(DojosAccount, Shogun);
29
30impl Shogun {
31    pub fn rarity_from_hash(hash: &[u8; 32]) -> u64 {
32        let v = u64::from_le_bytes(hash[0..8].try_into().unwrap()) % 1000;
33        if v < crate::consts::DROP_N {
34            0
35        } else if v < crate::consts::DROP_N + crate::consts::DROP_R {
36            1
37        } else if v < crate::consts::DROP_N + crate::consts::DROP_R + crate::consts::DROP_SR {
38            2
39        } else if v
40            < crate::consts::DROP_N
41                + crate::consts::DROP_R
42                + crate::consts::DROP_SR
43                + crate::consts::DROP_SSR
44        {
45            3
46        } else {
47            4
48        }
49    }
50
51    pub fn element_from_hash(hash: &[u8; 32]) -> u64 {
52        u64::from_le_bytes(hash[8..16].try_into().unwrap()) % 5
53    }
54
55    pub fn spirit_power_by_rarity(rarity: u64) -> u64 {
56        match rarity {
57            0 => crate::consts::SP_N,
58            1 => crate::consts::SP_R,
59            2 => crate::consts::SP_SR,
60            3 => crate::consts::SP_SSR,
61            4 => crate::consts::SP_UR,
62            _ => crate::consts::SP_N,
63        }
64    }
65
66    pub fn effective_spirit_power(rarity: u64, level: u64, prestige: u64) -> u64 {
67        let base = Self::spirit_power_by_rarity(rarity);
68        let lvl = level.max(1);
69        let prst = prestige.max(1).min(5);
70        let level_mult = 100u64.saturating_add((lvl - 1).saturating_mul(10));
71        let prestige_mult = [100u64, 125, 156, 195, 244][(prst - 1) as usize];
72        base.saturating_mul(level_mult).saturating_mul(prestige_mult) / 10_000
73    }
74
75    /// Cost to level up from `level` to `level+1` (raw $DOJO, 6 decimals). 200 + 800*(level-1).
76    pub fn level_up_cost(level: u64) -> u64 {
77        let lvl = level.max(1).min(crate::consts::MAX_SHOGUN_LEVEL);
78        crate::consts::LEVEL_UP_COST_BASE
79            .saturating_add(
80                crate::consts::LEVEL_UP_COST_INCREMENT.saturating_mul(lvl.saturating_sub(1)),
81            )
82    }
83
84    pub fn is_assigned(&self) -> bool {
85        self.assigned_barracks_slot != 0
86    }
87
88    pub fn slot_index(&self) -> u64 {
89        self.assigned_barracks_slot.saturating_sub(1)
90    }
91
92    pub fn is_empty(&self) -> bool {
93        self.rarity == 0 && self.level == 0 && self.spirit_power == 0
94    }
95}
96
97/// Shogun account: one per dojo. Barracks.slots[i] = pool index (or BARRACKS_SLOT_EMPTY).
98#[repr(C)]
99#[derive(Clone, Copy, Debug, PartialEq, bytemuck::Pod, bytemuck::Zeroable)]
100pub struct ShogunAccount {
101    pub dojo: Pubkey,
102    pub count: u64,
103    pub shoguns: [Shogun; crate::consts::MAX_SHOGUN_ACCOUNT_SIZE],
104}
105
106account!(DojosAccount, ShogunAccount);