main.rs 5.3 KB

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