From 1299524c918b88dc309cc25c5f107578a74eccef Mon Sep 17 00:00:00 2001 From: Llywelwyn Date: Sun, 24 Sep 2023 00:41:02 +0100 Subject: [PATCH] reimplementing gameloop with notan's App, instead of bracket-lib BTerm --- src/main.rs | 9 ++- src/player.rs | 44 +++++++++++ src/states/state.rs | 183 +++++++++++++++++++++++++++++++++++++++----- 3 files changed, 213 insertions(+), 23 deletions(-) diff --git a/src/main.rs b/src/main.rs index fc13f8a..97b7739 100644 --- a/src/main.rs +++ b/src/main.rs @@ -136,7 +136,7 @@ fn setup(gfx: &mut Graphics) -> State { gs.ecs.insert(gui::Ancestry::Human); // ancestry let player_entity = spawner::player(&mut gs.ecs, 0, 0); gs.ecs.insert(player_entity); // Player entity - gs.ecs.insert(RunState::MapGeneration {}); // RunState + gs.ecs.insert(RunState::AwaitingInput {}); // TODO: Set this back to RunState::MapGen gs.ecs.insert(particle_system::ParticleBuilder::new()); gs.ecs.insert(rex_assets::RexAssets::new()); @@ -156,6 +156,9 @@ fn draw(app: &mut App, gfx: &mut Graphics, gs: &mut State) { let px = idx_to_px(i, &map); draw.image(gs.atlas.get("floor_grass_d").unwrap()).position(px.0, px.1); } + let ppos = gs.ecs.fetch::(); + let px = idx_to_px(map.xy_idx(ppos.x, ppos.y), &map); + draw.image(gs.atlas.get("ui_heart_full").unwrap()).position(px.0, px.1); // Render batch gfx.render(&draw); } @@ -167,6 +170,6 @@ fn idx_to_px(idx: usize, map: &Map) -> (f32, f32) { ) } -fn update(app: &mut App, state: &mut State) { - //state.tick(app); +fn update(ctx: &mut App, state: &mut State) { + state.update(ctx); } diff --git a/src/player.rs b/src/player.rs index 35767a5..422b4ad 100644 --- a/src/player.rs +++ b/src/player.rs @@ -656,6 +656,50 @@ pub fn player_input(gs: &mut State, ctx: &mut App, on_overmap: bool) -> RunState return try_move_player(0, -1, &mut gs.ecs); } else if key.was_pressed(KeyCode::Numpad2) { return try_move_player(0, 1, &mut gs.ecs); + } else if key.was_pressed(KeyCode::Numpad9) { + return try_move_player(1, -1, &mut gs.ecs); + } else if key.was_pressed(KeyCode::Numpad7) { + return try_move_player(-1, -1, &mut gs.ecs); + } else if key.was_pressed(KeyCode::Numpad3) { + return try_move_player(1, 1, &mut gs.ecs); + } else if key.was_pressed(KeyCode::Numpad1) { + return try_move_player(-1, 1, &mut gs.ecs); + } else if key.was_pressed(KeyCode::Period) { + if key.shift() { + let dest = try_change_level(&mut gs.ecs, false); + let curr_map_id = gs.ecs.fetch::().id; + return match dest { + // If we have no destination, do nothing. + Destination::None => RunState::AwaitingInput, + // If we want to go to the next level, go to the up-stair tile of id + 1. + Destination::NextLevel => RunState::GoToLevel(curr_map_id + 1, TileType::UpStair), + // If we want to go to the previous level, go to the down-stair tile of id - 1. + Destination::PreviousLevel => + RunState::GoToLevel(curr_map_id - 1, TileType::DownStair), + Destination::ToLocal(id) => RunState::GoToLevel(ID_OVERMAP, TileType::ToLocal(id)), + Destination::ToOvermap(id) => RunState::GoToLevel(id, TileType::ToOvermap(id)), + }; + } else { + return skip_turn(&mut gs.ecs); // (Wait a turn) + } + } else if key.was_pressed(KeyCode::Comma) { + if key.shift() { + let dest = try_change_level(&mut gs.ecs, false); + let curr_map_id = gs.ecs.fetch::().id; + return match dest { + // If we have no destination, do nothing. + Destination::None => RunState::AwaitingInput, + // If we want to go to the next level, go to the up-stair tile of id + 1. + Destination::NextLevel => RunState::GoToLevel(curr_map_id + 1, TileType::UpStair), + // If we want to go to the previous level, go to the down-stair tile of id - 1. + Destination::PreviousLevel => + RunState::GoToLevel(curr_map_id - 1, TileType::DownStair), + Destination::ToLocal(id) => RunState::GoToLevel(ID_OVERMAP, TileType::ToLocal(id)), + Destination::ToOvermap(id) => RunState::GoToLevel(id, TileType::ToOvermap(id)), + }; + } else { + return skip_turn(&mut gs.ecs); // (Wait a turn) + } } return RunState::AwaitingInput; diff --git a/src/states/state.rs b/src/states/state.rs index 0a23297..1a212a8 100644 --- a/src/states/state.rs +++ b/src/states/state.rs @@ -23,9 +23,8 @@ use crate::camera; use crate::saveload_system; use crate::morgue; use crate::damage_system; -use crate::data::prelude::*; -use notan::prelude::*; use std::collections::HashMap; +use notan::prelude::*; #[derive(AppState)] pub struct State { @@ -163,21 +162,162 @@ impl State { } impl State { - pub fn tick(&mut self, app: &mut App) { + pub fn update(&mut self, ctx: &mut App) { + let mut new_runstate; + { + let runstate = self.ecs.fetch::(); + new_runstate = *runstate; + } + + // Particle ticker here + + match new_runstate { + | RunState::MainMenu { .. } + | RunState::CharacterCreation { .. } + | RunState::PreRun { .. } => {} + _ => { + // Draw map and ui + } + } + + match new_runstate { + RunState::PreRun => { + self.run_systems(); + self.ecs.maintain(); + new_runstate = RunState::AwaitingInput; + } + RunState::AwaitingInput => { + self.refresh_indexes(); + effects::run_effects_queue(&mut self.ecs); + let mut can_act = false; + { + let player_entity = self.ecs.fetch::(); + let turns = self.ecs.read_storage::(); + if let Some(_) = turns.get(*player_entity) { + can_act = true; + } + } + if can_act { + let on_overmap = self.ecs.fetch::().overmap; + new_runstate = player_input(self, ctx, on_overmap); + } else { + new_runstate = RunState::Ticking; + } + } + RunState::Ticking => { + while new_runstate == RunState::Ticking && particle_system::check_queue(&self.ecs) { + self.run_systems(); + self.ecs.maintain(); + try_spawn_interval(&mut self.ecs); + maybe_map_message(&mut self.ecs); + match *self.ecs.fetch::() { + RunState::AwaitingInput => { + new_runstate = RunState::AwaitingInput; + } + RunState::MagicMapReveal { row, cursed } => { + new_runstate = RunState::MagicMapReveal { row: row, cursed: cursed }; + } + RunState::ShowRemoveCurse => { + new_runstate = RunState::ShowRemoveCurse; + } + RunState::ShowIdentify => { + new_runstate = RunState::ShowIdentify; + } + _ => { + new_runstate = RunState::Ticking; + } + } + } + } + // RunState::Farlook + // RunState::ShowCheatMenu + // RunState::ShowInventory + // RunState::ShowDropItem + // RunState::ShowRemoveItem + // RunState::ShowTargeting + // RunState::ShowRemoveCurse + // RunState::ShowIdentify + // RunState::ActionWithDirection + // RunState::MainMenu + // RunState::CharacterCreation + RunState::SaveGame => { + saveload_system::save_game(&mut self.ecs); + new_runstate = RunState::MainMenu { + menu_selection: gui::MainMenuSelection::LoadGame, + }; + } + //RunState::GameOver + RunState::GoToLevel(id, dest_tile) => { + self.goto_id(id, dest_tile); + self.mapgen_next_state = Some(RunState::PreRun); + new_runstate = RunState::MapGeneration; + } + // RunState::HelpScreen + RunState::MagicMapReveal { row, cursed } => { + let mut map = self.ecs.fetch_mut::(); + + // Could probably toss this into a function somewhere, and/or + // have multiple simple animations for it. + for x in 0..map.width { + let idx; + if x % 2 == 0 { + idx = map.xy_idx(x as i32, row); + } else { + idx = map.xy_idx(x as i32, (map.height as i32) - 1 - row); + } + if !cursed { + map.revealed_tiles[idx] = true; + } else { + map.revealed_tiles[idx] = false; + } + } + // Dirtify viewshed only if cursed, so our currently visible tiles aren't removed too + if cursed { + let player_entity = self.ecs.fetch::(); + let mut viewshed_components = self.ecs.write_storage::(); + let viewshed = viewshed_components.get_mut(*player_entity); + if let Some(viewshed) = viewshed { + viewshed.dirty = true; + } + } + + if (row as usize) == (map.height as usize) - 1 { + new_runstate = RunState::Ticking; + } else { + new_runstate = RunState::MagicMapReveal { row: row + 1, cursed: cursed }; + } + } + // RunState::MapGeneration + _ => {} + } + { + let mut runwriter = self.ecs.write_resource::(); + *runwriter = new_runstate; + } + damage_system::delete_the_dead(&mut self.ecs); + } + fn tick(&mut self, ctx: &mut BTerm) { let mut new_runstate; { let runstate = self.ecs.fetch::(); new_runstate = *runstate; } // Clear screen - //particle_system::particle_ticker(&mut self.ecs, ctx); + ctx.set_active_console(2); + ctx.cls(); + ctx.set_active_console(1); + ctx.cls(); + ctx.set_active_console(0); + ctx.cls(); + particle_system::particle_ticker(&mut self.ecs, ctx); match new_runstate { - RunState::MainMenu { .. } | RunState::PreRun | RunState::CharacterCreation { .. } => {} + RunState::MainMenu { .. } => {} + RunState::CharacterCreation { .. } => {} _ => { // Draw map and ui - //camera::render_camera(&self.ecs, ctx); - //gui::draw_ui(&self.ecs, ctx); + camera::render_camera(&self.ecs, ctx); + gui::draw_ui(&self.ecs, ctx); } } @@ -206,7 +346,7 @@ impl State { } if can_act { let on_overmap = self.ecs.fetch::().overmap; - new_runstate = player_input(self, app, on_overmap); + new_runstate = RunState::AwaitingInput; //player_input(self, ctx, on_overmap); } else { new_runstate = RunState::Ticking; } @@ -237,7 +377,7 @@ impl State { } } RunState::Farlook { .. } => { - let result = gui::FarlookResult::Cancel; //gui::show_farlook(self, ctx); + let result = gui::show_farlook(self, ctx); match result { gui::FarlookResult::NoResponse { x, y } => { new_runstate = RunState::Farlook { x, y }; @@ -248,7 +388,7 @@ impl State { } } RunState::ShowCheatMenu => { - let result = gui::CheatMenuResult::Cancel; //gui::show_cheat_menu(self, ctx); + let result = gui::show_cheat_menu(self, ctx); match result { gui::CheatMenuResult::Cancel => { new_runstate = RunState::AwaitingInput; @@ -291,7 +431,7 @@ impl State { } } RunState::ShowInventory => { - let result = gui::ItemMenuResult::Cancel; //gui::show_inventory(self, ctx); + let result = gui::show_inventory(self, ctx); match result.0 { gui::ItemMenuResult::Cancel => { new_runstate = RunState::AwaitingInput; @@ -466,10 +606,7 @@ impl State { } } RunState::CharacterCreation { .. } => { - let result = gui::CharCreateResult::Selected { - ancestry: gui::Ancestry::Human, - class: gui::Class::Fighter, - }; //gui::character_creation(self, ctx); + let result = gui::character_creation(self, ctx); match result { gui::CharCreateResult::NoSelection { ancestry, class } => { new_runstate = RunState::CharacterCreation { ancestry, class }; @@ -494,7 +631,7 @@ impl State { }; } RunState::GameOver => { - let result = gui::YesNoResult::No; //gui::game_over(ctx); + let result = gui::game_over(ctx); let write_to_morgue: Option = match result { gui::YesNoResult::NoSelection => None, gui::YesNoResult::No => Some(false), @@ -517,7 +654,7 @@ impl State { new_runstate = RunState::MapGeneration; } RunState::HelpScreen => { - let result = gui::YesNoResult::Yes; //gui::show_help(ctx); + let result = gui::show_help(ctx); match result { gui::YesNoResult::Yes => { gamelog::record_event(EVENT::LookedForHelp(1)); @@ -566,9 +703,15 @@ impl State { new_runstate = self.mapgen_next_state.unwrap(); } if self.mapgen_history.len() != 0 { - //camera::render_debug_map(&self.mapgen_history[self.mapgen_index], ctx); + ctx.set_active_console(2); + ctx.cls(); + ctx.set_active_console(1); + ctx.cls(); + ctx.set_active_console(0); + ctx.cls(); + camera::render_debug_map(&self.mapgen_history[self.mapgen_index], ctx); - //self.mapgen_timer += ctx.frame_time_ms; + self.mapgen_timer += ctx.frame_time_ms; if self.mapgen_timer > 300.0 { self.mapgen_timer = 0.0; self.mapgen_index += 1; @@ -587,6 +730,6 @@ impl State { damage_system::delete_the_dead(&mut self.ecs); - //let _ = render_draw_buffer(ctx); + let _ = render_draw_buffer(ctx); } }