atagen

jelq

public

an http based roguelike rpg about jelqing

Star0
Watch0
c4d70621d377d45e3d418ac9197443c1b5d36399
1
ssh://brewery@pls.lobotomise.me:33/atagen/jelq.git
src/game/utility.rsRust183 lines6.3 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.warmed_up && !self.here.kettle_boiled {
23
            return Err(Problem::new(
24
                StatusCode::CONFLICT,
25
                "towel-cold",
26
                "The towel has gone cold. It warms once per floor, or once after the refractory period, 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.warmed_up {
61
            self.here.kettle_boiled = false;
62
        }
63
        self.warmed_up = true;
64
        self.eq = (self.eq + boost).min(100);
65
        Ok(Outcome::json(StatusCode::OK, json!({ "detail": detail })))
66
    }
67
68
    pub(super) fn ice(&mut self) -> Result<Outcome, Problem> {
69
        if self.items.ice_packs == 0 {
70
            return Err(Problem::new(
71
                StatusCode::FAILED_DEPENDENCY,
72
                "no-ice",
73
                "The ice technique depends on an ice pack. There are none.",
74
            ));
75
        }
76
        self.touch();
77
        self.step_away();
78
        self.items.ice_packs -= 1;
79
        if self.conditions.priapism_turns > 0 {
80
            return Ok(Outcome::json(
81
                StatusCode::OK,
82
                json!({ "detail": "The ice has no effect. The condition persists. The ice pack is gone." }),
83
            ));
84
        }
85
        self.eq = (self.eq - ICE_EQ).max(0);
86
        let detail = if self.conditions.friction_burn {
87
            self.conditions.friction_burn = false;
88
            "The friction burn is treated. EQ has been reduced. The ice pack is gone."
89
        } else {
90
            "EQ has been reduced. The ice pack is gone."
91
        };
92
        Ok(Outcome::json(StatusCode::OK, json!({ "detail": detail })))
93
    }
94
95
    pub(super) fn energy(&mut self) -> Result<Outcome, Problem> {
96
        if self.items.energy_drinks == 0 {
97
            return Err(Problem::new(
98
                StatusCode::FAILED_DEPENDENCY,
99
                "no-energy-drink",
100
                "The energy technique depends on an energy drink.",
101
            ));
102
        }
103
        self.items.energy_drinks -= 1;
104
        self.step_away();
105
        self.stamina = (self.stamina + ENERGY_STAMINA).min(self.max_stamina());
106
        self.touch();
107
        Ok(Outcome::json(
108
            StatusCode::OK,
109
            json!({ "detail": "The energy arrives before the regret. Stamina +3." }),
110
        ))
111
    }
112
113
    pub(super) fn supplement(&mut self) -> Result<Outcome, Problem> {
114
        if self.items.supplements == 0 {
115
            return Err(Problem::new(
116
                StatusCode::FAILED_DEPENDENCY,
117
                "no-supplement",
118
                "The supplement technique depends on a supplement.",
119
            ));
120
        }
121
        self.items.supplements -= 1;
122
        self.step_away();
123
        self.touch();
124
        if self.chance(
125
            self.decision(
126
                "supplement",
127
                "Does the supplement from Pump-Bro actually work?",
128
            ),
129
            SUPPLEMENT_WORKS,
130
        ) {
131
            self.stamina = self.max_stamina();
132
            self.conditions.priapism_turns = PRIAPISM_TURNS;
133
            self.eq = self.eq.max(PRIAPISM_EQ);
134
            return Ok(Outcome::json(
135
                StatusCode::OK,
136
                json!({ "detail": "The upstream returned a valid response. It is still returning it. Stamina is fully restored." }),
137
            ));
138
        }
139
        Err(Problem::new(
140
            StatusCode::BAD_GATEWAY,
141
            "bad-gateway",
142
            "The upstream returned an invalid response.",
143
        )
144
        .with("upstream", "Pump-Bro"))
145
    }
146
147
    pub(super) fn edge(&mut self) -> Result<Outcome, Problem> {
148
        self.chafe(None, 5);
149
        self.commit(5, None, 1);
150
        if let ControlFlow::Break(interrupted) = self.hazards(5)? {
151
            return Ok(interrupted);
152
        }
153
        self.here.edges += 1;
154
        self.eq = (self.eq + EDGE_EQ).min(100);
155
        self.girth += EDGE_GIRTH;
156
        if self.here.edges >= EDGE_LOOP {
157
            self.here.edges = 0;
158
            self.exhaust();
159
            return Err(Problem::new(
160
                StatusCode::LOOP_DETECTED,
161
                "edging-loop",
162
                "Edging has looped. The server detected an infinite loop and terminated it.",
163
            ));
164
        }
165
        Ok(Outcome::json(
166
            StatusCode::OK,
167
            json!({ "detail": "Edged. EQ is rising. Nothing else is.", "edges": self.here.edges }),
168
        ))
169
    }
170
171
    pub(super) fn pump(&mut self) -> Result<Outcome, Problem> {
172
        self.commit(4, None, 1);
173
        if let ControlFlow::Break(interrupted) = self.hazards(4)? {
174
            return Ok(interrupted);
175
        }
176
        self.here.temp_length += PUMP_GAIN;
177
        Ok(Outcome::json(
178
            StatusCode::TEMPORARY_REDIRECT,
179
            json!({ "detail": "Gains applied. They are temporary.", "length": PUMP_GAIN }),
180
        )
181
        .header(header::LOCATION, self.path("/length")))
182
    }
183
}