open_tavern/src/game/character_sheet.rs

97 lines
No EOL
3.2 KiB
Rust

use std::fmt::Debug;
use super::{entry::{ActionDefinition, ActionResult, GameEntry}, chat_message::ChatMessage};
pub trait Character<E: GameEntry> : CharacterSheet {
/// types of actions that can be done on the specified entry (e.g. cast for spells and wear for armor)
fn actions(&self, entry: &E) -> Vec<ActionDefinition>;
/// uses an action for a specific character, some actions should be split into multiple
///
/// for example, an attack sequence will be of:
///
/// - `Attack` invoked on a weapon entry, which will have the `roll damage` option in the chat
/// - `roll damage` will be done on the attacking character, which show the `damage` and `double` actions
/// - `damage` will be used on the target character (which could apply reductions as well)
fn use_action(&mut self, entry: &E, action: &ActionResult) -> ChatMessage;
}
pub trait CharacterSheet : Default {
/// Character sheet inputs (stuff that are not calculated from different items), such as Name, Age, Strength
fn inputs(&self, access: AccessLevel) -> Vec<(String, EntryType)>;
/// All fields in the character sheet, maybe change it to only a vec of strings?
fn fields(&self) -> Vec<(String, EntryType)>;
/// Character sheet to display, ordered. `None`s can be used to convey a seperator (of any sort)
fn display(&self, access: AccessLevel) -> Vec<Option<(String, EntryType)>>;
/// Gets a character sheet entry value
fn get(&self, entry: &str, access: AccessLevel) -> Option<EntryType>;
/// Sets a cahrater sheet entry value
fn set(&mut self, entry: &str, value: EntryType, access: AccessLevel);
}
#[derive(Debug, Copy, Clone)]
pub enum AccessLevel {
Admin = 0, Owner = 1, PartyMember = 2, World = 3,
}
impl AccessLevel {
pub fn has_access(self, other: Self) -> bool {
(self as u8) <= (other as u8)
}
}
#[derive(Debug)]
pub enum EntryType {
Number(i32),
Text(String),
Bool(bool),
Array(Vec<EntryType>),
}
impl Default for EntryType {
fn default() -> Self {
EntryType::Number(0)
}
}
impl EntryType {
pub fn as_num(&self) -> i32 {
if let EntryType::Number(n) = *self {
n
}
else {
0
}
}
pub fn as_text(&self) -> String {
if let EntryType::Text(t) = self {
t.clone()
}
else {
String::new()
}
}
pub fn as_bool(&self) -> bool {
if let EntryType::Bool(b) = *self {
b
}
else {
false
}
}
}
impl std::fmt::Display for EntryType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
EntryType::Number(n) => write!(f, "{}", n),
EntryType::Text(t) => write!(f, "{}", t),
EntryType::Bool(b) => write!(f, "{}", b),
EntryType::Array(v) => {
write!(f, "[ ")?;
if v.len() > 0 {
for i in v.iter().take(v.len() - 1) {
write!(f, "{}, ", i)?;
};
write!(f, "{} ", v.iter().last().unwrap())?;
};
write!(f, "]")
},
}
}
}