atagen

jelq

public

an http based roguelike rpg about jelqing

Star0
Watch0
ec6fd4bb5b6028e1fe0ec1bc286e57748b9728dc
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.",
9683736a2c5eatagen2026-10-10 13:15 UTC49
            Self::Bathroom => "The water is hot. The flatmate 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
782069860236atagen2026-10-10 12:44 UTC85
    pub fn timed(self) -> bool {
782069860236atagen2026-10-10 12:44 UTC86
        !matches!(self, Self::Forum | Self::Clinic)
782069860236atagen2026-10-10 12:44 UTC87
    }
782069860236atagen2026-10-10 12:44 UTC88
}
782069860236atagen2026-10-10 12:44 UTC89
782069860236atagen2026-10-10 12:44 UTC90
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
782069860236atagen2026-10-10 12:44 UTC91
pub enum Observer {
782069860236atagen2026-10-10 12:44 UTC92
    Cat,
782069860236atagen2026-10-10 12:44 UTC93
    Greg,
9683736a2c5eatagen2026-10-10 13:15 UTC94
    Nan,
782069860236atagen2026-10-10 12:44 UTC95
}
782069860236atagen2026-10-10 12:44 UTC96
782069860236atagen2026-10-10 12:44 UTC97
impl Observer {
782069860236atagen2026-10-10 12:44 UTC98
    pub fn name(self) -> &'static str {
782069860236atagen2026-10-10 12:44 UTC99
        match self {
782069860236atagen2026-10-10 12:44 UTC100
            Self::Cat => "cat",
782069860236atagen2026-10-10 12:44 UTC101
            Self::Greg => "greg",
9683736a2c5eatagen2026-10-10 13:15 UTC102
            Self::Nan => "nan",
782069860236atagen2026-10-10 12:44 UTC103
        }
782069860236atagen2026-10-10 12:44 UTC104
    }
782069860236atagen2026-10-10 12:44 UTC105
}
782069860236atagen2026-10-10 12:44 UTC106
782069860236atagen2026-10-10 12:44 UTC107
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
782069860236atagen2026-10-10 12:44 UTC108
pub enum Grip {
782069860236atagen2026-10-10 12:44 UTC109
    Overhand,
782069860236atagen2026-10-10 12:44 UTC110
    Underhand,
782069860236atagen2026-10-10 12:44 UTC111
}
782069860236atagen2026-10-10 12:44 UTC112
782069860236atagen2026-10-10 12:44 UTC113
impl Grip {
782069860236atagen2026-10-10 12:44 UTC114
    pub fn name(self) -> &'static str {
782069860236atagen2026-10-10 12:44 UTC115
        match self {
782069860236atagen2026-10-10 12:44 UTC116
            Self::Overhand => "overhand",
782069860236atagen2026-10-10 12:44 UTC117
            Self::Underhand => "underhand",
782069860236atagen2026-10-10 12:44 UTC118
        }
782069860236atagen2026-10-10 12:44 UTC119
    }
782069860236atagen2026-10-10 12:44 UTC120
782069860236atagen2026-10-10 12:44 UTC121
    pub fn parse(protocol: &str) -> Option<Self> {
782069860236atagen2026-10-10 12:44 UTC122
        match protocol.to_ascii_lowercase().as_str() {
782069860236atagen2026-10-10 12:44 UTC123
            "overhand" => Some(Self::Overhand),
782069860236atagen2026-10-10 12:44 UTC124
            "underhand" => Some(Self::Underhand),
782069860236atagen2026-10-10 12:44 UTC125
            _ => None,
782069860236atagen2026-10-10 12:44 UTC126
        }
782069860236atagen2026-10-10 12:44 UTC127
    }
782069860236atagen2026-10-10 12:44 UTC128
}
782069860236atagen2026-10-10 12:44 UTC129
782069860236atagen2026-10-10 12:44 UTC130
/// State that belongs to the current floor and resets when you leave it.
782069860236atagen2026-10-10 12:44 UTC131
#[derive(Default)]
782069860236atagen2026-10-10 12:44 UTC132
pub struct FloorState {
782069860236atagen2026-10-10 12:44 UTC133
    pub turns: u32,
782069860236atagen2026-10-10 12:44 UTC134
    pub drawer_searches: u8,
782069860236atagen2026-10-10 12:44 UTC135
    pub edges: u8,
782069860236atagen2026-10-10 12:44 UTC136
    pub temp_length: f64,
782069860236atagen2026-10-10 12:44 UTC137
    pub teapot: bool,
782069860236atagen2026-10-10 12:44 UTC138
    pub towel_stolen: bool,
9683736a2c5eatagen2026-10-10 13:15 UTC139
    pub flatmate_told: bool,
782069860236atagen2026-10-10 12:44 UTC140
    pub wifi_accepted: bool,
782069860236atagen2026-10-10 12:44 UTC141
}
782069860236atagen2026-10-10 12:44 UTC142
782069860236atagen2026-10-10 12:44 UTC143
#[derive(Default)]
782069860236atagen2026-10-10 12:44 UTC144
pub struct Conditions {
782069860236atagen2026-10-10 12:44 UTC145
    pub peyronie: bool,
782069860236atagen2026-10-10 12:44 UTC146
    pub pulled_muscle: bool,
782069860236atagen2026-10-10 12:44 UTC147
    pub priapism_turns: u8,
782069860236atagen2026-10-10 12:44 UTC148
}
782069860236atagen2026-10-10 12:44 UTC149
9683736a2c5eatagen2026-10-10 13:15 UTC150
pub struct MumVisit {
782069860236atagen2026-10-10 12:44 UTC151
    pub errand: &'static str,
782069860236atagen2026-10-10 12:44 UTC152
    pub nonce: String,
782069860236atagen2026-10-10 12:44 UTC153
    pub strikes: u8,
0d604ee39751atagen2026-10-10 14:15 UTC154
    pub knocked: bool,
782069860236atagen2026-10-10 12:44 UTC155
}
782069860236atagen2026-10-10 12:44 UTC156
782069860236atagen2026-10-10 12:44 UTC157
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
782069860236atagen2026-10-10 12:44 UTC158
pub enum Elder {
782069860236atagen2026-10-10 12:44 UTC159
    Unverified { strikes: u8 },
782069860236atagen2026-10-10 12:44 UTC160
    Verified,
782069860236atagen2026-10-10 12:44 UTC161
    Beaten,
782069860236atagen2026-10-10 12:44 UTC162
}
782069860236atagen2026-10-10 12:44 UTC163
782069860236atagen2026-10-10 12:44 UTC164
#[derive(Default)]
782069860236atagen2026-10-10 12:44 UTC165
pub struct Clinic {
782069860236atagen2026-10-10 12:44 UTC166
    pub intake_attempts: usize,
782069860236atagen2026-10-10 12:44 UTC167
    pub measured: bool,
782069860236atagen2026-10-10 12:44 UTC168
    pub cured: bool,
782069860236atagen2026-10-10 12:44 UTC169
}
782069860236atagen2026-10-10 12:44 UTC170
782069860236atagen2026-10-10 12:44 UTC171
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
782069860236atagen2026-10-10 12:44 UTC172
pub enum Story {
782069860236atagen2026-10-10 12:44 UTC173
    Unopened,
782069860236atagen2026-10-10 12:44 UTC174
    Pending,
782069860236atagen2026-10-10 12:44 UTC175
    ReadForum,
782069860236atagen2026-10-10 12:44 UTC176
    ClosedTab,
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 Cause {
782069860236atagen2026-10-10 12:44 UTC181
    Ruptured { ice_unused: bool },
782069860236atagen2026-10-10 12:44 UTC182
    Caught,
0d604ee39751atagen2026-10-10 14:15 UTC183
    Opened,
782069860236atagen2026-10-10 12:44 UTC184
    Banned,
782069860236atagen2026-10-10 12:44 UTC185
    Degloved,
9683736a2c5eatagen2026-10-10 13:15 UTC186
    Zip,
782069860236atagen2026-10-10 12:44 UTC187
    Abandoned,
782069860236atagen2026-10-10 12:44 UTC188
}
782069860236atagen2026-10-10 12:44 UTC189
782069860236atagen2026-10-10 12:44 UTC190
impl Cause {
782069860236atagen2026-10-10 12:44 UTC191
    pub fn slug(self) -> &'static str {
782069860236atagen2026-10-10 12:44 UTC192
        match self {
782069860236atagen2026-10-10 12:44 UTC193
            Self::Ruptured { .. } => "vascular-event",
782069860236atagen2026-10-10 12:44 UTC194
            Self::Caught => "caught",
0d604ee39751atagen2026-10-10 14:15 UTC195
            Self::Opened => "opened",
782069860236atagen2026-10-10 12:44 UTC196
            Self::Banned => "banned",
782069860236atagen2026-10-10 12:44 UTC197
            Self::Degloved => "degloved",
9683736a2c5eatagen2026-10-10 13:15 UTC198
            Self::Zip => "zip",
782069860236atagen2026-10-10 12:44 UTC199
            Self::Abandoned => "abandoned",
782069860236atagen2026-10-10 12:44 UTC200
        }
782069860236atagen2026-10-10 12:44 UTC201
    }
782069860236atagen2026-10-10 12:44 UTC202
782069860236atagen2026-10-10 12:44 UTC203
    pub fn detail(self) -> &'static str {
782069860236atagen2026-10-10 12:44 UTC204
        match self {
782069860236atagen2026-10-10 12:44 UTC205
            Self::Ruptured { ice_unused: true } => {
782069860236atagen2026-10-10 12:44 UTC206
                "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 UTC207
            }
782069860236atagen2026-10-10 12:44 UTC208
            Self::Ruptured { ice_unused: false } => {
782069860236atagen2026-10-10 12:44 UTC209
                "A vessel has exceeded its rated pressure. The run has ended."
782069860236atagen2026-10-10 12:44 UTC210
            }
782069860236atagen2026-10-10 12:44 UTC211
            Self::Caught => {
9683736a2c5eatagen2026-10-10 13:15 UTC212
                "Mum has seen enough. The run has ended. Nobody will mention it at dinner."
782069860236atagen2026-10-10 12:44 UTC213
            }
0d604ee39751atagen2026-10-10 14:15 UTC214
            Self::Opened => {
0d604ee39751atagen2026-10-10 14:15 UTC215
                "Mum has stopped knocking and opened the door. The run has ended. Nobody will mention it at dinner."
0d604ee39751atagen2026-10-10 14:15 UTC216
            }
782069860236atagen2026-10-10 12:44 UTC217
            Self::Banned => "Your account has been banned. The forum can tell. The run has ended.",
782069860236atagen2026-10-10 12:44 UTC218
            Self::Degloved => {
782069860236atagen2026-10-10 12:44 UTC219
                "The outer layer has been removed in one piece. It will not be returning. The run has ended."
782069860236atagen2026-10-10 12:44 UTC220
            }
9683736a2c5eatagen2026-10-10 13:15 UTC221
            Self::Zip => {
9683736a2c5eatagen2026-10-10 13:15 UTC222
                "The request conflicts with the current state of the zip. The run has ended."
782069860236atagen2026-10-10 12:44 UTC223
            }
782069860236atagen2026-10-10 12:44 UTC224
            Self::Abandoned => "The run was abandoned.",
782069860236atagen2026-10-10 12:44 UTC225
        }
782069860236atagen2026-10-10 12:44 UTC226
    }
782069860236atagen2026-10-10 12:44 UTC227
782069860236atagen2026-10-10 12:44 UTC228
    fn status(self) -> StatusCode {
782069860236atagen2026-10-10 12:44 UTC229
        match self {
782069860236atagen2026-10-10 12:44 UTC230
            Self::Ruptured { .. } => StatusCode::INTERNAL_SERVER_ERROR,
0d604ee39751atagen2026-10-10 14:15 UTC231
            Self::Caught | Self::Opened | Self::Degloved | Self::Abandoned => StatusCode::GONE,
782069860236atagen2026-10-10 12:44 UTC232
            Self::Banned => StatusCode::FORBIDDEN,
9683736a2c5eatagen2026-10-10 13:15 UTC233
            Self::Zip => StatusCode::CONFLICT,
782069860236atagen2026-10-10 12:44 UTC234
        }
782069860236atagen2026-10-10 12:44 UTC235
    }
782069860236atagen2026-10-10 12:44 UTC236
782069860236atagen2026-10-10 12:44 UTC237
    pub fn problem(self) -> Problem {
782069860236atagen2026-10-10 12:44 UTC238
        Problem::new(self.status(), self.slug(), self.detail())
782069860236atagen2026-10-10 12:44 UTC239
    }
782069860236atagen2026-10-10 12:44 UTC240
}
782069860236atagen2026-10-10 12:44 UTC241
782069860236atagen2026-10-10 12:44 UTC242
pub struct Ending {
782069860236atagen2026-10-10 12:44 UTC243
    pub cause: Cause,
782069860236atagen2026-10-10 12:44 UTC244
    pub turn: u32,
782069860236atagen2026-10-10 12:44 UTC245
}
782069860236atagen2026-10-10 12:44 UTC246
782069860236atagen2026-10-10 12:44 UTC247
pub struct Pending {
782069860236atagen2026-10-10 12:44 UTC248
    pub due: u32,
782069860236atagen2026-10-10 12:44 UTC249
    pub length: f64,
782069860236atagen2026-10-10 12:44 UTC250
    pub girth: f64,
782069860236atagen2026-10-10 12:44 UTC251
}