atagen

jelq

public

an http based roguelike rpg about jelqing

Star0
Watch0
0a0bfee8329e7283a802b33eb4365c2bf4c433b9
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,
782069860236atagen2026-10-10 12:44 UTC138
    pub drawer_searches: u8,
782069860236atagen2026-10-10 12:44 UTC139
    pub edges: u8,
782069860236atagen2026-10-10 12:44 UTC140
    pub temp_length: f64,
782069860236atagen2026-10-10 12:44 UTC141
    pub teapot: bool,
782069860236atagen2026-10-10 12:44 UTC142
    pub towel_stolen: bool,
7d3fb63208bfatagen2026-10-11 04:38 UTC143
    pub brother_told: bool,
7d3fb63208bfatagen2026-10-11 04:38 UTC144
    pub shopping: bool,
0fdc47364c8catagen2026-10-11 04:45 UTC145
    pub meditated: bool,
0a0bfee8329eatagen2026-10-11 05:11 UTC146
    pub melon_offered: bool,
4347977b8192atagen2026-10-11 04:56 UTC147
    pub warm_arrival: bool,
782069860236atagen2026-10-10 12:44 UTC148
    pub wifi_accepted: bool,
782069860236atagen2026-10-10 12:44 UTC149
}
782069860236atagen2026-10-10 12:44 UTC150
782069860236atagen2026-10-10 12:44 UTC151
#[derive(Default)]
782069860236atagen2026-10-10 12:44 UTC152
pub struct Conditions {
782069860236atagen2026-10-10 12:44 UTC153
    pub peyronie: bool,
782069860236atagen2026-10-10 12:44 UTC154
    pub pulled_muscle: bool,
782069860236atagen2026-10-10 12:44 UTC155
    pub priapism_turns: u8,
782069860236atagen2026-10-10 12:44 UTC156
}
782069860236atagen2026-10-10 12:44 UTC157
9683736a2c5eatagen2026-10-10 13:15 UTC158
pub struct MumVisit {
782069860236atagen2026-10-10 12:44 UTC159
    pub errand: &'static str,
782069860236atagen2026-10-10 12:44 UTC160
    pub nonce: String,
782069860236atagen2026-10-10 12:44 UTC161
    pub strikes: u8,
0d604ee39751atagen2026-10-10 14:15 UTC162
    pub knocked: bool,
782069860236atagen2026-10-10 12:44 UTC163
}
782069860236atagen2026-10-10 12:44 UTC164
782069860236atagen2026-10-10 12:44 UTC165
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
782069860236atagen2026-10-10 12:44 UTC166
pub enum Elder {
782069860236atagen2026-10-10 12:44 UTC167
    Unverified { strikes: u8 },
782069860236atagen2026-10-10 12:44 UTC168
    Verified,
782069860236atagen2026-10-10 12:44 UTC169
    Beaten,
782069860236atagen2026-10-10 12:44 UTC170
}
782069860236atagen2026-10-10 12:44 UTC171
782069860236atagen2026-10-10 12:44 UTC172
#[derive(Default)]
782069860236atagen2026-10-10 12:44 UTC173
pub struct Clinic {
782069860236atagen2026-10-10 12:44 UTC174
    pub intake_attempts: usize,
782069860236atagen2026-10-10 12:44 UTC175
    pub measured: bool,
782069860236atagen2026-10-10 12:44 UTC176
    pub cured: bool,
782069860236atagen2026-10-10 12:44 UTC177
}
782069860236atagen2026-10-10 12:44 UTC178
782069860236atagen2026-10-10 12:44 UTC179
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
782069860236atagen2026-10-10 12:44 UTC180
pub enum Story {
782069860236atagen2026-10-10 12:44 UTC181
    Unopened,
782069860236atagen2026-10-10 12:44 UTC182
    Pending,
782069860236atagen2026-10-10 12:44 UTC183
    ReadForum,
782069860236atagen2026-10-10 12:44 UTC184
    ClosedTab,
782069860236atagen2026-10-10 12:44 UTC185
}
782069860236atagen2026-10-10 12:44 UTC186
782069860236atagen2026-10-10 12:44 UTC187
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
782069860236atagen2026-10-10 12:44 UTC188
pub enum Cause {
782069860236atagen2026-10-10 12:44 UTC189
    Ruptured { ice_unused: bool },
782069860236atagen2026-10-10 12:44 UTC190
    Caught,
0d604ee39751atagen2026-10-10 14:15 UTC191
    Opened,
782069860236atagen2026-10-10 12:44 UTC192
    Banned,
782069860236atagen2026-10-10 12:44 UTC193
    Degloved,
9683736a2c5eatagen2026-10-10 13:15 UTC194
    Zip,
0a0bfee8329eatagen2026-10-11 05:11 UTC195
    Meloned,
782069860236atagen2026-10-10 12:44 UTC196
    Abandoned,
782069860236atagen2026-10-10 12:44 UTC197
}
782069860236atagen2026-10-10 12:44 UTC198
782069860236atagen2026-10-10 12:44 UTC199
impl Cause {
782069860236atagen2026-10-10 12:44 UTC200
    pub fn slug(self) -> &'static str {
782069860236atagen2026-10-10 12:44 UTC201
        match self {
782069860236atagen2026-10-10 12:44 UTC202
            Self::Ruptured { .. } => "vascular-event",
782069860236atagen2026-10-10 12:44 UTC203
            Self::Caught => "caught",
0d604ee39751atagen2026-10-10 14:15 UTC204
            Self::Opened => "opened",
782069860236atagen2026-10-10 12:44 UTC205
            Self::Banned => "banned",
782069860236atagen2026-10-10 12:44 UTC206
            Self::Degloved => "degloved",
9683736a2c5eatagen2026-10-10 13:15 UTC207
            Self::Zip => "zip",
0a0bfee8329eatagen2026-10-11 05:11 UTC208
            Self::Meloned => "watermelon",
782069860236atagen2026-10-10 12:44 UTC209
            Self::Abandoned => "abandoned",
782069860236atagen2026-10-10 12:44 UTC210
        }
782069860236atagen2026-10-10 12:44 UTC211
    }
782069860236atagen2026-10-10 12:44 UTC212
782069860236atagen2026-10-10 12:44 UTC213
    pub fn detail(self) -> &'static str {
782069860236atagen2026-10-10 12:44 UTC214
        match self {
782069860236atagen2026-10-10 12:44 UTC215
            Self::Ruptured { ice_unused: true } => {
782069860236atagen2026-10-10 12:44 UTC216
                "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 UTC217
            }
782069860236atagen2026-10-10 12:44 UTC218
            Self::Ruptured { ice_unused: false } => {
782069860236atagen2026-10-10 12:44 UTC219
                "A vessel has exceeded its rated pressure. The run has ended."
782069860236atagen2026-10-10 12:44 UTC220
            }
782069860236atagen2026-10-10 12:44 UTC221
            Self::Caught => {
9683736a2c5eatagen2026-10-10 13:15 UTC222
                "Mum has seen enough. The run has ended. Nobody will mention it at dinner."
782069860236atagen2026-10-10 12:44 UTC223
            }
0d604ee39751atagen2026-10-10 14:15 UTC224
            Self::Opened => {
0d604ee39751atagen2026-10-10 14:15 UTC225
                "Mum has stopped knocking and opened the door. The run has ended. Nobody will mention it at dinner."
0d604ee39751atagen2026-10-10 14:15 UTC226
            }
782069860236atagen2026-10-10 12:44 UTC227
            Self::Banned => "Your account has been banned. The forum can tell. The run has ended.",
782069860236atagen2026-10-10 12:44 UTC228
            Self::Degloved => {
782069860236atagen2026-10-10 12:44 UTC229
                "The outer layer has been removed in one piece. It will not be returning. The run has ended."
782069860236atagen2026-10-10 12:44 UTC230
            }
9683736a2c5eatagen2026-10-10 13:15 UTC231
            Self::Zip => {
9683736a2c5eatagen2026-10-10 13:15 UTC232
                "The request conflicts with the current state of the zip. The run has ended."
782069860236atagen2026-10-10 12:44 UTC233
            }
0a0bfee8329eatagen2026-10-11 05:11 UTC234
            Self::Meloned => {
0a0bfee8329eatagen2026-10-11 05:11 UTC235
                "You have been caught with the watermelon. Nobody will mention it at dinner. The run has ended."
0a0bfee8329eatagen2026-10-11 05:11 UTC236
            }
782069860236atagen2026-10-10 12:44 UTC237
            Self::Abandoned => "The run was abandoned.",
782069860236atagen2026-10-10 12:44 UTC238
        }
782069860236atagen2026-10-10 12:44 UTC239
    }
782069860236atagen2026-10-10 12:44 UTC240
782069860236atagen2026-10-10 12:44 UTC241
    fn status(self) -> StatusCode {
782069860236atagen2026-10-10 12:44 UTC242
        match self {
782069860236atagen2026-10-10 12:44 UTC243
            Self::Ruptured { .. } => StatusCode::INTERNAL_SERVER_ERROR,
0d604ee39751atagen2026-10-10 14:15 UTC244
            Self::Caught | Self::Opened | Self::Degloved | Self::Abandoned => StatusCode::GONE,
0a0bfee8329eatagen2026-10-11 05:11 UTC245
            Self::Meloned => StatusCode::GONE,
782069860236atagen2026-10-10 12:44 UTC246
            Self::Banned => StatusCode::FORBIDDEN,
9683736a2c5eatagen2026-10-10 13:15 UTC247
            Self::Zip => StatusCode::CONFLICT,
782069860236atagen2026-10-10 12:44 UTC248
        }
782069860236atagen2026-10-10 12:44 UTC249
    }
782069860236atagen2026-10-10 12:44 UTC250
782069860236atagen2026-10-10 12:44 UTC251
    pub fn problem(self) -> Problem {
782069860236atagen2026-10-10 12:44 UTC252
        Problem::new(self.status(), self.slug(), self.detail())
782069860236atagen2026-10-10 12:44 UTC253
    }
782069860236atagen2026-10-10 12:44 UTC254
}
782069860236atagen2026-10-10 12:44 UTC255
782069860236atagen2026-10-10 12:44 UTC256
pub struct Ending {
782069860236atagen2026-10-10 12:44 UTC257
    pub cause: Cause,
782069860236atagen2026-10-10 12:44 UTC258
    pub turn: u32,
782069860236atagen2026-10-10 12:44 UTC259
}
782069860236atagen2026-10-10 12:44 UTC260
782069860236atagen2026-10-10 12:44 UTC261
pub struct Pending {
782069860236atagen2026-10-10 12:44 UTC262
    pub due: u32,
782069860236atagen2026-10-10 12:44 UTC263
    pub length: f64,
782069860236atagen2026-10-10 12:44 UTC264
    pub girth: f64,
782069860236atagen2026-10-10 12:44 UTC265
}