main.rs 6.1 KB

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