atagen

jelq

public

an http based roguelike rpg about jelqing

Star0
Watch0
4b1f5f88827de40c3cc25edaf1c8acea7192d6cf
1
ssh://brewery@pls.lobotomise.me:33/atagen/jelq.git
src/game/utility.rsRust184 lines6.5 KB
1
use std::{
2
    ops::ControlFlow,
3
    time::{Duration, SystemTime},
4
};
5
6
use axum::http::{StatusCode, header};
7
use serde_json::json;
8
9
use super::{
10
    Floor, Outcome, Run,
11
    balance::{
12
        EDGE_EQ, EDGE_GIRTH, EDGE_LOOP, ENERGY_STAMINA, HOTEL_STRESS, ICE_EQ, PRIAPISM_EQ,
13
        PRIAPISM_TURNS, PUMP_GAIN, SHOWER_EQ, SUPPLEMENT_WORKS, TOWELLESS_EQ, WARMUP_EQ,
14
    },
15
};
16
use crate::problem::Problem;
17
18
const WEEK: Duration = Duration::from_secs(7 * 24 * 60 * 60);
19
20
impl Run {
21
    pub(super) fn warm_up(&mut self) -> Result<Outcome, Problem> {
22
        if self.here.towel_warmed && !self.here.kitchen.kettle_boiled {
23
            return Err(Problem::new(
24
                StatusCode::CONFLICT,
25
                "towel-cold",
26
                "The towel has gone cold. It warms once per floor, unless someone boils the kettle.",
27
            ));
28
        }
29
        if self.floor == Floor::Hotel
30
            && self.chance(
31
                self.decision(
32
                    "hotel-stress",
33
                    "Has the hotel's plumbing given up for the week?",
34
                ),
35
                HOTEL_STRESS,
36
            )
37
        {
38
            return Err(Problem::new(
39
                StatusCode::SERVICE_UNAVAILABLE,
40
                "service-unavailable",
41
                "Service is unavailable. The server estimates next week. The server is being pessimistic.",
42
            )
43
            .header(
44
                header::RETRY_AFTER,
45
                httpdate::fmt_http_date(SystemTime::now() + WEEK),
46
            ));
47
        }
48
        let (boost, detail) = if self.floor == Floor::Bathroom {
49
            (
50
                SHOWER_EQ,
51
                "Warmed up. The shower is hot. Your brother's will not be.",
52
            )
53
        } else if self.here.towel_stolen {
54
            (TOWELLESS_EQ, "Warmed up, poorly. The cat has the towel.")
55
        } else {
56
            (WARMUP_EQ, "Warmed up. The towel has cooled.")
57
        };
58
        self.touch();
59
        self.step_away();
60
        if self.here.towel_warmed {
61
            self.here.kitchen.kettle_boiled = false;
62
        }
63
        self.here.towel_warmed = true;
64
        self.body.warmed_up = true;
65
        self.body.eq = (self.body.eq + boost).min(100);
66
        Ok(Outcome::json(StatusCode::OK, json!({ "detail": detail })))
67
    }
68
69
    pub(super) fn ice(&mut self) -> Result<Outcome, Problem> {
70
        if self.items.stores.ice_packs == 0 {
71
            return Err(Problem::new(
72
                StatusCode::FAILED_DEPENDENCY,
73
                "no-ice",
74
                "The ice technique depends on an ice pack. There are none.",
75
            ));
76
        }
77
        self.touch();
78
        self.step_away();
79
        self.items.stores.ice_packs -= 1;
80
        if self.body.conditions.priapism_turns > 0 {
81
            return Ok(Outcome::json(
82
                StatusCode::OK,
83
                json!({ "detail": "The ice has no effect. The condition persists. The ice pack is gone." }),
84
            ));
85
        }
86
        self.body.eq = (self.body.eq - ICE_EQ).max(0);
87
        let detail = if self.body.conditions.friction_burn {
88
            self.body.conditions.friction_burn = false;
89
            "The friction burn is treated. EQ has been reduced. The ice pack is gone."
90
        } else {
91
            "EQ has been reduced. The ice pack is gone."
92
        };
93
        Ok(Outcome::json(StatusCode::OK, json!({ "detail": detail })))
94
    }
95
96
    pub(super) fn energy(&mut self) -> Result<Outcome, Problem> {
97
        if self.items.stores.energy_drinks == 0 {
98
            return Err(Problem::new(
99
                StatusCode::FAILED_DEPENDENCY,
100
                "no-energy-drink",
101
                "The energy technique depends on an energy drink.",
102
            ));
103
        }
104
        self.items.stores.energy_drinks -= 1;
105
        self.step_away();
106
        self.body.stamina = (self.body.stamina + ENERGY_STAMINA).min(self.max_stamina());
107
        self.touch();
108
        Ok(Outcome::json(
109
            StatusCode::OK,
110
            json!({ "detail": "The energy arrives before the regret. Stamina +3." }),
111
        ))
112
    }
113
114
    pub(super) fn supplement(&mut self) -> Result<Outcome, Problem> {
115
        if self.items.stores.supplements == 0 {
116
            return Err(Problem::new(
117
                StatusCode::FAILED_DEPENDENCY,
118
                "no-supplement",
119
                "The supplement technique depends on a supplement.",
120
            ));
121
        }
122
        self.items.stores.supplements -= 1;
123
        self.step_away();
124
        self.touch();
125
        if self.chance(
126
            self.decision(
127
                "supplement",
128
                "Does the supplement from Pump-Bro actually work?",
129
            ),
130
            SUPPLEMENT_WORKS,
131
        ) {
132
            self.body.stamina = self.max_stamina();
133
            self.body.conditions.priapism_turns = PRIAPISM_TURNS;
134
            self.body.eq = self.body.eq.max(PRIAPISM_EQ);
135
            return Ok(Outcome::json(
136
                StatusCode::OK,
137
                json!({ "detail": "The upstream returned a valid response. It is still returning it. Stamina is fully restored." }),
138
            ));
139
        }
140
        Err(Problem::new(
141
            StatusCode::BAD_GATEWAY,
142
            "bad-gateway",
143
            "The upstream returned an invalid response.",
144
        )
145
        .with("upstream", "Pump-Bro"))
146
    }
147
148
    pub(super) fn edge(&mut self) -> Result<Outcome, Problem> {
149
        self.chafe(None, 5);
150
        self.commit(5, None, 1);
151
        if let ControlFlow::Break(interrupted) = self.hazards(5)? {
152
            return Ok(interrupted);
153
        }
154
        self.here.edges += 1;
155
        self.body.eq = (self.body.eq + EDGE_EQ).min(100);
156
        self.body.girth += EDGE_GIRTH;
157
        if self.here.edges >= EDGE_LOOP {
158
            self.here.edges = 0;
159
            self.exhaust();
160
            return Err(Problem::new(
161
                StatusCode::LOOP_DETECTED,
162
                "edging-loop",
163
                "Edging has looped. The server detected an infinite loop and terminated it.",
164
            ));
165
        }
166
        Ok(Outcome::json(
167
            StatusCode::OK,
168
            json!({ "detail": "Edged. EQ is rising. Nothing else is.", "edges": self.here.edges }),
169
        ))
170
    }
171
172
    pub(super) fn pump(&mut self) -> Result<Outcome, Problem> {
173
        self.commit(4, None, 1);
174
        if let ControlFlow::Break(interrupted) = self.hazards(4)? {
175
            return Ok(interrupted);
176
        }
177
        self.here.temp_length += PUMP_GAIN;
178
        Ok(Outcome::json(
179
            StatusCode::TEMPORARY_REDIRECT,
180
            json!({ "detail": "Gains applied. They are temporary.", "length": PUMP_GAIN }),
181
        )
182
        .header(header::LOCATION, self.path("/length")))
183
    }
184
}