spawner.rs 5.2 KB

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