atagen

jelq

public

an http based roguelike rpg about jelqing

Star0
Watch0
cddf59e37d5f7b2a7e0f8b644252196caf5a7e97
1
ssh://brewery@pls.lobotomise.me:33/atagen/jelq.git

Blame: src/game/utility.rs

782069860236atagen2026-10-10 12:44 UTC1
use std::{
782069860236atagen2026-10-10 12:44 UTC2
    ops::ControlFlow,
a6caa2f99786atagen2026-10-12 10:38 UTC3
    time::{Duration, SystemTime},
782069860236atagen2026-10-10 12:44 UTC4
};
782069860236atagen2026-10-10 12:44 UTC5
782069860236atagen2026-10-10 12:44 UTC6
use axum::http::{StatusCode, header};
782069860236atagen2026-10-10 12:44 UTC7
use serde_json::json;
782069860236atagen2026-10-10 12:44 UTC8
782069860236atagen2026-10-10 12:44 UTC9
use super::{
782069860236atagen2026-10-10 12:44 UTC10
    Floor, Outcome, Run,
782069860236atagen2026-10-10 12:44 UTC11
    balance::{
0a0bfee8329eatagen2026-10-11 05:11 UTC12
        EDGE_EQ, EDGE_GIRTH, EDGE_LOOP, ENERGY_STAMINA, HOTEL_STRESS, ICE_EQ, PRIAPISM_EQ,
0a0bfee8329eatagen2026-10-11 05:11 UTC13
        PRIAPISM_TURNS, PUMP_GAIN, SHOWER_EQ, SUPPLEMENT_WORKS, TOWELLESS_EQ, WARMUP_EQ,
782069860236atagen2026-10-10 12:44 UTC14
    },
782069860236atagen2026-10-10 12:44 UTC15
};
782069860236atagen2026-10-10 12:44 UTC16
use crate::problem::Problem;
782069860236atagen2026-10-10 12:44 UTC17
782069860236atagen2026-10-10 12:44 UTC18
const WEEK: Duration = Duration::from_secs(7 * 24 * 60 * 60);
782069860236atagen2026-10-10 12:44 UTC19
782069860236atagen2026-10-10 12:44 UTC20
impl Run {
782069860236atagen2026-10-10 12:44 UTC21
    pub(super) fn warm_up(&mut self) -> Result<Outcome, Problem> {
4b1f5f88827datagen2026-10-13 10:18 UTC22
        if self.here.towel_warmed && !self.here.kitchen.kettle_boiled {
a6caa2f99786atagen2026-10-12 10:38 UTC23
            return Err(Problem::new(
a6caa2f99786atagen2026-10-12 10:38 UTC24
                StatusCode::CONFLICT,
a6caa2f99786atagen2026-10-12 10:38 UTC25
                "towel-cold",
4b1f5f88827datagen2026-10-13 10:18 UTC26
                "The towel has gone cold. It warms once per floor, unless someone boils the kettle.",
a6caa2f99786atagen2026-10-12 10:38 UTC27
            ));
a6caa2f99786atagen2026-10-12 10:38 UTC28
        }
3f9091557ec3atagen2026-10-11 11:43 UTC29
        if self.floor == Floor::Hotel
3f9091557ec3atagen2026-10-11 11:43 UTC30
            && self.chance(
3f9091557ec3atagen2026-10-11 11:43 UTC31
                self.decision(
3f9091557ec3atagen2026-10-11 11:43 UTC32
                    "hotel-stress",
3f9091557ec3atagen2026-10-11 11:43 UTC33
                    "Has the hotel's plumbing given up for the week?",
3f9091557ec3atagen2026-10-11 11:43 UTC34
                ),
3f9091557ec3atagen2026-10-11 11:43 UTC35
                HOTEL_STRESS,
3f9091557ec3atagen2026-10-11 11:43 UTC36
            )
3f9091557ec3atagen2026-10-11 11:43 UTC37
        {
782069860236atagen2026-10-10 12:44 UTC38
            return Err(Problem::new(
782069860236atagen2026-10-10 12:44 UTC39
                StatusCode::SERVICE_UNAVAILABLE,
782069860236atagen2026-10-10 12:44 UTC40
                "service-unavailable",
782069860236atagen2026-10-10 12:44 UTC41
                "Service is unavailable. The server estimates next week. The server is being pessimistic.",
782069860236atagen2026-10-10 12:44 UTC42
            )
782069860236atagen2026-10-10 12:44 UTC43
            .header(
782069860236atagen2026-10-10 12:44 UTC44
                header::RETRY_AFTER,
782069860236atagen2026-10-10 12:44 UTC45
                httpdate::fmt_http_date(SystemTime::now() + WEEK),
782069860236atagen2026-10-10 12:44 UTC46
            ));
782069860236atagen2026-10-10 12:44 UTC47
        }
782069860236atagen2026-10-10 12:44 UTC48
        let (boost, detail) = if self.floor == Floor::Bathroom {
782069860236atagen2026-10-10 12:44 UTC49
            (
782069860236atagen2026-10-10 12:44 UTC50
                SHOWER_EQ,
7d3fb63208bfatagen2026-10-11 04:38 UTC51
                "Warmed up. The shower is hot. Your brother's will not be.",
782069860236atagen2026-10-10 12:44 UTC52
            )
782069860236atagen2026-10-10 12:44 UTC53
        } else if self.here.towel_stolen {
782069860236atagen2026-10-10 12:44 UTC54
            (TOWELLESS_EQ, "Warmed up, poorly. The cat has the towel.")
782069860236atagen2026-10-10 12:44 UTC55
        } else {
782069860236atagen2026-10-10 12:44 UTC56
            (WARMUP_EQ, "Warmed up. The towel has cooled.")
782069860236atagen2026-10-10 12:44 UTC57
        };
782069860236atagen2026-10-10 12:44 UTC58
        self.touch();
e807266c323batagen2026-10-12 09:46 UTC59
        self.step_away();
4b1f5f88827datagen2026-10-13 10:18 UTC60
        if self.here.towel_warmed {
8b8e83329a1datagen2026-10-12 12:01 UTC61
            self.here.kitchen.kettle_boiled = false;
a6caa2f99786atagen2026-10-12 10:38 UTC62
        }
4b1f5f88827datagen2026-10-13 10:18 UTC63
        self.here.towel_warmed = true;
8b8e83329a1datagen2026-10-12 12:01 UTC64
        self.body.eq = (self.body.eq + boost).min(100);
782069860236atagen2026-10-10 12:44 UTC65
        Ok(Outcome::json(StatusCode::OK, json!({ "detail": detail })))
782069860236atagen2026-10-10 12:44 UTC66
    }
782069860236atagen2026-10-10 12:44 UTC67
782069860236atagen2026-10-10 12:44 UTC68
    pub(super) fn ice(&mut self) -> Result<Outcome, Problem> {
8b8e83329a1datagen2026-10-12 12:01 UTC69
        if self.items.stores.ice_packs == 0 {
782069860236atagen2026-10-10 12:44 UTC70
            return Err(Problem::new(
782069860236atagen2026-10-10 12:44 UTC71
                StatusCode::FAILED_DEPENDENCY,
782069860236atagen2026-10-10 12:44 UTC72
                "no-ice",
782069860236atagen2026-10-10 12:44 UTC73
                "The ice technique depends on an ice pack. There are none.",
782069860236atagen2026-10-10 12:44 UTC74
            ));
782069860236atagen2026-10-10 12:44 UTC75
        }
782069860236atagen2026-10-10 12:44 UTC76
        self.touch();
e807266c323batagen2026-10-12 09:46 UTC77
        self.step_away();
8b8e83329a1datagen2026-10-12 12:01 UTC78
        self.items.stores.ice_packs -= 1;
8b8e83329a1datagen2026-10-12 12:01 UTC79
        if self.body.conditions.priapism_turns > 0 {
782069860236atagen2026-10-10 12:44 UTC80
            return Ok(Outcome::json(
782069860236atagen2026-10-10 12:44 UTC81
                StatusCode::OK,
782069860236atagen2026-10-10 12:44 UTC82
                json!({ "detail": "The ice has no effect. The condition persists. The ice pack is gone." }),
782069860236atagen2026-10-10 12:44 UTC83
            ));
782069860236atagen2026-10-10 12:44 UTC84
        }
8b8e83329a1datagen2026-10-12 12:01 UTC85
        self.body.eq = (self.body.eq - ICE_EQ).max(0);
8b8e83329a1datagen2026-10-12 12:01 UTC86
        let detail = if self.body.conditions.friction_burn {
8b8e83329a1datagen2026-10-12 12:01 UTC87
            self.body.conditions.friction_burn = false;
5dfebcc0ac43atagen2026-10-11 05:28 UTC88
            "The friction burn is treated. EQ has been reduced. The ice pack is gone."
5dfebcc0ac43atagen2026-10-11 05:28 UTC89
        } else {
5dfebcc0ac43atagen2026-10-11 05:28 UTC90
            "EQ has been reduced. The ice pack is gone."
5dfebcc0ac43atagen2026-10-11 05:28 UTC91
        };
5dfebcc0ac43atagen2026-10-11 05:28 UTC92
        Ok(Outcome::json(StatusCode::OK, json!({ "detail": detail })))
782069860236atagen2026-10-10 12:44 UTC93
    }
782069860236atagen2026-10-10 12:44 UTC94
0a0bfee8329eatagen2026-10-11 05:11 UTC95
    pub(super) fn energy(&mut self) -> Result<Outcome, Problem> {
8b8e83329a1datagen2026-10-12 12:01 UTC96
        if self.items.stores.energy_drinks == 0 {
0a0bfee8329eatagen2026-10-11 05:11 UTC97
            return Err(Problem::new(
0a0bfee8329eatagen2026-10-11 05:11 UTC98
                StatusCode::FAILED_DEPENDENCY,
0a0bfee8329eatagen2026-10-11 05:11 UTC99
                "no-energy-drink",
0a0bfee8329eatagen2026-10-11 05:11 UTC100
                "The energy technique depends on an energy drink.",
0a0bfee8329eatagen2026-10-11 05:11 UTC101
            ));
0a0bfee8329eatagen2026-10-11 05:11 UTC102
        }
8b8e83329a1datagen2026-10-12 12:01 UTC103
        self.items.stores.energy_drinks -= 1;
e807266c323batagen2026-10-12 09:46 UTC104
        self.step_away();
a11497af08aaatagen2026-10-13 12:04 UTC105
        self.body.exhausted = false;
8b8e83329a1datagen2026-10-12 12:01 UTC106
        self.body.stamina = (self.body.stamina + ENERGY_STAMINA).min(self.max_stamina());
0a0bfee8329eatagen2026-10-11 05:11 UTC107
        self.touch();
0a0bfee8329eatagen2026-10-11 05:11 UTC108
        Ok(Outcome::json(
0a0bfee8329eatagen2026-10-11 05:11 UTC109
            StatusCode::OK,
0a0bfee8329eatagen2026-10-11 05:11 UTC110
            json!({ "detail": "The energy arrives before the regret. Stamina +3." }),
0a0bfee8329eatagen2026-10-11 05:11 UTC111
        ))
0a0bfee8329eatagen2026-10-11 05:11 UTC112
    }
0a0bfee8329eatagen2026-10-11 05:11 UTC113
782069860236atagen2026-10-10 12:44 UTC114
    pub(super) fn supplement(&mut self) -> Result<Outcome, Problem> {
8b8e83329a1datagen2026-10-12 12:01 UTC115
        if self.items.stores.supplements == 0 {
782069860236atagen2026-10-10 12:44 UTC116
            return Err(Problem::new(
782069860236atagen2026-10-10 12:44 UTC117
                StatusCode::FAILED_DEPENDENCY,
782069860236atagen2026-10-10 12:44 UTC118
                "no-supplement",
782069860236atagen2026-10-10 12:44 UTC119
                "The supplement technique depends on a supplement.",
782069860236atagen2026-10-10 12:44 UTC120
            ));
782069860236atagen2026-10-10 12:44 UTC121
        }
8b8e83329a1datagen2026-10-12 12:01 UTC122
        self.items.stores.supplements -= 1;
e807266c323batagen2026-10-12 09:46 UTC123
        self.step_away();
782069860236atagen2026-10-10 12:44 UTC124
        self.touch();
3f9091557ec3atagen2026-10-11 11:43 UTC125
        if self.chance(
3f9091557ec3atagen2026-10-11 11:43 UTC126
            self.decision(
3f9091557ec3atagen2026-10-11 11:43 UTC127
                "supplement",
3f9091557ec3atagen2026-10-11 11:43 UTC128
                "Does the supplement from Pump-Bro actually work?",
3f9091557ec3atagen2026-10-11 11:43 UTC129
            ),
3f9091557ec3atagen2026-10-11 11:43 UTC130
            SUPPLEMENT_WORKS,
3f9091557ec3atagen2026-10-11 11:43 UTC131
        ) {
8b8e83329a1datagen2026-10-12 12:01 UTC132
            self.body.stamina = self.max_stamina();
8b8e83329a1datagen2026-10-12 12:01 UTC133
            self.body.conditions.priapism_turns = PRIAPISM_TURNS;
8b8e83329a1datagen2026-10-12 12:01 UTC134
            self.body.eq = self.body.eq.max(PRIAPISM_EQ);
782069860236atagen2026-10-10 12:44 UTC135
            return Ok(Outcome::json(
782069860236atagen2026-10-10 12:44 UTC136
                StatusCode::OK,
0a0bfee8329eatagen2026-10-11 05:11 UTC137
                json!({ "detail": "The upstream returned a valid response. It is still returning it. Stamina is fully restored." }),
782069860236atagen2026-10-10 12:44 UTC138
            ));
782069860236atagen2026-10-10 12:44 UTC139
        }
782069860236atagen2026-10-10 12:44 UTC140
        Err(Problem::new(
782069860236atagen2026-10-10 12:44 UTC141
            StatusCode::BAD_GATEWAY,
782069860236atagen2026-10-10 12:44 UTC142
            "bad-gateway",
782069860236atagen2026-10-10 12:44 UTC143
            "The upstream returned an invalid response.",
782069860236atagen2026-10-10 12:44 UTC144
        )
782069860236atagen2026-10-10 12:44 UTC145
        .with("upstream", "Pump-Bro"))
782069860236atagen2026-10-10 12:44 UTC146
    }
782069860236atagen2026-10-10 12:44 UTC147
a6caa2f99786atagen2026-10-12 10:38 UTC148
    pub(super) fn edge(&mut self) -> Result<Outcome, Problem> {
bf5f8cb6f60fatagen2026-10-13 12:10 UTC149
        self.chafe(None, 5, false);
3ac624339c98atagen2026-10-13 12:21 UTC150
        self.commit(5, None, 1)?;
e807266c323batagen2026-10-12 09:46 UTC151
        if let ControlFlow::Break(interrupted) = self.hazards(5)? {
e807266c323batagen2026-10-12 09:46 UTC152
            return Ok(interrupted);
e807266c323batagen2026-10-12 09:46 UTC153
        }
782069860236atagen2026-10-10 12:44 UTC154
        self.here.edges += 1;
8b8e83329a1datagen2026-10-12 12:01 UTC155
        self.body.eq = (self.body.eq + EDGE_EQ).min(100);
8b8e83329a1datagen2026-10-12 12:01 UTC156
        self.body.girth += EDGE_GIRTH;
782069860236atagen2026-10-10 12:44 UTC157
        if self.here.edges >= EDGE_LOOP {
782069860236atagen2026-10-10 12:44 UTC158
            self.here.edges = 0;
a6caa2f99786atagen2026-10-12 10:38 UTC159
            self.exhaust();
782069860236atagen2026-10-10 12:44 UTC160
            return Err(Problem::new(
782069860236atagen2026-10-10 12:44 UTC161
                StatusCode::LOOP_DETECTED,
782069860236atagen2026-10-10 12:44 UTC162
                "edging-loop",
782069860236atagen2026-10-10 12:44 UTC163
                "Edging has looped. The server detected an infinite loop and terminated it.",
782069860236atagen2026-10-10 12:44 UTC164
            ));
782069860236atagen2026-10-10 12:44 UTC165
        }
782069860236atagen2026-10-10 12:44 UTC166
        Ok(Outcome::json(
782069860236atagen2026-10-10 12:44 UTC167
            StatusCode::OK,
782069860236atagen2026-10-10 12:44 UTC168
            json!({ "detail": "Edged. EQ is rising. Nothing else is.", "edges": self.here.edges }),
782069860236atagen2026-10-10 12:44 UTC169
        ))
782069860236atagen2026-10-10 12:44 UTC170
    }
782069860236atagen2026-10-10 12:44 UTC171
a6caa2f99786atagen2026-10-12 10:38 UTC172
    pub(super) fn pump(&mut self) -> Result<Outcome, Problem> {
3ac624339c98atagen2026-10-13 12:21 UTC173
        self.commit(4, None, 1)?;
782069860236atagen2026-10-10 12:44 UTC174
        if let ControlFlow::Break(interrupted) = self.hazards(4)? {
782069860236atagen2026-10-10 12:44 UTC175
            return Ok(interrupted);
782069860236atagen2026-10-10 12:44 UTC176
        }
782069860236atagen2026-10-10 12:44 UTC177
        self.here.temp_length += PUMP_GAIN;
782069860236atagen2026-10-10 12:44 UTC178
        Ok(Outcome::json(
782069860236atagen2026-10-10 12:44 UTC179
            StatusCode::TEMPORARY_REDIRECT,
782069860236atagen2026-10-10 12:44 UTC180
            json!({ "detail": "Gains applied. They are temporary.", "length": PUMP_GAIN }),
782069860236atagen2026-10-10 12:44 UTC181
        )
782069860236atagen2026-10-10 12:44 UTC182
        .header(header::LOCATION, self.path("/length")))
782069860236atagen2026-10-10 12:44 UTC183
    }
782069860236atagen2026-10-10 12:44 UTC184
}