Using items

This commit is contained in:
Michael Smith 2021-11-01 00:03:55 +01:00
parent 838dd7749e
commit 3a31fab361

View File

@ -47,6 +47,7 @@ const MSG_X: i32 = BAR_WIDTH + 2;
const MSG_WIDTH: i32 = SCREEN_WIDTH - BAR_WIDTH - 2;
const MSG_HEIGHT: usize = PANEL_HEIGHT as usize - 1;
const MAX_ROOM_ITEMS: i32 = 2;
const INVENTORY_WIDTH: i32 = 50;
struct Tcod {
root: Root,
@ -68,6 +69,7 @@ struct Object {
alive: bool,
fighter: Option<Fighter>,
ai: Option<Ai>,
item: Option<Item>,
}
impl Object {
@ -82,6 +84,7 @@ impl Object {
alive: false,
fighter: None,
ai: None,
item: None,
}
}
@ -316,6 +319,27 @@ fn handle_keys(tcod: &mut Tcod, game: &mut Game, objects: &mut Vec<Object>) -> P
TookTurn
}
(Key { code: Text, .. }, "g", true) => {
// Pick up an item
let item_id = objects
.iter()
.position(|object| object.pos() == objects[PLAYER].pos() && object.item.is_some());
if let Some(item_id) = item_id {
pick_item_up(item_id, game, objects);
}
DidntTakeTurn
}
(Key { code: Text, .. }, "i", true) => {
// Show the inventory
inventory_menu(
&game.inventory,
"Press the key next to an item to use it, or any other to cancel.\n",
&mut tcod.root,
);
TookTurn
}
_ => DidntTakeTurn,
}
}
@ -438,6 +462,7 @@ fn place_objects(room: Rect, map: &Map, objects: &mut Vec<Object>) {
if !is_blocked(x, y, map, objects) {
// Create a healing potion
let mut object = Object::new(x, y, '!', "healing potion", VIOLET, false);
object.item = Some(Item::Heal);
objects.push(object);
}
}
@ -546,6 +571,85 @@ fn monster_death(monster: &mut Object, game: &mut Game) {
monster.name = format!("remains of {}", monster.name);
}
fn menu<T: AsRef<str>>(header: &str, options: &[T], width: i32, root: &mut Root) -> Option<usize> {
// Limit the amount of menu options
assert!(
options.len() <= 26,
"Cannot have a menu with more than 26 options."
);
// Calculate total height for the header (after auto-wrap) and one line per option
let header_height = root.get_height_rect(0, 0, width, SCREEN_HEIGHT, header);
let height = options.len() as i32 + header_height;
// Create an off-screen console that represents the menu's window
let mut window = Offscreen::new(width, height);
// Print the header, with auto-wrap
window.set_default_foreground(WHITE);
window.print_rect_ex(
0,
0,
width,
height,
BackgroundFlag::None,
TextAlignment::Left,
header,
);
// Print all the options
for (index, option_text) in options.iter().enumerate() {
let menu_letter = (b'a' + index as u8) as char;
let text = format!("({}) {}", menu_letter, option_text.as_ref());
window.print_ex(
0,
header_height + index as i32,
BackgroundFlag::None,
TextAlignment::Left,
text,
);
}
// Blit the contents of the menu window to the root console
let x = SCREEN_WIDTH / 2 - width / 2;
let y = SCREEN_HEIGHT / 2 - height / 2;
blit(&window, (0, 0), (width, height), root, (x, y), 1.0, 0.7);
// Present the root console to the player and wait for a key-press
root.flush();
let key = root.wait_for_keypress(true);
// Convert the ASCII code to an index; if it corresponds to an option, return it
if key.printable.is_alphabetic() {
let index = key.printable.to_ascii_lowercase() as usize - 'a' as usize;
if index < options.len() {
Some(index)
} else {
None
}
} else {
None
}
}
fn inventory_menu(inventory: &[Object], header: &str, root: &mut Root) -> Option<usize> {
// Show a menu with each inventory item as an option
let options = if inventory.len() == 0 {
vec!["Inventory is empty.".into()]
} else {
inventory.iter().map(|item| item.name.clone()).collect()
};
let inventory_index = menu(header, &options, INVENTORY_WIDTH, root);
// If an item was chosen, return it
if inventory.len() > 0 {
inventory_index
} else {
None
}
}
fn render_bar(
panel: &mut Offscreen,
x: i32,