rust-rl/src/components.rs
Llywelwyn 44b0674b5a the oryx-ening - zoom factor, and renderables refactor
currently extremely unfinished - half the sprites are gnomes, and tiles have no colours
2023-10-06 09:22:11 +01:00

858 lines
21 KiB
Rust

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<i32, Vec<crate::gamelog::LogFragment>>,
pub event_counts: HashMap<String, i32>,
pub events: HashMap<u32, Vec<String>>,
}
#[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<String>,
pub fg: RGB,
pub fg_alt: Option<RGB>,
pub render_order: i32,
pub render_order_alt: Option<i32>,
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<Vec<usize>>,
},
}
#[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<String>,
}
#[derive(Component, Debug, Serialize, Deserialize, Clone)]
pub struct Mind {}
#[derive(Component, ConvertSaveload, Clone)]
pub struct Viewshed {
pub visible_tiles: Vec<Point>,
pub range: i32,
pub dirty: bool,
}
#[derive(Component, ConvertSaveload, Clone)]
pub struct Telepath {
pub telepath_tiles: Vec<Point>,
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<Skill, i32>,
}
#[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<KnownSpell>,
}
#[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<NaturalAttack>,
}
#[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<DamageType, DamageModifier>,
}
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<Intrinsic>,
}
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<Intrinsic>,
pub lost: HashSet<Intrinsic>,
}
#[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<Point>,
}
#[derive(Component, Debug, Serialize, Deserialize, Clone)]
pub struct WantsToApproach {
pub idx: i32,
}
#[derive(Component, Debug, Serialize, Deserialize, Clone)]
pub struct WantsToFlee {
pub indices: Vec<usize>, // 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 {}