gui, inventory, symmetrical shadowcasting, bugfixes

This commit is contained in:
Llywelwyn 2023-07-07 07:10:44 +01:00
parent 5b7eac3165
commit 986adb6fce
10 changed files with 355 additions and 71 deletions

View file

@ -1,4 +1,4 @@
use rltk::{GameState, Point, Rltk, RGB};
use rltk::{GameState, Point, Rltk};
use specs::prelude::*;
mod components;
@ -10,8 +10,8 @@ use player::*;
mod rect;
pub use rect::Rect;
mod gamelog;
use gamelog::GameLog;
mod gui;
mod spawner;
mod visibility_system;
use visibility_system::VisibilitySystem;
mod monster_ai_system;
@ -22,7 +22,10 @@ mod damage_system;
use damage_system::*;
mod melee_combat_system;
use melee_combat_system::MeleeCombatSystem;
mod inventory_system;
use inventory_system::*;
// Embedded resources for use in wasm build
rltk::embedded_resource!(TERMINAL8X8, "../resources/terminal8x8.jpg");
rltk::embedded_resource!(SCANLINESFS, "../resources/scanlines.fs");
rltk::embedded_resource!(SCANLINESVS, "../resources/scanlines.vs");
@ -33,6 +36,7 @@ pub enum RunState {
PreRun,
PlayerTurn,
MonsterTurn,
ShowInventory,
}
pub struct State {
@ -51,14 +55,35 @@ impl State {
melee_system.run_now(&self.ecs);
let mut damage_system = DamageSystem {};
damage_system.run_now(&self.ecs);
let mut inventory_system = ItemCollectionSystem {};
inventory_system.run_now(&self.ecs);
let mut potion_system = PotionUseSystem {};
potion_system.run_now(&self.ecs);
self.ecs.maintain();
}
}
impl GameState for State {
fn tick(&mut self, ctx: &mut Rltk) {
// Clear screen
ctx.cls();
// Draw map and ui
draw_map(&self.ecs, ctx);
{
let positions = self.ecs.read_storage::<Position>();
let renderables = self.ecs.read_storage::<Renderable>();
let map = self.ecs.fetch::<Map>();
for (pos, render) in (&positions, &renderables).join() {
let idx = map.xy_idx(pos.x, pos.y);
if map.visible_tiles[idx] {
ctx.set(pos.x, pos.y, render.fg, render.bg, render.glyph);
}
}
gui::draw_ui(&self.ecs, ctx);
}
let mut new_runstate;
{
let runstate = self.ecs.fetch::<RunState>();
@ -68,6 +93,7 @@ impl GameState for State {
match new_runstate {
RunState::PreRun => {
self.run_systems();
self.ecs.maintain();
new_runstate = RunState::AwaitingInput;
}
RunState::AwaitingInput => {
@ -75,12 +101,29 @@ impl GameState for State {
}
RunState::PlayerTurn => {
self.run_systems();
self.ecs.maintain();
new_runstate = RunState::MonsterTurn;
}
RunState::MonsterTurn => {
self.run_systems();
self.ecs.maintain();
new_runstate = RunState::AwaitingInput;
}
RunState::ShowInventory => {
let result = gui::show_inventory(self, ctx);
match result.0 {
gui::ItemMenuResult::Cancel => new_runstate = RunState::AwaitingInput,
gui::ItemMenuResult::NoResponse => {}
gui::ItemMenuResult::Selected => {
let item_entity = result.1.unwrap();
let mut intent = self.ecs.write_storage::<WantsToDrinkPotion>();
intent
.insert(*self.ecs.fetch::<Entity>(), WantsToDrinkPotion { potion: item_entity })
.expect("Unable to insert intent.");
new_runstate = RunState::PlayerTurn;
}
}
}
}
{
@ -89,20 +132,6 @@ impl GameState for State {
}
damage_system::delete_the_dead(&mut self.ecs);
draw_map(&self.ecs, ctx);
let positions = self.ecs.read_storage::<Position>();
let renderables = self.ecs.read_storage::<Renderable>();
let map = self.ecs.fetch::<Map>();
for (pos, render) in (&positions, &renderables).join() {
let idx = map.xy_idx(pos.x, pos.y);
if map.visible_tiles[idx] {
ctx.set(pos.x, pos.y, render.fg, render.bg, render.glyph);
}
}
gui::draw_ui(&self.ecs, ctx);
}
}
@ -126,47 +155,20 @@ fn main() -> rltk::BError {
gs.ecs.register::<CombatStats>();
gs.ecs.register::<WantsToMelee>();
gs.ecs.register::<SufferDamage>();
gs.ecs.register::<Item>();
gs.ecs.register::<Potion>();
gs.ecs.register::<InBackpack>();
gs.ecs.register::<WantsToPickupItem>();
gs.ecs.register::<WantsToDrinkPotion>();
let map = Map::new_map_rooms_and_corridors();
let (player_x, player_y) = map.rooms[0].centre();
let player_entity = gs
.ecs
.create_entity()
.with(Position { x: player_x, y: player_y })
.with(Renderable { glyph: rltk::to_cp437('@'), fg: RGB::named(rltk::YELLOW), bg: RGB::named(rltk::BLACK) })
.with(Player {})
.with(Viewshed { visible_tiles: Vec::new(), range: 8, dirty: true })
.with(Name { name: "Player".to_string() })
.with(CombatStats { max_hp: 30, hp: 30, defence: 2, power: 5 })
.build();
let player_entity = spawner::player(&mut gs.ecs, player_x, player_y);
let mut rng = rltk::RandomNumberGenerator::new();
for (i, room) in map.rooms.iter().skip(1).enumerate() {
let (x, y) = room.centre();
let glyph: rltk::FontCharType;
let name: String;
let roll = rng.roll_dice(1, 2);
match roll {
1 => {
glyph = rltk::to_cp437('g');
name = "Goblin".to_string();
}
_ => {
glyph = rltk::to_cp437('o');
name = "Orc".to_string();
}
}
gs.ecs
.create_entity()
.with(Position { x, y })
.with(Renderable { glyph: glyph, fg: RGB::named(rltk::RED), bg: RGB::named(rltk::BLACK) })
.with(Viewshed { visible_tiles: Vec::new(), range: 8, dirty: true })
.with(Monster {})
.with(Name { name: format!("{} #{}", &name, i) })
.with(BlocksTile {})
.with(CombatStats { max_hp: 16, hp: 16, defence: 1, power: 4 })
.build();
gs.ecs.insert(rltk::RandomNumberGenerator::new());
for room in map.rooms.iter().skip(1) {
spawner::spawn_room(&mut gs.ecs, room);
}
gs.ecs.insert(map);