an http based roguelike rpg about jelqing
Blame: src/game/rest.rs
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 1 | use super::{ |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 2 | Notice, Outcome, Run, Story, |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 3 | balance::{ |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 4 | DANGER_EQ, FRICTION_HOLD, FRICTION_MEDITATE, HOLD_EQ, MEDITATION_EQ, REFLECTION, |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 5 | RUPTURE_HOLD, |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 6 | }, |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 7 | }; |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 8 | use crate::problem::Problem; |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 9 | use axum::http::StatusCode; |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 10 | use serde_json::json; |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 11 | |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 12 | impl Run { |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 13 | pub fn can_hold(&self) -> bool { |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 14 | self.body.eq > DANGER_EQ || self.body.stamina <= 2 |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 15 | } |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 16 | |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 17 | pub fn hold(&mut self) -> Result<Outcome, Problem> { |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 18 | if self.online.story == Story::Pending { |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 19 | return Ok(self.branch_offer()); |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 20 | } |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 21 | if self.items.kit.cage { |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 22 | return Err(Problem::new( |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 23 | StatusCode::LOCKED, |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 24 | "caged", |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 25 | "The cage is locked. The key is not in the box.", |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 26 | )); |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 27 | } |
3ac624339c98 | atagen | 2026-10-13 12:21 UTC | 28 | self.begin_turn()?; |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 29 | if self.oracle.chance_not( |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 30 | self.decision("rupture", "The pause is uneventful"), |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 31 | RUPTURE_HOLD, |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 32 | ) { |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 33 | return Err(self.rupture()); |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 34 | } |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 35 | if self.body.exhausted { |
f48daa8adf59 | atagen | 2026-10-13 12:51 UTC | 36 | let second_wind = self.recover(); |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 37 | self.shed(FRICTION_HOLD); |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 38 | self.settle(); |
f48daa8adf59 | atagen | 2026-10-13 12:51 UTC | 39 | let back = if second_wind { |
f48daa8adf59 | atagen | 2026-10-13 12:51 UTC | 40 | "The count went well past ten, and something came back that had no business coming back. Stamina is full." |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 41 | } else { |
f48daa8adf59 | atagen | 2026-10-13 12:51 UTC | 42 | "The count went well past ten. Some of the stamina is back." |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 43 | }; |
f48daa8adf59 | atagen | 2026-10-13 12:51 UTC | 44 | let after = if self.body.conditions.priapism_turns > 0 { |
f48daa8adf59 | atagen | 2026-10-13 12:51 UTC | 45 | "It went down a little. Maybe. You hope." |
f48daa8adf59 | atagen | 2026-10-13 12:51 UTC | 46 | } else { |
f48daa8adf59 | atagen | 2026-10-13 12:51 UTC | 47 | "Everything else has gone quiet, and you are cold again." |
f48daa8adf59 | atagen | 2026-10-13 12:51 UTC | 48 | }; |
f48daa8adf59 | atagen | 2026-10-13 12:51 UTC | 49 | return Ok(Outcome::json( |
f48daa8adf59 | atagen | 2026-10-13 12:51 UTC | 50 | StatusCode::OK, |
f48daa8adf59 | atagen | 2026-10-13 12:51 UTC | 51 | json!({ "detail": format!("{back} {after}") }), |
f48daa8adf59 | atagen | 2026-10-13 12:51 UTC | 52 | )); |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 53 | } |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 54 | if self.chance( |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 55 | self.decision( |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 56 | "reflection", |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 57 | "In the quiet afterwards, have you caught your own eye in the mirror?", |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 58 | ), |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 59 | REFLECTION, |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 60 | ) { |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 61 | self.body.eq = 0; |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 62 | self.standing.shame += 1; |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 63 | self.notices.push(Notice::Reflection); |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 64 | } else { |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 65 | self.body.eq = (self.body.eq - HOLD_EQ).clamp(0, 100); |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 66 | } |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 67 | self.body.stamina = (self.body.stamina + 1).min(self.max_stamina()); |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 68 | self.shed(FRICTION_HOLD); |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 69 | self.settle(); |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 70 | Ok(Outcome::empty(StatusCode::NO_CONTENT)) |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 71 | } |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 72 | |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 73 | /// The breathing technique from the forum's replies. It spends no stamina and the turn is |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 74 | /// not the floor's, but each floor allows it once. |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 75 | pub(super) fn meditate(&mut self) -> Result<Outcome, Problem> { |
880b29a0c11e | atagen | 2026-10-13 09:27 UTC | 76 | if !self.online.meditation_taught { |
880b29a0c11e | atagen | 2026-10-13 09:27 UTC | 77 | return Err(Problem::new( |
880b29a0c11e | atagen | 2026-10-13 09:27 UTC | 78 | StatusCode::FORBIDDEN, |
880b29a0c11e | atagen | 2026-10-13 09:27 UTC | 79 | "technique-locked", |
880b29a0c11e | atagen | 2026-10-13 09:27 UTC | 80 | "Somebody on a forum knows how to breathe. You have not found the reply.", |
880b29a0c11e | atagen | 2026-10-13 09:27 UTC | 81 | )); |
880b29a0c11e | atagen | 2026-10-13 09:27 UTC | 82 | } |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 83 | if self.here.meditated { |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 84 | return Err(Problem::new( |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 85 | StatusCode::CONFLICT, |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 86 | "already-meditated", |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 87 | "This floor has had its meditation.", |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 88 | )); |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 89 | } |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 90 | self.here.meditated = true; |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 91 | self.step_away(); |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 92 | self.reset_eq(self.body.eq - MEDITATION_EQ); |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 93 | self.shed(FRICTION_MEDITATE); |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 94 | self.touch(); |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 95 | Ok(Outcome::json( |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 96 | StatusCode::OK, |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 97 | json!({ |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 98 | "detail": "In through the nose, out through the mouth. EQ falls by ten.", |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 99 | }), |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 100 | )) |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 101 | } |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 102 | } |