|
|
@@ -0,0 +1,296 @@ |
|
|
|
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 |
|
|
|
} |