WIP: 2.10

This commit is contained in:
Kasper Juul Hermansen 2022-01-27 19:42:51 +01:00
parent ecbecc1a58
commit f2f4c40c28
Signed by: kjuulh
GPG Key ID: 0F95C140730F2F23
7 changed files with 96 additions and 82 deletions

View File

@ -1,9 +1,11 @@
use rltk::{Point, RGB}; use rltk::{Point, RGB};
use serde::{Deserialize, Serialize};
use specs::error::NoError;
use specs::prelude::*; use specs::prelude::*;
use specs::saveload::*; use specs::saveload::{ConvertSaveload, Marker};
use specs_derive::*; use specs_derive::*;
#[derive(Component, Clone, ConvertSaveload)] #[derive(Component, ConvertSaveload, Clone)]
pub struct Position { pub struct Position {
pub x: i32, pub x: i32,
pub y: i32, pub y: i32,
@ -17,10 +19,10 @@ pub struct Renderable {
pub render_order: i32, pub render_order: i32,
} }
#[derive(Component, Debug, Serialize, Deserialize, Clone)] #[derive(Component, Serialize, Deserialize, Clone)]
pub struct Player {} pub struct Player {}
#[derive(Component, Clone, ConvertSaveload)] #[derive(Component, ConvertSaveload, Clone)]
pub struct Viewshed { pub struct Viewshed {
pub visible_tiles: Vec<rltk::Point>, pub visible_tiles: Vec<rltk::Point>,
pub range: i32, pub range: i32,
@ -30,15 +32,15 @@ pub struct Viewshed {
#[derive(Component, Serialize, Deserialize, Clone)] #[derive(Component, Serialize, Deserialize, Clone)]
pub struct Monster {} pub struct Monster {}
#[derive(Component, Debug, ConvertSaveload)] #[derive(Component, Debug, ConvertSaveload, Clone)]
pub struct Name { pub struct Name {
pub name: String, pub name: String,
} }
#[derive(Component, Debug, Serialize, Deserialize)] #[derive(Component, Debug, Serialize, Deserialize, Clone)]
pub struct BlocksTile {} pub struct BlocksTile {}
#[derive(Component, Debug, ConvertSaveload)] #[derive(Component, Debug, ConvertSaveload, Clone)]
pub struct CombatStats { pub struct CombatStats {
pub max_hp: i32, pub max_hp: i32,
pub hp: i32, pub hp: i32,
@ -46,12 +48,12 @@ pub struct CombatStats {
pub power: i32, pub power: i32,
} }
#[derive(Component, Debug, Clone, ConvertSaveload)] #[derive(Component, Debug, ConvertSaveload, Clone)]
pub struct WantsToMelee { pub struct WantsToMelee {
pub target: Entity, pub target: Entity,
} }
#[derive(Component, Debug, ConvertSaveload)] #[derive(Component, Debug, ConvertSaveload, Clone)]
pub struct SufferDamage { pub struct SufferDamage {
pub amount: Vec<i32>, pub amount: Vec<i32>,
} }
@ -69,15 +71,15 @@ impl SufferDamage {
} }
} }
#[derive(Component, Debug, Serialize, Deserialize)] #[derive(Component, Debug, Serialize, Deserialize, Clone)]
pub struct Item {} pub struct Item {}
#[derive(Component, Debug, ConvertSaveload)] #[derive(Component, Debug, ConvertSaveload, Clone)]
pub struct Potion { pub struct Potion {
pub heal_amount: i32, pub heal_amount: i32,
} }
#[derive(Component, Debug, ConvertSaveload)] #[derive(Component, Debug, ConvertSaveload, Clone)]
pub struct InBackpack { pub struct InBackpack {
pub owner: Entity, pub owner: Entity,
} }
@ -88,7 +90,7 @@ pub struct WantsToPickupItem {
pub item: Entity, pub item: Entity,
} }
#[derive(Component, Debug, Clone, ConvertSaveload)] #[derive(Component, Debug, ConvertSaveload, Clone)]
pub struct WantsToUseItem { pub struct WantsToUseItem {
pub item: Entity, pub item: Entity,
pub target: Option<Point>, pub target: Option<Point>,
@ -99,10 +101,10 @@ pub struct WantsToDropItem {
pub item: Entity, pub item: Entity,
} }
#[derive(Component, Debug, Serialize, Deserialize)] #[derive(Component, Debug, Serialize, Deserialize, Clone)]
pub struct Consumable {} pub struct Consumable {}
#[derive(Component, Debug, ConvertSaveload)] #[derive(Component, Debug, ConvertSaveload, Clone)]
pub struct ProvidesHealing { pub struct ProvidesHealing {
pub heal_amount: i32, pub heal_amount: i32,
} }
@ -117,19 +119,19 @@ pub struct InflictsDamage {
pub damage: i32, pub damage: i32,
} }
#[derive(Component, Debug, ConvertSaveload)] #[derive(Component, Debug, ConvertSaveload, Clone)]
pub struct AreaOfEffect { pub struct AreaOfEffect {
pub radius: i32, pub radius: i32,
} }
#[derive(Component, Debug, ConvertSaveload)] #[derive(Component, Debug, ConvertSaveload, Clone)]
pub struct Confusion { pub struct Confusion {
pub turns: i32, pub turns: i32,
} }
pub struct SerializeMe; pub struct SerializeMe;
#[derive(Component, Clone, Serialize, Deserialize)] #[derive(Component, Serialize, Deserialize, Clone)]
pub struct SerializationHelper { pub struct SerializationHelper {
pub map: super::map::Map, pub map: super::map::Map,
} }

View File

@ -1,14 +1,14 @@
use rltk::Rltk;
use rltk::RGB;
use rltk::{Point, VirtualKeyCode}; use rltk::{Point, VirtualKeyCode};
use rltk::RGB;
use rltk::Rltk;
use specs::prelude::*; use specs::prelude::*;
use crate::{CombatStats, InBackpack, RunState, State, Viewshed};
use crate::gamelog::GameLog; use crate::gamelog::GameLog;
use crate::Map; use crate::Map;
use crate::Name; use crate::Name;
use crate::Player; use crate::Player;
use crate::Position; use crate::Position;
use crate::{CombatStats, InBackpack, RunState, State, Viewshed};
pub fn draw_ui(ecs: &World, ctx: &mut Rltk) { pub fn draw_ui(ecs: &World, ctx: &mut Rltk) {
ctx.draw_box( ctx.draw_box(
@ -403,6 +403,7 @@ pub enum MainMenuResult {
} }
pub fn main_menu(gs: &mut State, ctx: &mut Rltk) -> 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::<RunState>(); let runstate = gs.ecs.fetch::<RunState>();
ctx.print_color_centered( ctx.print_color_centered(
@ -412,6 +413,7 @@ pub fn main_menu(gs: &mut State, ctx: &mut Rltk) -> MainMenuResult {
"Rust Roguelike Tutorial", "Rust Roguelike Tutorial",
); );
if let RunState::MainMenu { if let RunState::MainMenu {
menu_selection: selection, menu_selection: selection,
} = *runstate } = *runstate
@ -432,22 +434,25 @@ pub fn main_menu(gs: &mut State, ctx: &mut Rltk) -> MainMenuResult {
); );
} }
if selection == MainMenuSelection::LoadGame { if save_exists {
ctx.print_color_centered( if selection == MainMenuSelection::LoadGame {
25, ctx.print_color_centered(
RGB::named(rltk::MAGENTA), 25,
RGB::named(rltk::BLACK), RGB::named(rltk::MAGENTA),
"Load Game", RGB::named(rltk::BLACK),
); "Load Game",
} else { );
ctx.print_color_centered( } else {
25, ctx.print_color_centered(
RGB::named(rltk::WHITE), 25,
RGB::named(rltk::BLACK), RGB::named(rltk::WHITE),
"Load Game", RGB::named(rltk::BLACK),
); "Load Game",
);
}
} }
if selection == MainMenuSelection::Quit { if selection == MainMenuSelection::Quit {
ctx.print_color_centered( ctx.print_color_centered(
26, 26,

View File

@ -206,7 +206,11 @@ impl GameState for State {
} }
gui::MainMenuResult::Selected { selected } => match selected { gui::MainMenuResult::Selected { selected } => match selected {
gui::MainMenuSelection::NewGame => new_run_state = RunState::PreRun, 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), gui::MainMenuSelection::Quit => ::std::process::exit(0),
}, },
} }
@ -214,7 +218,7 @@ impl GameState for State {
RunState::SaveGame => { RunState::SaveGame => {
save_load_system::save_game(&mut self.ecs); save_load_system::save_game(&mut self.ecs);
new_run_state = RunState::MainMenu { 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() }; let mut gs = State { ecs: World::new() };
gs.ecs.insert(rltk::RandomNumberGenerator::new()); gs.ecs.insert(rltk::RandomNumberGenerator::new());
gs.ecs.insert(gamelog::GameLog {
entries: vec!["Welcome to Rusty Roguelike".to_string()],
});
gs.ecs.register::<Position>(); gs.ecs.register::<Position>();
gs.ecs.register::<Renderable>(); gs.ecs.register::<Renderable>();
@ -265,22 +266,27 @@ fn main() -> rltk::BError {
gs.ecs.register::<Confusion>(); gs.ecs.register::<Confusion>();
gs.ecs.register::<SimpleMarker<SerializeMe>>(); gs.ecs.register::<SimpleMarker<SerializeMe>>();
gs.ecs.register::<SerializationHelper>(); gs.ecs.register::<SerializationHelper>();
gs.ecs.insert(SimpleMarkerAllocator::<SerializeMe>::new());
let map = Map::new_map_rooms_and_corridors();
gs.ecs.insert(SimpleMarkerAllocator::<SerializeMe>::new());
let map = Map::new_map_rooms_and_corridors();
let (player_x, player_y) = map.rooms[0].center(); 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); 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) { for room in map.rooms.iter().skip(1) {
spawner::spawn_room(&mut gs.ecs, room); spawner::spawn_room(&mut gs.ecs, room);
} }
gs.ecs.insert(map); gs.ecs.insert(map);
gs.ecs.insert(Point::new(player_x, player_y));
gs.ecs.insert(player_entity);
gs.ecs.insert(RunState::MainMenu { gs.ecs.insert(RunState::MainMenu {
menu_selection: gui::MainMenuSelection::NewGame, menu_selection: gui::MainMenuSelection::NewGame,
}); });
gs.ecs.insert(gamelog::GameLog {
entries: vec!["Welcome to Rusty Roguelike".to_string()],
});
rltk::main_loop(context, gs) rltk::main_loop(context, gs)
} }

View File

@ -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 { pub fn new_map_rooms_and_corridors() -> Map {
let mut map = Map { let mut map = Map {
tiles: vec![TileType::Wall; MAP_COUNT], tiles: vec![TileType::Wall; MAP_COUNT],
@ -116,37 +137,11 @@ impl Map {
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 { impl BaseMap for Map {
fn is_opaque(&self, idx: usize) -> bool { 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 { 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) { pub fn draw_map(ecs: &World, ctx: &mut Rltk) {
let map = ecs.fetch::<Map>(); let map = ecs.fetch::<Map>();
@ -203,12 +204,12 @@ pub fn draw_map(ecs: &World, ctx: &mut Rltk) {
let mut fg; let mut fg;
match tile { match tile {
TileType::Floor => { 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('.'); glyph = rltk::to_cp437('.');
} }
TileType::Wall => { TileType::Wall => {
fg = RGB::from_f32(0.0, 1.0, 0.0); fg = RGB::from_f32(0., 1.0, 0.);
glyph = rltk::to_cp437('#'); glyph = rltk::to_cp437('#');
} }
} }
@ -219,7 +220,7 @@ pub fn draw_map(ecs: &World, ctx: &mut Rltk) {
} }
x += 1; x += 1;
if x > 79 { if x > MAP_WIDTH as i32 - 1 {
x = 0; x = 0;
y += 1; y += 1;
} }

View File

@ -3,12 +3,12 @@ use std::cmp::{max, min};
use rltk::{Point, Rltk, VirtualKeyCode}; use rltk::{Point, Rltk, VirtualKeyCode};
use specs::prelude::*; use specs::prelude::*;
use crate::gamelog::GameLog;
use crate::{ use crate::{
components::{CombatStats, Player, Position, Viewshed, WantsToMelee}, components::{CombatStats, Player, Position, Viewshed, WantsToMelee},
map::Map, Item,
Item, RunState, State, WantsToPickupItem, map::Map, RunState, State, WantsToPickupItem,
}; };
use crate::gamelog::GameLog;
pub fn try_move_player(delta_x: i32, delta_y: i32, ecs: &mut World) { pub fn try_move_player(delta_x: i32, delta_y: i32, ecs: &mut World) {
let mut positions = ecs.write_storage::<Position>(); let mut positions = ecs.write_storage::<Position>();
@ -20,8 +20,9 @@ pub fn try_move_player(delta_x: i32, delta_y: i32, ecs: &mut World) {
let map = ecs.fetch::<Map>(); let map = ecs.fetch::<Map>();
for (entity, _player, pos, viewshed) in 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); let destination_idx = map.xy_idx(pos.x + delta_x, pos.y + delta_y);
for potential_target in map.tile_content[destination_idx].iter() { for potential_target in map.tile_content[destination_idx].iter() {

View File

@ -168,7 +168,7 @@ pub fn magic_missile_scroll(ecs: &mut World, x: i32, y: i32) {
.with(Item {}) .with(Item {})
.with(Consumable {}) .with(Consumable {})
.with(Ranged { range: 6 }) .with(Ranged { range: 6 })
.with(InflictsDamage { damage: 8 }) .with(InflictsDamage { damage: 20 })
.marked::<SimpleMarker<SerializeMe>>() .marked::<SimpleMarker<SerializeMe>>()
.build(); .build();
} }
@ -178,7 +178,7 @@ pub fn fireball_scroll(ecs: &mut World, x: i32, y: i32) {
.with(Position { x, y }) .with(Position { x, y })
.with(Renderable { .with(Renderable {
glyph: rltk::to_cp437(')'), glyph: rltk::to_cp437(')'),
fg: RGB::named(rltk::CYAN), fg: RGB::named(rltk::ORANGE),
bg: RGB::named(rltk::BLACK), bg: RGB::named(rltk::BLACK),
render_order: 2, render_order: 2,
}) })
@ -199,7 +199,7 @@ pub fn confusion_scroll(ecs: &mut World, x: i32, y: i32) {
.with(Position { x, y }) .with(Position { x, y })
.with(Renderable { .with(Renderable {
glyph: rltk::to_cp437(')'), glyph: rltk::to_cp437(')'),
fg: RGB::named(rltk::CYAN), fg: RGB::named(rltk::PINK),
bg: RGB::named(rltk::BLACK), bg: RGB::named(rltk::BLACK),
render_order: 2, render_order: 2,
}) })

View File

@ -25,7 +25,6 @@ impl<'a> System<'a> for VisibilitySystem {
} }
viewshed.dirty = false; 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 = field_of_view(Point::new(pos.x, pos.y), viewshed.range, &*map);
viewshed viewshed
.visible_tiles .visible_tiles