main.rs 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. extern crate rltk;
  2. use rltk::{Console, GameState, Rltk, Point};
  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. mod gui;
  26. mod gamelog;
  27. mod spawner;
  28. mod inventory_system;
  29. use inventory_system::{ ItemCollectionSystem, PotionUseSystem, ItemDropSystem };
  30. rltk::add_wasm_support!();
  31. #[derive(PartialEq, Copy, Clone)]
  32. pub enum RunState { AwaitingInput, PreRun, PlayerTurn, MonsterTurn, ShowInventory, ShowDropItem }
  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. let mut pickup = ItemCollectionSystem{};
  49. pickup.run_now(&self.ecs);
  50. let mut potions = PotionUseSystem{};
  51. potions.run_now(&self.ecs);
  52. let mut drop_items = ItemDropSystem{};
  53. drop_items.run_now(&self.ecs);
  54. self.ecs.maintain();
  55. }
  56. }
  57. impl GameState for State {
  58. fn tick(&mut self, ctx : &mut Rltk) {
  59. ctx.cls();
  60. draw_map(&self.ecs, ctx);
  61. {
  62. let positions = self.ecs.read_storage::<Position>();
  63. let renderables = self.ecs.read_storage::<Renderable>();
  64. let map = self.ecs.fetch::<Map>();
  65. let mut data = (&positions, &renderables).join().collect::<Vec<_>>();
  66. data.sort_by(|&a, &b| b.1.render_order.cmp(&a.1.render_order) );
  67. for (pos, render) in data.iter() {
  68. let idx = map.xy_idx(pos.x, pos.y);
  69. if map.visible_tiles[idx] { ctx.set(pos.x, pos.y, render.fg, render.bg, render.glyph) }
  70. }
  71. gui::draw_ui(&self.ecs, ctx);
  72. }
  73. let mut newrunstate;
  74. {
  75. let runstate = self.ecs.fetch::<RunState>();
  76. newrunstate = *runstate;
  77. }
  78. match newrunstate {
  79. RunState::PreRun => {
  80. self.run_systems();
  81. self.ecs.maintain();
  82. newrunstate = RunState::AwaitingInput;
  83. }
  84. RunState::AwaitingInput => {
  85. newrunstate = player_input(self, ctx);
  86. }
  87. RunState::PlayerTurn => {
  88. self.run_systems();
  89. self.ecs.maintain();
  90. newrunstate = RunState::MonsterTurn;
  91. }
  92. RunState::MonsterTurn => {
  93. self.run_systems();
  94. self.ecs.maintain();
  95. newrunstate = RunState::AwaitingInput;
  96. }
  97. RunState::ShowInventory => {
  98. let result = gui::show_inventory(self, ctx);
  99. match result.0 {
  100. gui::ItemMenuResult::Cancel => newrunstate = RunState::AwaitingInput,
  101. gui::ItemMenuResult::NoResponse => {}
  102. gui::ItemMenuResult::Selected => {
  103. let item_entity = result.1.unwrap();
  104. let mut intent = self.ecs.write_storage::<WantsToDrinkPotion>();
  105. intent.insert(*self.ecs.fetch::<Entity>(), WantsToDrinkPotion{ potion: item_entity }).expect("Unable to insert intent");
  106. newrunstate = RunState::PlayerTurn;
  107. }
  108. }
  109. }
  110. RunState::ShowDropItem => {
  111. let result = gui::drop_item_menu(self, ctx);
  112. match result.0 {
  113. gui::ItemMenuResult::Cancel => newrunstate = RunState::AwaitingInput,
  114. gui::ItemMenuResult::NoResponse => {}
  115. gui::ItemMenuResult::Selected => {
  116. let item_entity = result.1.unwrap();
  117. let mut intent = self.ecs.write_storage::<WantsToDropItem>();
  118. intent.insert(*self.ecs.fetch::<Entity>(), WantsToDropItem{ item: item_entity }).expect("Unable to insert intent");
  119. newrunstate = RunState::PlayerTurn;
  120. }
  121. }
  122. }
  123. }
  124. {
  125. let mut runwriter = self.ecs.write_resource::<RunState>();
  126. *runwriter = newrunstate;
  127. }
  128. damage_system::delete_the_dead(&mut self.ecs);
  129. }
  130. }
  131. fn main() {
  132. let mut context = Rltk::init_simple8x8(80, 50, "Hello Rust World", "resources");
  133. context.with_post_scanlines(true);
  134. let mut gs = State {
  135. ecs: World::new(),
  136. };
  137. gs.ecs.register::<Position>();
  138. gs.ecs.register::<Renderable>();
  139. gs.ecs.register::<Player>();
  140. gs.ecs.register::<Viewshed>();
  141. gs.ecs.register::<Monster>();
  142. gs.ecs.register::<Name>();
  143. gs.ecs.register::<BlocksTile>();
  144. gs.ecs.register::<CombatStats>();
  145. gs.ecs.register::<WantsToMelee>();
  146. gs.ecs.register::<SufferDamage>();
  147. gs.ecs.register::<Item>();
  148. gs.ecs.register::<Potion>();
  149. gs.ecs.register::<InBackpack>();
  150. gs.ecs.register::<WantsToPickupItem>();
  151. gs.ecs.register::<WantsToDrinkPotion>();
  152. gs.ecs.register::<WantsToDropItem>();
  153. let map : Map = Map::new_map_rooms_and_corridors();
  154. let (player_x, player_y) = map.rooms[0].center();
  155. let player_entity = spawner::player(&mut gs.ecs, player_x, player_y);
  156. gs.ecs.insert(rltk::RandomNumberGenerator::new());
  157. for room in map.rooms.iter().skip(1) {
  158. spawner::spawn_room(&mut gs.ecs, room);
  159. }
  160. gs.ecs.insert(map);
  161. gs.ecs.insert(Point::new(player_x, player_y));
  162. gs.ecs.insert(player_entity);
  163. gs.ecs.insert(RunState::PreRun);
  164. gs.ecs.insert(gamelog::GameLog{ entries : vec!["Welcome to Rusty Roguelike".to_string()] });
  165. rltk::main_loop(context, gs);
  166. }