atagen

jelq

public

an http based roguelike rpg about jelqing

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