spawner.rs 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. extern crate rltk;
  2. use rltk::{ RGB, RandomNumberGenerator };
  3. extern crate specs;
  4. use specs::prelude::*;
  5. use super::{CombatStats, Player, Renderable, Name, Position, Viewshed, Monster, BlocksTile, Rect, Item,
  6. Consumable, Ranged, ProvidesHealing, map::MAPWIDTH, InflictsDamage, AreaOfEffect, Confusion};
  7. /// Spawns the player and returns his/her entity object.
  8. pub fn player(ecs : &mut World, player_x : i32, player_y : i32) -> Entity {
  9. ecs
  10. .create_entity()
  11. .with(Position { x: player_x, y: player_y })
  12. .with(Renderable {
  13. glyph: rltk::to_cp437('@'),
  14. fg: RGB::named(rltk::YELLOW),
  15. bg: RGB::named(rltk::BLACK),
  16. render_order: 0
  17. })
  18. .with(Player{})
  19. .with(Viewshed{ visible_tiles : Vec::new(), range: 8, dirty: true })
  20. .with(Name{name: "Player".to_string() })
  21. .with(CombatStats{ max_hp: 30, hp: 30, defense: 2, power: 5 })
  22. .build()
  23. }
  24. const MAX_MONSTERS : i32 = 4;
  25. const MAX_ITEMS : i32 = 2;
  26. /// Fills a room with stuff!
  27. pub fn spawn_room(ecs: &mut World, room : &Rect) {
  28. let mut monster_spawn_points : Vec<usize> = Vec::new();
  29. let mut item_spawn_points : Vec<usize> = Vec::new();
  30. // Scope to keep the borrow checker happy
  31. {
  32. let mut rng = ecs.write_resource::<RandomNumberGenerator>();
  33. let num_monsters = rng.roll_dice(1, MAX_MONSTERS + 2) - 3;
  34. let num_items = rng.roll_dice(1, MAX_ITEMS + 2) - 3;
  35. for _i in 0 .. num_monsters {
  36. let mut added = false;
  37. while !added {
  38. let x = (room.x1 + rng.roll_dice(1, i32::abs(room.x2 - room.x1))) as usize;
  39. let y = (room.y1 + rng.roll_dice(1, i32::abs(room.y2 - room.y1))) as usize;
  40. let idx = (y * MAPWIDTH) + x;
  41. if !monster_spawn_points.contains(&idx) {
  42. monster_spawn_points.push(idx);
  43. added = true;
  44. }
  45. }
  46. }
  47. for _i in 0 .. num_items {
  48. let mut added = false;
  49. while !added {
  50. let x = (room.x1 + rng.roll_dice(1, i32::abs(room.x2 - room.x1))) as usize;
  51. let y = (room.y1 + rng.roll_dice(1, i32::abs(room.y2 - room.y1))) as usize;
  52. let idx = (y * MAPWIDTH) + x;
  53. if !item_spawn_points.contains(&idx) {
  54. item_spawn_points.push(idx);
  55. added = true;
  56. }
  57. }
  58. }
  59. }
  60. // Actually spawn the monsters
  61. for idx in monster_spawn_points.iter() {
  62. let x = *idx % MAPWIDTH;
  63. let y = *idx / MAPWIDTH;
  64. random_monster(ecs, x as i32, y as i32);
  65. }
  66. // Actually spawn the items
  67. for idx in item_spawn_points.iter() {
  68. let x = *idx % MAPWIDTH;
  69. let y = *idx / MAPWIDTH;
  70. random_item(ecs, x as i32, y as i32);
  71. }
  72. }
  73. fn random_monster(ecs: &mut World, x: i32, y: i32) {
  74. let roll :i32;
  75. {
  76. let mut rng = ecs.write_resource::<RandomNumberGenerator>();
  77. roll = rng.roll_dice(1, 2);
  78. }
  79. match roll {
  80. 1 => { orc(ecs, x, y) }
  81. _ => { goblin(ecs, x, y) }
  82. }
  83. }
  84. fn random_item(ecs: &mut World, x: i32, y: i32) {
  85. let roll :i32;
  86. {
  87. let mut rng = ecs.write_resource::<RandomNumberGenerator>();
  88. roll = rng.roll_dice(1, 4);
  89. }
  90. match roll {
  91. 1 => { health_potion(ecs, x, y) }
  92. 2 => { fireball_scroll(ecs, x, y) }
  93. 3 => { confusion_scroll(ecs, x, y) }
  94. _ => { magic_missile_scroll(ecs, x, y) }
  95. }
  96. }
  97. fn orc(ecs: &mut World, x: i32, y: i32) { monster(ecs, x, y, rltk::to_cp437('o'), "Orc"); }
  98. fn goblin(ecs: &mut World, x: i32, y: i32) { monster(ecs, x, y, rltk::to_cp437('g'), "Goblin"); }
  99. fn monster<S : ToString>(ecs: &mut World, x: i32, y: i32, glyph : u8, name : S) {
  100. ecs.create_entity()
  101. .with(Position{ x, y })
  102. .with(Renderable{
  103. glyph,
  104. fg: RGB::named(rltk::RED),
  105. bg: RGB::named(rltk::BLACK),
  106. render_order: 1
  107. })
  108. .with(Viewshed{ visible_tiles : Vec::new(), range: 8, dirty: true })
  109. .with(Monster{})
  110. .with(Name{ name : name.to_string() })
  111. .with(BlocksTile{})
  112. .with(CombatStats{ max_hp: 16, hp: 16, defense: 1, power: 4 })
  113. .build();
  114. }
  115. fn health_potion(ecs: &mut World, x: i32, y: i32) {
  116. ecs.create_entity()
  117. .with(Position{ x, y })
  118. .with(Renderable{
  119. glyph: rltk::to_cp437('¡'),
  120. fg: RGB::named(rltk::MAGENTA),
  121. bg: RGB::named(rltk::BLACK),
  122. render_order: 2
  123. })
  124. .with(Name{ name : "Health Potion".to_string() })
  125. .with(Item{})
  126. .with(Consumable{})
  127. .with(ProvidesHealing{ heal_amount: 8 })
  128. .build();
  129. }
  130. fn magic_missile_scroll(ecs: &mut World, x: i32, y: i32) {
  131. ecs.create_entity()
  132. .with(Position{ x, y })
  133. .with(Renderable{
  134. glyph: rltk::to_cp437(')'),
  135. fg: RGB::named(rltk::CYAN),
  136. bg: RGB::named(rltk::BLACK),
  137. render_order: 2
  138. })
  139. .with(Name{ name : "Magic Missile Scroll".to_string() })
  140. .with(Item{})
  141. .with(Consumable{})
  142. .with(Ranged{ range: 6 })
  143. .with(InflictsDamage{ damage: 20 })
  144. .build();
  145. }
  146. fn fireball_scroll(ecs: &mut World, x: i32, y: i32) {
  147. ecs.create_entity()
  148. .with(Position{ x, y })
  149. .with(Renderable{
  150. glyph: rltk::to_cp437(')'),
  151. fg: RGB::named(rltk::ORANGE),
  152. bg: RGB::named(rltk::BLACK),
  153. render_order: 2
  154. })
  155. .with(Name{ name : "Fireball Scroll".to_string() })
  156. .with(Item{})
  157. .with(Consumable{})
  158. .with(Ranged{ range: 6 })
  159. .with(InflictsDamage{ damage: 20 })
  160. .with(AreaOfEffect{ radius: 3 })
  161. .build();
  162. }
  163. fn confusion_scroll(ecs: &mut World, x: i32, y: i32) {
  164. ecs.create_entity()
  165. .with(Position{ x, y })
  166. .with(Renderable{
  167. glyph: rltk::to_cp437(')'),
  168. fg: RGB::named(rltk::PINK),
  169. bg: RGB::named(rltk::BLACK),
  170. render_order: 2
  171. })
  172. .with(Name{ name : "Confusion Scroll".to_string() })
  173. .with(Item{})
  174. .with(Consumable{})
  175. .with(Ranged{ range: 6 })
  176. .with(Confusion{ turns: 4 })
  177. .build();
  178. }