1use super::DojosAccount;
2use crate::error::DojosError;
3use solana_program::program_error::ProgramError;
4use steel::*;
5
6pub const FODDER_PRESTIGE_LEN: usize = 25 * crate::consts::PRESTIGE_LEVELS;
8
9#[repr(C)]
11#[derive(Clone, Copy, Debug, PartialEq, bytemuck::Pod, bytemuck::Zeroable)]
12pub struct FodderPrestigeCounts {
13 pub head: [u64; 128],
14 pub tail: [u64; 22],
15}
16
17impl Default for FodderPrestigeCounts {
18 fn default() -> Self {
19 Self { head: [0; 128], tail: [0; 22] }
20 }
21}
22
23impl FodderPrestigeCounts {
24 #[inline]
25 pub fn get(&self, i: usize) -> u64 {
26 *self.head.get(i).or_else(|| self.tail.get(i.wrapping_sub(128))).unwrap_or(&0)
27 }
28 #[inline]
29 pub fn get_mut(&mut self, i: usize) -> Option<&mut u64> {
30 if i < 128 {
31 self.head.get_mut(i)
32 } else {
33 self.tail.get_mut(i - 128)
34 }
35 }
36 #[inline]
37 pub fn slice(&self, start: usize, len: usize) -> impl Iterator<Item = u64> + '_ {
38 (start..start + len).map(|i| self.get(i))
39 }
40}
41
42#[repr(C)]
43#[derive(Clone, Copy, Debug, PartialEq, bytemuck::Pod, bytemuck::Zeroable)]
44pub struct Dojo {
45 pub owner: Pubkey,
46 pub battles_count: u64,
48 pub shard_balance: u64,
51 pub last_ore_claim_slot: u64,
52 pub referrer: Pubkey, pub recruitment_ticket_balance: u64,
54 pub recruited_count: u64,
55 pub dine_count: u64,
56 pub pity_counter: u64,
58 pub flash_sale_count_today: u64,
59 pub last_flash_sale_reset_slot: u64,
60 pub amethyst_balance: u64,
61 pub active_scene_id: u64,
62 pub fodder_counts_prestige: FodderPrestigeCounts,
65 pub xp: u64,
68}
69
70account!(DojosAccount, Dojo);
71
72impl Dojo {
73 #[inline]
75 pub fn fodder_prestige_index(collection_index: usize, prestige: u64) -> usize {
76 let p = prestige.max(1).min(crate::consts::PRESTIGE_LEVELS as u64);
77 collection_index * crate::consts::PRESTIGE_LEVELS + (p - 1) as usize
78 }
79
80 #[inline]
82 pub fn fodder_prestige_get(&self, collection_index: usize, prestige: u64) -> u64 {
83 if collection_index >= 25 {
84 return 0;
85 }
86 let i = Self::fodder_prestige_index(collection_index, prestige);
87 self.fodder_counts_prestige.get(i)
88 }
89
90 #[inline]
92 pub fn fodder_prestige_add(&mut self, collection_index: usize, prestige: u64, amount: u64) {
93 if collection_index < 25 {
94 let i = Self::fodder_prestige_index(collection_index, prestige);
95 if let Some(c) = self.fodder_counts_prestige.get_mut(i) {
96 *c = c.saturating_add(amount);
97 }
98 }
99 }
100
101 #[inline]
103 pub fn fodder_prestige_sub(&mut self, collection_index: usize, prestige: u64, amount: u64) -> bool {
104 if collection_index >= 25 {
105 return false;
106 }
107 let i = Self::fodder_prestige_index(collection_index, prestige);
108 if let Some(c) = self.fodder_counts_prestige.get_mut(i) {
109 if *c >= amount {
110 *c -= amount;
111 return true;
112 }
113 }
114 false
115 }
116
117 #[inline]
119 pub fn fodder_total_for_collection(&self, collection_index: usize) -> u64 {
120 if collection_index >= 25 {
121 return 0;
122 }
123 let base = collection_index * crate::consts::PRESTIGE_LEVELS;
124 self.fodder_counts_prestige.slice(base, crate::consts::PRESTIGE_LEVELS).sum()
125 }
126
127 #[inline]
129 pub fn fodder_total(&self) -> u64 {
130 (0..25).map(|ci| self.fodder_total_for_collection(ci)).sum()
131 }
132
133 #[inline]
135 pub fn fodder_prestige_consume_from_collection(&mut self, collection_index: usize, amount: u64) -> bool {
136 if collection_index >= 25 || self.fodder_total_for_collection(collection_index) < amount {
137 return false;
138 }
139 let mut take_rem = amount;
140 for p in 1..=crate::consts::PRESTIGE_LEVELS as u64 {
141 if take_rem == 0 {
142 break;
143 }
144 let have = self.fodder_prestige_get(collection_index, p);
145 let sub = take_rem.min(have);
146 if sub > 0 {
147 self.fodder_prestige_sub(collection_index, p, sub);
148 take_rem -= sub;
149 }
150 }
151 take_rem == 0
152 }
153
154 pub fn assert_owner(&self, signer: &Pubkey) -> Result<(), ProgramError> {
155 if self.owner != *signer {
156 return Err(ProgramError::IllegalOwner);
157 }
158 Ok(())
159 }
160
161 pub fn add_amethyst(&mut self, amount: u64) {
162 self.amethyst_balance = self.amethyst_balance.saturating_add(amount);
163 }
164
165 pub fn sub_amethyst(&mut self, amount: u64) -> Result<(), ProgramError> {
166 if self.amethyst_balance < amount {
167 return Err(ProgramError::InsufficientFunds);
168 }
169 self.amethyst_balance -= amount;
170 Ok(())
171 }
172
173 #[inline]
175 pub fn sub_shard_balance(&mut self, amount: u64) -> Result<(), ProgramError> {
176 if self.shard_balance < amount {
177 return Err(DojosError::InsufficientShards.into());
178 }
179 self.shard_balance -= amount;
180 Ok(())
181 }
182}