inventory_system.rs 11 KB

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