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 {
|
impl color::Color for Color {
|
||||||
fn write_fg(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn write_fg(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
self.0.write_fg(f)
|
self.0.write_fg(f)
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use crate::display;
|
use crate::display;
|
||||||
|
use crate::entities::item::Item;
|
||||||
use crate::types::{Position, Speed};
|
use crate::types::{Position, Speed};
|
||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
|
|
||||||
|
@ -7,6 +8,7 @@ const DEFAULT_SPEED: Speed = Speed(100);
|
||||||
entity! {
|
entity! {
|
||||||
pub struct Character {
|
pub struct Character {
|
||||||
pub o_name: Option<String>,
|
pub o_name: Option<String>,
|
||||||
|
pub inventory: Vec<Box<Item>>,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,6 +20,7 @@ impl Character {
|
||||||
id: None,
|
id: None,
|
||||||
position: Position { x: 0, y: 0 },
|
position: Position { x: 0, y: 0 },
|
||||||
o_name: None,
|
o_name: None,
|
||||||
|
inventory: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ use crate::display::color::Color;
|
||||||
use std::fmt::{self, Display, Formatter};
|
use std::fmt::{self, Display, Formatter};
|
||||||
use termion::color;
|
use termion::color;
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize, PartialEq, Eq)]
|
||||||
pub struct EntityChar {
|
pub struct EntityChar {
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
color: Color,
|
color: Color,
|
||||||
|
|
|
@ -4,7 +4,7 @@ use crate::entities::{Describe, EntityID};
|
||||||
use crate::types::Position;
|
use crate::types::Position;
|
||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct Item {
|
pub struct Item {
|
||||||
pub id: Option<EntityID>,
|
pub id: Option<EntityID>,
|
||||||
pub typ: &'static ItemType<'static>,
|
pub typ: &'static ItemType<'static>,
|
||||||
|
|
|
@ -17,7 +17,7 @@ pub struct CreatureType<'a> {
|
||||||
pub friendly: bool,
|
pub friendly: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize, PartialEq, Eq)]
|
||||||
pub struct EdibleItem<'a> {
|
pub struct EdibleItem<'a> {
|
||||||
#[serde(borrow)]
|
#[serde(borrow)]
|
||||||
pub eat_message: Option<Message<'a>>,
|
pub eat_message: Option<Message<'a>>,
|
||||||
|
@ -26,7 +26,7 @@ pub struct EdibleItem<'a> {
|
||||||
pub hitpoints_healed: u16,
|
pub hitpoints_healed: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize, PartialEq, Eq)]
|
||||||
pub struct ItemType<'a> {
|
pub struct ItemType<'a> {
|
||||||
pub name: &'a str,
|
pub name: &'a str,
|
||||||
|
|
||||||
|
|
42
src/game.rs
42
src/game.rs
|
@ -1,5 +1,7 @@
|
||||||
use crate::description::list_to_sentence;
|
use crate::description::list_to_sentence;
|
||||||
use crate::display::{self, Viewport};
|
use crate::display::{self, Viewport};
|
||||||
|
use crate::entities::entity::Describe;
|
||||||
|
use crate::entities::entity::Entity;
|
||||||
use crate::entities::{
|
use crate::entities::{
|
||||||
AnEntity, Character, Creature, EntityID, Identified, Item,
|
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 downcast_entities_at<A: Entity>(&self, pos: Position) -> Vec<&A> {
|
||||||
fn creatures_at<'b>(&'b self, pos: Position) -> Vec<&'b Creature> {
|
|
||||||
self.entities
|
self.entities
|
||||||
.at(pos)
|
.at(pos)
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -196,6 +197,16 @@ impl<'a> Game<'a> {
|
||||||
.collect()
|
.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
|
/// Returns a collision, if any, at the given Position in the game
|
||||||
fn collision_at(&self, pos: Position) -> Option<Collision> {
|
fn collision_at(&self, pos: Position) -> Option<Collision> {
|
||||||
if !pos.within(self.viewport.inner) {
|
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) {
|
fn flush_promises(&mut self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let game = self as *mut Self;
|
let game = self as *mut Self;
|
||||||
|
@ -498,6 +534,8 @@ impl<'a> Game<'a> {
|
||||||
|
|
||||||
Some(PreviousMessage) => self.previous_message()?,
|
Some(PreviousMessage) => self.previous_message()?,
|
||||||
|
|
||||||
|
Some(PickUp) => self.pick_up()?,
|
||||||
|
|
||||||
None => (),
|
None => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
welcome = "Welcome to Xanthous, {{character.name}}! It's dangerous out there, why not stay inside?"
|
welcome = "Welcome to Xanthous, {{character.name}}! It's dangerous out there, why not stay inside?"
|
||||||
describe_entities = "You see here {{descriptions}}"
|
describe_entities = "You see here {{descriptions}}"
|
||||||
describe_no_entities = "You see nothing here."
|
describe_no_entities = "You see nothing here."
|
||||||
|
pick_up = "You pick up the {{item.name}}."
|
||||||
|
|
||||||
[combat]
|
[combat]
|
||||||
attack = "You attack the {{creature.name}}."
|
attack = "You attack the {{creature.name}}."
|
||||||
|
|
|
@ -10,6 +10,9 @@ pub enum Command {
|
||||||
/// Move the character in a direction
|
/// Move the character in a direction
|
||||||
Move(Direction),
|
Move(Direction),
|
||||||
|
|
||||||
|
/// Pick up any item(s) at the current position
|
||||||
|
PickUp,
|
||||||
|
|
||||||
/// Display the previous message
|
/// Display the previous message
|
||||||
PreviousMessage,
|
PreviousMessage,
|
||||||
}
|
}
|
||||||
|
@ -19,6 +22,7 @@ impl Command {
|
||||||
use Command::*;
|
use Command::*;
|
||||||
match k {
|
match k {
|
||||||
Char('q') => Some(Quit),
|
Char('q') => Some(Quit),
|
||||||
|
|
||||||
Char('h') | Char('a') | Key::Left => Some(Move(Left)),
|
Char('h') | Char('a') | Key::Left => Some(Move(Left)),
|
||||||
Char('k') | Char('w') | Key::Up => Some(Move(Up)),
|
Char('k') | Char('w') | Key::Up => Some(Move(Up)),
|
||||||
Char('j') | Char('s') | Key::Down => Some(Move(Down)),
|
Char('j') | Char('s') | Key::Down => Some(Move(Down)),
|
||||||
|
@ -29,6 +33,8 @@ impl Command {
|
||||||
Char('n') => Some(Move(DownRight)),
|
Char('n') => Some(Move(DownRight)),
|
||||||
|
|
||||||
Ctrl('p') => Some(PreviousMessage),
|
Ctrl('p') => Some(PreviousMessage),
|
||||||
|
Char(',') => Some(PickUp),
|
||||||
|
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue