main.rs 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. extern crate rltk;
  2. use rltk::{Console, GameState, Point, Rltk, RGB};
  3. extern crate specs;
  4. use specs::prelude::*;
  5. #[macro_use]
  6. extern crate specs_derive;
  7. mod components;
  8. pub use components::*;
  9. mod map;
  10. pub use map::*;
  11. mod player;
  12. use player::*;
  13. mod rect;
  14. pub use rect::Rect;
  15. mod draw_system;
  16. mod visibility_system;
  17. use visibility_system::VisibilitySystem;
  18. mod monster_ai_system;
  19. use monster_ai_system::MonsterAI;
  20. mod map_indexing_system;
  21. use map_indexing_system::MapIndexingSystem;
  22. mod melee_combat_system;
  23. use melee_combat_system::MeleeCombatSystem;
  24. mod movement_system;
  25. mod damage_system;
  26. use damage_system::DamageSystem;
  27. rltk::add_wasm_support!();
  28. #[derive(PartialEq, Copy, Clone)]
  29. pub enum RunState {
  30. AwaitingInput,
  31. PreRun,
  32. PlayerTurn,
  33. MonsterTurn,
  34. }
  35. pub struct State {
  36. pub ecs: World,
  37. }
  38. impl State {
  39. fn run_systems(&mut self) {
  40. MapIndexingSystem.run_now(&self.ecs);
  41. VisibilitySystem.run_now(&self.ecs);
  42. MonsterAI.run_now(&self.ecs);
  43. MeleeCombatSystem.run_now(&self.ecs);
  44. DamageSystem.run_now(&self.ecs);
  45. self.ecs.maintain();
  46. }
  47. }
  48. impl GameState for State {
  49. fn tick(&mut self, ctx: &mut Rltk) {
  50. ctx.cls();
  51. let mut newrunstate = *self.ecs.fetch::<RunState>();
  52. match newrunstate {
  53. RunState::PreRun => {
  54. self.run_systems();
  55. newrunstate = RunState::AwaitingInput;
  56. }
  57. RunState::AwaitingInput => {
  58. newrunstate = player_input(self, ctx);
  59. }
  60. RunState::PlayerTurn => {
  61. self.run_systems();
  62. newrunstate = RunState::MonsterTurn;
  63. }
  64. RunState::MonsterTurn => {
  65. self.run_systems();
  66. newrunstate = RunState::AwaitingInput;
  67. }
  68. }
  69. player::HandleInputEvent.run_now(&self.ecs);
  70. movement_system::HandleMoveEvent.run_now(&self.ecs);
  71. *self.ecs.write_resource() = newrunstate;
  72. damage_system::CleanupDead.run_now(&self.ecs);
  73. draw_map(&self.ecs, ctx);
  74. draw_system::DrawRenderables { ctx }.run_now(&self.ecs);
  75. }
  76. }
  77. fn main() {
  78. let context = Rltk::init_simple8x8(80, 50, "Hello Rust World", "resources");
  79. let mut gs = State { ecs: World::new() };
  80. gs.ecs.register::<Position>();
  81. gs.ecs.register::<Renderable>();
  82. gs.ecs.register::<Player>();
  83. gs.ecs.register::<Viewshed>();
  84. gs.ecs.register::<Monster>();
  85. gs.ecs.register::<Name>();
  86. gs.ecs.register::<BlocksTile>();
  87. gs.ecs.register::<CombatStats>();
  88. gs.ecs.register::<WantsToMelee>();
  89. gs.ecs.register::<SufferDamage>();
  90. gs.ecs.register::<InputEvent>();
  91. gs.ecs.register::<MoveEvent>();
  92. let map: Map = Map::new_map_rooms_and_corridors();
  93. let (player_x, player_y) = map.rooms[0].center();
  94. let player_entity = gs
  95. .ecs
  96. .create_entity()
  97. .with(Position {
  98. x: player_x,
  99. y: player_y,
  100. })
  101. .with(Renderable {
  102. glyph: rltk::to_cp437('@'),
  103. fg: RGB::named(rltk::YELLOW),
  104. bg: RGB::named(rltk::BLACK),
  105. })
  106. .with(Player)
  107. .with(Viewshed {
  108. visible_tiles: Vec::new(),
  109. range: 8,
  110. dirty: true,
  111. })
  112. .with(Name {
  113. name: "Player".to_string(),
  114. })
  115. .with(CombatStats {
  116. max_hp: 30,
  117. hp: 30,
  118. defense: 2,
  119. power: 5,
  120. })
  121. .build();
  122. let mut rng = rltk::RandomNumberGenerator::new();
  123. for (i, room) in map.rooms.iter().skip(1).enumerate() {
  124. let (x, y) = room.center();
  125. let glyph: u8;
  126. let name: String;
  127. let roll = rng.roll_dice(1, 2);
  128. match roll {
  129. 1 => {
  130. glyph = rltk::to_cp437('g');
  131. name = "Goblin".to_string();
  132. }
  133. _ => {
  134. glyph = rltk::to_cp437('o');
  135. name = "Orc".to_string();
  136. }
  137. }
  138. gs.ecs
  139. .create_entity()
  140. .with(Position { x, y })
  141. .with(Renderable {
  142. glyph,
  143. fg: RGB::named(rltk::RED),
  144. bg: RGB::named(rltk::BLACK),
  145. })
  146. .with(Viewshed {
  147. visible_tiles: Vec::new(),
  148. range: 8,
  149. dirty: true,
  150. })
  151. .with(Monster)
  152. .with(Name {
  153. name: format!("{} #{}", &name, i),
  154. })
  155. .with(BlocksTile)
  156. .with(CombatStats {
  157. max_hp: 16,
  158. hp: 16,
  159. defense: 1,
  160. power: 4,
  161. })
  162. .build();
  163. }
  164. gs.ecs.insert(map);
  165. gs.ecs.insert(Point::new(player_x, player_y));
  166. gs.ecs.insert(player_entity);
  167. gs.ecs.insert(RunState::PreRun);
  168. rltk::main_loop(context, gs);
  169. }