atagen

jelq

public

an http based roguelike rpg about jelqing

Star0
Watch0

Commit 35d571ccadc4

tarball

atagen <boss@atagen.co>2026-10-14 11:35 UTC

4 files changed+23-3
http: report the run's turn and the floor's turn against its limit

Overstaying ends a run at FLOOR_LIMIT, but the only countdown was a Warning two turns out, so a player could not plan a floor.
Modified file: src/game/gauges.rs+7 additions−1 deletions
@@ -4,7 +4,7 @@ use serde_json::{Value, json};
44
55 use super::{
66 Arousal, Arrival, Elder, Excuse, Floor, Grip, Item, Observer, Run, Story, Technique,
7- balance::DANGER_EQ,
7+ balance::{DANGER_EQ, FLOOR_LIMIT},
88 techniques::{Training, Utility},
99 };
1010
@@ -24,6 +24,9 @@ pub struct Gauges {
2424 pub(crate) suspicion: u8,
2525 pub(crate) cash: u32,
2626 pub(crate) floor: u8,
27+ pub(crate) turn: u32,
28+ pub(crate) floor_turns: u32,
29+ pub(crate) floor_limit: Option<u32>,
2730 pub(crate) observed: Option<Observer>,
2831 pub(crate) mum_challenge: Option<String>,
2932 pub(crate) warnings: Vec<&'static str>,
@@ -80,6 +83,9 @@ impl Run {
8083 suspicion: self.standing.suspicion,
8184 cash: self.standing.cash,
8285 floor: self.floor.number(),
86+ turn: self.turn,
87+ floor_turns: self.here.turns,
88+ floor_limit: self.floor.timed().then_some(FLOOR_LIMIT),
8389 observed: self.observed,
8490 mum_challenge: self.mum_challenge(),
8591 warnings,
Modified file: src/headers.rs+2 additions
@@ -5,6 +5,7 @@ pub const X_CASH: HeaderName = HeaderName::from_static("x-cash");
55 pub const X_DIAGNOSIS: HeaderName = HeaderName::from_static("x-diagnosis");
66 pub const X_EQ: HeaderName = HeaderName::from_static("x-eq");
77 pub const X_FLOOR: HeaderName = HeaderName::from_static("x-floor");
8+pub const X_FLOOR_TURN: HeaderName = HeaderName::from_static("x-floor-turn");
89 pub const X_FORESKIN: HeaderName = HeaderName::from_static("x-foreskin");
910 pub const X_FRICTION: HeaderName = HeaderName::from_static("x-friction");
1011 pub const X_FORUM_NOTE: HeaderName = HeaderName::from_static("x-forum-note");
@@ -19,3 +20,4 @@ pub const X_SELF_REPORTED_LENGTH: HeaderName = HeaderName::from_static("x-self-r
1920 pub const X_SHAME: HeaderName = HeaderName::from_static("x-shame");
2021 pub const X_STAMINA: HeaderName = HeaderName::from_static("x-stamina");
2122 pub const X_SUSPICION: HeaderName = HeaderName::from_static("x-suspicion");
23+pub const X_TURN: HeaderName = HeaderName::from_static("x-turn");
Modified file: src/http/run.rs+12 additions−2 deletions
@@ -16,8 +16,9 @@ use crate::{
1616 balance::{FRICTION_MAX, SUSPICION_LIMIT},
1717 },
1818 headers::{
19- X_CASH, X_EQ, X_FLOOR, X_FORESKIN, X_FRICTION, X_GAINS_ARRIVED, X_GIRTH, X_LENGTH,
20- X_OBSERVED_BY, X_RUN_OVER, X_SELF_REPORTED_LENGTH, X_SHAME, X_STAMINA, X_SUSPICION,
19+ X_CASH, X_EQ, X_FLOOR, X_FLOOR_TURN, X_FORESKIN, X_FRICTION, X_GAINS_ARRIVED, X_GIRTH,
20+ X_LENGTH, X_OBSERVED_BY, X_RUN_OVER, X_SELF_REPORTED_LENGTH, X_SHAME, X_STAMINA,
21+ X_SUSPICION, X_TURN,
2122 },
2223 locale::Locale,
2324 problem::{PROBLEM_BASE, Problem},
@@ -164,6 +165,15 @@ fn stats(gauges: &Gauges, shame: u32) -> Vec<(HeaderName, String)> {
164165 (X_SHAME, shame.to_string()),
165166 (X_CASH, gauges.cash.to_string()),
166167 (X_FLOOR, gauges.floor.to_string()),
168+ (X_TURN, gauges.turn.to_string()),
169+ (
170+ X_FLOOR_TURN,
171+ gauges
172+ .floor_limit
173+ .map_or(gauges.floor_turns.to_string(), |limit| {
174+ format!("{}/{limit}", gauges.floor_turns)
175+ }),
176+ ),
167177 ];
168178 if let Some(observer) = gauges.observed {
169179 stats.push((X_OBSERVED_BY, observer.name().into()));
Modified file: src/tests/methods.rs+2 additions
@@ -14,6 +14,8 @@ async fn bodies_do_not_repeat_the_headers() {
1414 let Harness { app, .. } = harness(Floor::Bedroom, SEED, |_| {});
1515 let response = send(&app, "GET", "/runs/cafebabe", &[], "").await;
1616 assert!(response.headers().contains_key("x-eq"));
17+ assert_eq!(header(&response, "x-turn"), "0");
18+ assert_eq!(header(&response, "x-floor-turn"), "0/10");
1719 let body = json(response).await;
1820 for stat in [
1921 "eq",