Using items
This commit is contained in:
parent
838dd7749e
commit
3a31fab361
104
src/main.rs
104
src/main.rs
@ -47,6 +47,7 @@ const MSG_X: i32 = BAR_WIDTH + 2;
|
|||||||
const MSG_WIDTH: i32 = SCREEN_WIDTH - BAR_WIDTH - 2;
|
const MSG_WIDTH: i32 = SCREEN_WIDTH - BAR_WIDTH - 2;
|
||||||
const MSG_HEIGHT: usize = PANEL_HEIGHT as usize - 1;
|
const MSG_HEIGHT: usize = PANEL_HEIGHT as usize - 1;
|
||||||
const MAX_ROOM_ITEMS: i32 = 2;
|
const MAX_ROOM_ITEMS: i32 = 2;
|
||||||
|
const INVENTORY_WIDTH: i32 = 50;
|
||||||
|
|
||||||
struct Tcod {
|
struct Tcod {
|
||||||
root: Root,
|
root: Root,
|
||||||
@ -68,6 +69,7 @@ struct Object {
|
|||||||
alive: bool,
|
alive: bool,
|
||||||
fighter: Option<Fighter>,
|
fighter: Option<Fighter>,
|
||||||
ai: Option<Ai>,
|
ai: Option<Ai>,
|
||||||
|
item: Option<Item>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Object {
|
impl Object {
|
||||||
@ -82,6 +84,7 @@ impl Object {
|
|||||||
alive: false,
|
alive: false,
|
||||||
fighter: None,
|
fighter: None,
|
||||||
ai: None,
|
ai: None,
|
||||||
|
item: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -316,6 +319,27 @@ fn handle_keys(tcod: &mut Tcod, game: &mut Game, objects: &mut Vec<Object>) -> P
|
|||||||
TookTurn
|
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,
|
_ => DidntTakeTurn,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -438,6 +462,7 @@ fn place_objects(room: Rect, map: &Map, objects: &mut Vec<Object>) {
|
|||||||
if !is_blocked(x, y, map, objects) {
|
if !is_blocked(x, y, map, objects) {
|
||||||
// Create a healing potion
|
// Create a healing potion
|
||||||
let mut object = Object::new(x, y, '!', "healing potion", VIOLET, false);
|
let mut object = Object::new(x, y, '!', "healing potion", VIOLET, false);
|
||||||
|
object.item = Some(Item::Heal);
|
||||||
objects.push(object);
|
objects.push(object);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -546,6 +571,85 @@ fn monster_death(monster: &mut Object, game: &mut Game) {
|
|||||||
monster.name = format!("remains of {}", monster.name);
|
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(
|
fn render_bar(
|
||||||
panel: &mut Offscreen,
|
panel: &mut Offscreen,
|
||||||
x: i32,
|
x: i32,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user