an http based roguelike rpg about jelqing
Commit fcc6cf6d5edc
tarball7 files changed+60-5
@@ -22,6 +22,7 @@ pub struct Body {
2222
pub(crate) put_applied: bool,2323
pub(crate) conditions: Conditions,2424
pub(crate) pending: Vec<Pending>,25
+ pub(crate) arrived: Option<Arrival>,2526
}2627
2728
impl Body {@@ -40,6 +41,7 @@ impl Body {
4041
put_applied: false,4142
conditions: Conditions::default(),4243
pending: Vec::new(),44
+ arrived: None,4345
}4446
}4547
}@@ -60,6 +62,13 @@ pub struct Pending {
6062
pub(crate) foreskin: f64,6163
}6264
65
+#[derive(Default)]66
+pub struct Arrival {67
+ pub(crate) length: f64,68
+ pub(crate) girth: f64,69
+ pub(crate) foreskin: Option<f64>,70
+}71
+6372
#[derive(Clone, Copy, PartialEq, Eq, Debug)]6473
pub enum Grip {6574
Overhand,@@ -3,7 +3,7 @@ use std::time::Instant;
33
use serde_json::{Value, json};44
55
use super::{6
- Elder, Excuse, Floor, Grip, Item, Observer, Run, Story, Technique,6
+ Arrival, Elder, Excuse, Floor, Grip, Item, Observer, Run, Story, Technique,77
balance::DANGER_EQ,88
techniques::{Training, Utility},99
};@@ -27,6 +27,7 @@ pub struct Gauges {
2727
pub(crate) observed: Option<Observer>,2828
pub(crate) mum_at_door: bool,2929
pub(crate) warnings: Vec<&'static str>,30
+ pub(crate) arrived: Option<Arrival>,3031
pub(crate) ruler: bool,3132
pub(crate) ring: bool,3233
}@@ -57,6 +58,10 @@ impl Run {
5758
warnings.push("friction burn");5859
}5960
warnings.extend(self.notices.drain(..).map(|notice| notice.text()));61
+ let arrived = self.body.arrived.take();62
+ if arrived.is_some() {63
+ warnings.push("the queued gains have arrived");64
+ }6065
if self.body.eq > DANGER_EQ && self.ended.is_none() {6166
warnings.push("it is turning purple");6267
}@@ -78,6 +83,7 @@ impl Run {
7883
observed: self.observed,7984
mum_at_door: self.household.mum.is_some(),8085
warnings,86
+ arrived,8187
ruler: self.items.kit.ruler,8288
ring: self.items.kit.ring,8389
}@@ -31,7 +31,7 @@ mod utility;
3131
3232
#[cfg(test)]3333
pub use body::Pending;34
-pub use body::{Body, Grip};34
+pub use body::{Arrival, Body, Grip};3535
pub use cause::{Cause, Ending, RunStatus};3636
pub use clinic::Clinic;3737
pub use floor::{Floor, FloorState, Observer};@@ -358,7 +358,13 @@ impl Run {
358358
.partition(|p| p.due <= self.turn);359359
self.body.pending = waiting;360360
for p in due {361
- self.gain(p.length, p.girth, p.foreskin);361
+ let foreskin = self.gain(p.length, p.girth, p.foreskin);362
+ let arrived = self.body.arrived.get_or_insert_default();363
+ arrived.length += p.length;364
+ arrived.girth += p.girth;365
+ if let Some(grown) = foreskin {366
+ *arrived.foreskin.get_or_insert(0.0) += grown;367
+ }362368
}363369
}364370
@@ -9,6 +9,7 @@ pub const X_FLOOR: HeaderName = HeaderName::from_static("x-floor");
99
pub const X_FORESKIN: HeaderName = HeaderName::from_static("x-foreskin");1010
pub const X_FRICTION: HeaderName = HeaderName::from_static("x-friction");1111
pub const X_FORUM_NOTE: HeaderName = HeaderName::from_static("x-forum-note");12
+pub const X_GAINS_ARRIVED: HeaderName = HeaderName::from_static("x-gains-arrived");1213
pub const X_GIRTH: HeaderName = HeaderName::from_static("x-girth");1314
pub const X_LENGTH: HeaderName = HeaderName::from_static("x-length");1415
pub const X_OBSERVED_BY: HeaderName = HeaderName::from_static("x-observed-by");@@ -16,8 +16,8 @@ use crate::{
1616
balance::{FRICTION_MAX, SUSPICION_LIMIT},1717
},1818
headers::{19
- X_CASH, X_EQ, X_FLOOR, X_FORESKIN, X_FRICTION, X_GIRTH, X_LENGTH, X_OBSERVED_BY,20
- X_SELF_REPORTED_LENGTH, X_SHAME, X_STAMINA, X_SUSPICION,19
+ X_CASH, X_EQ, X_FLOOR, X_FORESKIN, X_FRICTION, X_GAINS_ARRIVED, X_GIRTH, X_LENGTH,20
+ X_OBSERVED_BY, X_SELF_REPORTED_LENGTH, X_SHAME, X_STAMINA, X_SUSPICION,2121
},2222
locale::Locale,2323
problem::{PROBLEM_BASE, Problem},@@ -166,6 +166,13 @@ fn stats(gauges: &Gauges, shame: u32) -> Vec<(HeaderName, String)> {
166166
stats.push((header::VIA, "1.1 mum".into()));167167
stats.push((header::VARY, "Mum".into()));168168
}169
+ if let Some(arrived) = &gauges.arrived {170
+ let mut gains = format!("length={:.3}, girth={:.3}", arrived.length, arrived.girth);171
+ if let Some(foreskin) = arrived.foreskin {172
+ gains.push_str(&format!(", foreskin={foreskin:.3}"));173
+ }174
+ stats.push((X_GAINS_ARRIVED, gains));175
+ }169176
// RFC 9111 obsoleted Warning, which is why nobody heeds it.170177
for warning in &gauges.warnings {171178
stats.push((header::WARNING, format!("199 - \"{warning}\"")));@@ -225,3 +225,29 @@ async fn energy_drinks_add_three_stamina() {
225225
let again = send(&app, "JELQ", "/runs/cafebabe?technique=energy", &[], "").await;226226
assert_eq!(again.status(), StatusCode::FAILED_DEPENDENCY);227227
}228
+229
+#[tokio::test]230
+async fn queued_gains_announce_their_arrival() {231
+ let app = seeded_with(Floor::Bedroom, |run| {232
+ run.body.eq = 75;233
+ run.body.foreskin = Some(1.0);234
+ run.body.pending.push(crate::game::Pending {235
+ due: run.turn + 1,236
+ length: 0.105,237
+ girth: 0.0,238
+ foreskin: 0.03,239
+ });240
+ });241
+ let held = send(&app, "HOLD", "/runs/cafebabe", &[], "").await;242
+ assert_eq!(243
+ header(&held, "x-gains-arrived"),244
+ "length=0.105, girth=0.000, foreskin=0.030"245
+ );246
+ assert!(247
+ warnings(&held)248
+ .iter()249
+ .any(|w| w.contains("the queued gains have arrived"))250
+ );251
+ let later = send(&app, "GET", "/runs/cafebabe", &[], "").await;252
+ assert!(later.headers().get("x-gains-arrived").is_none());253
+}