diff options
| author | 2025-09-12 18:19:16 +0800 | |
|---|---|---|
| committer | 2025-09-12 18:19:16 +0800 | |
| commit | 2778db81c6973078dc0e8e04c4bb711143aef84d (patch) | |
| tree | a262ee069fe4155c1bf315ed549161d3ee4ee1f8 /src | |
| parent | 899ca820e34b1b62190e88da71cf734295974a19 (diff) | |
| download | OneRoll-2778db81c6973078dc0e8e04c4bb711143aef84d.tar.gz OneRoll-2778db81c6973078dc0e8e04c4bb711143aef84d.zip | |
feat: add new reroll modifiers for enhanced dice functionality
Diffstat (limited to 'src')
| -rw-r--r-- | src/calculator.rs | 25 | ||||
| -rw-r--r-- | src/oneroll/grammar.pest | 4 | ||||
| -rw-r--r-- | src/parser.rs | 10 | ||||
| -rw-r--r-- | src/types.rs | 2 |
4 files changed, 40 insertions, 1 deletions
diff --git a/src/calculator.rs b/src/calculator.rs index 5376f76..07518b0 100644 --- a/src/calculator.rs +++ b/src/calculator.rs @@ -45,7 +45,7 @@ impl DiceCalculator { } } - // handle reroll + // handle reroll variants for modifier in &dice.modifiers { match modifier { DiceModifier::Reroll(threshold) => { @@ -60,6 +60,27 @@ impl DiceCalculator { final_rolls[pos] = new_roll as i32; } } + DiceModifier::RerollUntil(threshold) => { + // keep rolling until > threshold (safety cap) + let mut current = *final_rolls.last().unwrap_or(&((roll) as i32)); + let mut attempts = 0; + const MAX_ATTEMPTS: usize = 100; + while current <= *threshold && attempts < MAX_ATTEMPTS { + let new_roll = rand::random::<u32>() % dice.sides as u32 + 1; + current = new_roll as i32; + final_rolls = vec![current]; + attempts += 1; + } + } + DiceModifier::RerollAndAdd(threshold) => { + // if <= threshold, roll again and add to the last value + if final_rolls.iter().any(|&r| r <= *threshold) { + let new_roll = rand::random::<u32>() % dice.sides as u32 + 1; + let mut sum = final_rolls.iter().sum::<i32>(); + sum += new_roll as i32; + final_rolls = vec![sum]; + } + } _ => {} } } @@ -246,6 +267,8 @@ impl DiceCalculator { DiceModifier::ExplodeKeepHigh(n) => result.push_str(&format!("K{}", n)), DiceModifier::Reroll(n) => result.push_str(&format!("r{}", n)), DiceModifier::RerollOnce(n) => result.push_str(&format!("ro{}", n)), + DiceModifier::RerollUntil(n) => result.push_str(&format!("R{}", n)), + DiceModifier::RerollAndAdd(n) => result.push_str(&format!("a{}", n)), DiceModifier::KeepAlias(n) => result.push_str(&format!("k{}", n)), DiceModifier::KeepHigh(n) => result.push_str(&format!("kh{}", n)), DiceModifier::KeepLow(n) => result.push_str(&format!("kl{}", n)), diff --git a/src/oneroll/grammar.pest b/src/oneroll/grammar.pest index 09b86f8..006be64 100644 --- a/src/oneroll/grammar.pest +++ b/src/oneroll/grammar.pest @@ -26,6 +26,8 @@ modifier = { | explode_keep_high | reroll | reroll_once + | reroll_until + | reroll_add | keep_alias | keep_high | keep_low @@ -41,6 +43,8 @@ explode_alias = { "e" } explode_keep_high = { "K" ~ number } reroll = { "r" ~ number } reroll_once = { "ro" ~ number } +reroll_until = { "R" ~ number } +reroll_add = { "a" ~ number } keep_alias = { "k" ~ number } keep_high = { "kh" ~ number } keep_low = { "kl" ~ number } diff --git a/src/parser.rs b/src/parser.rs index 50231c0..20cd992 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -126,6 +126,16 @@ impl DiceParser { .map_err(|_| DiceError::ParseError("无效的条件重投数值".to_string()))?; Ok(DiceModifier::RerollOnce(num)) } + Rule::reroll_until => { + let num = inner.into_inner().next().unwrap().as_str().parse::<i32>() + .map_err(|_| DiceError::ParseError("无效的直到重投数值".to_string()))?; + Ok(DiceModifier::RerollUntil(num)) + } + Rule::reroll_add => { + let num = inner.into_inner().next().unwrap().as_str().parse::<i32>() + .map_err(|_| DiceError::ParseError("无效的重投并相加数值".to_string()))?; + Ok(DiceModifier::RerollAndAdd(num)) + } Rule::keep_alias => { let num = inner.into_inner().next().unwrap().as_str().parse::<i32>() .map_err(|_| DiceError::ParseError("无效的取高数值".to_string()))?; diff --git a/src/types.rs b/src/types.rs index aad0080..1d5d369 100644 --- a/src/types.rs +++ b/src/types.rs @@ -24,6 +24,8 @@ pub enum DiceModifier { ExplodeKeepHigh(i32), // KX == explode then keep high X Reroll(i32), // rX RerollOnce(i32), // roX + RerollUntil(i32), // RX (until > X; with cap) + RerollAndAdd(i32), // aX (reroll if <= X and add) KeepAlias(i32), // kX == khX KeepHigh(i32), // khX KeepLow(i32), // klX |
