diff --git a/proto/cofd.proto b/proto/cofd.proto index 2cdf07d..323e73f 100644 --- a/proto/cofd.proto +++ b/proto/cofd.proto @@ -2,6 +2,24 @@ syntax = "proto3"; package models.proto.cofd; +//TODO do we want a single "morality" value, or keep it separate +//inside the system-specific fields? + +//Information and values specific to the core game. +message CoreFields { + int32 integrity = 1; +} + +//Information and values specific to Mage 2E. +message MageFields { + int32 widsom = 1; +} + +//Information and values specific to Changeling 2E. +message ChangelingFields { + int32 clarity = 1; +} + //Base sheet for Chronicles of Darkness systems. message CofdSheet { message Merit { @@ -72,8 +90,10 @@ message CofdSheet { repeated Attack attacks = 26; map other_data = 27; -} -message ChangelingSheet { - CofdSheet base = 1; -} \ No newline at end of file + oneof system_fields { + CoreFields core = 28; + MageFields mage = 29; + ChangelingFields changeling = 30; + } +} diff --git a/src/migrator/migrations/V2__characters.rs b/src/migrator/migrations/V2__characters.rs index 0d52a7f..74cf727 100644 --- a/src/migrator/migrations/V2__characters.rs +++ b/src/migrator/migrations/V2__characters.rs @@ -6,7 +6,7 @@ pub fn migration() -> String { println!("Applying migration: {}", file!()); m.create_table("characters", move |t| { - let db_enum = r#"CHECK(data_type IN ('chronicles_of_darkness_v1', 'changeling_v1'))"#; + let db_enum = r#"CHECK(data_type IN ('chronicles_of_darkness', 'changeling'))"#; t.add_column("id", types::primary()); t.add_column("user_id", types::integer()); t.add_column("viewable", types::boolean()); diff --git a/src/models/characters.rs b/src/models/characters.rs index 3f39f06..b6155c4 100644 --- a/src/models/characters.rs +++ b/src/models/characters.rs @@ -1,5 +1,4 @@ use crate::errors::Error; -use crate::models::proto::cofd::cofd_sheet::*; use crate::models::proto::cofd::*; use crate::models::users::User; use prost::bytes::BytesMut; @@ -46,12 +45,16 @@ pub(crate) trait Visibility { /// games use the same (or similar) character sheets. This is because /// of the possibility for slight differences in rules and data /// between even similar systems. It's simpler to err on the side of -/// uniqueness. Enum variants are also versioned, in case of drastic -/// rewrites or migrations in the future. +/// uniqueness. Usually, systems based on the same ruleset will have +/// one character sheet type, with a oneof field for game-specific +/// information. #[derive(Debug, Serialize, PartialEq, Clone, Copy, EnumIter, EnumString, sqlx::Type)] #[sqlx(rename_all = "snake_case")] pub enum CharacterDataType { + /// A character for the core Chronicles of Darkness rules. ChroniclesOfDarkness, + + /// A character for Changeling 2E rules. Changeling, } @@ -62,14 +65,8 @@ impl CharacterDataType { use prost::Message; use CharacterDataType::*; let data: BytesMut = match self { - ChroniclesOfDarkness => { - let sheet = CofdSheet::default_sheet(); - let mut buf = BytesMut::with_capacity(std::mem::size_of_val(&sheet)); - sheet.encode(&mut buf)?; - buf - } - Changeling => { - let sheet = ChangelingSheet::default_sheet(); + ChroniclesOfDarkness | Changeling => { + let sheet = CofdSheet::default_sheet(*self); let mut buf = BytesMut::with_capacity(std::mem::size_of_val(&sheet)); sheet.encode(&mut buf)?; buf @@ -78,6 +75,15 @@ impl CharacterDataType { Ok(data) } + + /// Returns whether or not this enum variant represents a Chronicles + /// of Darkness game system. + pub fn is_cofd_system(&self) -> bool { + use CharacterDataType::*; + match self { + ChroniclesOfDarkness | Changeling => true, + } + } } /// An entry that appears in a user's character list. Properties are @@ -122,7 +128,7 @@ impl Character { use CharacterDataType::*; let decoded: Box = match self.data_type { ChroniclesOfDarkness => Box::new(self.try_deserialize::()?), - Changeling => Box::new(self.try_deserialize::()?), + Changeling => Box::new(self.try_deserialize::()?), }; Ok(decoded) diff --git a/src/models/proto/cofd.rs b/src/models/proto/cofd.rs index 5b4b75d..6ad0dd5 100644 --- a/src/models/proto/cofd.rs +++ b/src/models/proto/cofd.rs @@ -2,6 +2,7 @@ //! buffer types, as well as utilities and extensions for working with //! them. +use crate::models::characters::CharacterDataType; use std::collections::BTreeMap; //Add the generated protobuf code into this module. @@ -12,6 +13,8 @@ pub mod api { include!(concat!(env!("OUT_DIR"), "/models.proto.cofd.api.rs")); } +/// Default mental skill names for a regular Chronicles of Darkness +/// (or derivative system) game. const MENTAL_SKILLS: &'static [&'static str] = &[ "Academics", "Computer", @@ -23,6 +26,8 @@ const MENTAL_SKILLS: &'static [&'static str] = &[ "Science", ]; +/// Default physical skill names for a regular Chronicles of Darkness +/// (or derivative system) game. const PHYSICAL_SKILLS: &'static [&'static str] = &[ "Athletics", "Brawl", @@ -34,6 +39,8 @@ const PHYSICAL_SKILLS: &'static [&'static str] = &[ "Weaponry", ]; +/// Default social skill names for a regular Chronicles of Darkness +/// (or derivative system) game. const SOCIAL_SKILLS: &'static [&'static str] = &[ "Animal Ken", "Empathy", @@ -56,26 +63,24 @@ fn create_skill_list(skill_names: &[&str]) -> BTreeMap CofdSheet { + /// Create the default (blank) character sheet for a Chronicles of + /// Darkness-based character. This fills in skills and other + /// information that needs to be pre-populated. System specifics + /// are set based on the given character data type (aka game + /// system). + pub fn default_sheet(system: CharacterDataType) -> CofdSheet { let mut sheet = Self::default(); sheet.mental_skills = create_skill_list(&MENTAL_SKILLS); sheet.physical_skills = create_skill_list(&PHYSICAL_SKILLS); sheet.social_skills = create_skill_list(&SOCIAL_SKILLS); - sheet - } -} -impl ChangelingSheet { - /// Create the default (blank) character sheet for a Changeling - /// character. This fills in skills and other information that - /// needs to be pre-populated. - pub fn default_sheet() -> ChangelingSheet { - let mut sheet = Self::default(); - sheet.base = Some(CofdSheet::default_sheet()); - //TODO fill in changeling-specific stuff + use crate::models::proto::cofd::cofd_sheet::SystemFields; + let specifics: SystemFields = match system { + CharacterDataType::Changeling => SystemFields::Changeling(ChangelingFields::default()), + CharacterDataType::ChroniclesOfDarkness => SystemFields::Core(CoreFields::default()), + }; + + sheet.system_fields = Some(specifics); sheet } } diff --git a/src/routes/characters.rs b/src/routes/characters.rs index d61a960..53ceb32 100644 --- a/src/routes/characters.rs +++ b/src/routes/characters.rs @@ -37,10 +37,10 @@ fn view_character_template(user: &User, character: Character) -> Result