atagen

jelq

public

an http based roguelike rpg about jelqing

Star0
Watch0
139164489032852fc1d60b88c7c430c9939858f7
1
ssh://brewery@pls.lobotomise.me:33/atagen/jelq.git
src/game/hazards.rsRust155 lines5.6 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
        BURN_RUPTURE, COLD_EQ, CURVE_MISSES, DANGER_EQ, DEGLOVING, DEGLOVING_INTENSITY, FRIEND,
11
        HOT_EQ, 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 burn = if self.conditions.friction_burn {
32
            BURN_RUPTURE
33
        } else {
34
            0
35
        };
36
        let odds = if self.eq <= DANGER_EQ - burn {
37
            RUPTURE_IN_BAND
38
        } else if self.eq <= HOT_EQ - burn {
39
            RUPTURE_WARM
40
        } else {
41
            RUPTURE_HOT
42
        };
43
        if self.chance(odds) {
44
            return Err(self.rupture());
45
        }
46
        if self.floor.has_window() && !self.items.blinds && self.chance(WINDOW) {
47
            self.shame += 30;
48
            self.filmed_at.get_or_insert_with(SystemTime::now);
49
            return Ok(ControlFlow::Break(
50
                Outcome::json(
51
                    StatusCode::CREATED,
52
                    json!({ "detail": "A neighbour was at the window. A recording has been created. It has been shared." }),
53
                )
54
                .header(header::LOCATION, self.path("/footage")),
55
            ));
56
        }
57
        if self.floor == Floor::ChangingRoom && self.chance(FRIEND) {
58
            self.shame += 1;
59
            return Err(Problem::new(
60
                StatusCode::USE_PROXY,
61
                "friend",
62
                "A friend has offered to help. Use Proxy is deprecated, and the server has declined on your behalf.",
63
            ));
64
        }
65
        if self.conditions.peyronie && self.chance(CURVE_MISSES) {
66
            return Err(Problem::new(
67
                StatusCode::MISDIRECTED_REQUEST,
68
                "misdirected",
69
                "The technique landed slightly to the left. It was meant for a different server.",
70
            ));
71
        }
72
        if intensity <= 2 && self.eq < 50 {
73
            self.eq = (self.eq - 10).max(0);
74
            return Err(Problem::new(
75
                StatusCode::REQUEST_TIMEOUT,
76
                "lost-it",
77
                "The request took too long. It was lost.",
78
            )
79
            .header(header::CONNECTION, "close"));
80
        }
81
        if self.eq > PREMATURE_EQ - burn {
82
            if self.chance(RUPTURE_PREMATURE) {
83
                return Err(self.rupture());
84
            }
85
            self.shame += 5;
86
            self.next_floor(false);
87
            return Err(Problem::new(
88
                StatusCode::TOO_EARLY,
89
                "premature",
90
                "The floor has ended early. Everyone involved has agreed not to discuss it.",
91
            ));
92
        }
93
        if self.eq < COLD_EQ {
94
            return Err(Problem::new(
95
                StatusCode::NOT_FOUND,
96
                "cold",
97
                "The resource exists. It is cold.",
98
            ));
99
        }
100
        Ok(ControlFlow::Continue(()))
101
    }
102
103
    /// The enemies suspicion summons on floors without Mum.
104
    pub(super) fn floor_enemy(&mut self) -> Result<(), Problem> {
105
        let visits = u32::from(self.suspicion) + 1;
106
        let wanders_in = matches!(self.floor, Floor::Bathroom | Floor::Hotel)
107
            && self.rng.random_ratio(visits, WANDERER_VISIT);
108
        if self.suspicion < SUSPICION_LIMIT && !wanders_in {
109
            return Ok(());
110
        }
111
        match self.floor {
112
            Floor::Bathroom => {
113
                self.suspicion = 0;
114
                self.touch();
115
                if self.items.door_locks > 0 {
116
                    self.items.door_locks -= 1;
117
                    self.notices.push("your brother tried the door");
118
                    return Ok(());
119
                }
120
                self.here.brother_told = true;
121
                Err(Problem::new(
122
                    StatusCode::CONFLICT,
123
                    "brother",
124
                    "Your brother needs the bathroom. He will tell Mum.",
125
                ))
126
            }
127
            Floor::ChangingRoom => {
128
                self.suspicion = 0;
129
                self.shame += 5;
130
                self.touch();
131
                Err(Problem::new(
132
                    StatusCode::UNAVAILABLE_FOR_LEGAL_REASONS,
133
                    "gym-staff",
134
                    "Gym staff have been notified. The server cannot serve this request for legal reasons.",
135
                ))
136
            }
137
            Floor::Hotel => {
138
                self.suspicion = 0;
139
                self.touch();
140
                if self.items.dnd_sign {
141
                    self.notices.push("housekeeping read the sign");
142
                    return Ok(());
143
                }
144
                self.shame += 3;
145
                Err(Problem::new(
146
                    StatusCode::UNAUTHORIZED,
147
                    "housekeeping",
148
                    "Housekeeping has entered. Housekeeping accepts no excuses.",
149
                )
150
                .header(header::WWW_AUTHENTICATE, "Excuse realm=\"housekeeping\""))
151
            }
152
            _ => Ok(()),
153
        }
154
    }
155
}