spawner.rs 4.3 KB

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