atagen

jelq

public

an http based roguelike rpg about jelqing

Star0
Watch0
431c1bc8ded1d56c4871dc3268b363eca5d8b93e
1
ssh://brewery@pls.lobotomise.me:33/atagen/jelq.git
src/game/hazards.rsRust148 lines5.3 KB
1
use std::{ops::ControlFlow, time::SystemTime};
2
3
use axum::http::{StatusCode, header};
4
use rand::Rng;
5
use serde_json::json;
6
7
use super::{
8
    Cause, Floor, Outcome, Run,
9
    balance::{
10
        COLD_EQ, CURVE_MISSES, DANGER_EQ, DEGLOVING, DEGLOVING_INTENSITY, FRIEND, HOT_EQ,
11
        PREMATURE_EQ, RUPTURE_HOT, RUPTURE_IN_BAND, RUPTURE_PREMATURE, RUPTURE_WARM,
12
        SUSPICION_LIMIT, WANDERER_VISIT, WINDOW,
13
    },
14
    techniques::Training,
15
};
16
use crate::problem::Problem;
17
18
type Interruption = Result<ControlFlow<Outcome>, Problem>;
19
20
impl Run {
21
    /// Accidents tied to a specific technique.
22
    pub(super) fn mishaps(&mut self, training: Training, intensity: i32) -> Interruption {
23
        if training == Training::Dry && intensity >= DEGLOVING_INTENSITY && self.chance(DEGLOVING) {
24
            return Err(self.end(Cause::Degloved));
25
        }
26
        Ok(ControlFlow::Continue(()))
27
    }
28
29
    /// Everything that can go wrong on a committed turn before the roll.
30
    pub(super) fn hazards(&mut self, intensity: i32) -> Interruption {
31
        let odds = if self.eq <= DANGER_EQ {
32
            RUPTURE_IN_BAND
33
        } else if self.eq <= HOT_EQ {
34
            RUPTURE_WARM
35
        } else {
36
            RUPTURE_HOT
37
        };
38
        if self.chance(odds) {
39
            return Err(self.rupture());
40
        }
41
        if self.floor.has_window() && !self.items.blinds && self.chance(WINDOW) {
42
            self.shame += 30;
43
            self.filmed_at.get_or_insert_with(SystemTime::now);
44
            return Ok(ControlFlow::Break(
45
                Outcome::json(
46
                    StatusCode::CREATED,
47
                    json!({ "detail": "A neighbour was at the window. A recording has been created. It has been shared." }),
48
                )
49
                .header(header::LOCATION, self.path("/footage")),
50
            ));
51
        }
52
        if self.floor == Floor::ChangingRoom && self.chance(FRIEND) {
53
            self.shame += 1;
54
            return Err(Problem::new(
55
                StatusCode::USE_PROXY,
56
                "friend",
57
                "A friend has offered to help. Use Proxy is deprecated, and the server has declined on your behalf.",
58
            ));
59
        }
60
        if self.conditions.peyronie && self.chance(CURVE_MISSES) {
61
            return Err(Problem::new(
62
                StatusCode::MISDIRECTED_REQUEST,
63
                "misdirected",
64
                "The technique landed slightly to the left. It was meant for a different server.",
65
            ));
66
        }
67
        if intensity <= 2 && self.eq < 50 {
68
            self.eq = (self.eq - 10).max(0);
69
            return Err(Problem::new(
70
                StatusCode::REQUEST_TIMEOUT,
71
                "lost-it",
72
                "The request took too long. It was lost.",
73
            )
74
            .header(header::CONNECTION, "close"));
75
        }
76
        if self.eq > PREMATURE_EQ {
77
            if self.chance(RUPTURE_PREMATURE) {
78
                return Err(self.rupture());
79
            }
80
            self.shame += 5;
81
            self.next_floor(false);
82
            return Err(Problem::new(
83
                StatusCode::TOO_EARLY,
84
                "premature",
85
                "The floor has ended early. Everyone involved has agreed not to discuss it.",
86
            ));
87
        }
88
        if self.eq < COLD_EQ {
89
            return Err(Problem::new(
90
                StatusCode::NOT_FOUND,
91
                "cold",
92
                "The resource exists. It is cold.",
93
            ));
94
        }
95
        Ok(ControlFlow::Continue(()))
96
    }
97
98
    /// The enemies suspicion summons on floors without Mum.
99
    pub(super) fn floor_enemy(&mut self) -> Result<(), Problem> {
100
        let visits = u32::from(self.suspicion) + 1;
101
        let wanders_in = matches!(self.floor, Floor::Bathroom | Floor::Hotel)
102
            && self.rng.random_ratio(visits, WANDERER_VISIT);
103
        if self.suspicion < SUSPICION_LIMIT && !wanders_in {
104
            return Ok(());
105
        }
106
        match self.floor {
107
            Floor::Bathroom => {
108
                self.suspicion = 0;
109
                self.touch();
110
                if self.items.door_locks > 0 {
111
                    self.items.door_locks -= 1;
112
                    return Ok(());
113
                }
114
                self.here.flatmate_told = true;
115
                Err(Problem::new(
116
                    StatusCode::CONFLICT,
117
                    "flatmate",
118
                    "The flatmate needs the bathroom. He will mention this to people.",
119
                ))
120
            }
121
            Floor::ChangingRoom => {
122
                self.suspicion = 0;
123
                self.shame += 5;
124
                self.touch();
125
                Err(Problem::new(
126
                    StatusCode::UNAVAILABLE_FOR_LEGAL_REASONS,
127
                    "gym-staff",
128
                    "Gym staff have been notified. The server cannot serve this request for legal reasons.",
129
                ))
130
            }
131
            Floor::Hotel => {
132
                self.suspicion = 0;
133
                self.touch();
134
                if self.items.dnd_sign {
135
                    return Ok(());
136
                }
137
                self.shame += 3;
138
                Err(Problem::new(
139
                    StatusCode::UNAUTHORIZED,
140
                    "housekeeping",
141
                    "Housekeeping has entered. Housekeeping accepts no excuses.",
142
                )
143
                .header(header::WWW_AUTHENTICATE, "Excuse realm=\"housekeeping\""))
144
            }
145
            _ => Ok(()),
146
        }
147
    }
148
}