use std::fmt::Debug; use super::{entry::{ActionDefinition, ActionResult, GameEntry}, chat_message::ChatMessage}; pub trait Character : 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; /// 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>; /// Gets a character sheet entry value fn get(&self, entry: &str, access: AccessLevel) -> Option; /// 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), } 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, "]") }, } } }