1use std::cmp::Ordering;
19use std::fmt::Debug;
20use std::hash::Hash;
21
22pub mod equip;
23pub mod kind;
24pub mod use_driver;
25pub use use_driver::{
26 buy, sell, use_item, ItemUseResult, ShopError, ShopReceipt, UsageContext,
27};
28pub use kind::ItemKind;
29pub use equip::{EquipProvider, EquipSlot};
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| {
247 cmp(a.as_ref().unwrap(), b.as_ref().unwrap())
248 });
249 }
250
251 pub fn sort_by_name<F>(&mut self, name_fn: F)
254 where
255 F: Fn(&I) -> &str,
256 {
257 self.items[..self.len].sort_by(|a, b| {
258 name_fn(&a.as_ref().unwrap().0).cmp(name_fn(&b.as_ref().unwrap().0))
259 });
260 }
261
262 pub fn into_inner(self) -> Vec<(I, u32)> {
264 self.items.iter().flatten().copied().collect()
265 }
266
267 pub fn iter(&self) -> impl Iterator<Item = &(I, u32)> {
269 self.items[..self.len].iter().filter_map(Option::as_ref)
270 }
271
272 pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut (I, u32)> {
274 self.items[..self.len].iter_mut().filter_map(Option::as_mut)
275 }
276
277 pub fn get(&self, index: usize) -> Option<&(I, u32)> {
279 self.items.get(index).and_then(Option::as_ref)
280 }
281
282 pub fn get_mut(&mut self, index: usize) -> Option<&mut (I, u32)> {
284 self.items.get_mut(index).and_then(Option::as_mut)
285 }
286
287 pub fn push_slot(&mut self, item: I, quantity: u32) -> Result<(), AddError> {
290 if self.is_full() {
291 return Err(AddError::InventoryFull);
292 }
293 self.items[self.len] = Some((item, quantity));
294 self.len += 1;
295 Ok(())
296 }
297
298 pub fn remove_at(&mut self, index: usize) {
304 assert!(index < self.len, "inventory slot index out of bounds");
305 self.items.copy_within(index + 1..self.len, index);
306 self.items[self.len - 1] = None;
307 self.len -= 1;
308 }
309
310 pub fn swap(&mut self, a: usize, b: usize) {
316 self.items.swap(a, b);
317 }
318
319 pub fn clear(&mut self) {
321 self.items.fill(None);
322 self.len = 0;
323 }
324}
325
326impl<I: Copy + Eq + Hash + Debug, const N: usize> Default for Inventory<I, N> {
327 fn default() -> Self {
328 Self::new()
329 }
330}
331
332pub trait ItemProvider {
346 type Item: Copy + Eq + Hash + Debug;
348 type Effect;
350 type Monster;
352
353 type CustomKind: Copy + Eq + Hash + Debug;
355
356 fn item_name(&self, item: &Self::Item) -> &str;
358
359 fn item_description(&self, item: &Self::Item) -> &str;
361
362 fn item_effect(&self, item: &Self::Item) -> Self::Effect;
364
365 fn item_price(&self, item: &Self::Item) -> u32;
367
368 fn can_use_outside_battle(&self, item: &Self::Item) -> bool;
371
372 fn can_use_in_battle(&self, item: &Self::Item) -> bool;
374
375 fn use_on_monster(&self, item: &Self::Item, monster: &mut Self::Monster) -> ItemResult;
380
381 fn consume(&self, item: &Self::Item) -> bool;
385
386 fn item_kind(&self, item: &Self::Item) -> ItemKind<Self::CustomKind>;
394
395 fn on_teach_move<M: crate::party::MonsterProvider>(
398 &self,
399 item: Self::Item,
400 target: &mut crate::party::MonsterInstance<M>,
401 ) -> Option<ItemUseResult<Self::Item>> {
402 let _ = (item, target);
403 None
404 }
405
406 fn on_use_field(&self, item: Self::Item) -> Option<ItemUseResult<Self::Item>> {
409 let _ = item;
410 None
411 }
412
413 fn usable_in(&self, item: &Self::Item) -> UsageContext {
421 let _ = item;
422 UsageContext::FieldAndBattle
423 }
424
425 fn apply_effect<M: crate::party::MonsterProvider>(
443 &self,
444 provider: &M,
445 item: Self::Item,
446 ctx: UsageContext,
447 target: Option<&mut crate::party::MonsterInstance<M>>,
448 rng: &mut dyn crate::battle::rng::BattleRng,
449 ) -> ItemUseResult<Self::Item> {
450 let _ = (provider, item, ctx, target, rng);
451 ItemUseResult::NoEffect
452 }
453}
454
455pub trait ShopProvider {
466 type Item: Copy + Eq + Hash + Debug;
468 type ShopId: Copy + Eq + Hash + Debug;
470
471 fn shop_inventory(&self, shop_id: &Self::ShopId) -> Vec<(Self::Item, u32)>;
476
477 fn shop_name(&self, shop_id: &Self::ShopId) -> &str;
479
480 fn buy_price(&self, item: &Self::Item) -> u32 {
487 let _ = item;
488 0
489 }
490
491 fn sell_price(&self, item: &Self::Item) -> u32 {
497 self.buy_price(item) / 2
498 }
499
500 fn can_sell(&self, item: &Self::Item) -> bool {
506 let _ = item;
507 true
508 }
509
510 fn discount_rate(&self, _shop_id: &Self::ShopId) -> f32 {
517 1.0
518 }
519
520 fn sell_rate(&self, _shop_id: &Self::ShopId) -> f32 {
528 1.0
529 }
530
531 fn has_limited_stock(&self, _item: &Self::Item) -> bool {
535 false
536 }
537
538 fn max_stock(&self, _item: &Self::Item) -> u32 {
543 0
544 }
545
546 fn restocks(&self, _shop_id: &Self::ShopId) -> bool {
550 false
551 }
552
553 fn restock_interval(&self, _shop_id: &Self::ShopId) -> u32 {
557 0
558 }
559}
560
561#[cfg(test)]
564mod tests {
565 use super::*;
566
567 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
571 struct MockItem {
572 name: &'static str,
573 price: u32,
574 heal_amount: u32,
575 }
576
577 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
579 enum MockEffect {
580 Heal(u32),
581 None,
582 }
583
584 #[derive(Debug, Clone)]
586 #[allow(dead_code)]
587 struct MockMonster {
588 name: &'static str,
589 max_hp: u32,
590 current_hp: u32,
591 }
592
593 struct MockItemProvider;
596
597 impl ItemProvider for MockItemProvider {
598 type Item = MockItem;
599 type Effect = MockEffect;
600 type Monster = MockMonster;
601 type CustomKind = ();
602
603 fn item_name(&self, item: &Self::Item) -> &str {
604 item.name
605 }
606
607 fn item_description(&self, item: &Self::Item) -> &str {
608 if item.heal_amount > 0 {
609 "Restores HP."
610 } else {
611 "Has no effect in battle."
612 }
613 }
614
615 fn item_effect(&self, item: &Self::Item) -> Self::Effect {
616 if item.heal_amount > 0 {
617 MockEffect::Heal(item.heal_amount)
618 } else {
619 MockEffect::None
620 }
621 }
622
623 fn item_price(&self, item: &Self::Item) -> u32 {
624 item.price
625 }
626
627 fn can_use_outside_battle(&self, _item: &Self::Item) -> bool {
628 true
629 }
630
631 fn can_use_in_battle(&self, _item: &Self::Item) -> bool {
632 true
633 }
634
635 fn use_on_monster(&self, item: &Self::Item, monster: &mut Self::Monster) -> ItemResult {
636 match self.item_effect(item) {
637 MockEffect::Heal(amount) => {
638 if monster.current_hp >= monster.max_hp {
639 return ItemResult::NoEffect;
640 }
641 monster.current_hp = (monster.current_hp + amount).min(monster.max_hp);
642 ItemResult::Used
643 }
644 MockEffect::None => ItemResult::NoEffect,
645 }
646 }
647
648 fn consume(&self, _item: &Self::Item) -> bool {
649 true
650 }
651
652 fn item_kind(&self, item: &Self::Item) -> ItemKind<()> {
653 if item.heal_amount > 0 {
654 ItemKind::Consumable
655 } else {
656 ItemKind::Consumable
657 }
658 }
659 }
660
661 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
662 enum MockShopId {
663 CityMart,
664 }
665
666 struct MockShopProvider;
667
668 impl ShopProvider for MockShopProvider {
669 type Item = MockItem;
670 type ShopId = MockShopId;
671
672 fn shop_inventory(&self, shop_id: &Self::ShopId) -> Vec<(Self::Item, u32)> {
673 match shop_id {
674 MockShopId::CityMart => vec![
675 (
676 MockItem {
677 name: "Potion",
678 price: 300,
679 heal_amount: 20,
680 },
681 300,
682 ),
683 (
684 MockItem {
685 name: "Elixir",
686 price: 500,
687 heal_amount: 0,
688 },
689 500,
690 ),
691 ],
692 }
693 }
694
695 fn shop_name(&self, shop_id: &Self::ShopId) -> &str {
696 match shop_id {
697 MockShopId::CityMart => "City Mart",
698 }
699 }
700 }
701
702 #[test]
705 fn potion_heals_monster() {
706 let provider = MockItemProvider;
707 let potion = MockItem {
708 name: "Potion",
709 price: 300,
710 heal_amount: 20,
711 };
712 let mut monster = MockMonster {
713 name: "Sprout",
714 max_hp: 100,
715 current_hp: 50,
716 };
717
718 let result = provider.use_on_monster(&potion, &mut monster);
719 assert_eq!(result, ItemResult::Used);
720 assert_eq!(monster.current_hp, 70);
721 assert!(provider.consume(&potion));
722 }
723
724 #[test]
725 fn potion_no_effect_on_full_hp() {
726 let provider = MockItemProvider;
727 let potion = MockItem {
728 name: "Potion",
729 price: 300,
730 heal_amount: 20,
731 };
732 let mut monster = MockMonster {
733 name: "Sprout",
734 max_hp: 100,
735 current_hp: 100,
736 };
737
738 let result = provider.use_on_monster(&potion, &mut monster);
739 assert_eq!(result, ItemResult::NoEffect);
740 assert_eq!(monster.current_hp, 100);
741 }
742
743 #[test]
744 fn elixir_has_no_heal_effect() {
745 let provider = MockItemProvider;
746 let elixir = MockItem {
747 name: "Elixir",
748 price: 500,
749 heal_amount: 0,
750 };
751 let mut monster = MockMonster {
752 name: "Sprout",
753 max_hp: 100,
754 current_hp: 50,
755 };
756
757 let result = provider.use_on_monster(&elixir, &mut monster);
758 assert_eq!(result, ItemResult::NoEffect);
759 assert_eq!(monster.current_hp, 50); }
761
762 #[test]
765 fn shop_inventory_has_two_items() {
766 let provider = MockShopProvider;
767 let inventory = provider.shop_inventory(&MockShopId::CityMart);
768
769 assert_eq!(inventory.len(), 2);
770 assert_eq!(inventory[0].0.name, "Potion");
771 assert_eq!(inventory[0].1, 300);
772 assert_eq!(inventory[1].0.name, "Elixir");
773 assert_eq!(inventory[1].1, 500);
774 }
775
776 #[test]
777 fn shop_name_is_correct() {
778 let provider = MockShopProvider;
779 assert_eq!(
780 provider.shop_name(&MockShopId::CityMart),
781 "City Mart"
782 );
783 }
784
785 #[test]
788 fn inventory_add_and_remove() {
789 let mut inv: Inventory<MockItem, 8> = Inventory::new();
790 let potion = MockItem {
791 name: "Potion",
792 price: 300,
793 heal_amount: 20,
794 };
795
796 inv.add(potion, 3).unwrap();
797 assert_eq!(inv.count(), 1);
798 assert!(inv.contains(&potion, 2));
799 assert!(!inv.contains(&potion, 4));
800
801 assert!(inv.remove(&potion, 2));
802 assert_eq!(inv.count(), 1);
803 assert!(inv.contains(&potion, 1));
804
805 assert!(inv.remove(&potion, 1));
806 assert_eq!(inv.count(), 0);
807 assert!(!inv.contains(&potion, 1));
808 }
809
810 #[test]
811 fn inventory_stacks_same_item() {
812 let mut inv: Inventory<MockItem, 8> = Inventory::new();
813 let potion = MockItem {
814 name: "Potion",
815 price: 300,
816 heal_amount: 20,
817 };
818
819 inv.add(potion, 3).unwrap();
820 inv.add(potion, 5).unwrap();
821 assert_eq!(inv.count(), 1); assert!(inv.contains(&potion, 8));
823 }
824
825 #[test]
826 fn inventory_remove_insufficient_quantity() {
827 let mut inv: Inventory<MockItem, 8> = Inventory::new();
828 let potion = MockItem {
829 name: "Potion",
830 price: 300,
831 heal_amount: 20,
832 };
833
834 inv.add(potion, 2).unwrap();
835 assert!(!inv.remove(&potion, 5));
836 assert_eq!(inv.count(), 1);
837 assert!(inv.contains(&potion, 2)); }
839
840 #[test]
841 fn inventory_remove_nonexistent_item() {
842 let mut inv: Inventory<MockItem, 8> = Inventory::new();
843 let potion = MockItem {
844 name: "Potion",
845 price: 300,
846 heal_amount: 20,
847 };
848
849 assert!(!inv.remove(&potion, 1));
850 }
851
852 #[test]
855 fn inventory_new_is_unlimited() {
856 let inv: Inventory<MockItem, 8> = Inventory::new();
857 assert!(!inv.is_full());
858 let potion = MockItem {
859 name: "Potion",
860 price: 300,
861 heal_amount: 20,
862 };
863 assert!(!inv.would_exceed_per_slot_cap(&potion, u32::MAX));
864 }
865
866 #[test]
867 fn inventory_with_capacity_rejects_overfill() {
868 let mut inv = Inventory::<MockItem, 2>::with_capacity(10);
869 let potion = MockItem {
870 name: "Potion",
871 price: 300,
872 heal_amount: 20,
873 };
874 let elixir = MockItem {
875 name: "Elixir",
876 price: 500,
877 heal_amount: 0,
878 };
879 let antidote = MockItem {
880 name: "Antidote",
881 price: 200,
882 heal_amount: 0,
883 };
884
885 assert!(inv.add(potion, 1).is_ok());
886 assert!(inv.add(elixir, 1).is_ok());
887 assert_eq!(inv.add(antidote, 1), Err(AddError::InventoryFull));
888 }
889
890 #[test]
891 fn inventory_with_capacity_rejects_per_slot_overflow() {
892 let mut inv = Inventory::<MockItem, 10>::with_capacity(5);
893 let potion = MockItem {
894 name: "Potion",
895 price: 300,
896 heal_amount: 20,
897 };
898
899 assert!(inv.add(potion, 3).is_ok());
900 assert!(inv.add(potion, 2).is_ok()); assert_eq!(inv.add(potion, 1), Err(AddError::PerSlotCapReached(5)));
902 }
903
904 #[test]
905 fn inventory_quantity() {
906 let mut inv: Inventory<MockItem, 8> = Inventory::new();
907 let potion = MockItem {
908 name: "Potion",
909 price: 300,
910 heal_amount: 20,
911 };
912
913 assert_eq!(inv.quantity(&potion), 0);
914 inv.add(potion, 3).unwrap();
915 assert_eq!(inv.quantity(&potion), 3);
916 }
917
918 #[test]
919 fn inventory_add_zero_is_ok() {
920 let mut inv: Inventory<MockItem, 8> = Inventory::new();
921 let potion = MockItem {
922 name: "Potion",
923 price: 300,
924 heal_amount: 20,
925 };
926 assert!(inv.add(potion, 0).is_ok());
927 assert_eq!(inv.count(), 0);
928 }
929
930 #[test]
931 fn inventory_filter() {
932 let mut inv: Inventory<MockItem, 8> = Inventory::new();
933 inv.add(
934 MockItem {
935 name: "Potion",
936 price: 300,
937 heal_amount: 20,
938 },
939 1,
940 )
941 .unwrap();
942 inv.add(
943 MockItem {
944 name: "Elixir",
945 price: 500,
946 heal_amount: 0,
947 },
948 1,
949 )
950 .unwrap();
951 inv.add(
952 MockItem {
953 name: "Antidote",
954 price: 200,
955 heal_amount: 0,
956 },
957 1,
958 )
959 .unwrap();
960
961 let cheap = inv.filter(|i| i.price < 350);
962 assert_eq!(cheap.len(), 2); }
964
965 #[test]
966 fn inventory_sort_by_name() {
967 let mut inv: Inventory<MockItem, 8> = Inventory::new();
968 let antidote = MockItem {
969 name: "Antidote",
970 price: 200,
971 heal_amount: 0,
972 };
973 let elixir = MockItem {
974 name: "Elixir",
975 price: 500,
976 heal_amount: 0,
977 };
978 let potion = MockItem {
979 name: "Potion",
980 price: 300,
981 heal_amount: 20,
982 };
983
984 inv.add(elixir, 1).unwrap();
985 inv.add(antidote, 1).unwrap();
986 inv.add(potion, 1).unwrap();
987
988 inv.sort_by_name(|i| i.name);
989 assert_eq!(inv.get(0).unwrap().0.name, "Antidote");
990 assert_eq!(inv.get(1).unwrap().0.name, "Elixir");
991 assert_eq!(inv.get(2).unwrap().0.name, "Potion");
992 }
993
994 #[test]
995 fn inventory_sort_by_price() {
996 let mut inv: Inventory<MockItem, 8> = Inventory::new();
997 inv.add(
998 MockItem {
999 name: "Potion",
1000 price: 300,
1001 heal_amount: 20,
1002 },
1003 1,
1004 )
1005 .unwrap();
1006 inv.add(
1007 MockItem {
1008 name: "Antidote",
1009 price: 200,
1010 heal_amount: 0,
1011 },
1012 1,
1013 )
1014 .unwrap();
1015 inv.add(
1016 MockItem {
1017 name: "Elixir",
1018 price: 500,
1019 heal_amount: 0,
1020 },
1021 1,
1022 )
1023 .unwrap();
1024
1025 inv.sort_by(|a, b| a.0.price.cmp(&b.0.price));
1026 assert_eq!(inv.get(0).unwrap().0.name, "Antidote");
1027 assert_eq!(inv.get(1).unwrap().0.name, "Potion");
1028 assert_eq!(inv.get(2).unwrap().0.name, "Elixir");
1029 }
1030
1031 #[test]
1032 fn inventory_into_inner() {
1033 let mut inv: Inventory<MockItem, 8> = Inventory::new();
1034 let potion = MockItem {
1035 name: "Potion",
1036 price: 300,
1037 heal_amount: 20,
1038 };
1039 inv.add(potion, 3).unwrap();
1040
1041 let inner = inv.into_inner();
1042 assert_eq!(inner.len(), 1);
1043 assert_eq!(inner[0].0.name, "Potion");
1044 assert_eq!(inner[0].1, 3);
1045 }
1046
1047 #[test]
1048 fn inventory_iter() {
1049 let mut inv: Inventory<MockItem, 8> = Inventory::new();
1050 inv.add(
1051 MockItem {
1052 name: "Potion",
1053 price: 300,
1054 heal_amount: 20,
1055 },
1056 1,
1057 )
1058 .unwrap();
1059 inv.add(
1060 MockItem {
1061 name: "Elixir",
1062 price: 500,
1063 heal_amount: 0,
1064 },
1065 1,
1066 )
1067 .unwrap();
1068
1069 let names: Vec<&str> = inv.iter().map(|(i, _)| i.name).collect();
1070 assert_eq!(names, vec!["Potion", "Elixir"]);
1071 }
1072
1073 #[test]
1074 fn inventory_simple_inventory_alias() {
1075 let mut inv: SimpleInventory<MockItem> = SimpleInventory::new();
1076 let potion = MockItem {
1077 name: "Potion",
1078 price: 300,
1079 heal_amount: 20,
1080 };
1081 inv.add(potion, 1).unwrap();
1082 assert_eq!(inv.count(), 1);
1083 }
1084
1085 #[test]
1086 fn inventory_is_full_false_when_under_cap() {
1087 let mut inv = Inventory::<MockItem, 3>::with_capacity(99);
1088 let potion = MockItem {
1089 name: "Potion",
1090 price: 300,
1091 heal_amount: 20,
1092 };
1093 assert!(!inv.is_full());
1094 inv.add(potion, 1).unwrap();
1095 assert!(!inv.is_full());
1096 }
1097
1098 #[test]
1099 fn inventory_is_full_true_at_cap() {
1100 let mut inv = Inventory::<MockItem, 2>::with_capacity(99);
1101 let potion = MockItem {
1102 name: "Potion",
1103 price: 300,
1104 heal_amount: 20,
1105 };
1106 let elixir = MockItem {
1107 name: "Elixir",
1108 price: 500,
1109 heal_amount: 0,
1110 };
1111 inv.add(potion, 1).unwrap();
1112 inv.add(elixir, 1).unwrap();
1113 assert!(inv.is_full());
1114 }
1115
1116 #[test]
1117 fn inventory_would_exceed_per_slot_cap() {
1118 let mut inv = Inventory::<MockItem, 10>::with_capacity(5);
1119 let potion = MockItem {
1120 name: "Potion",
1121 price: 300,
1122 heal_amount: 20,
1123 };
1124 assert!(!inv.would_exceed_per_slot_cap(&potion, 5)); assert!(inv.would_exceed_per_slot_cap(&potion, 6)); inv.add(potion, 3).unwrap();
1127 assert!(!inv.would_exceed_per_slot_cap(&potion, 2)); assert!(inv.would_exceed_per_slot_cap(&potion, 3)); }
1130}