Preparing for combat

This commit is contained in:
Michael Smith 2021-10-25 23:56:05 +02:00
parent 99795856af
commit d81ace4555
3 changed files with 334 additions and 156 deletions

82
Cargo.lock generated
View File

@ -14,22 +14,82 @@ version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e70cc2f62c6ce1868963827bd677764c62d07c3d9a3e1fb1177ee1a9ab199eb2" checksum = "e70cc2f62c6ce1868963827bd677764c62d07c3d9a3e1fb1177ee1a9ab199eb2"
[[package]]
name = "fuchsia-cprng"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
[[package]] [[package]]
name = "lazy_static" name = "lazy_static"
version = "0.1.16" version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf186d1a8aa5f5bee5fd662bc9c1b949e0259e1bcc379d1f006847b0080c7417" checksum = "cf186d1a8aa5f5bee5fd662bc9c1b949e0259e1bcc379d1f006847b0080c7417"
[[package]]
name = "libc"
version = "0.2.105"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "869d572136620d55835903746bcb5cdc54cb2851fd0aeec53220b4bb65ef3013"
[[package]] [[package]]
name = "pkg-config" name = "pkg-config"
version = "0.3.19" version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c"
[[package]]
name = "rand"
version = "0.3.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c"
dependencies = [
"libc",
"rand 0.4.6",
]
[[package]]
name = "rand"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293"
dependencies = [
"fuchsia-cprng",
"libc",
"rand_core 0.3.1",
"rdrand",
"winapi",
]
[[package]]
name = "rand_core"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
dependencies = [
"rand_core 0.4.2",
]
[[package]]
name = "rand_core"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
[[package]]
name = "rdrand"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
dependencies = [
"rand_core 0.3.1",
]
[[package]] [[package]]
name = "roguelike" name = "roguelike"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"rand 0.3.23",
"tcod", "tcod",
] ]
@ -53,3 +113,25 @@ dependencies = [
"cc", "cc",
"pkg-config", "pkg-config",
] ]
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

View File

@ -7,3 +7,4 @@ edition = "2018"
[dependencies] [dependencies]
tcod = "*" tcod = "*"
rand = "0.3.9"

View File

@ -3,9 +3,11 @@
#![allow(unused_mut)] #![allow(unused_mut)]
#![allow(dead_code)] #![allow(dead_code)]
use rand::Rng;
use std::cmp; use std::cmp;
use tcod::colors::*; use tcod::colors::*;
use tcod::console::*; use tcod::console::*;
use tcod::map::{FovAlgorithm, Map as FovMap};
const SCREEN_WIDTH: i32 = 80; const SCREEN_WIDTH: i32 = 80;
const SCREEN_HEIGHT: i32 = 50; const SCREEN_HEIGHT: i32 = 50;
@ -13,15 +15,32 @@ const FPS: i32 = 20;
const MAP_WIDTH: i32 = 80; const MAP_WIDTH: i32 = 80;
const MAP_HEIGHT: i32 = 45; const MAP_HEIGHT: i32 = 45;
const COLOR_DARK_WALL: Color = Color { r: 0, g: 0, b: 100 }; const COLOR_DARK_WALL: Color = Color { r: 0, g: 0, b: 100 };
const COLOR_LIGHT_WALL: Color = Color {
r: 130,
g: 110,
b: 50,
};
const COLOR_DARK_GROUND: Color = Color { const COLOR_DARK_GROUND: Color = Color {
r: 50, r: 50,
g: 50, g: 50,
b: 150, b: 150,
}; };
const COLOR_LIGHT_GROUND: Color = Color {
r: 200,
g: 180,
b: 50,
};
const ROOM_MAX_SIZE: i32 = 10;
const ROOM_MIN_SIZE: i32 = 6;
const MAX_ROOMS: i32 = 30;
const FOV_ALGO: FovAlgorithm = FovAlgorithm::Basic;
const FOV_LIGHT_WALLS: bool = true;
const TORCH_RADIUS: i32 = 10;
struct Tcod { struct Tcod {
root: Root, root: Root,
con: Offscreen, con: Offscreen,
fov: FovMap,
} }
#[derive(Debug)] #[derive(Debug)]
@ -55,6 +74,7 @@ impl Object {
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
struct Tile { struct Tile {
blocked: bool, blocked: bool,
explored: bool,
block_sight: bool, block_sight: bool,
} }
@ -62,6 +82,7 @@ impl Tile {
pub fn empty() -> Self { pub fn empty() -> Self {
Tile { Tile {
blocked: false, blocked: false,
explored: false,
block_sight: false, block_sight: false,
} }
} }
@ -69,6 +90,7 @@ impl Tile {
pub fn wall() -> Self { pub fn wall() -> Self {
Tile { Tile {
blocked: true, blocked: true,
explored: false,
block_sight: true, block_sight: true,
} }
} }
@ -98,6 +120,16 @@ impl Rect {
y2: y + h, y2: y + h,
} }
} }
pub fn center(&self) -> (i32, i32) {
let center_x = (self.x1 + self.x2) / 2;
let center_y = (self.y1 + self.y2) / 2;
(center_x, center_y)
}
pub fn intersects_with(&self, other: &Rect) -> bool {
(self.x1 <= other.x2) && (self.x2 >= other.x1) && (self.y1 <= other.y2) && (self.y2 >= other.y1)
}
} }
fn handle_keys(tcod: &mut Tcod, game: &Game, player: &mut Object) -> bool { fn handle_keys(tcod: &mut Tcod, game: &Game, player: &mut Object) -> bool {
@ -127,16 +159,44 @@ fn handle_keys(tcod: &mut Tcod, game: &Game, player: &mut Object) -> bool {
false false
} }
fn make_map() -> Map { fn make_map(player: &mut Object) -> Map {
// Fill the map with unblocked tiles // Fill the map with unblocked tiles
let mut map = vec![vec![Tile::wall(); MAP_HEIGHT as usize]; MAP_WIDTH as usize]; let mut map = vec![vec![Tile::wall(); MAP_HEIGHT as usize]; MAP_WIDTH as usize];
// Create two rooms let mut rooms = vec![];
let room1 = Rect::new(20, 15, 10, 15);
let room2 = Rect::new(50, 15, 10, 15); for _ in 0..MAX_ROOMS {
create_room(room1, &mut map); let w = rand::thread_rng().gen_range(ROOM_MIN_SIZE, ROOM_MAX_SIZE + 1);
create_room(room2, &mut map); let h = rand::thread_rng().gen_range(ROOM_MIN_SIZE, ROOM_MAX_SIZE + 1);
create_h_tunnel(25, 55, 23, &mut map); let x = rand::thread_rng().gen_range(0, MAP_WIDTH - w);
let y = rand::thread_rng().gen_range(0, MAP_HEIGHT - h);
let new_room = Rect::new(x, y, w, h);
let failed = rooms
.iter()
.any(|other_room| new_room.intersects_with(other_room));
if !failed {
create_room(new_room, &mut map);
let (new_x, new_y) = new_room.center();
if rooms.is_empty() {
player.x = new_x;
player.y = new_y;
} else {
let (prev_x, prev_y) = rooms[rooms.len() - 1].center();
if rand::random() {
create_h_tunnel(prev_x, new_x, prev_y, &mut map);
create_v_tunnel(prev_y, new_y, new_x, &mut map);
} else {
create_v_tunnel(prev_y, new_y, prev_x, &mut map);
create_h_tunnel(prev_x, new_x, new_y, &mut map);
}
}
rooms.push(new_room);
}
}
map map
} }
@ -165,22 +225,42 @@ fn create_v_tunnel(y1: i32, y2: i32, x: i32, map: &mut Map) {
} }
} }
fn render_all(tcod: &mut Tcod, game: &Game, objects: &[Object]) { fn render_all(tcod: &mut Tcod, game: &mut Game, objects: &[Object], fov_recompute: bool) {
if fov_recompute {
let player = &objects[0];
tcod
.fov
.compute_fov(player.x, player.y, TORCH_RADIUS, FOV_LIGHT_WALLS, FOV_ALGO);
}
// Draw all objects in the list // Draw all objects in the list
for object in objects { for object in objects {
if tcod.fov.is_in_fov(object.x, object.y) {
object.draw(&mut tcod.con); object.draw(&mut tcod.con);
} }
}
// Go through all tiles and set their background color // Go through all tiles and set their background color
for y in 0..MAP_HEIGHT { for y in 0..MAP_HEIGHT {
for x in 0..MAP_WIDTH { for x in 0..MAP_WIDTH {
let visible = tcod.fov.is_in_fov(x, y);
let wall = game.map[x as usize][y as usize].block_sight; let wall = game.map[x as usize][y as usize].block_sight;
if wall { let color = match (visible, wall) {
tcod.con // Outside fov:
.set_char_background(x, y, COLOR_DARK_WALL, BackgroundFlag::Set); (false, true) => COLOR_DARK_WALL,
} else { (false, false) => COLOR_DARK_GROUND,
tcod.con // INside fov:
.set_char_background(x, y, COLOR_DARK_GROUND, BackgroundFlag::Set) (true, true) => COLOR_LIGHT_WALL,
(true, false) => COLOR_LIGHT_GROUND,
};
let explored = &mut game.map[x as usize][y as usize].explored;
if visible {
*explored = true;
}
if *explored {
tcod
.con
.set_char_background(x, y, color, BackgroundFlag::Set);
} }
} }
} }
@ -207,12 +287,14 @@ fn main() {
.title("Rust/libtcod tutorial") .title("Rust/libtcod tutorial")
.init(); .init();
let con = Offscreen::new(MAP_WIDTH, MAP_HEIGHT); let mut tcod = Tcod {
root,
let mut tcod = Tcod { root, con }; con: Offscreen::new(MAP_WIDTH, MAP_HEIGHT),
fov: FovMap::new(MAP_WIDTH, MAP_HEIGHT),
};
// Create player object // Create player object
let player = Object::new(25, 23, '@', WHITE); let player = Object::new(0, 0, '@', WHITE);
// // Create an NPC // // Create an NPC
let npc = Object::new(SCREEN_WIDTH / 2 - 5, SCREEN_HEIGHT / 2, '@', YELLOW); let npc = Object::new(SCREEN_WIDTH / 2 - 5, SCREEN_HEIGHT / 2, '@', YELLOW);
@ -220,22 +302,35 @@ fn main() {
// List of objects in the world // List of objects in the world
let mut objects = [player, npc]; let mut objects = [player, npc];
let game = Game { let mut game = Game {
// Generate map // Generate map
map: make_map(), map: make_map(&mut objects[0]),
}; };
// Populate FOV map, according to generated map
for y in 0..MAP_HEIGHT {
for x in 0..MAP_WIDTH {
tcod.fov.set(
x,
y,
!game.map[x as usize][y as usize].block_sight,
!game.map[x as usize][y as usize].blocked,
)
}
}
let mut previous_player_position = (-1, -1);
// Main game loop
while !tcod.root.window_closed() { while !tcod.root.window_closed() {
tcod.con.clear(); tcod.con.clear();
for object in &objects { let fov_recompute = previous_player_position != (objects[0].x, objects[0].y);
object.draw(&mut tcod.con) render_all(&mut tcod, &mut game, &objects, fov_recompute);
}
render_all(&mut tcod, &game, &objects);
tcod.root.flush(); tcod.root.flush();
let player = &mut objects[0]; let player = &mut objects[0];
previous_player_position = (player.x, player.y);
let exit = handle_keys(&mut tcod, &game, player); let exit = handle_keys(&mut tcod, &game, player);
if exit { if exit {
break; break;