use super::session::Session; use crate::{ language, regular_tasks::queued_command::QueueCommand, static_content::possession_type::PossessionType, static_content::room::Direction, static_content::species::SpeciesType, }; use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use std::collections::BTreeMap; use std::collections::VecDeque; #[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq, PartialOrd)] pub enum BuffCause { WaitingTask { task_code: String, task_type: String, }, ByItem { item_code: String, item_type: String, }, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, PartialOrd)] pub enum BuffImpact { ChangeStat { stat: StatType, magnitude: f64 }, ChangeSkill { skill: SkillType, magnitude: f64 }, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, PartialOrd)] pub struct Buff { pub description: String, pub cause: BuffCause, pub impacts: Vec, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] pub enum SkillType { Appraise, Blades, Bombs, Chemistry, Climb, Clubs, Craft, Dodge, Fish, Fists, Flails, Focus, Fuck, Hack, Locksmith, Medic, Persuade, Pilot, Pistols, Quickdraw, Repair, Ride, Rifles, Scavenge, Science, Sneak, Spears, Swim, Teach, Throw, Track, Wrestle, Whips, } impl SkillType { pub fn values() -> Vec { use SkillType::*; vec![ Appraise, Blades, Bombs, Chemistry, Climb, Clubs, Craft, Dodge, Fish, Fists, Flails, Focus, Fuck, Hack, Locksmith, Medic, Persuade, Pilot, Pistols, Quickdraw, Repair, Ride, Rifles, Scavenge, Science, Sneak, Spears, Swim, Teach, Throw, Track, Wrestle, Whips, ] } pub fn display(&self) -> &'static str { use SkillType::*; match self { Appraise => "appraise", Blades => "blades", Bombs => "bombs", Chemistry => "chemistry", Climb => "climb", Clubs => "clubs", Craft => "craft", Dodge => "dodge", Fish => "fish", Fists => "fists", Flails => "flails", Focus => "focus", Fuck => "fuck", Hack => "hack", Locksmith => "locksmith", Medic => "medic", Persuade => "persuade", Pilot => "pilot", Pistols => "pistols", Quickdraw => "quickdraw", Repair => "repair", Ride => "ride", Rifles => "rifles", Scavenge => "scavenge", Science => "science", Sneak => "sneak", Spears => "spears", Swim => "swim", Teach => "teach", Throw => "throw", Track => "track", Wrestle => "wrestle", Whips => "whips", } } } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] pub enum StatType { Brains, Senses, Brawn, Reflexes, Endurance, Cool, } impl StatType { pub fn values() -> Vec { use StatType::*; vec![Brains, Senses, Brawn, Reflexes, Endurance, Cool] } pub fn display(&self) -> &'static str { use StatType::*; match self { Brains => "brains", Senses => "senses", Brawn => "brawn", Reflexes => "reflexes", Endurance => "endurance", Cool => "cool", } } } #[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] pub struct Pronouns { pub subject: String, pub object: String, pub intensive: String, pub possessive: String, // And some miscellaneous details to determine context pub is_plural: bool, // ... are instead of ... is pub is_proper: bool, // When naming, just ... instead of The ... } impl Pronouns { pub fn default_inanimate() -> Pronouns { Pronouns { subject: "it".to_owned(), object: "it".to_owned(), intensive: "itself".to_owned(), possessive: "its".to_owned(), is_plural: false, is_proper: true, } } pub fn default_animate() -> Pronouns { Pronouns { subject: "they".to_owned(), object: "them".to_owned(), intensive: "themselves".to_owned(), possessive: "their".to_owned(), is_plural: true, is_proper: true, } } #[allow(dead_code)] pub fn default_male() -> Pronouns { Pronouns { subject: "he".to_owned(), object: "him".to_owned(), intensive: "himself".to_owned(), possessive: "his".to_owned(), is_plural: false, is_proper: true, } } #[allow(dead_code)] pub fn default_female() -> Pronouns { Pronouns { subject: "she".to_owned(), object: "her".to_owned(), intensive: "herself".to_owned(), possessive: "her".to_owned(), is_plural: false, is_proper: true, } } } #[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] pub enum Subattack { Normal, Powerattacking, Feinting, Grabbing, Wrestling, } #[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] pub enum LocationActionType { Normal, Sitting, Reclining, Worn, // Clothing etc... Wielded, Attacking(Subattack), InstalledOnDoorAsLock(Direction), } impl LocationActionType { pub fn is_visible_in_look(&self) -> bool { use LocationActionType::*; match self { InstalledOnDoorAsLock(_) => false, _ => true, } } pub fn is_in_direction(&self, dir: &Direction) -> bool { use LocationActionType::*; match self { InstalledOnDoorAsLock(d) if d == dir => true, _ => false, } } } #[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] pub enum Sex { Male, Female, } #[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] pub enum ItemFlag { NoSay, NoSeeContents, DroppedItemsDontExpire, PrivatePlace, Hireable, NPCsDontAttack, CanLoad, } #[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] #[serde(default)] pub struct ActiveCombat { pub attacking: Option, pub attacked_by: Vec, } impl Default for ActiveCombat { fn default() -> Self { Self { attacking: None, attacked_by: vec![], } } } #[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] #[serde(default)] pub struct ActiveClimb { pub height: u64, } impl Default for ActiveClimb { fn default() -> Self { Self { height: 0 } } } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, PartialOrd)] pub enum ItemSpecialData { ItemWriting { text: String, }, DynroomData { dynzone_code: String, dynroom_code: String, }, DynzoneData { zone_exit: Option, vacate_after: Option>, }, HireData { hired_by: Option, }, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, PartialOrd)] pub struct DynamicEntrance { pub direction: Direction, pub source_item: String, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, PartialOrd)] #[serde(default)] pub struct DoorState { pub open: bool, pub description: String, } impl Default for DoorState { fn default() -> Self { Self { open: false, description: "a solid looking wooden door".to_owned(), } } } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, PartialOrd)] #[serde(default)] pub struct DeathData { pub parts_remaining: Vec, } impl Default for DeathData { fn default() -> Self { Self { parts_remaining: vec![], } } } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, PartialOrd)] pub enum FollowState { // Every move is mirrored to the follower. Active, // If the followee is in the same room, mirror a movement and go to Active, // otherwise ignore and don't mirror. This happens after a mirrored move fails, // or the follower moves independently. IfSameRoom, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, PartialOrd)] pub struct FollowData { pub follow_whom: String, pub state: FollowState, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, PartialOrd)] #[serde(default)] pub struct Item { pub item_code: String, pub item_type: String, pub possession_type: Option, pub display: String, pub display_less_explicit: Option, pub details: Option, pub details_less_explicit: Option, pub aliases: Vec, pub location: String, // Item reference as item_type/item_code. pub action_type: LocationActionType, pub action_type_started: Option>, pub presence_target: Option, // e.g. what are they sitting on. pub is_static: bool, pub death_data: Option, pub species: SpeciesType, pub health: u64, pub total_xp: u64, pub total_stats: BTreeMap, pub total_skills: BTreeMap, pub temporary_buffs: Vec, pub pronouns: Pronouns, pub flags: Vec, pub sex: Option, pub active_combat: Option, pub active_climb: Option, pub weight: u64, pub charges: u8, pub special_data: Option, pub dynamic_entrance: Option, pub owner: Option, pub door_states: Option>, pub following: Option, pub queue: VecDeque, } impl Item { pub fn display_for_sentence(&self, explicit_ok: bool, pluralise: usize, caps: bool) -> String { let mut buf = String::new(); if self.death_data.is_some() { if pluralise > 1 { buf.push_str("the bodies of "); } else { buf.push_str("the body of "); } } let singular = if explicit_ok { &self.display } else { self.display_less_explicit.as_ref().unwrap_or(&self.display) }; if !self.pronouns.is_proper && pluralise == 1 { buf.push_str(language::indefinite_article(&singular)); buf.push(' '); } if pluralise > 1 { buf.push_str(&format!("{} ", pluralise)); } if pluralise > 1 { buf.push_str(&language::pluralise(singular)); } else { buf.push_str(singular); } if caps { language::caps_first(&buf) } else { buf } } pub fn display_for_session<'l>(self: &'l Self, session: &Session) -> String { self.display_for_sentence(!session.less_explicit_mode, 1, false) } pub fn details_for_session<'l>(self: &'l Self, session: &Session) -> Option<&'l str> { self.details.as_ref().map(|dets| { session.explicit_if_allowed( dets.as_str(), self.details_less_explicit.as_ref().map(String::as_str), ) }) } pub fn refstr(&self) -> String { format!("{}/{}", &self.item_type, &self.item_code) } } impl Default for Item { fn default() -> Self { Self { item_code: "unset".to_owned(), item_type: "unset".to_owned(), possession_type: None, display: "Item".to_owned(), display_less_explicit: None, details: None, details_less_explicit: None, aliases: vec![], location: "room/storage".to_owned(), action_type: LocationActionType::Normal, action_type_started: None, presence_target: None, is_static: false, death_data: None, species: SpeciesType::Human, health: 24, total_xp: 0, total_stats: BTreeMap::new(), total_skills: BTreeMap::new(), temporary_buffs: Vec::new(), pronouns: Pronouns::default_inanimate(), flags: vec![], sex: None, active_combat: Some(Default::default()), active_climb: None, weight: 0, charges: 0, special_data: None, dynamic_entrance: None, owner: None, door_states: None, following: None, queue: VecDeque::new(), } } }