an http based roguelike rpg about jelqing
Commit 53bce0d93000
tarball5 files changed+58-15
@@ -13,6 +13,8 @@ pub struct Body {
1313
pub(crate) foreskin: Option<f64>,1414
pub(crate) inflation: f64,1515
pub(crate) eq: i32,16
+ /// `heat` as the current turn began, so no rupture is judged hotter than the turn started.17
+ pub(crate) heat_at_turn_start: i32,1618
pub(crate) stamina: i32,1719
pub(crate) friction: i32,1820
pub(crate) grip: Grip,@@ -34,6 +36,7 @@ impl Body {
3436
foreskin: Some(foreskin),3537
inflation,3638
eq: STARTING_EQ,39
+ heat_at_turn_start: STARTING_EQ,3740
stamina: MAX_STAMINA,3841
friction: 0,3942
grip: Grip::Overhand,@@ -20,21 +20,31 @@ use crate::problem::Problem;
2020
type Interruption = Result<ControlFlow<Outcome>, Problem>;2121
2222
impl Run {23
- /// Whether EQ is past `line`, with a friction burn dragging every line down.24
- pub(super) fn hotter_than(&self, line: i32) -> bool {23
+ /// EQ with a friction burn dragging every line down.24
+ pub(super) fn heat(&self) -> i32 {2525
let burn = if self.body.conditions.friction_burn {2626
BURN_RUPTURE2727
} else {2828
02929
};30
- self.body.eq > line - burn30
+ self.body.eq + burn31
+ }32
+33
+ pub(super) fn hotter_than(&self, line: i32) -> bool {34
+ self.heat() > line35
+ }36
+37
+ /// Ruptures go by the cooler of now and the turn's start, so a line crossed this turn cannot rupture38
+ /// before `X-EQ` has had a chance to name it.39
+ pub(super) fn risked(&self, line: i32) -> bool {40
+ self.heat().min(self.body.heat_at_turn_start) > line3141
}3242
3343
/// The rupture tier for any turn that is not a jelq, so never the premature band's 1 in 3.3444
pub(super) fn rupture_odds(&self) -> u32 {35
- if !self.hotter_than(DANGER_EQ) {45
+ if !self.risked(DANGER_EQ) {3646
RUPTURE_IN_BAND37
- } else if !self.hotter_than(HOT_EQ) {47
+ } else if !self.risked(HOT_EQ) {3848
RUPTURE_WARM3949
} else {4050
RUPTURE_HOT@@ -183,13 +193,15 @@ impl Run {
183193
.header(header::CONNECTION, "close"));184194
}185195
if self.hotter_than(PREMATURE_EQ) {186
- if self.chance(187
- self.decision(188
- "rupture",189
- "Right at the edge of finishing, does it rupture instead?",190
- ),191
- RUPTURE_PREMATURE,192
- ) {196
+ if self.risked(PREMATURE_EQ)197
+ && self.chance(198
+ self.decision(199
+ "rupture",200
+ "Right at the edge of finishing, does it rupture instead?",201
+ ),202
+ RUPTURE_PREMATURE,203
+ )204
+ {193205
return Err(self.rupture());194206
}195207
self.standing.shame += 5;@@ -49,10 +49,10 @@ impl Run {
4949
return Err(timed(self.critical_failure(training, &profile)));5050
}5151
self.here.warm_arrival = false;52
- if natural == 2 && self.hotter_than(DANGER_EQ) {52
+ if natural == 2 && self.risked(DANGER_EQ) {5353
return Err(timed(self.rupture()));5454
}55
- if self.hotter_than(rupture_line) && total < dc {55
+ if self.risked(rupture_line) && total < dc {5656
return Err(timed(self.rupture()));5757
}5858
if natural == 20 {@@ -178,7 +178,7 @@ impl Run {
178178
.with("foreskin", -round3(lost))179179
.header(header::CONTENT_LOCATION, self.path("/foreskin"));180180
}181
- if self.hotter_than(DANGER_EQ) {181
+ if self.risked(DANGER_EQ) {182182
return self.rupture();183183
}184184
if training == Training::Stretch && !self.here.teapot {@@ -163,6 +163,7 @@ impl Run {
163163
self.here.turns += 1;164164
self.body.torn = 0.0;165165
self.standing.at_turn_start = self.standing.suspicion;166
+ self.body.heat_at_turn_start = self.heat();166167
self.realise(false);167168
if self.floor.timed() && self.here.turns + 2 == FLOOR_LIMIT {168169
self.notices.push(Notice::RunningLong(self.floor));@@ -227,3 +227,30 @@ async fn degloving_takes_one_cold_stroke_in_twenty() {
227227
"{degloved} degloved in 1200 cold strokes, about 60 expected"228228
);229229
}230
+231
+#[tokio::test]232
+async fn a_turn_cannot_rupture_for_heat_it_only_just_reached() {233
+ let mut ruptured = 0;234
+ for seed in 0..300u64 {235
+ let app = app_with(Floor::Bedroom, seed, |run| run.body.eq = 70);236
+ let turn = send(237
+ &app,238
+ "JELQ",239
+ "/runs/cafebabe?technique=stretch&intensity=10",240
+ &[],241
+ "",242
+ )243
+ .await;244
+ if turn245
+ .headers()246
+ .get("x-run-over")247
+ .is_some_and(|v| v == "ruptured")248
+ {249
+ ruptured += 1;250
+ }251
+ }252
+ assert!(253
+ ruptured <= 6,254
+ "Ideal at the start of the turn kept the in-band 1 in 250, but {ruptured} of 300 ruptured"255
+ );256
+}