Add inventory, and the ability to pick up items
Add inventory as a basic vector of items attached to the character, and the ability to pick up a single item where the character stands
This commit is contained in:
parent
82cefedab9
commit
48fb3f6624
8 changed files with 63 additions and 6 deletions
|
@ -15,6 +15,15 @@ impl Color {
|
|||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Color {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
format!("{}{}", color::Fg(self), color::Bg(self))
|
||||
== format!("{}{}", color::Fg(other), color::Bg(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Color {}
|
||||
|
||||
impl color::Color for Color {
|
||||
fn write_fg(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.0.write_fg(f)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use crate::display;
|
||||
use crate::entities::item::Item;
|
||||
use crate::types::{Position, Speed};
|
||||
use std::io::{self, Write};
|
||||
|
||||
|
@ -7,6 +8,7 @@ const DEFAULT_SPEED: Speed = Speed(100);
|
|||
entity! {
|
||||
pub struct Character {
|
||||
pub o_name: Option<String>,
|
||||
pub inventory: Vec<Box<Item>>,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,6 +20,7 @@ impl Character {
|
|||
id: None,
|
||||
position: Position { x: 0, y: 0 },
|
||||
o_name: None,
|
||||
inventory: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ use crate::display::color::Color;
|
|||
use std::fmt::{self, Display, Formatter};
|
||||
use termion::color;
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[derive(Debug, Deserialize, PartialEq, Eq)]
|
||||
pub struct EntityChar {
|
||||
#[serde(default)]
|
||||
color: Color,
|
||||
|
|
|
@ -4,7 +4,7 @@ use crate::entities::{Describe, EntityID};
|
|||
use crate::types::Position;
|
||||
use std::io::{self, Write};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Item {
|
||||
pub id: Option<EntityID>,
|
||||
pub typ: &'static ItemType<'static>,
|
||||
|
|
|
@ -17,7 +17,7 @@ pub struct CreatureType<'a> {
|
|||
pub friendly: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[derive(Debug, Deserialize, PartialEq, Eq)]
|
||||
pub struct EdibleItem<'a> {
|
||||
#[serde(borrow)]
|
||||
pub eat_message: Option<Message<'a>>,
|
||||
|
@ -26,7 +26,7 @@ pub struct EdibleItem<'a> {
|
|||
pub hitpoints_healed: u16,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[derive(Debug, Deserialize, PartialEq, Eq)]
|
||||
pub struct ItemType<'a> {
|
||||
pub name: &'a str,
|
||||
|
||||
|
|
42
src/game.rs
42
src/game.rs
|
@ -1,5 +1,7 @@
|
|||
use crate::description::list_to_sentence;
|
||||
use crate::display::{self, Viewport};
|
||||
use crate::entities::entity::Describe;
|
||||
use crate::entities::entity::Entity;
|
||||
use crate::entities::{
|
||||
AnEntity, Character, Creature, EntityID, Identified, Item,
|
||||
};
|
||||
|
@ -187,8 +189,7 @@ impl<'a> Game<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns a list of all creature entities at the given position
|
||||
fn creatures_at<'b>(&'b self, pos: Position) -> Vec<&'b Creature> {
|
||||
fn downcast_entities_at<A: Entity>(&self, pos: Position) -> Vec<&A> {
|
||||
self.entities
|
||||
.at(pos)
|
||||
.iter()
|
||||
|
@ -196,6 +197,16 @@ impl<'a> Game<'a> {
|
|||
.collect()
|
||||
}
|
||||
|
||||
/// Returns a list of all creature entities at the given position
|
||||
fn creatures_at(&self, pos: Position) -> Vec<&Creature> {
|
||||
self.downcast_entities_at(pos)
|
||||
}
|
||||
|
||||
/// Returns a list of all item entities at the given position
|
||||
fn items_at(&self, pos: Position) -> Vec<&Item> {
|
||||
self.downcast_entities_at(pos)
|
||||
}
|
||||
|
||||
/// Returns a collision, if any, at the given Position in the game
|
||||
fn collision_at(&self, pos: Position) -> Option<Collision> {
|
||||
if !pos.within(self.viewport.inner) {
|
||||
|
@ -436,6 +447,31 @@ impl<'a> Game<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn pick_up(&mut self) -> io::Result<()> {
|
||||
let pos = self.character().position;
|
||||
let items = self.items_at(pos);
|
||||
match items.len() {
|
||||
0 => Ok(()),
|
||||
1 => {
|
||||
let item_id = items.get(0).unwrap().id();
|
||||
let item: Box<Item> =
|
||||
self.entities.remove(item_id).unwrap().downcast().unwrap();
|
||||
let desc = item.description();
|
||||
self.mut_character().inventory.push(item);
|
||||
self.say(
|
||||
"global.pick_up",
|
||||
&template_params!({
|
||||
"item" => { "name" => &desc, },
|
||||
}),
|
||||
)
|
||||
}
|
||||
_ => {
|
||||
// TODO prompt with a menu of items to pick up
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn flush_promises(&mut self) {
|
||||
unsafe {
|
||||
let game = self as *mut Self;
|
||||
|
@ -498,6 +534,8 @@ impl<'a> Game<'a> {
|
|||
|
||||
Some(PreviousMessage) => self.previous_message()?,
|
||||
|
||||
Some(PickUp) => self.pick_up()?,
|
||||
|
||||
None => (),
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
welcome = "Welcome to Xanthous, {{character.name}}! It's dangerous out there, why not stay inside?"
|
||||
describe_entities = "You see here {{descriptions}}"
|
||||
describe_no_entities = "You see nothing here."
|
||||
pick_up = "You pick up the {{item.name}}."
|
||||
|
||||
[combat]
|
||||
attack = "You attack the {{creature.name}}."
|
||||
|
|
|
@ -10,6 +10,9 @@ pub enum Command {
|
|||
/// Move the character in a direction
|
||||
Move(Direction),
|
||||
|
||||
/// Pick up any item(s) at the current position
|
||||
PickUp,
|
||||
|
||||
/// Display the previous message
|
||||
PreviousMessage,
|
||||
}
|
||||
|
@ -19,6 +22,7 @@ impl Command {
|
|||
use Command::*;
|
||||
match k {
|
||||
Char('q') => Some(Quit),
|
||||
|
||||
Char('h') | Char('a') | Key::Left => Some(Move(Left)),
|
||||
Char('k') | Char('w') | Key::Up => Some(Move(Up)),
|
||||
Char('j') | Char('s') | Key::Down => Some(Move(Down)),
|
||||
|
@ -29,6 +33,8 @@ impl Command {
|
|||
Char('n') => Some(Move(DownRight)),
|
||||
|
||||
Ctrl('p') => Some(PreviousMessage),
|
||||
Char(',') => Some(PickUp),
|
||||
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue