inventory_system.rs 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. extern crate specs;
  2. use specs::prelude::*;
  3. use super::{WantsToPickupItem, Name, InBackpack, Position, gamelog::GameLog, WantsToUseItem,
  4. Consumable, ProvidesHealing, CombatStats, WantsToDropItem, InflictsDamage, Map, SufferDamage,
  5. AreaOfEffect, Confusion};
  6. pub struct ItemCollectionSystem {}
  7. impl<'a> System<'a> for ItemCollectionSystem {
  8. #[allow(clippy::type_complexity)]
  9. type SystemData = ( ReadExpect<'a, Entity>,
  10. WriteExpect<'a, GameLog>,
  11. WriteStorage<'a, WantsToPickupItem>,
  12. WriteStorage<'a, Position>,
  13. ReadStorage<'a, Name>,
  14. WriteStorage<'a, InBackpack>
  15. );
  16. fn run(&mut self, data : Self::SystemData) {
  17. let (player_entity, mut gamelog, mut wants_pickup, mut positions, names, mut backpack) = data;
  18. for pickup in wants_pickup.join() {
  19. positions.remove(pickup.item);
  20. backpack.insert(pickup.item, InBackpack{ owner: pickup.collected_by }).expect("Unable to insert backpack entry");
  21. if pickup.collected_by == *player_entity {
  22. gamelog.entries.insert(0, format!("You pick up the {}.", names.get(pickup.item).unwrap().name));
  23. }
  24. }
  25. wants_pickup.clear();
  26. }
  27. }
  28. pub struct ItemUseSystem {}
  29. impl<'a> System<'a> for ItemUseSystem {
  30. #[allow(clippy::type_complexity)]
  31. type SystemData = ( ReadExpect<'a, Entity>,
  32. WriteExpect<'a, GameLog>,
  33. ReadExpect<'a, Map>,
  34. Entities<'a>,
  35. WriteStorage<'a, WantsToUseItem>,
  36. ReadStorage<'a, Name>,
  37. ReadStorage<'a, Consumable>,
  38. ReadStorage<'a, ProvidesHealing>,
  39. ReadStorage<'a, InflictsDamage>,
  40. WriteStorage<'a, CombatStats>,
  41. WriteStorage<'a, SufferDamage>,
  42. ReadStorage<'a, AreaOfEffect>,
  43. WriteStorage<'a, Confusion>
  44. );
  45. fn run(&mut self, data : Self::SystemData) {
  46. let (player_entity, mut gamelog, map, entities, mut wants_use, names,
  47. consumables, healing, inflict_damage, mut combat_stats, mut suffer_damage,
  48. aoe, mut confused) = data;
  49. for (entity, useitem) in (&entities, &wants_use).join() {
  50. let mut used_item = true;
  51. // Targeting
  52. let mut targets : Vec<Entity> = Vec::new();
  53. match useitem.target {
  54. None => { targets.push( *player_entity ); }
  55. Some(target) => {
  56. let area_effect = aoe.get(useitem.item);
  57. match area_effect {
  58. None => {
  59. // Single target in tile
  60. let idx = map.xy_idx(target.x, target.y);
  61. for mob in map.tile_content[idx].iter() {
  62. targets.push(*mob);
  63. }
  64. }
  65. Some(area_effect) => {
  66. // AoE
  67. let blast_tiles = rltk::field_of_view(target, area_effect.radius, &*map);
  68. for tile_idx in blast_tiles.iter() {
  69. let idx = map.xy_idx(tile_idx.x, tile_idx.y);
  70. for mob in map.tile_content[idx].iter() {
  71. targets.push(*mob);
  72. }
  73. }
  74. }
  75. }
  76. }
  77. }
  78. // If it heals, apply the healing
  79. let item_heals = healing.get(useitem.item);
  80. match item_heals {
  81. None => {}
  82. Some(healer) => {
  83. used_item = false;
  84. for target in targets.iter() {
  85. let stats = combat_stats.get_mut(*target);
  86. if let Some(stats) = stats {
  87. stats.hp = i32::max(stats.max_hp, stats.hp + healer.heal_amount);
  88. if entity == *player_entity {
  89. gamelog.entries.insert(0, format!("You use the {}, healing {} hp.", names.get(useitem.item).unwrap().name, healer.heal_amount));
  90. }
  91. used_item = true;
  92. }
  93. }
  94. }
  95. }
  96. // If it inflicts damage, apply it to the target cell
  97. let item_damages = inflict_damage.get(useitem.item);
  98. match item_damages {
  99. None => {}
  100. Some(damage) => {
  101. used_item = false;
  102. for mob in targets.iter() {
  103. suffer_damage.insert(*mob, SufferDamage{ amount : damage.damage }).expect("Unable to insert");
  104. if entity == *player_entity {
  105. let mob_name = names.get(*mob).unwrap();
  106. let item_name = names.get(useitem.item).unwrap();
  107. gamelog.entries.insert(0, format!("You use {} on {}, inflicting {} hp.", item_name.name, mob_name.name, damage.damage));
  108. }
  109. used_item = true;
  110. }
  111. }
  112. }
  113. // Can it pass along confusion? Note the use of scopes to escape from the borrow checker!
  114. let mut add_confusion = Vec::new();
  115. {
  116. let causes_confusion = confused.get(useitem.item);
  117. match causes_confusion {
  118. None => {}
  119. Some(confusion) => {
  120. used_item = false;
  121. for mob in targets.iter() {
  122. add_confusion.push((*mob, confusion.turns ));
  123. if entity == *player_entity {
  124. let mob_name = names.get(*mob).unwrap();
  125. let item_name = names.get(useitem.item).unwrap();
  126. gamelog.entries.insert(0, format!("You use {} on {}, confusing them.", item_name.name, mob_name.name));
  127. }
  128. }
  129. }
  130. }
  131. }
  132. for mob in add_confusion.iter() {
  133. confused.insert(mob.0, Confusion{ turns: mob.1 }).expect("Unable to insert status");
  134. }
  135. // If its a consumable, we delete it on use
  136. if used_item {
  137. let consumable = consumables.get(useitem.item);
  138. match consumable {
  139. None => {}
  140. Some(_) => {
  141. entities.delete(useitem.item).expect("Delete failed");
  142. }
  143. }
  144. }
  145. }
  146. wants_use.clear();
  147. }
  148. }
  149. pub struct ItemDropSystem {}
  150. impl<'a> System<'a> for ItemDropSystem {
  151. #[allow(clippy::type_complexity)]
  152. type SystemData = ( ReadExpect<'a, Entity>,
  153. WriteExpect<'a, GameLog>,
  154. Entities<'a>,
  155. WriteStorage<'a, WantsToDropItem>,
  156. ReadStorage<'a, Name>,
  157. WriteStorage<'a, Position>,
  158. WriteStorage<'a, InBackpack>
  159. );
  160. fn run(&mut self, data : Self::SystemData) {
  161. let (player_entity, mut gamelog, entities, mut wants_drop, names, mut positions, mut backpack) = data;
  162. for (entity, to_drop) in (&entities, &wants_drop).join() {
  163. let mut dropper_pos : Position = Position{x:0, y:0};
  164. {
  165. let dropped_pos = positions.get(entity).unwrap();
  166. dropper_pos.x = dropped_pos.x;
  167. dropper_pos.y = dropped_pos.y;
  168. }
  169. positions.insert(to_drop.item, Position{ x : dropper_pos.x, y : dropper_pos.y }).expect("Unable to insert position");
  170. backpack.remove(to_drop.item);
  171. if entity == *player_entity {
  172. gamelog.entries.insert(0, format!("You drop up the {}.", names.get(to_drop.item).unwrap().name));
  173. }
  174. }
  175. wants_drop.clear();
  176. }
  177. }