atagen

jelq

public

an http based roguelike rpg about jelqing

Star0
Watch0
058650ec79d6eb6841ce768ab49335ed74ae8b97
1
ssh://brewery@pls.lobotomise.me:33/atagen/jelq.git

Blame: src/game/state.rs

782069860236atagen2026-10-10 12:44 UTC1
use axum::http::StatusCode;
782069860236atagen2026-10-10 12:44 UTC2
782069860236atagen2026-10-10 12:44 UTC3
use crate::problem::Problem;
782069860236atagen2026-10-10 12:44 UTC4
782069860236atagen2026-10-10 12:44 UTC5
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
782069860236atagen2026-10-10 12:44 UTC6
#[repr(u8)]
782069860236atagen2026-10-10 12:44 UTC7
pub enum Floor {
782069860236atagen2026-10-10 12:44 UTC8
    Bedroom = 1,
782069860236atagen2026-10-10 12:44 UTC9
    Bathroom = 2,
9683736a2c5eatagen2026-10-10 13:15 UTC10
    ChangingRoom = 3,
9683736a2c5eatagen2026-10-10 13:15 UTC11
    Nans = 4,
782069860236atagen2026-10-10 12:44 UTC12
    Hotel = 5,
782069860236atagen2026-10-10 12:44 UTC13
    Forum = 6,
782069860236atagen2026-10-10 12:44 UTC14
    Clinic = 7,
782069860236atagen2026-10-10 12:44 UTC15
}
782069860236atagen2026-10-10 12:44 UTC16
782069860236atagen2026-10-10 12:44 UTC17
impl Floor {
782069860236atagen2026-10-10 12:44 UTC18
    pub fn number(self) -> u8 {
782069860236atagen2026-10-10 12:44 UTC19
        self as u8
782069860236atagen2026-10-10 12:44 UTC20
    }
782069860236atagen2026-10-10 12:44 UTC21
782069860236atagen2026-10-10 12:44 UTC22
    pub fn next(self) -> Option<Self> {
782069860236atagen2026-10-10 12:44 UTC23
        match self {
782069860236atagen2026-10-10 12:44 UTC24
            Self::Bedroom => Some(Self::Bathroom),
9683736a2c5eatagen2026-10-10 13:15 UTC25
            Self::Bathroom => Some(Self::ChangingRoom),
9683736a2c5eatagen2026-10-10 13:15 UTC26
            Self::ChangingRoom => Some(Self::Nans),
9683736a2c5eatagen2026-10-10 13:15 UTC27
            Self::Nans => Some(Self::Hotel),
782069860236atagen2026-10-10 12:44 UTC28
            Self::Hotel => Some(Self::Forum),
782069860236atagen2026-10-10 12:44 UTC29
            Self::Forum => Some(Self::Clinic),
782069860236atagen2026-10-10 12:44 UTC30
            Self::Clinic => None,
782069860236atagen2026-10-10 12:44 UTC31
        }
782069860236atagen2026-10-10 12:44 UTC32
    }
782069860236atagen2026-10-10 12:44 UTC33
782069860236atagen2026-10-10 12:44 UTC34
    pub fn name(self) -> &'static str {
782069860236atagen2026-10-10 12:44 UTC35
        match self {
782069860236atagen2026-10-10 12:44 UTC36
            Self::Bedroom => "the bedroom",
782069860236atagen2026-10-10 12:44 UTC37
            Self::Bathroom => "the shared bathroom",
9683736a2c5eatagen2026-10-10 13:15 UTC38
            Self::ChangingRoom => "the gym changing room",
9683736a2c5eatagen2026-10-10 13:15 UTC39
            Self::Nans => "Nan's house at Christmas",
782069860236atagen2026-10-10 12:44 UTC40
            Self::Hotel => "a business trip hotel",
782069860236atagen2026-10-10 12:44 UTC41
            Self::Forum => "the forum",
782069860236atagen2026-10-10 12:44 UTC42
            Self::Clinic => "the urologist's office",
782069860236atagen2026-10-10 12:44 UTC43
        }
782069860236atagen2026-10-10 12:44 UTC44
    }
782069860236atagen2026-10-10 12:44 UTC45
782069860236atagen2026-10-10 12:44 UTC46
    pub fn note(self) -> &'static str {
782069860236atagen2026-10-10 12:44 UTC47
        match self {
782069860236atagen2026-10-10 12:44 UTC48
            Self::Bedroom => "The door does not lock. The cat is present.",
7d3fb63208bfatagen2026-10-11 04:38 UTC49
            Self::Bathroom => "The water is hot. Your brother showers at eight.",
9683736a2c5eatagen2026-10-10 13:15 UTC50
            Self::ChangingRoom => {
782069860236atagen2026-10-10 12:44 UTC51
                "It is cold. Discretion is advised. Everyone here is lying. Pump-Bro is by the lockers."
782069860236atagen2026-10-10 12:44 UTC52
            }
9683736a2c5eatagen2026-10-10 13:15 UTC53
            Self::Nans => {
9683736a2c5eatagen2026-10-10 13:15 UTC54
                "The walls are thin. Mum is here, and she has been reading about Digest authentication."
782069860236atagen2026-10-10 12:44 UTC55
            }
782069860236atagen2026-10-10 12:44 UTC56
            Self::Hotel => {
782069860236atagen2026-10-10 12:44 UTC57
                "The wifi requires agreement. Housekeeping does not knock. Pump-Bro is in the lobby."
782069860236atagen2026-10-10 12:44 UTC58
            }
782069860236atagen2026-10-10 12:44 UTC59
            Self::Forum => "Nothing physical happens here. The Elder has a spreadsheet.",
782069860236atagen2026-10-10 12:44 UTC60
            Self::Clinic => "The urologist will see you now. He is bored.",
782069860236atagen2026-10-10 12:44 UTC61
        }
782069860236atagen2026-10-10 12:44 UTC62
    }
782069860236atagen2026-10-10 12:44 UTC63
782069860236atagen2026-10-10 12:44 UTC64
    pub fn observer(self) -> Option<Observer> {
782069860236atagen2026-10-10 12:44 UTC65
        match self {
782069860236atagen2026-10-10 12:44 UTC66
            Self::Bedroom => Some(Observer::Cat),
9683736a2c5eatagen2026-10-10 13:15 UTC67
            Self::ChangingRoom => Some(Observer::Greg),
9683736a2c5eatagen2026-10-10 13:15 UTC68
            Self::Nans => Some(Observer::Nan),
782069860236atagen2026-10-10 12:44 UTC69
            _ => None,
782069860236atagen2026-10-10 12:44 UTC70
        }
782069860236atagen2026-10-10 12:44 UTC71
    }
782069860236atagen2026-10-10 12:44 UTC72
9683736a2c5eatagen2026-10-10 13:15 UTC73
    pub fn has_mum(self) -> bool {
9683736a2c5eatagen2026-10-10 13:15 UTC74
        matches!(self, Self::Bedroom | Self::Nans)
782069860236atagen2026-10-10 12:44 UTC75
    }
782069860236atagen2026-10-10 12:44 UTC76
782069860236atagen2026-10-10 12:44 UTC77
    pub fn has_window(self) -> bool {
9683736a2c5eatagen2026-10-10 13:15 UTC78
        matches!(self, Self::Bedroom | Self::Nans | Self::Hotel)
782069860236atagen2026-10-10 12:44 UTC79
    }
782069860236atagen2026-10-10 12:44 UTC80
782069860236atagen2026-10-10 12:44 UTC81
    pub fn shop_open(self) -> bool {
9683736a2c5eatagen2026-10-10 13:15 UTC82
        matches!(self, Self::ChangingRoom | Self::Hotel)
782069860236atagen2026-10-10 12:44 UTC83
    }
782069860236atagen2026-10-10 12:44 UTC84
0a0bfee8329eatagen2026-10-11 05:11 UTC85
    pub fn has_kitchen(self) -> bool {
0a0bfee8329eatagen2026-10-11 05:11 UTC86
        matches!(self, Self::Bedroom | Self::Nans)
0a0bfee8329eatagen2026-10-11 05:11 UTC87
    }
0a0bfee8329eatagen2026-10-11 05:11 UTC88
782069860236atagen2026-10-10 12:44 UTC89
    pub fn timed(self) -> bool {
782069860236atagen2026-10-10 12:44 UTC90
        !matches!(self, Self::Forum | Self::Clinic)
782069860236atagen2026-10-10 12:44 UTC91
    }
782069860236atagen2026-10-10 12:44 UTC92
}
782069860236atagen2026-10-10 12:44 UTC93
782069860236atagen2026-10-10 12:44 UTC94
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
782069860236atagen2026-10-10 12:44 UTC95
pub enum Observer {
782069860236atagen2026-10-10 12:44 UTC96
    Cat,
782069860236atagen2026-10-10 12:44 UTC97
    Greg,
9683736a2c5eatagen2026-10-10 13:15 UTC98
    Nan,
782069860236atagen2026-10-10 12:44 UTC99
}
782069860236atagen2026-10-10 12:44 UTC100
782069860236atagen2026-10-10 12:44 UTC101
impl Observer {
782069860236atagen2026-10-10 12:44 UTC102
    pub fn name(self) -> &'static str {
782069860236atagen2026-10-10 12:44 UTC103
        match self {
782069860236atagen2026-10-10 12:44 UTC104
            Self::Cat => "cat",
782069860236atagen2026-10-10 12:44 UTC105
            Self::Greg => "greg",
9683736a2c5eatagen2026-10-10 13:15 UTC106
            Self::Nan => "nan",
782069860236atagen2026-10-10 12:44 UTC107
        }
782069860236atagen2026-10-10 12:44 UTC108
    }
782069860236atagen2026-10-10 12:44 UTC109
}
782069860236atagen2026-10-10 12:44 UTC110
782069860236atagen2026-10-10 12:44 UTC111
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
782069860236atagen2026-10-10 12:44 UTC112
pub enum Grip {
782069860236atagen2026-10-10 12:44 UTC113
    Overhand,
782069860236atagen2026-10-10 12:44 UTC114
    Underhand,
782069860236atagen2026-10-10 12:44 UTC115
}
782069860236atagen2026-10-10 12:44 UTC116
782069860236atagen2026-10-10 12:44 UTC117
impl Grip {
782069860236atagen2026-10-10 12:44 UTC118
    pub fn name(self) -> &'static str {
782069860236atagen2026-10-10 12:44 UTC119
        match self {
782069860236atagen2026-10-10 12:44 UTC120
            Self::Overhand => "overhand",
782069860236atagen2026-10-10 12:44 UTC121
            Self::Underhand => "underhand",
782069860236atagen2026-10-10 12:44 UTC122
        }
782069860236atagen2026-10-10 12:44 UTC123
    }
782069860236atagen2026-10-10 12:44 UTC124
782069860236atagen2026-10-10 12:44 UTC125
    pub fn parse(protocol: &str) -> Option<Self> {
782069860236atagen2026-10-10 12:44 UTC126
        match protocol.to_ascii_lowercase().as_str() {
782069860236atagen2026-10-10 12:44 UTC127
            "overhand" => Some(Self::Overhand),
782069860236atagen2026-10-10 12:44 UTC128
            "underhand" => Some(Self::Underhand),
782069860236atagen2026-10-10 12:44 UTC129
            _ => None,
782069860236atagen2026-10-10 12:44 UTC130
        }
782069860236atagen2026-10-10 12:44 UTC131
    }
782069860236atagen2026-10-10 12:44 UTC132
}
782069860236atagen2026-10-10 12:44 UTC133
782069860236atagen2026-10-10 12:44 UTC134
/// State that belongs to the current floor and resets when you leave it.
782069860236atagen2026-10-10 12:44 UTC135
#[derive(Default)]
782069860236atagen2026-10-10 12:44 UTC136
pub struct FloorState {
782069860236atagen2026-10-10 12:44 UTC137
    pub turns: u32,
e807266c323batagen2026-10-12 09:46 UTC138
    pub drawer_searched: bool,
a6caa2f99786atagen2026-10-12 10:38 UTC139
    pub drawer_jammed: bool,
a6caa2f99786atagen2026-10-12 10:38 UTC140
    pub kettle_boiled: bool,
a6caa2f99786atagen2026-10-12 10:38 UTC141
    pub thread_rolls: u8,
782069860236atagen2026-10-10 12:44 UTC142
    pub edges: u8,
782069860236atagen2026-10-10 12:44 UTC143
    pub temp_length: f64,
782069860236atagen2026-10-10 12:44 UTC144
    pub teapot: bool,
782069860236atagen2026-10-10 12:44 UTC145
    pub towel_stolen: bool,
7d3fb63208bfatagen2026-10-11 04:38 UTC146
    pub brother_told: bool,
7d3fb63208bfatagen2026-10-11 04:38 UTC147
    pub shopping: bool,
0fdc47364c8catagen2026-10-11 04:45 UTC148
    pub meditated: bool,
0a0bfee8329eatagen2026-10-11 05:11 UTC149
    pub melon_offered: bool,
4347977b8192atagen2026-10-11 04:56 UTC150
    pub warm_arrival: bool,
782069860236atagen2026-10-10 12:44 UTC151
    pub wifi_accepted: bool,
782069860236atagen2026-10-10 12:44 UTC152
}
782069860236atagen2026-10-10 12:44 UTC153
782069860236atagen2026-10-10 12:44 UTC154
#[derive(Default)]
782069860236atagen2026-10-10 12:44 UTC155
pub struct Conditions {
782069860236atagen2026-10-10 12:44 UTC156
    pub peyronie: bool,
782069860236atagen2026-10-10 12:44 UTC157
    pub pulled_muscle: bool,
782069860236atagen2026-10-10 12:44 UTC158
    pub priapism_turns: u8,
5dfebcc0ac43atagen2026-10-11 05:28 UTC159
    pub friction_burn: bool,
782069860236atagen2026-10-10 12:44 UTC160
}
782069860236atagen2026-10-10 12:44 UTC161
9683736a2c5eatagen2026-10-10 13:15 UTC162
pub struct MumVisit {
782069860236atagen2026-10-10 12:44 UTC163
    pub errand: &'static str,
782069860236atagen2026-10-10 12:44 UTC164
    pub nonce: String,
782069860236atagen2026-10-10 12:44 UTC165
    pub strikes: u8,
0d604ee39751atagen2026-10-10 14:15 UTC166
    pub knocked: bool,
782069860236atagen2026-10-10 12:44 UTC167
}
782069860236atagen2026-10-10 12:44 UTC168
782069860236atagen2026-10-10 12:44 UTC169
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
782069860236atagen2026-10-10 12:44 UTC170
pub enum Elder {
782069860236atagen2026-10-10 12:44 UTC171
    Unverified { strikes: u8 },
782069860236atagen2026-10-10 12:44 UTC172
    Verified,
782069860236atagen2026-10-10 12:44 UTC173
    Beaten,
782069860236atagen2026-10-10 12:44 UTC174
}
782069860236atagen2026-10-10 12:44 UTC175
782069860236atagen2026-10-10 12:44 UTC176
#[derive(Default)]
782069860236atagen2026-10-10 12:44 UTC177
pub struct Clinic {
782069860236atagen2026-10-10 12:44 UTC178
    pub intake_attempts: usize,
782069860236atagen2026-10-10 12:44 UTC179
    pub measured: bool,
782069860236atagen2026-10-10 12:44 UTC180
    pub cured: bool,
782069860236atagen2026-10-10 12:44 UTC181
}
782069860236atagen2026-10-10 12:44 UTC182
782069860236atagen2026-10-10 12:44 UTC183
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
782069860236atagen2026-10-10 12:44 UTC184
pub enum Story {
782069860236atagen2026-10-10 12:44 UTC185
    Unopened,
782069860236atagen2026-10-10 12:44 UTC186
    Pending,
782069860236atagen2026-10-10 12:44 UTC187
    ReadForum,
782069860236atagen2026-10-10 12:44 UTC188
    ClosedTab,
782069860236atagen2026-10-10 12:44 UTC189
}
782069860236atagen2026-10-10 12:44 UTC190
782069860236atagen2026-10-10 12:44 UTC191
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
782069860236atagen2026-10-10 12:44 UTC192
pub enum Cause {
782069860236atagen2026-10-10 12:44 UTC193
    Ruptured { ice_unused: bool },
782069860236atagen2026-10-10 12:44 UTC194
    Caught,
0d604ee39751atagen2026-10-10 14:15 UTC195
    Opened,
782069860236atagen2026-10-10 12:44 UTC196
    Banned,
782069860236atagen2026-10-10 12:44 UTC197
    Degloved,
9683736a2c5eatagen2026-10-10 13:15 UTC198
    Zip,
0a0bfee8329eatagen2026-10-11 05:11 UTC199
    Meloned,
782069860236atagen2026-10-10 12:44 UTC200
    Abandoned,
782069860236atagen2026-10-10 12:44 UTC201
}
782069860236atagen2026-10-10 12:44 UTC202
782069860236atagen2026-10-10 12:44 UTC203
impl Cause {
782069860236atagen2026-10-10 12:44 UTC204
    pub fn slug(self) -> &'static str {
782069860236atagen2026-10-10 12:44 UTC205
        match self {
782069860236atagen2026-10-10 12:44 UTC206
            Self::Ruptured { .. } => "vascular-event",
782069860236atagen2026-10-10 12:44 UTC207
            Self::Caught => "caught",
0d604ee39751atagen2026-10-10 14:15 UTC208
            Self::Opened => "opened",
782069860236atagen2026-10-10 12:44 UTC209
            Self::Banned => "banned",
782069860236atagen2026-10-10 12:44 UTC210
            Self::Degloved => "degloved",
9683736a2c5eatagen2026-10-10 13:15 UTC211
            Self::Zip => "zip",
0a0bfee8329eatagen2026-10-11 05:11 UTC212
            Self::Meloned => "watermelon",
782069860236atagen2026-10-10 12:44 UTC213
            Self::Abandoned => "abandoned",
782069860236atagen2026-10-10 12:44 UTC214
        }
782069860236atagen2026-10-10 12:44 UTC215
    }
782069860236atagen2026-10-10 12:44 UTC216
782069860236atagen2026-10-10 12:44 UTC217
    pub fn detail(self) -> &'static str {
782069860236atagen2026-10-10 12:44 UTC218
        match self {
782069860236atagen2026-10-10 12:44 UTC219
            Self::Ruptured { ice_unused: true } => {
782069860236atagen2026-10-10 12:44 UTC220
                "A vessel has exceeded its rated pressure. The run has ended. An ice pack was available and was not used."
782069860236atagen2026-10-10 12:44 UTC221
            }
782069860236atagen2026-10-10 12:44 UTC222
            Self::Ruptured { ice_unused: false } => {
782069860236atagen2026-10-10 12:44 UTC223
                "A vessel has exceeded its rated pressure. The run has ended."
782069860236atagen2026-10-10 12:44 UTC224
            }
782069860236atagen2026-10-10 12:44 UTC225
            Self::Caught => {
9683736a2c5eatagen2026-10-10 13:15 UTC226
                "Mum has seen enough. The run has ended. Nobody will mention it at dinner."
782069860236atagen2026-10-10 12:44 UTC227
            }
0d604ee39751atagen2026-10-10 14:15 UTC228
            Self::Opened => {
0d604ee39751atagen2026-10-10 14:15 UTC229
                "Mum has stopped knocking and opened the door. The run has ended. Nobody will mention it at dinner."
0d604ee39751atagen2026-10-10 14:15 UTC230
            }
782069860236atagen2026-10-10 12:44 UTC231
            Self::Banned => "Your account has been banned. The forum can tell. The run has ended.",
782069860236atagen2026-10-10 12:44 UTC232
            Self::Degloved => {
782069860236atagen2026-10-10 12:44 UTC233
                "The outer layer has been removed in one piece. It will not be returning. The run has ended."
782069860236atagen2026-10-10 12:44 UTC234
            }
9683736a2c5eatagen2026-10-10 13:15 UTC235
            Self::Zip => {
9683736a2c5eatagen2026-10-10 13:15 UTC236
                "The request conflicts with the current state of the zip. The run has ended."
782069860236atagen2026-10-10 12:44 UTC237
            }
0a0bfee8329eatagen2026-10-11 05:11 UTC238
            Self::Meloned => {
0a0bfee8329eatagen2026-10-11 05:11 UTC239
                "You have been caught with the watermelon. Nobody will mention it at dinner. The run has ended."
0a0bfee8329eatagen2026-10-11 05:11 UTC240
            }
782069860236atagen2026-10-10 12:44 UTC241
            Self::Abandoned => "The run was abandoned.",
782069860236atagen2026-10-10 12:44 UTC242
        }
782069860236atagen2026-10-10 12:44 UTC243
    }
782069860236atagen2026-10-10 12:44 UTC244
782069860236atagen2026-10-10 12:44 UTC245
    fn status(self) -> StatusCode {
782069860236atagen2026-10-10 12:44 UTC246
        match self {
782069860236atagen2026-10-10 12:44 UTC247
            Self::Ruptured { .. } => StatusCode::INTERNAL_SERVER_ERROR,
0d604ee39751atagen2026-10-10 14:15 UTC248
            Self::Caught | Self::Opened | Self::Degloved | Self::Abandoned => StatusCode::GONE,
0a0bfee8329eatagen2026-10-11 05:11 UTC249
            Self::Meloned => StatusCode::GONE,
782069860236atagen2026-10-10 12:44 UTC250
            Self::Banned => StatusCode::FORBIDDEN,
9683736a2c5eatagen2026-10-10 13:15 UTC251
            Self::Zip => StatusCode::CONFLICT,
782069860236atagen2026-10-10 12:44 UTC252
        }
782069860236atagen2026-10-10 12:44 UTC253
    }
782069860236atagen2026-10-10 12:44 UTC254
782069860236atagen2026-10-10 12:44 UTC255
    pub fn problem(self) -> Problem {
782069860236atagen2026-10-10 12:44 UTC256
        Problem::new(self.status(), self.slug(), self.detail())
782069860236atagen2026-10-10 12:44 UTC257
    }
782069860236atagen2026-10-10 12:44 UTC258
}
782069860236atagen2026-10-10 12:44 UTC259
782069860236atagen2026-10-10 12:44 UTC260
pub struct Ending {
782069860236atagen2026-10-10 12:44 UTC261
    pub cause: Cause,
782069860236atagen2026-10-10 12:44 UTC262
    pub turn: u32,
782069860236atagen2026-10-10 12:44 UTC263
}
782069860236atagen2026-10-10 12:44 UTC264
782069860236atagen2026-10-10 12:44 UTC265
pub struct Pending {
782069860236atagen2026-10-10 12:44 UTC266
    pub due: u32,
782069860236atagen2026-10-10 12:44 UTC267
    pub length: f64,
782069860236atagen2026-10-10 12:44 UTC268
    pub girth: f64,
782069860236atagen2026-10-10 12:44 UTC269
}