Fix cthulhu advancement rolls, add remaining dice tests.

This commit is contained in:
projectmoon 2020-11-01 19:26:51 +00:00
parent 7e15379c58
commit a15d3e0bac
1 changed files with 188 additions and 18 deletions

View File

@ -50,6 +50,7 @@ impl fmt::Display for DiceRollModifier {
}
/// The outcome of a die roll, either some kind of success or failure.
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum RollResult {
/// Basic success. The rolled number was equal to or less than the target number.
Success,
@ -262,6 +263,30 @@ fn roll_regular_dice<R: DieRoller>(roll: &DiceRoll, roller: &mut R) -> RolledDic
}
}
fn roll_advancement_dice<R: DieRoller>(
roll: &AdvancementRoll,
roller: &mut R,
) -> RolledAdvancement {
let unit_roll = roller.roll();
let percentile_roll = roll_percentile_dice(roller, unit_roll);
if percentile_roll > roll.existing_skill || percentile_roll > 95 {
RolledAdvancement {
num_rolled: percentile_roll,
existing_skill: roll.existing_skill,
advancement: roller.roll() + 1,
successful: true,
}
} else {
RolledAdvancement {
num_rolled: percentile_roll,
existing_skill: roll.existing_skill,
advancement: 0,
successful: false,
}
}
}
impl DiceRoll {
/// Make a roll with a target number and potential modifier. In a
/// normal roll, only one percentile die is rolled (1d100). With
@ -280,24 +305,7 @@ impl DiceRoll {
impl AdvancementRoll {
pub fn roll(&self) -> RolledAdvancement {
let mut roller = RngDieRoller(rand::thread_rng());
let unit_roll = roller.roll();
let percentile_roll = roll_percentile_dice(&mut roller, unit_roll);
if percentile_roll < self.existing_skill || percentile_roll > 95 {
RolledAdvancement {
num_rolled: percentile_roll,
existing_skill: self.existing_skill,
advancement: roller.roll() + 1,
successful: true,
}
} else {
RolledAdvancement {
num_rolled: percentile_roll,
existing_skill: self.existing_skill,
advancement: 0,
successful: false,
}
}
roll_advancement_dice(self, &mut roller)
}
}
@ -331,6 +339,133 @@ mod tests {
}
}
#[test]
fn regular_roll_succeeds_when_below_target() {
let roll = DiceRoll {
target: 50,
modifier: DiceRollModifier::Normal,
};
//Roll 30, succeeding.
let mut roller = SequentialDieRoller::new(vec![0, 3]);
let rolled = roll_regular_dice(&roll, &mut roller);
assert_eq!(RollResult::Success, rolled.result());
}
#[test]
fn regular_roll_hard_success_when_rolling_half() {
let roll = DiceRoll {
target: 50,
modifier: DiceRollModifier::Normal,
};
//Roll 25, succeeding.
let mut roller = SequentialDieRoller::new(vec![5, 2]);
let rolled = roll_regular_dice(&roll, &mut roller);
assert_eq!(RollResult::HardSuccess, rolled.result());
}
#[test]
fn regular_roll_extreme_success_when_rolling_one_fifth() {
let roll = DiceRoll {
target: 50,
modifier: DiceRollModifier::Normal,
};
//Roll 10, succeeding extremely.
let mut roller = SequentialDieRoller::new(vec![0, 1]);
let rolled = roll_regular_dice(&roll, &mut roller);
assert_eq!(RollResult::ExtremeSuccess, rolled.result());
}
#[test]
fn regular_roll_extreme_success_target_above_100() {
let roll = DiceRoll {
target: 150,
modifier: DiceRollModifier::Normal,
};
//Roll 30, succeeding extremely.
let mut roller = SequentialDieRoller::new(vec![0, 3]);
let rolled = roll_regular_dice(&roll, &mut roller);
assert_eq!(RollResult::ExtremeSuccess, rolled.result());
}
#[test]
fn regular_roll_critical_success_on_one() {
let roll = DiceRoll {
target: 50,
modifier: DiceRollModifier::Normal,
};
//Roll 1.
let mut roller = SequentialDieRoller::new(vec![1, 0]);
let rolled = roll_regular_dice(&roll, &mut roller);
assert_eq!(RollResult::CriticalSuccess, rolled.result());
}
#[test]
fn regular_roll_fail_when_above_target() {
let roll = DiceRoll {
target: 50,
modifier: DiceRollModifier::Normal,
};
//Roll 60.
let mut roller = SequentialDieRoller::new(vec![0, 6]);
let rolled = roll_regular_dice(&roll, &mut roller);
assert_eq!(RollResult::Failure, rolled.result());
}
#[test]
fn regular_roll_is_fumble_when_skill_below_50_and_roll_at_least_96() {
let roll = DiceRoll {
target: 49,
modifier: DiceRollModifier::Normal,
};
//Roll 96.
let mut roller = SequentialDieRoller::new(vec![6, 9]);
let rolled = roll_regular_dice(&roll, &mut roller);
assert_eq!(RollResult::Fumble, rolled.result());
}
#[test]
fn regular_roll_is_failure_when_skill_at_or_above_50_and_roll_at_least_96() {
let roll = DiceRoll {
target: 50,
modifier: DiceRollModifier::Normal,
};
//Roll 96.
let mut roller = SequentialDieRoller::new(vec![6, 9]);
let rolled = roll_regular_dice(&roll, &mut roller);
assert_eq!(RollResult::Failure, rolled.result());
let roll = DiceRoll {
target: 68,
modifier: DiceRollModifier::Normal,
};
//Roll 96.
let mut roller = SequentialDieRoller::new(vec![6, 9]);
let rolled = roll_regular_dice(&roll, &mut roller);
assert_eq!(RollResult::Failure, rolled.result());
}
#[test]
fn regular_roll_always_fumble_on_100() {
let roll = DiceRoll {
target: 100,
modifier: DiceRollModifier::Normal,
};
//Roll 100.
let mut roller = SequentialDieRoller::new(vec![0, 0]);
let rolled = roll_regular_dice(&roll, &mut roller);
assert_eq!(RollResult::Fumble, rolled.result());
}
#[test]
fn one_penalty_picks_highest_of_two() {
let roll = DiceRoll {
@ -395,4 +530,39 @@ mod tests {
let rolled = roll_regular_dice(&roll, &mut roller);
assert_eq!(30, rolled.num_rolled);
}
#[test]
fn advancement_succeeds_on_above_skill() {
let roll = AdvancementRoll { existing_skill: 30 };
//Roll 52, then advance skill by 5. (advancement adds +1 to 0-9 roll)
let mut roller = SequentialDieRoller::new(vec![2, 5, 4]);
let rolled = roll_advancement_dice(&roll, &mut roller);
assert!(rolled.successful());
assert_eq!(5, rolled.advancement());
assert_eq!(35, rolled.new_skill_amount());
}
#[test]
fn advancement_succeeds_on_above_95() {
let roll = AdvancementRoll { existing_skill: 97 };
//Roll 96, then advance skill by 1. (advancement adds +1 to 0-9 roll)
let mut roller = SequentialDieRoller::new(vec![6, 9, 0]);
let rolled = roll_advancement_dice(&roll, &mut roller);
assert!(rolled.successful());
assert_eq!(1, rolled.advancement());
assert_eq!(98, rolled.new_skill_amount());
}
#[test]
fn advancement_fails_on_below_skill() {
let roll = AdvancementRoll { existing_skill: 30 };
//Roll 25, failing.
let mut roller = SequentialDieRoller::new(vec![5, 2]);
let rolled = roll_advancement_dice(&roll, &mut roller);
assert!(!rolled.successful());
assert_eq!(0, rolled.advancement());
}
}