dsa-rs/src/skill.rs

296 lines
8.1 KiB
Rust

use super::{characteristic::Characteristic, dice::DiceThrow, hero::Hero};
/// A skill identifier with a value how good the hero is in it.
pub struct Skill {
/// The identifier takes the form of `<book it is introduced in first>/<name of the skill in lowercase ascii>`
pub identifier: &'static str,
pub value: i8,
pub characteristics: [&'static str; 3],
pub hero: Hero,
}
impl Skill {
pub fn new(
identifier: &'static str,
value: i8,
characteristics: [&'static str; 3],
hero: Hero,
) -> Skill {
Skill {
identifier,
value,
characteristics,
hero,
}
}
pub fn trial(
&self,
dice_throws: [DiceThrow; 3],
modifier: i8,
) -> ([DiceThrow; 3], SkillTrialResult) {
let mut ones = 0;
let mut twenties = 0;
let mut per_trait_mod = 0;
let mut remainder = self.value + modifier;
if remainder < 0 {
per_trait_mod = remainder;
remainder = 0;
}
for i in 0..3 {
let trait_trial_result = self.hero
.characteristics
.get(self.characteristics[i])
.unwrap()
.trial(dice_throws[i], per_trait_mod);
if trait_trial_result < 0 {
remainder += trait_trial_result;
}
match dice_throws[i].throw {
20 => twenties += 1,
1 => ones += 1,
_ => {}
}
}
{
use self::SkillTrialResult::*;
(
dice_throws,
match (ones, twenties, remainder) {
(_, 3, _) => TripleTwenty,
(_, 2, _) => DoubleTwenty,
(3, _, _) => TripleOne,
(2, _, _) => DoubleOne,
(_, _, n) if n < 0 => Failure,
(_, _, n) if n >= 0 && n <= 3 => Success(1),
(_, _, n) if n >= 4 && n <= 6 => Success(2),
(_, _, n) if n >= 7 && n <= 9 => Success(3),
(_, _, n) if n >= 10 && n <= 12 => Success(4),
(_, _, n) if n >= 13 && n <= 15 => Success(5),
(_, _, n) if n >= 16 => Success(6),
(_, _, _) => Failure,
// TODO: exhaustive integer matching, this is unreachable, removal blocked by
// https://github.com/rust-lang/rust/pull/50912 being in stable
},
)
}
}
}
pub enum SkillTrialResult {
TripleTwenty,
DoubleTwenty,
Failure,
Success(u8),
DoubleOne,
TripleOne,
}
#[cfg(test)]
mod tests {
use super::super::{
characteristic::Characteristic, dice::Dice, hero::Hero, skill::{Skill, SkillTrialResult},
};
#[test]
fn create_skill() {
let skill = skill();
}
fn skill() -> Skill {
let mut hero = Hero::new();
hero.add_characteristic("AA", 12);
hero.add_characteristic("BB", 15);
hero.add_characteristic("CC", 09);
Skill::new("skill", 6, ["AA", "BB", "CC"], hero)
}
#[test]
fn triple_twenty() {
let skill = skill();
let d20 = Dice::new(20);
let throws = [
d20.throw_with_result(20),
d20.throw_with_result(20),
d20.throw_with_result(20),
];
match skill.trial(throws, 0) {
(_, SkillTrialResult::TripleTwenty) => {}
(_, _) => panic!("Putting in three twenties doesn't return triple twenty"),
}
}
#[test]
fn double_twenty() {
let skill = skill();
let d20 = Dice::new(20);
let throws = [
d20.throw_with_result(20),
d20.throw_with_result(19),
d20.throw_with_result(20),
];
match skill.trial(throws, 0) {
(_, SkillTrialResult::DoubleTwenty) => {}
(_, _) => panic!("Putting in two twenties doesn't return double twenty"),
}
}
#[test]
fn triple_one() {
let skill = skill();
let d20 = Dice::new(20);
let throws = [
d20.throw_with_result(1),
d20.throw_with_result(1),
d20.throw_with_result(1),
];
match skill.trial(throws, 0) {
(_, SkillTrialResult::TripleOne) => {}
(_, _) => panic!("Putting in three ones doesn't return triple one"),
}
}
#[test]
fn double_one() {
let skill = skill();
let d20 = Dice::new(20);
let throws = [
d20.throw_with_result(1),
d20.throw_with_result(1),
d20.throw_with_result(20),
];
match skill.trial(throws, 0) {
(_, SkillTrialResult::DoubleOne) => {}
(_, _) => panic!("Putting in two ones doesn't return double one"),
}
}
#[test]
fn failure() {
let skill = skill();
let d20 = Dice::new(20);
let throws = [
d20.throw_with_result(19),
d20.throw_with_result(19),
d20.throw_with_result(19),
];
match skill.trial(throws, 0) {
(_, SkillTrialResult::Failure) => {}
(_, _) => panic!("Failing doesn't fail"),
}
}
#[test]
fn success_qs1() {
let skill = skill();
let d20 = Dice::new(20);
let throws = [
d20.throw_with_result(2),
d20.throw_with_result(2),
d20.throw_with_result(2),
];
match skill.trial(throws, -4) {
(_, SkillTrialResult::Success(1)) => {}
(_, _) => panic!("QS 1 is failing"),
}
}
#[test]
fn success_qs2() {
let skill = skill();
let d20 = Dice::new(20);
let throws = [
d20.throw_with_result(2),
d20.throw_with_result(2),
d20.throw_with_result(2),
];
match skill.trial(throws, -1) {
(_, SkillTrialResult::Success(2)) => {}
(_, _) => panic!("QS 1 is failing"),
}
}
#[test]
fn success_qs3() {
let skill = skill();
let d20 = Dice::new(20);
let throws = [
d20.throw_with_result(2),
d20.throw_with_result(2),
d20.throw_with_result(2),
];
match skill.trial(throws, 2) {
(_, SkillTrialResult::Success(3)) => {}
(_, _) => panic!("QS 1 is failing"),
}
}
#[test]
fn success_qs4() {
let skill = skill();
let d20 = Dice::new(20);
let throws = [
d20.throw_with_result(2),
d20.throw_with_result(2),
d20.throw_with_result(2),
];
match skill.trial(throws, 5) {
(_, SkillTrialResult::Success(4)) => {}
(_, _) => panic!("QS 1 is failing"),
}
}
#[test]
fn success_qs5() {
let skill = skill();
let d20 = Dice::new(20);
let throws = [
d20.throw_with_result(2),
d20.throw_with_result(2),
d20.throw_with_result(2),
];
match skill.trial(throws, 8) {
(_, SkillTrialResult::Success(5)) => {}
(_, _) => panic!("QS 1 is failing"),
}
}
#[test]
fn success_qs6() {
let skill = skill();
let d20 = Dice::new(20);
let throws = [
d20.throw_with_result(2),
d20.throw_with_result(2),
d20.throw_with_result(2),
];
match skill.trial(throws, 11) {
(_, SkillTrialResult::Success(6)) => {}
(_, _) => panic!("QS 1 is failing"),
}
}
#[test]
fn success_with_19_qs6() {
let skill = skill();
let d20 = Dice::new(20);
let throws = [
d20.throw_with_result(19),
d20.throw_with_result(2),
d20.throw_with_result(2),
];
match skill.trial(throws, 20) {
(_, SkillTrialResult::Success(6)) => {}
(_, _) => panic!("QS 1 is failing"),
}
}
}
struct A {
bs: Vec<B>,
}
struct B {
a: A
}