wiwi/vh/
jewel.rs

1extern crate hashbrown;
2
3use crate::prelude::*;
4use crate::num::*;
5use crate::rc::{ RcStr, Counter, AtomicCounter };
6use hashbrown::HashSet;
7
8struct JewelStore<C = AtomicCounter>
9where
10	C: Counter
11{
12	modifiers: HashSet<Modifier<C>>,
13	jewels: Vec<Jewel<C>>
14}
15
16struct Jewel<C = AtomicCounter>
17where
18	C: Counter
19{
20	level: u16,
21	size: i16,
22	modifiers: JewelModifiers<C>
23}
24
25enum JewelModifiers<C = AtomicCounter>
26where
27	C: Counter
28{
29	Chipped([ModifierInstance<C>; 1]),
30	Flawed([ModifierInstance<C>; 2]),
31	Flawless([ModifierInstance<C>; 3]),
32	Perfect([ModifierInstance<C>; 4])
33}
34
35struct ModifierInstance<C = AtomicCounter>
36where
37	C: Counter
38{
39	modifier: Modifier<C>,
40	value: ModifierValue
41}
42
43struct Modifier<C = AtomicCounter>
44where
45	C: Counter
46{
47	inner: RcStr<C, ModifierMeta<C>>
48}
49
50struct ModifierMeta<C = AtomicCounter>
51where
52	C: Counter
53{
54	display_name: RcStr<C>,
55	modifier_type: ModifierType
56}
57
58/// Type of modifier (flag or with numeric value, and associated
59/// metadata if applicable)
60enum ModifierType {
61	/// A modifier that is either present, or not (eg. Soulbound)
62	///
63	/// For modifiers of this type, the modifier value is meaningless, and for
64	/// the sake of being deterministic, it should be set to 0.
65	Flag,
66
67	/// A modifier that has an attached number (eg. +100% Trap Disarm, or +15.3 Mining Speed)
68	NumericValue {
69		/// The power of 10 the stored value needs to be divided by
70		/// to get the true value
71		///
72		/// For example, if you have mining speed with value of 76 (76.0), and decimal
73		/// shift 1, you'd need to divide the value by 10^1, or shift the decimal left
74		/// by 1, to get the real value of 7.6.
75		decimal_shift: u8
76	}
77}
78
79/// The value of a modifier, including whether or not the modifier is legendary
80struct ModifierValue {
81	/// The highest bit stores if the modifier is legendary, and the rest store
82	/// the modifier's value (if applicable)
83	raw: i32
84}
85
86impl JewelStore {
87	#[inline]
88	fn new() -> Self {
89		Self::with_counter()
90	}
91
92	#[inline]
93	fn with_counter<C>() -> JewelStore<C>
94	where
95		C: Counter
96	{
97		JewelStore {
98			modifiers: HashSet::new(),
99			jewels: Vec::new()
100		}
101	}
102}
103
104impl<C> JewelStore<C>
105where
106	C: Counter
107{
108	/// Register a modifier by its identifier, return [`Ok`] if added and [`Err`]
109	/// if the modifier already exists
110	#[inline]
111	fn add_modifier(&mut self, id: &str, display_name: &str, modifier_type: ModifierType) -> Result<(), ()> {
112		if self.modifiers.get(id).is_none() {
113			let modifier = Modifier::new(id, display_name, modifier_type);
114
115			// SAFETY: just checked `id` is not in set
116			unsafe {
117				self.modifiers.insert_unique_unchecked(modifier);
118			}
119
120			Ok(())
121		} else {
122			Err(())
123		}
124	}
125}
126
127impl<C> Modifier<C>
128where
129	C: Counter
130{
131	/// Create new modifier
132	///
133	/// This will always allocate, as it has no knowledge of existing modifier
134	/// instances. Clone an existing modifier instance if you want to reuse
135	/// the allocation.
136	#[inline]
137	fn new(id: &str, display_name: &str, modifier_type: ModifierType) -> Self {
138		Self {
139			inner: RcStr::with_metadata(id, ModifierMeta {
140				display_name: RcStr::new(display_name),
141				modifier_type
142			})
143		}
144	}
145}
146
147impl<C> Borrow<str> for Modifier<C>
148where
149	C: Counter
150{
151	#[inline]
152	fn borrow(&self) -> &str {
153		&self.inner
154	}
155}
156
157impl<C> Clone for Modifier<C>
158where
159	C: Counter
160{
161	#[inline]
162	fn clone(&self) -> Self {
163		Self { inner: self.inner.clone() }
164	}
165}
166
167impl<C, C2> PartialEq<Modifier<C2>> for Modifier<C>
168where
169	C: Counter,
170	C2: Counter
171{
172	#[inline]
173	fn eq(&self, other: &Modifier<C2>) -> bool {
174		*self.inner == *other.inner
175	}
176}
177
178impl<C> Eq for Modifier<C>
179where
180	C: Counter
181{}
182
183impl<C> Hash for Modifier<C>
184where
185	C: Counter
186{
187	#[inline]
188	fn hash<H>(&self, state: &mut H)
189	where
190		H: Hasher
191	{
192		Hash::hash(&*self.inner, state)
193	}
194}
195
196impl ModifierValue {
197	/// Maximum storable modifier value
198	const MAX: i32 = i32::MAX >> 1;
199
200	/// Minimum storable modifier value (negative)
201	const MIN: i32 = i32::MIN >> 1;
202
203	#[inline]
204	fn new(value: i32, is_legendary: bool) -> Self {
205		Self::new_checked(value, is_legendary)
206			.expect("modifier value out of bounds")
207	}
208
209	#[inline]
210	fn new_checked(value: i32, is_legendary: bool) -> Option<Self> {
211		(Self::MIN..=Self::MAX).contains(&value).then(|| {
212			// SAFETY: we just checked we're within the allowed range
213			unsafe { Self::new_unchecked(value, is_legendary) }
214		})
215	}
216
217	/// # Safety
218	///
219	/// `value` must be within the range `MIN..=MAX`
220	#[inline]
221	unsafe fn new_unchecked(value: i32, is_legendary: bool) -> Self {
222		Self { raw: value | (is_legendary.into_i32() << 31) }
223	}
224
225	#[inline]
226	fn value(&self) -> i32 {
227		// first shift left one to push out the legendary bit, then
228		// (arithmetic) shift right one to bring back the bit with correct sign
229		(self.raw << 1) >> 1
230	}
231
232	#[inline]
233	fn is_legendary(&self) -> bool {
234		self.raw >> 31 == 1
235	}
236}