1use std::cmp::Ordering;
19use std::fmt::Debug;
20use std::hash::Hash;
21
22pub mod equip;
23pub mod kind;
24pub mod mart;
25pub mod use_driver;
26pub use equip::{EquipProvider, EquipSlot};
27pub use kind::ItemKind;
28pub use mart::{MartBackend, MartDriver, MartState, MartStock};
29pub use use_driver::{buy, sell, use_item, ItemUseResult, ShopError, ShopReceipt, UsageContext};
30
31#[derive(Debug, Clone, Copy, PartialEq, Eq)]
35pub enum ItemResult {
36 Used,
38 NotUsable,
41 NotOwned,
43 NoEffect,
46}
47
48#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
50pub enum BagCategory {
51 Items,
53 Medicine,
55 Balls,
57 Battle,
59 Key,
61 Other,
63}
64
65#[derive(Debug, Clone, Copy, PartialEq, Eq)]
68pub enum AddError {
69 InventoryFull,
71 PerSlotCapReached(u32),
73}
74
75#[derive(Debug, Clone, PartialEq, Eq)]
91pub struct Inventory<I: Copy + Eq + Hash + Debug, const N: usize> {
92 items: [Option<(I, u32)>; N],
94 len: usize,
96 max_per_slot: Option<u32>,
98}
99
100pub type SimpleInventory<I> = Inventory<I, 256>;
107
108impl<I: Copy + Eq + Hash + Debug, const N: usize> Inventory<I, N> {
109 pub fn new() -> Self {
111 Self {
112 items: [None; N],
113 len: 0,
114 max_per_slot: None,
115 }
116 }
117
118 pub fn with_capacity(max_per_slot: u32) -> Self {
121 Self {
122 items: [None; N],
123 len: 0,
124 max_per_slot: Some(max_per_slot),
125 }
126 }
127
128 pub fn count(&self) -> usize {
130 self.len
131 }
132
133 pub fn is_empty(&self) -> bool {
135 self.len == 0
136 }
137
138 pub fn capacity(&self) -> usize {
140 N
141 }
142
143 pub fn contains(&self, item: &I, quantity: u32) -> bool {
145 self.iter().any(|(i, q)| i == item && *q >= quantity)
146 }
147
148 pub fn add(&mut self, item: I, quantity: u32) -> Result<(), AddError> {
161 if quantity == 0 {
162 return Ok(());
163 }
164 if self.would_exceed_per_slot_cap(&item, quantity) {
166 return Err(AddError::PerSlotCapReached(self.max_per_slot.unwrap()));
167 }
168 let exists = self.iter().any(|(i, _)| *i == item);
170 if !exists && self.is_full() {
171 return Err(AddError::InventoryFull);
172 }
173 for slot in &mut self.items[..self.len] {
174 if let Some((existing, qty)) = slot {
175 if *existing == item {
176 *qty = qty.saturating_add(quantity);
177 return Ok(());
178 }
179 }
180 }
181 self.items[self.len] = Some((item, quantity));
182 self.len += 1;
183 Ok(())
184 }
185
186 pub fn remove(&mut self, item: &I, quantity: u32) -> bool {
190 for i in 0..self.len {
191 if let Some((existing, qty)) = &mut self.items[i] {
192 if existing == item {
193 if *qty < quantity {
194 return false;
195 }
196 if *qty == quantity {
197 self.remove_at(i);
198 } else {
199 *qty -= quantity;
200 }
201 return true;
202 }
203 }
204 }
205 false
206 }
207
208 pub fn quantity(&self, item: &I) -> u32 {
212 self.iter()
213 .find(|(i, _)| i == item)
214 .map(|(_, q)| *q)
215 .unwrap_or(0)
216 }
217
218 pub fn is_full(&self) -> bool {
220 self.len >= N
221 }
222
223 pub fn would_exceed_per_slot_cap(&self, item: &I, add_quantity: u32) -> bool {
226 let Some(cap) = self.max_per_slot else {
227 return false;
228 };
229 let current = self.quantity(item);
230 current.saturating_add(add_quantity) > cap
231 }
232
233 pub fn filter<F>(&self, pred: F) -> Vec<&(I, u32)>
235 where
236 F: Fn(&I) -> bool,
237 {
238 self.iter().filter(|(i, _)| pred(i)).collect()
239 }
240
241 pub fn sort_by<F>(&mut self, mut cmp: F)
243 where
244 F: FnMut(&(I, u32), &(I, u32)) -> Ordering,
245 {
246 self.items[..self.len].sort_by(|a, b| cmp(a.as_ref().unwrap(), b.as_ref().unwrap()));
247 }
248
249 pub fn sort_by_name<F>(&mut self, name_fn: F)
252 where
253 F: Fn(&I) -> &str,
254 {
255 self.items[..self.len]
256 .sort_by(|a, b| name_fn(&a.as_ref().unwrap().0).cmp(name_fn(&b.as_ref().unwrap().0)));
257 }
258
259 pub fn into_inner(self) -> Vec<(I, u32)> {
261 self.items.iter().flatten().copied().collect()
262 }
263
264 pub fn iter(&self) -> impl Iterator<Item = &(I, u32)> {
266 self.items[..self.len].iter().filter_map(Option::as_ref)
267 }
268
269 pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut (I, u32)> {
271 self.items[..self.len].iter_mut().filter_map(Option::as_mut)
272 }
273
274 pub fn get(&self, index: usize) -> Option<&(I, u32)> {
276 self.items.get(index).and_then(Option::as_ref)
277 }
278
279 pub fn get_mut(&mut self, index: usize) -> Option<&mut (I, u32)> {
281 self.items.get_mut(index).and_then(Option::as_mut)
282 }
283
284 pub fn push_slot(&mut self, item: I, quantity: u32) -> Result<(), AddError> {
287 if self.is_full() {
288 return Err(AddError::InventoryFull);
289 }
290 self.items[self.len] = Some((item, quantity));
291 self.len += 1;
292 Ok(())
293 }
294
295 pub fn remove_at(&mut self, index: usize) {
301 assert!(index < self.len, "inventory slot index out of bounds");
302 self.items.copy_within(index + 1..self.len, index);
303 self.items[self.len - 1] = None;
304 self.len -= 1;
305 }
306
307 pub fn swap(&mut self, a: usize, b: usize) {
313 self.items.swap(a, b);
314 }
315
316 pub fn clear(&mut self) {
318 self.items.fill(None);
319 self.len = 0;
320 }
321}
322
323impl<I: Copy + Eq + Hash + Debug, const N: usize> Default for Inventory<I, N> {
324 fn default() -> Self {
325 Self::new()
326 }
327}
328
329pub trait ItemProvider {
343 type Item: Copy + Eq + Hash + Debug;
345 type Effect;
347 type Monster;
349
350 type CustomKind: Copy + Eq + Hash + Debug;
352
353 fn item_name(&self, item: &Self::Item) -> &str;
355
356 fn item_description(&self, item: &Self::Item) -> &str;
358
359 fn item_effect(&self, item: &Self::Item) -> Self::Effect;
361
362 fn item_price(&self, item: &Self::Item) -> u32;
364
365 fn can_use_outside_battle(&self, item: &Self::Item) -> bool;
368
369 fn can_use_in_battle(&self, item: &Self::Item) -> bool;
371
372 fn use_on_monster(&self, item: &Self::Item, monster: &mut Self::Monster) -> ItemResult;
377
378 fn consume(&self, item: &Self::Item) -> bool;
382
383 fn item_kind(&self, item: &Self::Item) -> ItemKind<Self::CustomKind>;
391
392 fn on_teach_move<M: crate::party::MonsterProvider>(
395 &self,
396 item: Self::Item,
397 target: &mut crate::party::MonsterInstance<M>,
398 ) -> Option<ItemUseResult<Self::Item>> {
399 let _ = (item, target);
400 None
401 }
402
403 fn on_use_field(&self, item: Self::Item) -> Option<ItemUseResult<Self::Item>> {
406 let _ = item;
407 None
408 }
409
410 fn usable_in(&self, item: &Self::Item) -> UsageContext {
418 let _ = item;
419 UsageContext::FieldAndBattle
420 }
421
422 fn apply_effect<M: crate::party::MonsterProvider>(
440 &self,
441 provider: &M,
442 item: Self::Item,
443 ctx: UsageContext,
444 target: Option<&mut crate::party::MonsterInstance<M>>,
445 rng: &mut dyn crate::battle::rng::BattleRng,
446 ) -> ItemUseResult<Self::Item> {
447 let _ = (provider, item, ctx, target, rng);
448 ItemUseResult::NoEffect
449 }
450}
451
452pub trait ShopProvider {
463 type Item: Copy + Eq + Hash + Debug;
465 type ShopId: Copy + Eq + Hash + Debug;
467
468 fn shop_inventory(&self, shop_id: &Self::ShopId) -> Vec<(Self::Item, u32)>;
473
474 fn shop_name(&self, shop_id: &Self::ShopId) -> &str;
476
477 fn buy_price(&self, item: &Self::Item) -> u32 {
484 let _ = item;
485 0
486 }
487
488 fn sell_price(&self, item: &Self::Item) -> u32 {
494 self.buy_price(item) / 2
495 }
496
497 fn can_sell(&self, item: &Self::Item) -> bool {
503 let _ = item;
504 true
505 }
506
507 fn discount_rate(&self, _shop_id: &Self::ShopId) -> f32 {
514 1.0
515 }
516
517 fn sell_rate(&self, _shop_id: &Self::ShopId) -> f32 {
525 1.0
526 }
527
528 fn has_limited_stock(&self, _item: &Self::Item) -> bool {
532 false
533 }
534
535 fn max_stock(&self, _item: &Self::Item) -> u32 {
540 0
541 }
542
543 fn restocks(&self, _shop_id: &Self::ShopId) -> bool {
547 false
548 }
549
550 fn restock_interval(&self, _shop_id: &Self::ShopId) -> u32 {
554 0
555 }
556}
557
558#[cfg(test)]
561mod tests {
562 use super::*;
563
564 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
568 struct MockItem {
569 name: &'static str,
570 price: u32,
571 heal_amount: u32,
572 }
573
574 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
576 enum MockEffect {
577 Heal(u32),
578 None,
579 }
580
581 #[derive(Debug, Clone)]
583 #[allow(dead_code)]
584 struct MockMonster {
585 name: &'static str,
586 max_hp: u32,
587 current_hp: u32,
588 }
589
590 struct MockItemProvider;
593
594 impl ItemProvider for MockItemProvider {
595 type Item = MockItem;
596 type Effect = MockEffect;
597 type Monster = MockMonster;
598 type CustomKind = ();
599
600 fn item_name(&self, item: &Self::Item) -> &str {
601 item.name
602 }
603
604 fn item_description(&self, item: &Self::Item) -> &str {
605 if item.heal_amount > 0 {
606 "Restores HP."
607 } else {
608 "Has no effect in battle."
609 }
610 }
611
612 fn item_effect(&self, item: &Self::Item) -> Self::Effect {
613 if item.heal_amount > 0 {
614 MockEffect::Heal(item.heal_amount)
615 } else {
616 MockEffect::None
617 }
618 }
619
620 fn item_price(&self, item: &Self::Item) -> u32 {
621 item.price
622 }
623
624 fn can_use_outside_battle(&self, _item: &Self::Item) -> bool {
625 true
626 }
627
628 fn can_use_in_battle(&self, _item: &Self::Item) -> bool {
629 true
630 }
631
632 fn use_on_monster(&self, item: &Self::Item, monster: &mut Self::Monster) -> ItemResult {
633 match self.item_effect(item) {
634 MockEffect::Heal(amount) => {
635 if monster.current_hp >= monster.max_hp {
636 return ItemResult::NoEffect;
637 }
638 monster.current_hp = (monster.current_hp + amount).min(monster.max_hp);
639 ItemResult::Used
640 }
641 MockEffect::None => ItemResult::NoEffect,
642 }
643 }
644
645 fn consume(&self, _item: &Self::Item) -> bool {
646 true
647 }
648
649 fn item_kind(&self, item: &Self::Item) -> ItemKind<()> {
650 if item.heal_amount > 0 {
651 ItemKind::Consumable
652 } else {
653 ItemKind::Consumable
654 }
655 }
656 }
657
658 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
659 enum MockShopId {
660 CityMart,
661 }
662
663 struct MockShopProvider;
664
665 impl ShopProvider for MockShopProvider {
666 type Item = MockItem;
667 type ShopId = MockShopId;
668
669 fn shop_inventory(&self, shop_id: &Self::ShopId) -> Vec<(Self::Item, u32)> {
670 match shop_id {
671 MockShopId::CityMart => vec![
672 (
673 MockItem {
674 name: "Potion",
675 price: 300,
676 heal_amount: 20,
677 },
678 300,
679 ),
680 (
681 MockItem {
682 name: "Elixir",
683 price: 500,
684 heal_amount: 0,
685 },
686 500,
687 ),
688 ],
689 }
690 }
691
692 fn shop_name(&self, shop_id: &Self::ShopId) -> &str {
693 match shop_id {
694 MockShopId::CityMart => "City Mart",
695 }
696 }
697 }
698
699 #[test]
702 fn potion_heals_monster() {
703 let provider = MockItemProvider;
704 let potion = MockItem {
705 name: "Potion",
706 price: 300,
707 heal_amount: 20,
708 };
709 let mut monster = MockMonster {
710 name: "Sprout",
711 max_hp: 100,
712 current_hp: 50,
713 };
714
715 let result = provider.use_on_monster(&potion, &mut monster);
716 assert_eq!(result, ItemResult::Used);
717 assert_eq!(monster.current_hp, 70);
718 assert!(provider.consume(&potion));
719 }
720
721 #[test]
722 fn potion_no_effect_on_full_hp() {
723 let provider = MockItemProvider;
724 let potion = MockItem {
725 name: "Potion",
726 price: 300,
727 heal_amount: 20,
728 };
729 let mut monster = MockMonster {
730 name: "Sprout",
731 max_hp: 100,
732 current_hp: 100,
733 };
734
735 let result = provider.use_on_monster(&potion, &mut monster);
736 assert_eq!(result, ItemResult::NoEffect);
737 assert_eq!(monster.current_hp, 100);
738 }
739
740 #[test]
741 fn elixir_has_no_heal_effect() {
742 let provider = MockItemProvider;
743 let elixir = MockItem {
744 name: "Elixir",
745 price: 500,
746 heal_amount: 0,
747 };
748 let mut monster = MockMonster {
749 name: "Sprout",
750 max_hp: 100,
751 current_hp: 50,
752 };
753
754 let result = provider.use_on_monster(&elixir, &mut monster);
755 assert_eq!(result, ItemResult::NoEffect);
756 assert_eq!(monster.current_hp, 50); }
758
759 #[test]
762 fn shop_inventory_has_two_items() {
763 let provider = MockShopProvider;
764 let inventory = provider.shop_inventory(&MockShopId::CityMart);
765
766 assert_eq!(inventory.len(), 2);
767 assert_eq!(inventory[0].0.name, "Potion");
768 assert_eq!(inventory[0].1, 300);
769 assert_eq!(inventory[1].0.name, "Elixir");
770 assert_eq!(inventory[1].1, 500);
771 }
772
773 #[test]
774 fn shop_name_is_correct() {
775 let provider = MockShopProvider;
776 assert_eq!(provider.shop_name(&MockShopId::CityMart), "City Mart");
777 }
778
779 #[test]
782 fn inventory_add_and_remove() {
783 let mut inv: Inventory<MockItem, 8> = Inventory::new();
784 let potion = MockItem {
785 name: "Potion",
786 price: 300,
787 heal_amount: 20,
788 };
789
790 inv.add(potion, 3).unwrap();
791 assert_eq!(inv.count(), 1);
792 assert!(inv.contains(&potion, 2));
793 assert!(!inv.contains(&potion, 4));
794
795 assert!(inv.remove(&potion, 2));
796 assert_eq!(inv.count(), 1);
797 assert!(inv.contains(&potion, 1));
798
799 assert!(inv.remove(&potion, 1));
800 assert_eq!(inv.count(), 0);
801 assert!(!inv.contains(&potion, 1));
802 }
803
804 #[test]
805 fn inventory_stacks_same_item() {
806 let mut inv: Inventory<MockItem, 8> = Inventory::new();
807 let potion = MockItem {
808 name: "Potion",
809 price: 300,
810 heal_amount: 20,
811 };
812
813 inv.add(potion, 3).unwrap();
814 inv.add(potion, 5).unwrap();
815 assert_eq!(inv.count(), 1); assert!(inv.contains(&potion, 8));
817 }
818
819 #[test]
820 fn inventory_remove_insufficient_quantity() {
821 let mut inv: Inventory<MockItem, 8> = Inventory::new();
822 let potion = MockItem {
823 name: "Potion",
824 price: 300,
825 heal_amount: 20,
826 };
827
828 inv.add(potion, 2).unwrap();
829 assert!(!inv.remove(&potion, 5));
830 assert_eq!(inv.count(), 1);
831 assert!(inv.contains(&potion, 2)); }
833
834 #[test]
835 fn inventory_remove_nonexistent_item() {
836 let mut inv: Inventory<MockItem, 8> = Inventory::new();
837 let potion = MockItem {
838 name: "Potion",
839 price: 300,
840 heal_amount: 20,
841 };
842
843 assert!(!inv.remove(&potion, 1));
844 }
845
846 #[test]
849 fn inventory_new_is_unlimited() {
850 let inv: Inventory<MockItem, 8> = Inventory::new();
851 assert!(!inv.is_full());
852 let potion = MockItem {
853 name: "Potion",
854 price: 300,
855 heal_amount: 20,
856 };
857 assert!(!inv.would_exceed_per_slot_cap(&potion, u32::MAX));
858 }
859
860 #[test]
861 fn inventory_with_capacity_rejects_overfill() {
862 let mut inv = Inventory::<MockItem, 2>::with_capacity(10);
863 let potion = MockItem {
864 name: "Potion",
865 price: 300,
866 heal_amount: 20,
867 };
868 let elixir = MockItem {
869 name: "Elixir",
870 price: 500,
871 heal_amount: 0,
872 };
873 let antidote = MockItem {
874 name: "Antidote",
875 price: 200,
876 heal_amount: 0,
877 };
878
879 assert!(inv.add(potion, 1).is_ok());
880 assert!(inv.add(elixir, 1).is_ok());
881 assert_eq!(inv.add(antidote, 1), Err(AddError::InventoryFull));
882 }
883
884 #[test]
885 fn inventory_with_capacity_rejects_per_slot_overflow() {
886 let mut inv = Inventory::<MockItem, 10>::with_capacity(5);
887 let potion = MockItem {
888 name: "Potion",
889 price: 300,
890 heal_amount: 20,
891 };
892
893 assert!(inv.add(potion, 3).is_ok());
894 assert!(inv.add(potion, 2).is_ok()); assert_eq!(inv.add(potion, 1), Err(AddError::PerSlotCapReached(5)));
896 }
897
898 #[test]
899 fn inventory_quantity() {
900 let mut inv: Inventory<MockItem, 8> = Inventory::new();
901 let potion = MockItem {
902 name: "Potion",
903 price: 300,
904 heal_amount: 20,
905 };
906
907 assert_eq!(inv.quantity(&potion), 0);
908 inv.add(potion, 3).unwrap();
909 assert_eq!(inv.quantity(&potion), 3);
910 }
911
912 #[test]
913 fn inventory_add_zero_is_ok() {
914 let mut inv: Inventory<MockItem, 8> = Inventory::new();
915 let potion = MockItem {
916 name: "Potion",
917 price: 300,
918 heal_amount: 20,
919 };
920 assert!(inv.add(potion, 0).is_ok());
921 assert_eq!(inv.count(), 0);
922 }
923
924 #[test]
925 fn inventory_filter() {
926 let mut inv: Inventory<MockItem, 8> = Inventory::new();
927 inv.add(
928 MockItem {
929 name: "Potion",
930 price: 300,
931 heal_amount: 20,
932 },
933 1,
934 )
935 .unwrap();
936 inv.add(
937 MockItem {
938 name: "Elixir",
939 price: 500,
940 heal_amount: 0,
941 },
942 1,
943 )
944 .unwrap();
945 inv.add(
946 MockItem {
947 name: "Antidote",
948 price: 200,
949 heal_amount: 0,
950 },
951 1,
952 )
953 .unwrap();
954
955 let cheap = inv.filter(|i| i.price < 350);
956 assert_eq!(cheap.len(), 2); }
958
959 #[test]
960 fn inventory_sort_by_name() {
961 let mut inv: Inventory<MockItem, 8> = Inventory::new();
962 let antidote = MockItem {
963 name: "Antidote",
964 price: 200,
965 heal_amount: 0,
966 };
967 let elixir = MockItem {
968 name: "Elixir",
969 price: 500,
970 heal_amount: 0,
971 };
972 let potion = MockItem {
973 name: "Potion",
974 price: 300,
975 heal_amount: 20,
976 };
977
978 inv.add(elixir, 1).unwrap();
979 inv.add(antidote, 1).unwrap();
980 inv.add(potion, 1).unwrap();
981
982 inv.sort_by_name(|i| i.name);
983 assert_eq!(inv.get(0).unwrap().0.name, "Antidote");
984 assert_eq!(inv.get(1).unwrap().0.name, "Elixir");
985 assert_eq!(inv.get(2).unwrap().0.name, "Potion");
986 }
987
988 #[test]
989 fn inventory_sort_by_price() {
990 let mut inv: Inventory<MockItem, 8> = Inventory::new();
991 inv.add(
992 MockItem {
993 name: "Potion",
994 price: 300,
995 heal_amount: 20,
996 },
997 1,
998 )
999 .unwrap();
1000 inv.add(
1001 MockItem {
1002 name: "Antidote",
1003 price: 200,
1004 heal_amount: 0,
1005 },
1006 1,
1007 )
1008 .unwrap();
1009 inv.add(
1010 MockItem {
1011 name: "Elixir",
1012 price: 500,
1013 heal_amount: 0,
1014 },
1015 1,
1016 )
1017 .unwrap();
1018
1019 inv.sort_by(|a, b| a.0.price.cmp(&b.0.price));
1020 assert_eq!(inv.get(0).unwrap().0.name, "Antidote");
1021 assert_eq!(inv.get(1).unwrap().0.name, "Potion");
1022 assert_eq!(inv.get(2).unwrap().0.name, "Elixir");
1023 }
1024
1025 #[test]
1026 fn inventory_into_inner() {
1027 let mut inv: Inventory<MockItem, 8> = Inventory::new();
1028 let potion = MockItem {
1029 name: "Potion",
1030 price: 300,
1031 heal_amount: 20,
1032 };
1033 inv.add(potion, 3).unwrap();
1034
1035 let inner = inv.into_inner();
1036 assert_eq!(inner.len(), 1);
1037 assert_eq!(inner[0].0.name, "Potion");
1038 assert_eq!(inner[0].1, 3);
1039 }
1040
1041 #[test]
1042 fn inventory_iter() {
1043 let mut inv: Inventory<MockItem, 8> = Inventory::new();
1044 inv.add(
1045 MockItem {
1046 name: "Potion",
1047 price: 300,
1048 heal_amount: 20,
1049 },
1050 1,
1051 )
1052 .unwrap();
1053 inv.add(
1054 MockItem {
1055 name: "Elixir",
1056 price: 500,
1057 heal_amount: 0,
1058 },
1059 1,
1060 )
1061 .unwrap();
1062
1063 let names: Vec<&str> = inv.iter().map(|(i, _)| i.name).collect();
1064 assert_eq!(names, vec!["Potion", "Elixir"]);
1065 }
1066
1067 #[test]
1068 fn inventory_simple_inventory_alias() {
1069 let mut inv: SimpleInventory<MockItem> = SimpleInventory::new();
1070 let potion = MockItem {
1071 name: "Potion",
1072 price: 300,
1073 heal_amount: 20,
1074 };
1075 inv.add(potion, 1).unwrap();
1076 assert_eq!(inv.count(), 1);
1077 }
1078
1079 #[test]
1080 fn inventory_is_full_false_when_under_cap() {
1081 let mut inv = Inventory::<MockItem, 3>::with_capacity(99);
1082 let potion = MockItem {
1083 name: "Potion",
1084 price: 300,
1085 heal_amount: 20,
1086 };
1087 assert!(!inv.is_full());
1088 inv.add(potion, 1).unwrap();
1089 assert!(!inv.is_full());
1090 }
1091
1092 #[test]
1093 fn inventory_is_full_true_at_cap() {
1094 let mut inv = Inventory::<MockItem, 2>::with_capacity(99);
1095 let potion = MockItem {
1096 name: "Potion",
1097 price: 300,
1098 heal_amount: 20,
1099 };
1100 let elixir = MockItem {
1101 name: "Elixir",
1102 price: 500,
1103 heal_amount: 0,
1104 };
1105 inv.add(potion, 1).unwrap();
1106 inv.add(elixir, 1).unwrap();
1107 assert!(inv.is_full());
1108 }
1109
1110 #[test]
1111 fn inventory_would_exceed_per_slot_cap() {
1112 let mut inv = Inventory::<MockItem, 10>::with_capacity(5);
1113 let potion = MockItem {
1114 name: "Potion",
1115 price: 300,
1116 heal_amount: 20,
1117 };
1118 assert!(!inv.would_exceed_per_slot_cap(&potion, 5)); assert!(inv.would_exceed_per_slot_cap(&potion, 6)); inv.add(potion, 3).unwrap();
1121 assert!(!inv.would_exceed_per_slot_cap(&potion, 2)); assert!(inv.would_exceed_per_slot_cap(&potion, 3)); }
1124}