diff --git a/src/components.rs b/src/components.rs index 94575da..4025351 100644 --- a/src/components.rs +++ b/src/components.rs @@ -1,9 +1,11 @@ use rltk::{Point, RGB}; +use serde::{Deserialize, Serialize}; +use specs::error::NoError; use specs::prelude::*; -use specs::saveload::*; +use specs::saveload::{ConvertSaveload, Marker}; use specs_derive::*; -#[derive(Component, Clone, ConvertSaveload)] +#[derive(Component, ConvertSaveload, Clone)] pub struct Position { pub x: i32, pub y: i32, @@ -17,10 +19,10 @@ pub struct Renderable { pub render_order: i32, } -#[derive(Component, Debug, Serialize, Deserialize, Clone)] +#[derive(Component, Serialize, Deserialize, Clone)] pub struct Player {} -#[derive(Component, Clone, ConvertSaveload)] +#[derive(Component, ConvertSaveload, Clone)] pub struct Viewshed { pub visible_tiles: Vec, pub range: i32, @@ -30,15 +32,15 @@ pub struct Viewshed { #[derive(Component, Serialize, Deserialize, Clone)] pub struct Monster {} -#[derive(Component, Debug, ConvertSaveload)] +#[derive(Component, Debug, ConvertSaveload, Clone)] pub struct Name { pub name: String, } -#[derive(Component, Debug, Serialize, Deserialize)] +#[derive(Component, Debug, Serialize, Deserialize, Clone)] pub struct BlocksTile {} -#[derive(Component, Debug, ConvertSaveload)] +#[derive(Component, Debug, ConvertSaveload, Clone)] pub struct CombatStats { pub max_hp: i32, pub hp: i32, @@ -46,12 +48,12 @@ pub struct CombatStats { pub power: i32, } -#[derive(Component, Debug, Clone, ConvertSaveload)] +#[derive(Component, Debug, ConvertSaveload, Clone)] pub struct WantsToMelee { pub target: Entity, } -#[derive(Component, Debug, ConvertSaveload)] +#[derive(Component, Debug, ConvertSaveload, Clone)] pub struct SufferDamage { pub amount: Vec, } @@ -69,15 +71,15 @@ impl SufferDamage { } } -#[derive(Component, Debug, Serialize, Deserialize)] +#[derive(Component, Debug, Serialize, Deserialize, Clone)] pub struct Item {} -#[derive(Component, Debug, ConvertSaveload)] +#[derive(Component, Debug, ConvertSaveload, Clone)] pub struct Potion { pub heal_amount: i32, } -#[derive(Component, Debug, ConvertSaveload)] +#[derive(Component, Debug, ConvertSaveload, Clone)] pub struct InBackpack { pub owner: Entity, } @@ -88,7 +90,7 @@ pub struct WantsToPickupItem { pub item: Entity, } -#[derive(Component, Debug, Clone, ConvertSaveload)] +#[derive(Component, Debug, ConvertSaveload, Clone)] pub struct WantsToUseItem { pub item: Entity, pub target: Option, @@ -99,10 +101,10 @@ pub struct WantsToDropItem { pub item: Entity, } -#[derive(Component, Debug, Serialize, Deserialize)] +#[derive(Component, Debug, Serialize, Deserialize, Clone)] pub struct Consumable {} -#[derive(Component, Debug, ConvertSaveload)] +#[derive(Component, Debug, ConvertSaveload, Clone)] pub struct ProvidesHealing { pub heal_amount: i32, } @@ -117,19 +119,19 @@ pub struct InflictsDamage { pub damage: i32, } -#[derive(Component, Debug, ConvertSaveload)] +#[derive(Component, Debug, ConvertSaveload, Clone)] pub struct AreaOfEffect { pub radius: i32, } -#[derive(Component, Debug, ConvertSaveload)] +#[derive(Component, Debug, ConvertSaveload, Clone)] pub struct Confusion { pub turns: i32, } pub struct SerializeMe; -#[derive(Component, Clone, Serialize, Deserialize)] +#[derive(Component, Serialize, Deserialize, Clone)] pub struct SerializationHelper { pub map: super::map::Map, } \ No newline at end of file diff --git a/src/gui.rs b/src/gui.rs index 64574d2..3e359bd 100644 --- a/src/gui.rs +++ b/src/gui.rs @@ -1,14 +1,14 @@ -use rltk::Rltk; -use rltk::RGB; use rltk::{Point, VirtualKeyCode}; +use rltk::RGB; +use rltk::Rltk; use specs::prelude::*; +use crate::{CombatStats, InBackpack, RunState, State, Viewshed}; use crate::gamelog::GameLog; use crate::Map; use crate::Name; use crate::Player; use crate::Position; -use crate::{CombatStats, InBackpack, RunState, State, Viewshed}; pub fn draw_ui(ecs: &World, ctx: &mut Rltk) { ctx.draw_box( @@ -403,6 +403,7 @@ pub enum MainMenuResult { } pub fn main_menu(gs: &mut State, ctx: &mut Rltk) -> MainMenuResult { + let save_exists = super::save_load_system::does_save_exist(); let runstate = gs.ecs.fetch::(); ctx.print_color_centered( @@ -412,6 +413,7 @@ pub fn main_menu(gs: &mut State, ctx: &mut Rltk) -> MainMenuResult { "Rust Roguelike Tutorial", ); + if let RunState::MainMenu { menu_selection: selection, } = *runstate @@ -432,22 +434,25 @@ pub fn main_menu(gs: &mut State, ctx: &mut Rltk) -> MainMenuResult { ); } - if selection == MainMenuSelection::LoadGame { - ctx.print_color_centered( - 25, - RGB::named(rltk::MAGENTA), - RGB::named(rltk::BLACK), - "Load Game", - ); - } else { - ctx.print_color_centered( - 25, - RGB::named(rltk::WHITE), - RGB::named(rltk::BLACK), - "Load Game", - ); + if save_exists { + if selection == MainMenuSelection::LoadGame { + ctx.print_color_centered( + 25, + RGB::named(rltk::MAGENTA), + RGB::named(rltk::BLACK), + "Load Game", + ); + } else { + ctx.print_color_centered( + 25, + RGB::named(rltk::WHITE), + RGB::named(rltk::BLACK), + "Load Game", + ); + } } + if selection == MainMenuSelection::Quit { ctx.print_color_centered( 26, diff --git a/src/main.rs b/src/main.rs index 7beb39e..d415650 100644 --- a/src/main.rs +++ b/src/main.rs @@ -206,7 +206,11 @@ impl GameState for State { } gui::MainMenuResult::Selected { selected } => match selected { gui::MainMenuSelection::NewGame => new_run_state = RunState::PreRun, - gui::MainMenuSelection::LoadGame => new_run_state = RunState::PreRun, + gui::MainMenuSelection::LoadGame => { + save_load_system::load_game(&mut self.ecs); + new_run_state = RunState::AwaitingInput; + save_load_system::delete_save(); + } gui::MainMenuSelection::Quit => ::std::process::exit(0), }, } @@ -214,7 +218,7 @@ impl GameState for State { RunState::SaveGame => { save_load_system::save_game(&mut self.ecs); new_run_state = RunState::MainMenu { - menu_selection: gui::MainMenuSelection::LoadGame, + menu_selection: gui::MainMenuSelection::Quit, }; } } @@ -238,9 +242,6 @@ fn main() -> rltk::BError { let mut gs = State { ecs: World::new() }; gs.ecs.insert(rltk::RandomNumberGenerator::new()); - gs.ecs.insert(gamelog::GameLog { - entries: vec!["Welcome to Rusty Roguelike".to_string()], - }); gs.ecs.register::(); gs.ecs.register::(); @@ -265,22 +266,27 @@ fn main() -> rltk::BError { gs.ecs.register::(); gs.ecs.register::>(); gs.ecs.register::(); - gs.ecs.insert(SimpleMarkerAllocator::::new()); - let map = Map::new_map_rooms_and_corridors(); + gs.ecs.insert(SimpleMarkerAllocator::::new()); + + let map = Map::new_map_rooms_and_corridors(); let (player_x, player_y) = map.rooms[0].center(); - gs.ecs.insert(Point::new(player_x, player_y)); + let player_entity = spawner::player(&mut gs.ecs, player_x, player_y); - gs.ecs.insert(player_entity); for room in map.rooms.iter().skip(1) { spawner::spawn_room(&mut gs.ecs, room); } gs.ecs.insert(map); + gs.ecs.insert(Point::new(player_x, player_y)); + gs.ecs.insert(player_entity); gs.ecs.insert(RunState::MainMenu { menu_selection: gui::MainMenuSelection::NewGame, }); + gs.ecs.insert(gamelog::GameLog { + entries: vec!["Welcome to Rusty Roguelike".to_string()], + }); rltk::main_loop(context, gs) } diff --git a/src/map.rs b/src/map.rs index 6cdbd66..2c1b55f 100644 --- a/src/map.rs +++ b/src/map.rs @@ -65,6 +65,27 @@ impl Map { } } + + fn is_exit_valid(&self, x: i32, y: i32) -> bool { + if x < 1 || x > self.width - 1 || y < 1 || y > self.height - 1 { + return false; + } + let idx = self.xy_idx(x, y); + !self.blocked[idx] + } + + pub fn populate_blocked(&mut self) { + for (i, tile) in self.tiles.iter_mut().enumerate() { + self.blocked[i] = *tile == TileType::Wall; + } + } + + pub fn clear_content_index(&mut self) { + for content in self.tile_content.iter_mut() { + content.clear(); + } + } + pub fn new_map_rooms_and_corridors() -> Map { let mut map = Map { tiles: vec![TileType::Wall; MAP_COUNT], @@ -116,37 +137,11 @@ impl Map { map } - - fn is_exit_valid(&self, x: i32, y: i32) -> bool { - if x < 1 || x > self.width - 1 || y < 1 || y > self.height - 1 { - return false; - } - let idx = self.xy_idx(x, y); - !self.blocked[idx] - } - - pub fn populate_blocked(&mut self) { - for (i, tile) in self.tiles.iter_mut().enumerate() { - self.blocked[i] = *tile == TileType::Wall; - } - } - - pub fn clear_content_index(&mut self) { - for content in self.tile_content.iter_mut() { - content.clear(); - } - } -} - -impl Algorithm2D for Map { - fn dimensions(&self) -> rltk::Point { - Point::new(self.width, self.height) - } } impl BaseMap for Map { fn is_opaque(&self, idx: usize) -> bool { - self.tiles[idx as usize] == TileType::Wall + self.tiles[idx] == TileType::Wall } fn get_pathing_distance(&self, idx1: usize, idx2: usize) -> f32 { @@ -192,6 +187,12 @@ impl BaseMap for Map { } } +impl Algorithm2D for Map { + fn dimensions(&self) -> rltk::Point { + Point::new(self.width, self.height) + } +} + pub fn draw_map(ecs: &World, ctx: &mut Rltk) { let map = ecs.fetch::(); @@ -203,12 +204,12 @@ pub fn draw_map(ecs: &World, ctx: &mut Rltk) { let mut fg; match tile { TileType::Floor => { - fg = RGB::from_f32(0.5, 0.5, 0.5); + fg = RGB::from_f32(0.0, 0.5, 0.5); glyph = rltk::to_cp437('.'); } TileType::Wall => { - fg = RGB::from_f32(0.0, 1.0, 0.0); + fg = RGB::from_f32(0., 1.0, 0.); glyph = rltk::to_cp437('#'); } } @@ -219,7 +220,7 @@ pub fn draw_map(ecs: &World, ctx: &mut Rltk) { } x += 1; - if x > 79 { + if x > MAP_WIDTH as i32 - 1 { x = 0; y += 1; } diff --git a/src/player.rs b/src/player.rs index 94704a4..488933d 100644 --- a/src/player.rs +++ b/src/player.rs @@ -3,12 +3,12 @@ use std::cmp::{max, min}; use rltk::{Point, Rltk, VirtualKeyCode}; use specs::prelude::*; -use crate::gamelog::GameLog; use crate::{ components::{CombatStats, Player, Position, Viewshed, WantsToMelee}, - map::Map, - Item, RunState, State, WantsToPickupItem, + Item, + map::Map, RunState, State, WantsToPickupItem, }; +use crate::gamelog::GameLog; pub fn try_move_player(delta_x: i32, delta_y: i32, ecs: &mut World) { let mut positions = ecs.write_storage::(); @@ -20,8 +20,9 @@ pub fn try_move_player(delta_x: i32, delta_y: i32, ecs: &mut World) { let map = ecs.fetch::(); for (entity, _player, pos, viewshed) in - (&entities, &mut players, &mut positions, &mut viewsheds).join() + (&entities, &mut players, &mut positions, &mut viewsheds).join() { + if pos.x + delta_x < 1 || pos.x + delta_x > map.width - 1 || pos.y + delta_y < 1 || pos.y + delta_y > map.height - 1 { return; } let destination_idx = map.xy_idx(pos.x + delta_x, pos.y + delta_y); for potential_target in map.tile_content[destination_idx].iter() { diff --git a/src/spawner.rs b/src/spawner.rs index 222bace..7fc890b 100644 --- a/src/spawner.rs +++ b/src/spawner.rs @@ -168,7 +168,7 @@ pub fn magic_missile_scroll(ecs: &mut World, x: i32, y: i32) { .with(Item {}) .with(Consumable {}) .with(Ranged { range: 6 }) - .with(InflictsDamage { damage: 8 }) + .with(InflictsDamage { damage: 20 }) .marked::>() .build(); } @@ -178,7 +178,7 @@ pub fn fireball_scroll(ecs: &mut World, x: i32, y: i32) { .with(Position { x, y }) .with(Renderable { glyph: rltk::to_cp437(')'), - fg: RGB::named(rltk::CYAN), + fg: RGB::named(rltk::ORANGE), bg: RGB::named(rltk::BLACK), render_order: 2, }) @@ -199,7 +199,7 @@ pub fn confusion_scroll(ecs: &mut World, x: i32, y: i32) { .with(Position { x, y }) .with(Renderable { glyph: rltk::to_cp437(')'), - fg: RGB::named(rltk::CYAN), + fg: RGB::named(rltk::PINK), bg: RGB::named(rltk::BLACK), render_order: 2, }) diff --git a/src/visibility_system.rs b/src/visibility_system.rs index a6a9cd4..dcb0d91 100644 --- a/src/visibility_system.rs +++ b/src/visibility_system.rs @@ -25,7 +25,6 @@ impl<'a> System<'a> for VisibilitySystem { } viewshed.dirty = false; - viewshed.visible_tiles.clear(); viewshed.visible_tiles = field_of_view(Point::new(pos.x, pos.y), viewshed.range, &*map); viewshed .visible_tiles