Base data structures

This commit is contained in:
Savanni D'Gerinel 2021-09-30 23:44:26 -04:00
commit f2b9e6ccb3
9 changed files with 327 additions and 0 deletions

1
.envrc Normal file
View File

@ -0,0 +1 @@
use_nix

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
**/target

11
common/Cargo.toml Normal file
View File

@ -0,0 +1,11 @@
[package]
name = "common"
version = "0.1.0"
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
serde = { version = "1" }
serde_derive = { version = "1" }
thiserror = { version = "1" }

12
common/src/lib.rs Normal file
View File

@ -0,0 +1,12 @@
#[macro_use]
extern crate serde_derive;
pub mod types;
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
assert_eq!(2 + 2, 4);
}
}

201
common/src/types.rs Normal file
View File

@ -0,0 +1,201 @@
use thiserror::Error;
#[derive(Clone, Debug, Error)]
pub enum Error {
#[error("Tier out of range {0}")]
TierOutOfRange(u8),
}
#[derive(Debug, Serialize, Deserialize)]
pub enum Type {
Arkus,
Delve,
Glaive,
Jack,
Nano,
Wright,
}
#[derive(Debug, Serialize, Deserialize)]
pub enum StatType {
Might,
Speed,
Intellect,
}
#[derive(Debug, Serialize, Deserialize)]
pub enum Cost {
Nothing,
Constant { stat: StatType, cost: u8 },
Variable(StatType),
}
#[derive(Debug, Serialize, Deserialize)]
pub struct Tier(u8);
impl Tier {
pub fn new(val: u8) -> Result<Tier, Error> {
if val < 1 || val > 6 {
Err(Error::TierOutOfRange(val))
} else {
Ok(Tier(val))
}
}
}
#[derive(Debug, Serialize, Deserialize)]
pub struct Stat {
current: u8,
max: u8,
edge: u8,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct Stats {
might: Stat,
speed: Stat,
intellect: Stat,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct SpecialAbility {
name: String,
cost: Cost,
description: String,
}
#[derive(Debug, Serialize, Deserialize)]
pub enum SkillRank {
Inability,
Trained,
Specialized,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct Skill {
skill: String,
rank: SkillRank,
}
#[derive(Debug, Serialize, Deserialize)]
pub enum Range {
Immediate,
Short,
Long,
VeryLong,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct Attack {
weapon: String,
damage: u8,
range: Range,
ammo: Option<u8>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct Defense {
armor: String,
defense: u8,
speed_cost: u8,
}
#[derive(Debug, Serialize, Deserialize)]
struct CharacterSheet {
name: String,
descriptor: String,
type_: Type,
focus: String,
tier: Tier,
pools: Stats,
effort: u8,
cypher_limit: u8,
special_abilities: Vec<SpecialAbility>,
skills: Vec<Skill>,
attacks: Vec<Attack>,
defenses: Vec<Defense>,
equipment: Vec<String>,
cyphers: Vec<Cypher>,
}
#[derive(Debug, Serialize, Deserialize)]
struct Cypher {
name: String,
level: u8,
form: String,
description: String,
}
#[cfg(any(test, feature = "test_data"))]
mod test_data {
use super::*;
fn opal() -> CharacterSheet {
CharacterSheet {
name: "Opal".to_owned(),
descriptor: "Adaptable".to_owned(),
type_: Type::Jack,
focus: "Speaks with a Silver Tongue".to_owned(),
tier: Tier::new(1).unwrap(),
pools: Stats {
might: Stat {
current: 11,
max: 11,
edge: 0,
},
speed: Stat {
current: 12,
max: 12,
edge: 0,
},
intellect: Stat {
current: 13,
max: 13,
edge: 1,
},
},
effort: 1,
cypher_limit: 3,
special_abilities: vec![
SpecialAbility { name: "Versatile".to_owned(),
cost: Cost::Nothing,
description: "+2 to any pool. It can be reassigned after each ten-hour recovery roll.".to_owned() },
SpecialAbility { name: "Flex Skill".to_owned(),
cost: Cost::Nothing,
description: "at the beginning of each day, choose one skill (other than attack or defense). For the rest of the day, you are trained in that skill.".to_owned() },
SpecialAbility{ name: "Face Morph".to_owned(),
cost: Cost::Constant { stat: StatType::Intellect, cost: 2 },
description: "You alter your features and coloration for one hour.".to_owned() },
],
skills: vec![
Skill{ skill: "Perception".to_owned(), rank: SkillRank::Trained },
Skill{ skill: "Resilient".to_owned(), rank: SkillRank::Trained },
Skill{ skill: "Social interactions".to_owned(), rank: SkillRank::Trained },
Skill{ skill: "Pleasant social interactiosn".to_owned(), rank: SkillRank::Specialized },
],
attacks: vec![
Attack { weapon: "Crank Crossbow".to_owned(), damage: 4, range: Range::Long, ammo: Some(25), },
Attack { weapon: "Rapier".to_owned(), damage: 2, range: Range::Immediate, ammo: None, },
],
defenses: vec![
Defense {
armor: "Brigandine".to_owned(),
defense: 2,
speed_cost: 2,
}
],
equipment: vec![
"A book for recording favorite words, inspiration stories, and speech anecdotes.".to_owned(),
"Explorer's pack".to_owned(),
],
cyphers: vec![
Cypher {
name: "Flying Cap".to_owned(),
level: 3,
form: "Hat".to_owned(),
description: "Whatever".to_owned(),
}
],
}
}
}

25
docs/stories.md Normal file
View File

@ -0,0 +1,25 @@
# Tasks
- Players
- need to be able to see their character sheets
- need to be able to edit their character sheets
- need to record damage
- need to mark abilities as used
- need to see active status effects ("flex skill")
- need to trigger recovery (regain pool points, reset skills that reset on recovery)
- need to mark artifacts as depleted
- need to expend cyphers
- GM
- needs to see all character sheet
- needs to send items to players
- needs a pool of potential cyphers
- Other
- all actions must be undoable
Cypher:
- name
- level
- form
- description
Character Sheet

10
server/Cargo.toml Normal file
View File

@ -0,0 +1,10 @@
[package]
name = "datasphere-server"
version = "0.1.0"
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
tokio = { version = "1", features = ["full"] }
warp = { version = "0.3.1" }

46
server/src/main.rs Normal file
View File

@ -0,0 +1,46 @@
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use warp::Filter;
fn gm_paths() -> impl Filter {
let base = warp::path("gm").and(warp::header("authentication"));
let character_sheet = base
.clone()
.and(warp::path!("character" / String))
.map(|auth: String, name| format!("name: {}", name));
let send_item = base
.clone()
.and(warp::path("send_item"))
.map(|auth| format!("send_item"));
let send_resource = base
.clone()
.and(warp::path("send_resource"))
.map(|auth| format!("send_resource"));
character_sheet.or(send_item).or(send_resource)
}
fn player_paths() -> impl Filter {
let base = warp::path("player").and(warp::header("authentication"));
let character_sheet = base
.and(warp::path!("character" / String))
.map(|authentication: String, name: String| format!("name: {}", name));
character_sheet
}
#[tokio::main]
pub async fn main() {
let hi = warp::path!("hello" / String)
.and(warp::header("user-agent"))
.map(|param: String, agent: String| format!("Saluton! {}, {}", param, agent));
let bye = warp::path!("goodbye").map(|| "Goodbye!");
let server = warp::serve(hi.or(bye));
server
.run(SocketAddr::new(
IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)),
8000,
))
.await;
}

20
shell.nix Normal file
View File

@ -0,0 +1,20 @@
let
rust_overlay = import (builtins.fetchTarball "https://github.com/oxalica/rust-overlay/archive/master.tar.gz");
pkgs = import <pkgs-21.05> { overlays = [ rust_overlay ]; };
unstable = import <unstable> {};
rust = pkgs.rust-bin.stable."1.54.0".default.override {
extensions = [ "rust-src" ];
};
in pkgs.mkShell {
name = "datasphere";
nativeBuildInputs = [
rust
unstable.rust-analyzer
];
shellHook = ''
if [ -e ~/.nixpkgs/shellhook.sh ]; then . ~/.nixpkgs/shellhook.sh; fi
'';
}