Character progression

This commit is contained in:
Michael Smith 2021-11-17 22:23:36 +01:00
parent 4f543d7298
commit b8f68df801

View File

@ -81,6 +81,7 @@ struct Object {
fighter: Option<Fighter>,
ai: Option<Ai>,
item: Option<Item>,
always_visible: bool,
}
impl Object {
@ -96,6 +97,7 @@ impl Object {
fighter: None,
ai: None,
item: None,
always_visible: false,
}
}
@ -209,6 +211,7 @@ struct Game {
map: Map,
messages: Messages,
inventory: Vec<Object>,
dungeon_level: u32,
}
// A rectangle on the map, used to characterise a room.
@ -394,6 +397,17 @@ fn handle_keys(tcod: &mut Tcod, game: &mut Game, objects: &mut Vec<Object>) -> P
DidntTakeTurn
}
(Key { code: Text, .. }, "<", true) => {
// Go down stairs, if the player is on them
let player_on_stairs = objects
.iter()
.any(|object| object.pos() == objects[PLAYER].pos() && object.name == "stairs");
if player_on_stairs {
next_level(tcod, game, objects);
}
DidntTakeTurn
}
_ => DidntTakeTurn,
}
}
@ -402,6 +416,11 @@ fn make_map(objects: &mut Vec<Object>) -> Map {
// Fill the map with unblocked tiles
let mut map = vec![vec![Tile::wall(); MAP_HEIGHT as usize]; MAP_WIDTH as usize];
// Player is the first element, remove everything else.
// NOTE: works only when the player is the first object!
assert_eq!(&objects[PLAYER] as *const _, &objects[0] as *const _);
objects.truncate(1);
let mut rooms = vec![];
for _ in 0..MAX_ROOMS {
@ -437,6 +456,12 @@ fn make_map(objects: &mut Vec<Object>) -> Map {
}
}
// Create stairs at the center of the last room
let (last_room_x, last_room_y) = rooms[rooms.len() - 1].center();
let mut stairs = Object::new(last_room_x, last_room_y, '<', "stairs", WHITE, false);
stairs.always_visible = true;
objects.push(stairs);
map
}
@ -515,7 +540,7 @@ fn place_objects(room: Rect, map: &Map, objects: &mut Vec<Object>) {
// Only place it if the tile is note blocked
if !is_blocked(x, y, map, objects) {
let dice = rand::random::<f32>();
let item = if dice < 0.7 {
let mut item = if dice < 0.7 {
// Create a healing potion (70% chance)
let mut object = Object::new(x, y, '!', "healing potion", VIOLET, false);
object.item = Some(Item::Heal);
@ -537,6 +562,7 @@ fn place_objects(room: Rect, map: &Map, objects: &mut Vec<Object>) {
object
};
item.always_visible = true;
objects.push(item);
}
}
@ -1100,7 +1126,10 @@ fn render_all(tcod: &mut Tcod, game: &mut Game, objects: &[Object], fov_recomput
// Only render objects in fov
let mut to_draw: Vec<_> = objects
.iter()
.filter(|o| tcod.fov.is_in_fov(o.x, o.y))
.filter(|o| {
tcod.fov.is_in_fov(o.x, o.y)
|| (o.always_visible && game.map[o.x as usize][o.y as usize].explored)
})
.collect();
// Sort so that non-blocking objects are rendered behind blocking objects
@ -1166,6 +1195,15 @@ fn render_all(tcod: &mut Tcod, game: &mut Game, objects: &[Object], fov_recomput
DARKER_RED,
);
// Display the current level
tcod.panel.print_ex(
1,
3,
BackgroundFlag::None,
TextAlignment::Left,
format!("Dungeon level: {}", game.dungeon_level),
);
// Display names of objects under the mouse
tcod.panel.set_default_foreground(LIGHT_GREY);
tcod.panel.print_ex(
@ -1235,6 +1273,7 @@ fn new_game(tcod: &mut Tcod) -> (Game, Vec<Object>) {
map: make_map(&mut objects),
messages: Messages::new(),
inventory: vec![],
dungeon_level: 1,
};
initialise_fov(tcod, &game.map);
@ -1365,6 +1404,26 @@ fn msgbox(text: &str, width: i32, root: &mut Root) {
menu(text, options, width, root);
}
// Advance to the next level
fn next_level(tcod: &mut Tcod, game: &mut Game, objects: &mut Vec<Object>) {
game.messages.add(
"You take a moment to rest, and recover your strength.",
VIOLET,
);
let heal_hp = objects[PLAYER].fighter.map_or(0, |f| f.max_hp / 2);
objects[PLAYER].heal(heal_hp);
game.messages.add(
"After a rare moment of peace, you descend deeper into \
the heart of the dungeon...",
RED,
);
game.dungeon_level += 1;
game.map = make_map(objects);
initialise_fov(tcod, &game.map);
}
fn main() {
tcod::system::set_fps(FPS);