use crate::gui::Ancestry; use crate::gui::Class; use bracket_lib::prelude::*; use serde::{ Deserialize, Serialize }; use specs::error::NoError; use specs::prelude::*; use specs::saveload::{ ConvertSaveload, Marker }; use specs_derive::*; use std::collections::{ HashMap, HashSet }; // Serialization helper code. We need to implement ConvertSaveload for each type that contains an // Entity. pub struct SerializeMe; // Special component that exists to help serialize the game data #[derive(Component, Serialize, Deserialize, Clone)] pub struct SerializationHelper { pub map: super::map::Map, } #[derive(Component, Serialize, Deserialize, Clone)] pub struct DMSerializationHelper { pub map: super::map::MasterDungeonMap, pub log: std::collections::BTreeMap>, pub event_counts: HashMap, pub events: HashMap>, } #[derive(Component, ConvertSaveload, Clone)] pub struct Position { pub x: i32, pub y: i32, } #[derive(Component, Serialize, Deserialize, Clone)] pub struct OtherLevelPosition { pub x: i32, pub y: i32, pub id: i32, } #[derive(Debug, Component, ConvertSaveload, Clone)] pub struct Renderable { pub glyph: FontCharType, // Legacy, and for drawing the morgue map. pub sprite: String, pub sprite_alt: Option, pub fg: RGB, pub fg_alt: Option, pub render_order: i32, pub render_order_alt: Option, pub offset: (f32, f32), pub offset_alt: Option<(f32, f32)>, // 0 = always on top: particle effects // 1 = things that should appear infront of the player: railings, etc. // 2 = the player // 3 = other mobs // 4 = interactable items // 5 = other props: table, etc. } impl Renderable { pub fn new(glyph: FontCharType, sprite: String, fg: RGB, render_order: i32) -> Self { Self { glyph, sprite, sprite_alt: None, fg, fg_alt: None, render_order, render_order_alt: None, offset: (0.0, 0.0), offset_alt: None, } } pub fn swap(&mut self) { let sprite = self.swap_sprite(); let fg = self.swap_fg(); let render_order = self.swap_render_order(); let offset = self.swap_offset(); let did_something = sprite || fg || render_order || offset; if !did_something { unreachable!( ".swap() was called on a Renderable component, but nothing happened. {:?}", self ); } } pub fn swap_sprite(&mut self) -> bool { if let Some(sprite_alt) = &mut self.sprite_alt { std::mem::swap(&mut self.sprite, sprite_alt); return true; } false } pub fn swap_fg(&mut self) -> bool { if let Some(fg_alt) = &mut self.fg_alt { std::mem::swap(&mut self.fg, fg_alt); return true; } false } pub fn swap_render_order(&mut self) -> bool { if let Some(render_order_alt) = &mut self.render_order_alt { std::mem::swap(&mut self.render_order, render_order_alt); return true; } false } pub fn swap_offset(&mut self) -> bool { if let Some(offset_alt) = &mut self.offset_alt { std::mem::swap(&mut self.offset, offset_alt); return true; } false } } #[derive(Component, Debug, Serialize, Deserialize, Clone)] pub struct Bleeds { pub colour: RGB, } #[derive(Component, Debug, Serialize, Deserialize, Clone)] pub struct Player {} #[derive(Component, Debug, Serialize, Deserialize, Clone)] pub struct Faction { pub name: String, } #[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)] pub enum Movement { Static, Random, RandomWaypoint { path: Option>, }, } #[derive(Component, Debug, Serialize, Deserialize, Clone)] pub struct MoveMode { pub mode: Movement, } #[derive(Component, Debug, Serialize, Deserialize, Clone)] pub struct Prop {} #[derive(Component, Debug, Serialize, Deserialize, Clone)] pub struct LootTable { pub table: String, pub chance: f32, } #[derive(Component, Debug, Serialize, Deserialize, Clone)] pub struct Energy { pub current: i32, pub speed: i32, } #[derive(Component, Debug, Serialize, Deserialize, Clone)] pub struct Clock {} #[derive(Component, Debug, Serialize, Deserialize, Clone)] pub struct TakingTurn {} #[derive(Component, Debug, Serialize, Deserialize, Clone)] pub struct Quips { pub available: Vec, } #[derive(Component, Debug, Serialize, Deserialize, Clone)] pub struct Mind {} #[derive(Component, ConvertSaveload, Clone)] pub struct Viewshed { pub visible_tiles: Vec, pub range: i32, pub dirty: bool, } #[derive(Component, ConvertSaveload, Clone)] pub struct Telepath { pub telepath_tiles: Vec, pub range: i32, pub dirty: bool, } #[derive(Component, Debug, ConvertSaveload, Clone)] pub struct Name { pub name: String, pub plural: String, } #[derive(Component, Debug, Serialize, Deserialize, Clone)] pub struct BlocksTile {} #[derive(Component, Debug, Serialize, Deserialize, Clone)] pub struct BlocksVisibility {} #[derive(Component, Debug, Serialize, Deserialize, Clone)] pub struct Door { pub open: bool, pub locked: bool, pub blocks_vis: bool, pub blocks_move: bool, } #[derive(Serialize, Deserialize, Copy, Clone, PartialEq)] pub enum HungerState { Satiated, Normal, Hungry, Weak, Fainting, Starving, } #[derive(Component, Serialize, Deserialize, Clone)] pub struct HungerClock { pub state: HungerState, pub duration: i32, } #[derive(Component, Debug, Serialize, Deserialize, Clone)] pub struct ProvidesNutrition {} #[derive(Component, Serialize, Deserialize, Clone)] pub struct HasAncestry { pub name: Ancestry, } #[derive(Component, Serialize, Deserialize, Clone)] pub struct HasClass { pub name: Class, } #[derive(Debug, Serialize, Deserialize, Clone)] pub struct Pool { pub max: i32, pub current: i32, } #[derive(Component, Debug, Serialize, Deserialize, Clone)] pub struct Pools { pub hit_points: Pool, pub mana: Pool, pub xp: i32, pub bac: i32, pub level: i32, pub weight: f32, pub god: bool, } #[derive(Debug, Serialize, Deserialize, Clone)] pub struct Attribute { pub base: i32, pub bonuses: i32, pub exercise: i32, } impl Attribute { pub fn new(base: i32) -> Self { Self { base, bonuses: 0, exercise: 0, } } // Raw attribute score. e.g. 10 base, + 4 from armour: 14 strength. pub fn current(&self) -> i32 { self.base + self.bonuses } // Attribute bonus. e.g. 14 strength = +2, 8 strength = -1 pub fn modifier(&self) -> i32 { crate::gamesystem::attr_bonus(self.current()) } pub fn improve(&mut self) { if self.exercise < 50 { self.exercise += 1; } } pub fn abuse(&mut self) { if self.exercise > -50 { self.exercise -= 1; } } } #[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)] pub enum Skill { Melee, Defence, Magic, } #[derive(Component, Debug, Serialize, Deserialize, Clone)] pub struct Skills { pub skills: HashMap, } #[derive(Debug, Serialize, Deserialize, Clone)] pub struct KnownSpell { pub display_name: String, pub mana_cost: i32, } #[derive(Component, Debug, Serialize, Deserialize, Clone)] pub struct KnownSpells { pub list: Vec, } #[derive(Component, Debug, Serialize, Deserialize, Clone)] pub struct GrantsSpell { pub spell: String, } // TODO: GrantsIntrinsic, Intrinsics, etc. ? Done the same way as spells? #[derive(Component, Debug, Serialize, Deserialize, Clone)] pub struct Attributes { pub strength: Attribute, pub dexterity: Attribute, pub constitution: Attribute, pub intelligence: Attribute, pub wisdom: Attribute, pub charisma: Attribute, } impl Attributes { pub const STR: i32 = 0; pub const DEX: i32 = 1; pub const CON: i32 = 2; pub const INT: i32 = 3; pub const WIS: i32 = 4; pub const CHA: i32 = 5; pub fn default() -> Self { Self { strength: Attribute::new(10), dexterity: Attribute::new(10), constitution: Attribute::new(10), intelligence: Attribute::new(10), wisdom: Attribute::new(10), charisma: Attribute::new(10), } } pub fn with_stats(str: i32, dex: i32, con: i32, int: i32, wis: i32, cha: i32) -> Self { Self { strength: Attribute::new(str), dexterity: Attribute::new(dex), constitution: Attribute::new(con), intelligence: Attribute::new(int), wisdom: Attribute::new(wis), charisma: Attribute::new(cha), } } pub fn attr_from_index(&self, attr: i32) -> &Attribute { match attr { Self::STR => &self.strength, Self::DEX => &self.dexterity, Self::CON => &self.constitution, Self::INT => &self.intelligence, Self::WIS => &self.wisdom, Self::CHA => &self.charisma, _ => unreachable!("Tried to get an attribute that doesn't exist."), } } pub fn exercise(&mut self, attr: i32, improve: bool) { match attr { Self::STR => { if improve { self.strength.improve(); } else { self.strength.abuse(); } } Self::DEX => { if improve { self.dexterity.improve(); } else { self.dexterity.abuse(); } } Self::CON => { if improve { self.constitution.improve(); } else { self.constitution.abuse(); } } Self::INT => { if improve { self.intelligence.improve(); } else { self.intelligence.abuse(); } } Self::WIS => { if improve { self.wisdom.improve(); } else { self.wisdom.abuse(); } } Self::CHA => { if improve { self.charisma.improve(); } else { self.charisma.abuse(); } } _ => unreachable!("Tried to exercise an attribute that doesn't exist."), } } } #[derive(Component, Debug, ConvertSaveload, Clone)] pub struct WantsToMelee { pub target: Entity, } #[derive(Component, Debug, ConvertSaveload, Clone)] pub struct GrantsXP { pub amount: i32, } #[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)] pub enum BUC { Cursed, Uncursed, Blessed, } impl BUC { pub fn noncursed(&self) -> bool { match self { BUC::Cursed => false, _ => true, } } } #[derive(Component, Debug, Serialize, Deserialize, Eq, PartialEq, Hash, Clone)] pub struct Beatitude { pub buc: BUC, pub known: bool, } #[derive(Debug, Serialize, Deserialize, Copy, Clone, PartialEq, Eq)] pub enum ItemType { Amulet, Weapon, Armour, Comestible, Scroll, Spellbook, Potion, Ring, Wand, } impl ItemType { pub fn string(&self) -> &str { match self { ItemType::Amulet => "Amulets", ItemType::Weapon => "Weapons", ItemType::Armour => "Armour", ItemType::Comestible => "Comestibles", ItemType::Scroll => "Scrolls", ItemType::Spellbook => "Spellbooks", ItemType::Potion => "Potions", ItemType::Ring => "Rings", ItemType::Wand => "Wands", } } } #[derive(Component, Debug, Serialize, Deserialize, Clone)] pub struct Item { pub weight: f32, // in lbs pub value: f32, // base pub category: ItemType, } #[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)] pub enum MagicItemClass { Common, Uncommon, Rare, VeryRare, Legendary, } #[derive(Component, Debug, Serialize, Deserialize, Clone)] pub struct MagicItem { pub class: MagicItemClass, } #[derive(Component, Debug, Serialize, Deserialize, Clone)] pub struct ObfuscatedName { pub name: String, pub plural: String, } #[derive(Component, Debug, Serialize, Deserialize, Clone)] pub struct IdentifiedItem { pub name: String, } #[derive(Component, Debug, Serialize, Deserialize, Clone)] pub struct Stackable {} #[derive(Component, Debug, Serialize, Deserialize, Clone)] pub struct EquipmentChanged {} #[derive(Component, Debug, Serialize, Deserialize, Clone)] pub struct WantsToRemoveKey {} #[derive(Component, Debug, Serialize, Deserialize, Clone)] pub struct WantsToDelete {} #[derive(Component, Debug, Serialize, Deserialize, Clone)] pub struct Key { pub idx: usize, } #[derive(PartialEq, Copy, Clone, Serialize, Deserialize)] pub enum BurdenLevel { Burdened, Strained, Overloaded, } #[derive(Component, Serialize, Deserialize, Clone)] pub struct Burden { pub level: BurdenLevel, } #[derive(PartialEq, Copy, Clone, Serialize, Deserialize)] pub enum EquipmentSlot { Melee, Shield, Head, Body, Hands, Feet, Neck, Back, } #[derive(PartialEq, Copy, Clone, Serialize, Deserialize)] pub enum WeaponAttribute { Strength, Dexterity, Finesse, } #[derive(Component, Serialize, Deserialize, Clone)] pub struct MeleeWeapon { pub damage_type: DamageType, pub attribute: WeaponAttribute, pub damage_n_dice: i32, pub damage_die_type: i32, pub damage_bonus: i32, pub hit_bonus: i32, } #[derive(Serialize, Deserialize, Clone)] pub struct NaturalAttack { pub name: String, pub damage_type: DamageType, pub damage_n_dice: i32, pub damage_die_type: i32, pub damage_bonus: i32, pub hit_bonus: i32, } #[derive(Component, Serialize, Deserialize, Clone)] pub struct NaturalAttacks { pub attacks: Vec, } #[derive(Component, ConvertSaveload, Clone)] pub struct ArmourClassBonus { pub amount: i32, } #[derive(Component, ConvertSaveload, Clone)] pub struct ToHitBonus { pub amount: i32, } #[derive(Component, Serialize, Deserialize, Clone)] pub struct Equippable { pub slot: EquipmentSlot, } #[derive(Component, ConvertSaveload, Clone)] pub struct Equipped { pub owner: Entity, pub slot: EquipmentSlot, } #[derive(Component, Debug, ConvertSaveload, Clone)] pub struct ProvidesHealing { pub n_dice: i32, pub sides: i32, pub modifier: i32, } #[derive(Debug, PartialEq, Eq, Hash, Copy, Clone, Serialize, Deserialize)] pub enum DamageType { Physical, Magic, // e.g. magic missiles, silvered weapons Fire, // e.g. fireball Cold, // e.g. cone of cold Poison, // e.g. poison gas Forced, // Bypasses any immunities. e.g. Hunger ticks. } impl DamageType { pub fn is_magic(&self) -> bool { match self { DamageType::Magic | DamageType::Fire | DamageType::Cold => true, _ => false, } } } #[derive(Debug, PartialEq, Copy, Clone, Serialize, Deserialize)] pub enum DamageModifier { None, Weakness, Resistance, Immune, } impl DamageModifier { const NONE_MOD: f32 = 1.0; const WEAK_MOD: f32 = 2.0; const RESIST_MOD: f32 = 0.5; const IMMUNE_MOD: f32 = 0.0; pub fn multiplier(&self) -> f32 { match self { DamageModifier::None => Self::NONE_MOD, DamageModifier::Weakness => Self::WEAK_MOD, DamageModifier::Resistance => Self::RESIST_MOD, DamageModifier::Immune => Self::IMMUNE_MOD, } } } #[derive(Component, Serialize, Deserialize, Debug, Clone)] pub struct HasDamageModifiers { pub modifiers: HashMap, } impl HasDamageModifiers { pub fn modifier(&self, damage_type: &DamageType) -> &DamageModifier { self.modifiers.get(damage_type).unwrap_or(&DamageModifier::None) } } #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum Intrinsic { Regeneration, // Regenerate 1 HP on every tick Speed, // 4/3x speed multiplier } impl Intrinsic { pub fn describe(&self) -> &str { match self { Intrinsic::Regeneration => "regenerates health", Intrinsic::Speed => "is hasted", } } } #[derive(Component, Serialize, Deserialize, Debug, Clone)] pub struct Intrinsics { pub list: HashSet, } impl Intrinsics { pub fn describe(&self) -> String { let mut descriptions = Vec::new(); for intrinsic in &self.list { descriptions.push(intrinsic.describe()); } match descriptions.len() { 0 => unreachable!("describe() should never be called on an empty Intrinsics component."), 1 => format!("It {}.", descriptions[0]), _ => { let last = descriptions.pop().unwrap(); let joined = descriptions.join(", "); format!("It {}, and {}.", joined, last) } } } } #[derive(Component, Serialize, Deserialize, Debug, Clone)] pub struct IntrinsicChanged { pub gained: HashSet, pub lost: HashSet, } #[derive(Component, Debug, ConvertSaveload, Clone)] pub struct InflictsDamage { pub damage_type: DamageType, pub n_dice: i32, pub sides: i32, pub modifier: i32, } #[derive(Component, Debug, ConvertSaveload, Clone)] pub struct Ranged { pub range: i32, } #[derive(Component, Debug, ConvertSaveload, Clone)] pub struct AOE { pub radius: i32, } #[derive(Component, Debug, ConvertSaveload, Clone)] pub struct Confusion { pub turns: i32, } #[derive(Component, Serialize, Deserialize, Clone)] pub struct Blind {} #[derive(Component, Serialize, Deserialize, Clone)] pub struct MagicMapper {} #[derive(Component, Debug, ConvertSaveload)] pub struct InBackpack { pub owner: Entity, } #[derive(Component, Serialize, Deserialize, Clone)] pub struct WantsToAssignKey {} #[derive(Component, Debug, ConvertSaveload)] pub struct WantsToPickupItem { pub collected_by: Entity, pub item: Entity, } #[derive(Component, Debug, ConvertSaveload)] pub struct WantsToDropItem { pub item: Entity, } #[derive(Component, Debug, ConvertSaveload)] pub struct WantsToRemoveItem { pub item: Entity, } #[derive(Component, Debug, ConvertSaveload)] pub struct WantsToUseItem { pub item: Entity, pub target: Option, } #[derive(Component, Debug, Serialize, Deserialize, Clone)] pub struct WantsToApproach { pub idx: i32, } #[derive(Component, Debug, Serialize, Deserialize, Clone)] pub struct WantsToFlee { pub indices: Vec, // Dijkstra } #[derive(Component, Debug, ConvertSaveload, Clone)] pub struct Chasing { pub target: Entity, } #[derive(Component, Debug, Serialize, Deserialize, Clone)] pub struct Consumable {} #[derive(Component, Debug, ConvertSaveload)] pub struct Charges { pub uses: i32, pub max_uses: i32, } #[derive(Component, Serialize, Deserialize, Clone)] pub struct SpawnParticleLine { pub glyph: FontCharType, pub sprite: String, pub tail_glyph: FontCharType, pub tail_sprite: String, pub colour: RGB, pub lifetime_ms: f32, pub trail_colour: RGB, pub trail_lifetime_ms: f32, } #[derive(Component, Serialize, Deserialize, Clone)] pub struct SpawnParticleSimple { pub glyph: FontCharType, pub sprite: String, pub colour: RGB, pub lifetime_ms: f32, } #[derive(Component, Serialize, Deserialize, Clone)] pub struct SpawnParticleBurst { pub glyph: FontCharType, pub sprite: String, pub head_glyph: FontCharType, pub head_sprite: String, pub tail_glyph: FontCharType, pub tail_sprite: String, pub colour: RGB, pub lerp: RGB, pub lifetime_ms: f32, pub trail_colour: RGB, pub trail_lifetime_ms: f32, } #[derive(Component, Debug, Serialize, Deserialize, Clone)] pub struct Destructible {} #[derive(Component, Debug, Serialize, Deserialize, Clone)] pub struct ProvidesRemoveCurse {} #[derive(Component, Debug, Serialize, Deserialize, Clone)] pub struct ProvidesIdentify {} #[derive(Component, Debug, Serialize, Deserialize, Clone)] pub struct Digger {} #[derive(Component, Debug, Serialize, Deserialize, Clone)] pub struct Hidden {} #[derive(Component, Debug, Serialize, Deserialize, Clone)] pub struct SingleActivation {} #[derive(Component, Debug, Serialize, Deserialize, Clone)] pub struct IdentifiedBeatitude {} #[derive(Component, Clone, ConvertSaveload)] pub struct ParticleLifetime { pub lifetime_ms: f32, } #[derive(Component, Debug, Serialize, Deserialize, Clone)] pub struct EntryTrigger {} #[derive(Component, Debug, Serialize, Deserialize, Clone)] pub struct EntityMoved {} #[derive(Component, Debug, Serialize, Deserialize, Clone)] pub struct MultiAttack {}