diff options
author | Iago Garrido <iago086@gmail.com> | 2019-11-12 14:55:19 +0100 |
---|---|---|
committer | Iago Garrido <iago086@gmail.com> | 2019-11-12 14:55:19 +0100 |
commit | 76fc41b3c803ad4db3c19a76d408ab301438aa1e (patch) | |
tree | 99df93ff7678775a4cb179fbd6a0b52a15ede426 | |
parent | d84906ec92e45ed2cf2611c2f646d72ef5f1bb64 (diff) | |
parent | 8fa3fa881bc3b954e136295fe6cc7022737ae9db (diff) |
Merge branch 'master' of https://github.com/Etenil/roguerust
-rw-r--r-- | .vscode/launch.json | 2 | ||||
-rw-r--r-- | src/computer.rs | 36 | ||||
-rw-r--r-- | src/entities.rs (renamed from src/character.rs) | 124 | ||||
-rw-r--r-- | src/main.rs | 26 | ||||
-rw-r--r-- | src/state.rs | 6 | ||||
-rw-r--r-- | src/tiling.rs | 52 | ||||
-rw-r--r-- | src/world.rs | 132 |
7 files changed, 208 insertions, 170 deletions
diff --git a/.vscode/launch.json b/.vscode/launch.json index dfa5895..e2e657d 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -16,7 +16,7 @@ "externalConsole": true
},
{
- "name": "(OSX) Launch",
+ "name": "(Unix) Launch",
"type": "lldb",
"request": "launch",
"program": "${workspaceRoot}/target/debug/roguelike",
diff --git a/src/computer.rs b/src/computer.rs deleted file mode 100644 index a8b9b3e..0000000 --- a/src/computer.rs +++ /dev/null @@ -1,36 +0,0 @@ -pub struct Computer {
- level: i32,
- difficulty: i32,
-}
-
-pub trait Enemy {
- fn new(level: i32, difficulty: i32) -> Self;
-
- fn action(&self) -> (i32, i32);
-
- fn level_up(&mut self);
-
- fn stats(&self) -> String;
-}
-
-impl Enemy for Computer {
- fn new(level: i32, difficulty: i32) -> Computer {
- Computer {
- level: level,
- difficulty: difficulty
- }
- }
-
- fn action(&self) -> (i32, i32) {
- (self.level, self.difficulty)
- }
-
- fn level_up(&mut self) {
- self.level += 1;
- self.difficulty += 3;
- }
-
- fn stats(&self) -> String {
- format!("level: {} difficulty: {}", self.level, self.difficulty)
- }
-}
diff --git a/src/character.rs b/src/entities.rs index ded4fa4..145741c 100644 --- a/src/character.rs +++ b/src/entities.rs @@ -1,7 +1,14 @@ use std::cmp;
-use crate::world::Point;
+use crate::world::{Point, Direction};
+use crate::tiling::TileType;
+pub trait Entity {
+ fn info(&self) -> String;
+ fn place(&mut self, location: Point);
+}
+
+#[derive(Clone)]
pub struct Character {
pub name: String,
pub class: String,
@@ -11,46 +18,80 @@ pub struct Character { dodge: i32,
luck: i32,
xp: i32,
- gold: i32,
- location: Point
+ location: Point,
+ tile_type: TileType
}
-pub trait Player {
+pub trait Enemy {
fn new(
- name: String,
class: String,
health: i32,
attack: i32,
dodge: i32,
luck: i32,
- ) -> Character;
-
- fn place(&mut self, location: Point);
+ location: Point
+ ) -> Self;
- fn select(&self, player_name: String, player_luck: i32) -> Self;
+ fn set_tile_type(&mut self, tile_type: TileType);
+}
+pub trait Player {
+ fn new(
+ name: String,
+ class: String,
+ health: i32,
+ attack: i32,
+ dodge: i32,
+ luck: i32,
+ location: Point
+ ) -> Self;
fn damage(&mut self, damage_amount: i32);
-
fn heal(&mut self, heal_amount: i32);
-
fn attack(&self) -> i32;
-
fn dodge(&self) -> i32;
-
- fn info(&self) -> String;
-
fn stats(&self) -> String;
-
fn walk(&mut self, dir: Direction);
+}
- fn get_gold(&self) -> i32;
+impl Entity for Character {
+ fn place(&mut self, location: Point) {
+ self.location = location;
+ }
+
+ fn info(&self) -> String {
+ format!(
+ "{} \thp: {} attack: {} dodge: {} luck: {}",
+ self.class, self.health, self.attack, self.dodge, self.luck
+ )
+ }
}
-pub enum Direction {
- North,
- South,
- East,
- West
+impl Enemy for Character {
+ fn new(
+ class: String,
+ health: i32,
+ attack: i32,
+ dodge: i32,
+ luck: i32,
+ location: Point
+ ) -> Character {
+ Character {
+ name: class.clone(),
+ class: class.clone(),
+ max_health: health,
+ health,
+ attack,
+ dodge,
+ luck,
+ xp: 0,
+ location: location,
+ tile_type: TileType::Character
+ }
+ }
+
+ fn set_tile_type(&mut self, tile_type: TileType) {
+ self.tile_type = tile_type
+ }
}
impl Player for Character {
@@ -61,6 +102,7 @@ impl Player for Character { attack: i32,
dodge: i32,
luck: i32,
+ location: Point
) -> Character {
Character {
name: name,
@@ -71,26 +113,11 @@ impl Player for Character { dodge: dodge,
luck: luck,
xp: 0,
- gold: 0,
- location: (0, 0),
+ location: location,
+ tile_type: TileType::Player
}
}
- fn place(&mut self, location: Point) {
- self.location = location;
- }
-
- fn select(&self, player_name: String, player_luck: i32) -> Self {
- Self::new(
- player_name,
- self.class.to_string(),
- self.health,
- self.attack,
- self.dodge,
- self.luck + player_luck,
- )
- }
-
fn walk(&mut self, dir: Direction) {
match dir {
Direction::North => { (); },
@@ -120,23 +147,12 @@ impl Player for Character { self.xp + self.dodge + self.luck / 2
}
- fn info(&self) -> String {
- format!(
- "{} \thp: {} attack: {} dodge: {} luck: {}",
- self.class, self.health, self.attack, self.dodge, self.luck
- )
- }
-
fn stats(&self) -> String {
format!(
- "{} - hp: {}/{} attack: {} dodge: {} luck: {} experience: {} gold: {}",
- self.class, self.health, self.max_health, self.attack, self.dodge, self.luck, self.xp, self.gold
+ "{} - hp: {}/{} attack: {} dodge: {} luck: {} experience: {}",
+ self.class, self.health, self.max_health, self.attack, self.dodge, self.luck, self.xp
)
}
-
- fn get_gold(&self) -> i32 {
- self.gold
- }
}
#[cfg(test)]
@@ -144,8 +160,8 @@ mod tests { use super::*;
fn test_attack() {
- let player = Character::new("".to_string(), "Rogue".to_string(), 1, 4, 1, 4);
+ let bob: Character = Enemy::new("Rogue".to_string(), 1, 4, 1, 4, (0, 0));
- assert_eq!(player.attack(), 6);
+ assert_eq!(bob.attack(), 6);
}
}
diff --git a/src/main.rs b/src/main.rs index 8662438..12e92c9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,33 +4,36 @@ extern crate pancurses; #[macro_use] extern crate text_io; -mod character; -mod computer; mod state; +mod entities; mod world; +mod tiling; -use character::Player; -use character::Character; +use entities::Player; use pancurses::{ initscr, endwin, - Input + Input, + noecho }; use state::State; use world::Dungeon; fn main() { + let window = initscr(); + let mut state = State::new( - Character::new( + Player::new( "Kshar".to_string(), - "Warror".to_string(), + "Warrior".to_string(), 30, 10, 10, 20, + (0, 0) ), - Dungeon::new(80, 24, 5), + Dungeon::new(window.get_max_x() as usize, window.get_max_y() as usize, 5), ); state.init(); @@ -38,10 +41,11 @@ fn main() { // Dump the whole dungeon structure in terminal for debugging state.debug(); - let window = initscr(); - state.render_level(&window); + window.keypad(true); + noecho(); + loop { // update actors // update character @@ -61,6 +65,4 @@ fn main() { } } endwin(); - - println!("You quit with {} gold pieces", state.character.get_gold()) } diff --git a/src/state.rs b/src/state.rs index 3e8516b..20b49d7 100644 --- a/src/state.rs +++ b/src/state.rs @@ -1,10 +1,8 @@ use pancurses::Window; use std::env; -use crate::character::Character; -use crate::character::Player; -use crate::computer::Enemy; -use crate::world::{Dungeon, Generable, Level}; +use crate::entities::{Character, Entity}; +use crate::world::{Dungeon, Generatable, Level}; pub struct State { pub character: Character, diff --git a/src/tiling.rs b/src/tiling.rs new file mode 100644 index 0000000..139af24 --- /dev/null +++ b/src/tiling.rs @@ -0,0 +1,52 @@ +pub struct TileGrid { + grid: Vec<Vec<TileType>> +} + +impl<'a> TileGrid { + pub fn new(xsize: usize, ysize: usize) -> TileGrid { + let mut grid = TileGrid { + grid: Vec::with_capacity(ysize) + }; + + for _ in 0..ysize { + let mut subvec = Vec::with_capacity(xsize); + for _ in 0..xsize { + subvec.push(TileType::Empty); + } + grid.grid.push(subvec); + } + + return grid; + } + + pub fn set_tile(&mut self, x: usize, y: usize, tile: TileType) { + self.grid[y][x] = tile; + } + + /// Sets a tile if nothing lies underneath it. + pub fn set_empty_tile(&mut self, x: usize, y: usize, tile: TileType) { + self.set_tile(x, y, match self.grid[y][x] { + TileType::Empty => tile, + _ => self.grid[y][x].clone() + }) + } + + pub fn raw_data(&'a self) -> &'a Vec<Vec<TileType>> { + &self.grid + } +} + +pub trait Tileable { + fn tile(&self, grid: &mut TileGrid) -> Result<(), String>; +} + +#[derive(Clone)] +pub enum TileType { + Empty, + Wall, + Floor, + StairsUp, + StairsDown, + Character, + Player +} diff --git a/src/world.rs b/src/world.rs index 4f2a645..bf8b498 100644 --- a/src/world.rs +++ b/src/world.rs @@ -1,16 +1,15 @@ use rand::Rng;
use pancurses::{Window};
+use crate::entities::{Entity};
+use crate::tiling::{TileGrid, Tileable, TileType};
pub type Point = (usize, usize);
-#[derive(Clone)]
-enum TileType {
- Empty,
- Wall,
- Floor,
- StairsUp,
- StairsDown,
- Character,
+pub enum Direction {
+ North,
+ South,
+ East,
+ West
}
enum CorridorType {
@@ -18,10 +17,6 @@ enum CorridorType { Vertical
}
-trait Tileable {
- fn tile(&self, grid: &mut TileGrid) -> Result<(), String>;
-}
-
const LEFT: (i8, i8) = (-1i8, 0);
const RIGHT: (i8, i8) = (1i8, 0);
const UP: (i8, i8) = (0, -1i8);
@@ -59,7 +54,7 @@ impl Room { start,
width,
height,
- center: (start.0 + width / 2, start.1 + height / 2),
+ center: (start.0 + (width as f32 / 2.0) as usize, start.1 + (height as f32 / 2.0) as usize),
edges: [
RoomEdge::new(start, (start.0 + width, start.1), UP),
RoomEdge::new(start, (start.0, start.1 + height), LEFT),
@@ -145,49 +140,14 @@ impl Tileable for Corridor { }
}
-pub struct TileGrid {
- grid: Vec<Vec<TileType>>
-}
-
-impl<'a> TileGrid {
- pub fn new(xsize: usize, ysize: usize) -> TileGrid {
- let mut grid = TileGrid {
- grid: Vec::with_capacity(ysize)
- };
-
- for _ in 0..ysize {
- let mut subvec = Vec::with_capacity(xsize);
- for _ in 0..xsize {
- subvec.push(TileType::Empty);
- }
- grid.grid.push(subvec);
- }
-
- return grid;
- }
-
- fn set_tile(&mut self, x: usize, y: usize, tile: TileType) {
- self.grid[y][x] = tile;
- }
-
- /// Sets a tile if nothing lies underneath it.
- fn set_empty_tile(&mut self, x: usize, y: usize, tile: TileType) {
- self.set_tile(x, y, match self.grid[y][x] {
- TileType::Empty => tile,
- _ => self.grid[y][x].clone()
- })
- }
-
- pub fn raw_data(&'a self) -> &'a Vec<Vec<TileType>> {
- &self.grid
- }
-}
-
pub struct Level {
xsize: usize,
ysize: usize,
rooms: Vec<Room>,
- corridors: Vec<Corridor>
+ corridors: Vec<Corridor>,
+ entities: Vec<Box<dyn Entity>>,
+ entrance: Point,
+ exit: Point
}
pub struct Dungeon {
@@ -197,7 +157,7 @@ pub struct Dungeon { pub levels: Vec<Level>
}
-pub trait Generable {
+pub trait Generatable {
fn generate(&mut self);
}
@@ -256,16 +216,23 @@ impl Dungeon { TileType::Empty => " ",
TileType::StairsDown => ">",
TileType::StairsUp => "<",
- TileType::Character => "@",
+ TileType::Player => "@",
+ _ => "?"
}
}
}
-impl Generable for Dungeon {
+impl Generatable for Dungeon {
fn generate(&mut self) {
- for _ in 0..self.depth {
- let mut level = Level::new(self.xsize, self.ysize, None);
+ let mut level = Level::new(self.xsize, self.ysize, None);
+ level.generate();
+ let mut next_entrance = level.get_exit();
+ self.levels.push(level);
+
+ for _ in 1..self.depth {
+ level = Level::new(self.xsize, self.ysize, Some(next_entrance));
level.generate();
+ next_entrance = level.get_exit();
self.levels.push(level);
}
}
@@ -279,8 +246,14 @@ impl Level { Level {
xsize,
ysize,
- rooms: Vec::new(),
- corridors: Vec::new()
+ rooms: vec![],
+ corridors: vec![],
+ entities: vec![],
+ entrance: match start {
+ Some(st) => st,
+ None => (0, 0)
+ },
+ exit: (0, 0)
}
}
@@ -295,6 +268,9 @@ impl Level { corridor.tile(&mut grid)?;
}
+ grid.set_tile(self.entrance.0, self.entrance.1, TileType::StairsUp);
+ grid.set_tile(self.exit.0, self.exit.1, TileType::StairsDown);
+
Ok(grid)
}
@@ -316,6 +292,14 @@ impl Level { }
}
+ pub fn get_entrance(&self) -> Point {
+ self.entrance
+ }
+
+ pub fn get_exit(&self) -> Point {
+ self.exit
+ }
+
fn overlaps(&self, start: Point, width: usize, height: usize, padding: usize) -> bool {
for room in &self.rooms {
if room.start.0 < start.0 + width + padding &&
@@ -344,8 +328,8 @@ impl Level { fn random_room(&self) -> Result<Room, String> {
// TODO: Detect when not enough space is left to allocate a room.
let mut rng = rand::thread_rng();
- let room_width = rng.gen_range(3, 12);
- let room_height = rng.gen_range(3, 12);
+ let room_width = rng.gen_range(4, 12);
+ let room_height = rng.gen_range(4, 12);
// TODO: Find a way to write a lambda to generate the start point.
let mut start: Point = (
@@ -362,15 +346,32 @@ impl Level { Ok(Room::new(start, room_width, room_height))
}
+
+ fn centered_room(&self, center: Point) -> Room {
+ let mut rng = rand::thread_rng();
+ let room_width = rng.gen_range(3, 12);
+ let room_height = rng.gen_range(3, 12);
+
+ let start = (
+ (center.0 as f32 - (room_width as f32 / 2f32)).round() as usize,
+ (center.1 as f32 - (room_height as f32 / 2f32)).round() as usize
+ );
+
+ Room::new(start, room_width, room_height)
+ }
}
-impl Generable for Level {
+impl Generatable for Level {
fn generate(&mut self) {
let mut rng = rand::thread_rng();
let room_number = rng.gen_range(3, 5);
+ if self.entrance != (0, 0) {
+ self.rooms.push(self.centered_room(self.entrance));
+ }
+
// Generate rooms
- for _ in 0..room_number {
+ for _ in self.rooms.len()..room_number {
self.rooms.push(self.random_room().unwrap());
}
@@ -409,6 +410,11 @@ impl Generable for Level { CorridorType::Vertical
));
}
+
+ if self.entrance == (0, 0) {
+ self.entrance = self.rooms[0].center;
+ }
+ self.exit = self.rooms.last().unwrap().center;
}
}
|