296 lines
8.1 KiB
Rust
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
|
|
} |