inventory_system.rs 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. use specs::prelude::*;
  2. use crate::{Consumable, ProvidesHealing, InflictsDamage};
  3. use super::{WantsToPickupItem, Name, InBackpack,
  4. Position, GameLog, WantsToUseItem,
  5. CombatStats, Item, WantsToDropItem,
  6. Map, SufferDamage, AreaOfEffect,
  7. Equippable,Equipped,WantsToRemoveItem};
  8. pub struct ItemCollectionSystem {}
  9. impl<'a> System<'a> for ItemCollectionSystem {
  10. #[allow(clippy::type_complexity)]
  11. type SystemData = ( ReadExpect<'a, Entity>,
  12. WriteExpect<'a, GameLog>,
  13. WriteStorage<'a, WantsToPickupItem>,
  14. WriteStorage<'a, Position>,
  15. ReadStorage<'a, Name>,
  16. WriteStorage<'a, InBackpack>
  17. );
  18. fn run(&mut self, data : Self::SystemData) {
  19. let (player_entity, mut gamelog, mut wants_pickup, mut positions, names, mut backpack) = data;
  20. for pickup in wants_pickup.join() {
  21. positions.remove(pickup.item);
  22. backpack.insert(pickup.item, InBackpack{ owner: pickup.collected_by }).expect("Unable to insert backpack entry");
  23. if pickup.collected_by == *player_entity {
  24. gamelog.entries.push(format!("You pick up the {}.", names.get(pickup.item).unwrap().name));
  25. }
  26. }
  27. wants_pickup.clear();
  28. }
  29. }
  30. pub struct ItemRemoveSystem {}
  31. impl<'a> System<'a> for ItemRemoveSystem {
  32. #[allow(clippy::type_complexity)]
  33. type SystemData = (
  34. Entities<'a>,
  35. WriteStorage<'a, WantsToRemoveItem>,
  36. WriteStorage<'a, Equipped>,
  37. WriteStorage<'a, InBackpack>
  38. );
  39. fn run(&mut self, data : Self::SystemData) {
  40. let (entities, mut wants_remove, mut equipped, mut backpack) = data;
  41. for (entity, to_remove) in (&entities, &wants_remove).join() {
  42. equipped.remove(to_remove.item);
  43. backpack.insert(to_remove.item, InBackpack{ owner: entity }).expect("Unable to insert backpack");
  44. }
  45. wants_remove.clear();
  46. }
  47. }
  48. pub struct ItemUseSystem {}
  49. impl<'a> System<'a> for ItemUseSystem {
  50. #[allow(clippy::type_complexity)]
  51. type SystemData = ( ReadExpect<'a, Entity>,
  52. WriteExpect<'a, GameLog>,
  53. ReadExpect<'a, Map>,
  54. Entities<'a>,
  55. WriteStorage<'a, WantsToUseItem>,
  56. ReadStorage<'a, Name>,
  57. ReadStorage<'a, ProvidesHealing>,
  58. WriteStorage<'a, CombatStats>,
  59. ReadStorage<'a, Consumable>,
  60. ReadStorage<'a, Item>,
  61. ReadStorage<'a, InflictsDamage>,
  62. WriteStorage<'a, SufferDamage>,
  63. ReadStorage<'a, AreaOfEffect>,
  64. ReadStorage<'a, Equippable>,
  65. WriteStorage<'a, Equipped>,
  66. WriteStorage<'a, InBackpack>
  67. );
  68. fn run(&mut self, data : Self::SystemData) {
  69. let (player_entity,
  70. mut gamelog,
  71. map,
  72. entities,
  73. mut wants_use,
  74. names,
  75. healing,
  76. mut combat_stats,
  77. consumables,
  78. _item,
  79. inflict_damage,
  80. mut suffer_damage,
  81. aoe,
  82. equippable,
  83. mut equipped,
  84. mut backpack) = data;
  85. for (entity, useitem) in (&entities, &wants_use).join() {
  86. // Targeting
  87. let mut targets : Vec<Entity> = Vec::new();
  88. match useitem.target {
  89. None => { targets.push( *player_entity ); }
  90. Some(target) => {
  91. let area_effect = aoe.get(useitem.item);
  92. match area_effect {
  93. None => {
  94. // Single target in tile
  95. let idx = map.xy_idx(target.x, target.y);
  96. for mob in map.tile_content[idx].iter() {
  97. targets.push(*mob);
  98. }
  99. }
  100. Some(area_effect) => {
  101. // AoE
  102. let mut blast_tiles = rltk::field_of_view(target, area_effect.radius, &*map);
  103. blast_tiles.retain(|p| p.x > 0 && p.x < map.width-1 && p.y > 0 && p.y < map.height-1 );
  104. for tile_idx in blast_tiles.iter() {
  105. let idx = map.xy_idx(tile_idx.x, tile_idx.y);
  106. for mob in map.tile_content[idx].iter() {
  107. targets.push(*mob);
  108. }
  109. }
  110. }
  111. }
  112. }
  113. }
  114. let item_equippable = equippable.get(useitem.item);
  115. match item_equippable {
  116. None => {}
  117. Some(can_equip) => {
  118. let target_slot = can_equip.slot;
  119. let target = targets[0];
  120. // Remove any items the target has in the item's slot
  121. let mut to_unequip : Vec<Entity> = Vec::new();
  122. for (item_entity, already_equipped, name) in (&entities, &equipped, &names).join() {
  123. if already_equipped.owner == target && already_equipped.slot == target_slot {
  124. to_unequip.push(item_entity);
  125. if target == *player_entity {
  126. gamelog.entries.push(format!("You unequip {}.", name.name));
  127. }
  128. }
  129. }
  130. for item in to_unequip.iter() {
  131. equipped.remove(*item);
  132. backpack.insert(*item, InBackpack{ owner: target }).expect("Unable to insert backpack entry");
  133. }
  134. // Wield the item
  135. equipped.insert(useitem.item, Equipped{ owner: target, slot: target_slot }).expect("Unable to insert equipped component");
  136. backpack.remove(useitem.item);
  137. if target == *player_entity {
  138. gamelog.entries.push(format!("You equip {}.", names.get(useitem.item).unwrap().name));
  139. }
  140. }
  141. }
  142. // If it inflicts damage, apply it to the target cell
  143. let item_damages = inflict_damage.get(useitem.item);
  144. match item_damages {
  145. None => {}
  146. Some(damage) => {
  147. for mob in targets.iter() {
  148. SufferDamage::new_damage(&mut suffer_damage, *mob, damage.damage);
  149. if entity == *player_entity {
  150. let mob_name = names.get(*mob).unwrap();
  151. let item_name = names.get(useitem.item).unwrap();
  152. gamelog.entries.push(format!("You use {} on {}, inflicting {} damage.", item_name.name, mob_name.name, damage.damage));
  153. }
  154. }
  155. }
  156. }
  157. // If it heals, apply the healing
  158. let item_heals = healing.get(useitem.item);
  159. match item_heals {
  160. None => {}
  161. Some(healer) => {
  162. for target in targets.iter() {
  163. let stats = combat_stats.get_mut(*target);
  164. if let Some(stats) = stats {
  165. stats.hp = i32::min(stats.max_hp, stats.hp + healer.heal_amount);
  166. if entity == *player_entity {
  167. gamelog.entries.push(format!("You use the {}, healing {} hp.", names.get(useitem.item).unwrap().name, healer.heal_amount));
  168. }
  169. }
  170. }
  171. }
  172. }
  173. let consumable = consumables.get(useitem.item);
  174. match consumable {
  175. None => {}
  176. Some(_) => {
  177. entities.delete(useitem.item).expect("Delete failed");
  178. }
  179. }
  180. }
  181. wants_use.clear();
  182. }
  183. }
  184. pub struct ItemDropSystem {}
  185. impl<'a> System<'a> for ItemDropSystem {
  186. #[allow(clippy::type_complexity)]
  187. type SystemData = ( ReadExpect<'a, Entity>,
  188. WriteExpect<'a, GameLog>,
  189. Entities<'a>,
  190. WriteStorage<'a, WantsToDropItem>,
  191. ReadStorage<'a, Name>,
  192. WriteStorage<'a, Position>,
  193. WriteStorage<'a, InBackpack>
  194. );
  195. fn run(&mut self, data : Self::SystemData) {
  196. let (player_entity, mut gamelog, entities, mut wants_drop, names, mut positions, mut backpack) = data;
  197. for (entity, to_drop) in (&entities, &wants_drop).join() {
  198. let mut dropper_pos : Position = Position{x:0, y:0};
  199. {
  200. let dropped_pos = positions.get(entity).unwrap();
  201. dropper_pos.x = dropped_pos.x;
  202. dropper_pos.y = dropped_pos.y;
  203. }
  204. positions.insert(to_drop.item, Position{ x : dropper_pos.x, y : dropper_pos.y }).expect("Unable to insert position");
  205. backpack.remove(to_drop.item);
  206. if entity == *player_entity {
  207. gamelog.entries.push(format!("You drop the {}.", names.get(to_drop.item).unwrap().name));
  208. }
  209. }
  210. wants_drop.clear();
  211. }
  212. }