atagen

jelq

public

an http based roguelike rpg about jelqing

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

Blame: src/game/drawer.rs

8b8e83329a1datagen2026-10-12 12:01 UTC1
use super::{
8b8e83329a1datagen2026-10-12 12:01 UTC2
    Floor, Item, Notice, Outcome, Run,
56d34031c321atagen2026-10-14 09:23 UTC3
    balance::{
56d34031c321atagen2026-10-14 09:23 UTC4
        BATHROOM_VASELINE, DRAWER_JAMS, GREGS_LOCKER, KEY_IN_DRAWER, RULER_IN_DRAWER, RULER_SHAME,
56d34031c321atagen2026-10-14 09:23 UTC5
    },
8b8e83329a1datagen2026-10-12 12:01 UTC6
};
8b8e83329a1datagen2026-10-12 12:01 UTC7
use crate::problem::Problem;
8b8e83329a1datagen2026-10-12 12:01 UTC8
use axum::http::{StatusCode, header};
8b8e83329a1datagen2026-10-12 12:01 UTC9
use serde_json::json;
8b8e83329a1datagen2026-10-12 12:01 UTC10
8b8e83329a1datagen2026-10-12 12:01 UTC11
fn nothing() -> Result<Outcome, Problem> {
8b8e83329a1datagen2026-10-12 12:01 UTC12
    Ok(Outcome::empty(StatusCode::NO_CONTENT))
8b8e83329a1datagen2026-10-12 12:01 UTC13
}
8b8e83329a1datagen2026-10-12 12:01 UTC14
8b8e83329a1datagen2026-10-12 12:01 UTC15
impl Run {
8b8e83329a1datagen2026-10-12 12:01 UTC16
    pub(super) fn found(&self, item: Item, detail: &str) -> Outcome {
8b8e83329a1datagen2026-10-12 12:01 UTC17
        Outcome::json(StatusCode::FOUND, json!({ "detail": detail })).header(
8b8e83329a1datagen2026-10-12 12:01 UTC18
            header::LOCATION,
8b8e83329a1datagen2026-10-12 12:01 UTC19
            self.path(&format!("/inventory/{}", item.slug())),
8b8e83329a1datagen2026-10-12 12:01 UTC20
        )
8b8e83329a1datagen2026-10-12 12:01 UTC21
    }
8b8e83329a1datagen2026-10-12 12:01 UTC22
8b8e83329a1datagen2026-10-12 12:01 UTC23
    pub fn search_drawer(&mut self) -> Result<Outcome, Problem> {
8b8e83329a1datagen2026-10-12 12:01 UTC24
        self.touch();
8b8e83329a1datagen2026-10-12 12:01 UTC25
        self.end_kitchen_visit();
8b8e83329a1datagen2026-10-12 12:01 UTC26
        if self.items.kit.cage {
3ac624339c98atagen2026-10-13 12:21 UTC27
            return self.rummage_for_key();
8b8e83329a1datagen2026-10-12 12:01 UTC28
        }
8b8e83329a1datagen2026-10-12 12:01 UTC29
        let first = !self.here.drawer.searched;
8b8e83329a1datagen2026-10-12 12:01 UTC30
        self.here.drawer.searched = true;
8b8e83329a1datagen2026-10-12 12:01 UTC31
        match self.floor {
8b8e83329a1datagen2026-10-12 12:01 UTC32
            Floor::Bedroom => self.search_bedroom(first),
8b8e83329a1datagen2026-10-12 12:01 UTC33
            Floor::Bathroom if first => Ok(self.search_bathroom()),
8b8e83329a1datagen2026-10-12 12:01 UTC34
            Floor::ChangingRoom => self.search_locker(first),
8b8e83329a1datagen2026-10-12 12:01 UTC35
            Floor::Nans if first => {
8b8e83329a1datagen2026-10-12 12:01 UTC36
                self.items.grant(Item::Cage);
8b8e83329a1datagen2026-10-12 12:01 UTC37
                self.standing.shame += 5;
8b8e83329a1datagen2026-10-12 12:01 UTC38
                Ok(self.found(
8b8e83329a1datagen2026-10-12 12:01 UTC39
                    Item::Cage,
8b8e83329a1datagen2026-10-12 12:01 UTC40
                    "A small box. Inside was a cage. It is now on. The key is not in the box.",
8b8e83329a1datagen2026-10-12 12:01 UTC41
                ))
8b8e83329a1datagen2026-10-12 12:01 UTC42
            }
8b8e83329a1datagen2026-10-12 12:01 UTC43
            Floor::Hotel if first => {
8b8e83329a1datagen2026-10-12 12:01 UTC44
                for item in [Item::DndSign, Item::IcePack, Item::IcePack, Item::Lotion] {
8b8e83329a1datagen2026-10-12 12:01 UTC45
                    self.items.grant(item);
8b8e83329a1datagen2026-10-12 12:01 UTC46
                }
8b8e83329a1datagen2026-10-12 12:01 UTC47
                Ok(self.found(
8b8e83329a1datagen2026-10-12 12:01 UTC48
                    Item::DndSign,
8b8e83329a1datagen2026-10-12 12:01 UTC49
                    "A Do Not Disturb sign, two ice packs from the machine down the hall, and a complimentary lotion.",
8b8e83329a1datagen2026-10-12 12:01 UTC50
                ))
8b8e83329a1datagen2026-10-12 12:01 UTC51
            }
8b8e83329a1datagen2026-10-12 12:01 UTC52
            Floor::Forum if first => {
8b8e83329a1datagen2026-10-12 12:01 UTC53
                self.items.grant(Item::Spreadsheet);
8b8e83329a1datagen2026-10-12 12:01 UTC54
                Ok(self.found(
8b8e83329a1datagen2026-10-12 12:01 UTC55
                    Item::Spreadsheet,
8b8e83329a1datagen2026-10-12 12:01 UTC56
                    "Your own spreadsheet. Every line is flat.",
8b8e83329a1datagen2026-10-12 12:01 UTC57
                ))
8b8e83329a1datagen2026-10-12 12:01 UTC58
            }
8b8e83329a1datagen2026-10-12 12:01 UTC59
            Floor::Clinic => Err(Problem::new(
8b8e83329a1datagen2026-10-12 12:01 UTC60
                StatusCode::FORBIDDEN,
8b8e83329a1datagen2026-10-12 12:01 UTC61
                "doctors-drawer",
8b8e83329a1datagen2026-10-12 12:01 UTC62
                "That is the doctor's drawer.",
8b8e83329a1datagen2026-10-12 12:01 UTC63
            )),
8b8e83329a1datagen2026-10-12 12:01 UTC64
            _ => nothing(),
8b8e83329a1datagen2026-10-12 12:01 UTC65
        }
8b8e83329a1datagen2026-10-12 12:01 UTC66
    }
8b8e83329a1datagen2026-10-12 12:01 UTC67
8b8e83329a1datagen2026-10-12 12:01 UTC68
    fn search_bedroom(&mut self, first: bool) -> Result<Outcome, Problem> {
8b8e83329a1datagen2026-10-12 12:01 UTC69
        let ruler_here = self.chance(
8b8e83329a1datagen2026-10-12 12:01 UTC70
            self.decision("ruler", "Is there a ruler hiding in the drawer?"),
8b8e83329a1datagen2026-10-12 12:01 UTC71
            RULER_IN_DRAWER,
8b8e83329a1datagen2026-10-12 12:01 UTC72
        );
8b8e83329a1datagen2026-10-12 12:01 UTC73
        if !first || self.items.kit.ruler || !ruler_here {
8b8e83329a1datagen2026-10-12 12:01 UTC74
            return nothing();
8b8e83329a1datagen2026-10-12 12:01 UTC75
        }
8b8e83329a1datagen2026-10-12 12:01 UTC76
        self.items.grant(Item::Ruler);
56d34031c321atagen2026-10-14 09:23 UTC77
        self.standing.shame += RULER_SHAME;
8b8e83329a1datagen2026-10-12 12:01 UTC78
        Ok(self.found(
8b8e83329a1datagen2026-10-12 12:01 UTC79
            Item::Ruler,
8b8e83329a1datagen2026-10-12 12:01 UTC80
            "You now know. This is the first honest measurement of the run.",
8b8e83329a1datagen2026-10-12 12:01 UTC81
        ))
8b8e83329a1datagen2026-10-12 12:01 UTC82
    }
8b8e83329a1datagen2026-10-12 12:01 UTC83
8b8e83329a1datagen2026-10-12 12:01 UTC84
    fn search_bathroom(&mut self) -> Outcome {
8b8e83329a1datagen2026-10-12 12:01 UTC85
        self.items.grant(Item::DoorLock);
8b8e83329a1datagen2026-10-12 12:01 UTC86
        let vaseline = self.chance(
8b8e83329a1datagen2026-10-12 12:01 UTC87
            self.decision(
8b8e83329a1datagen2026-10-12 12:01 UTC88
                "bathroom-vaseline",
8b8e83329a1datagen2026-10-12 12:01 UTC89
                "Is it the vaseline behind the door lock, rather than the lotion?",
8b8e83329a1datagen2026-10-12 12:01 UTC90
            ),
8b8e83329a1datagen2026-10-12 12:01 UTC91
            BATHROOM_VASELINE,
8b8e83329a1datagen2026-10-12 12:01 UTC92
        );
8b8e83329a1datagen2026-10-12 12:01 UTC93
        let (lube, detail) = if vaseline {
8b8e83329a1datagen2026-10-12 12:01 UTC94
            (
8b8e83329a1datagen2026-10-12 12:01 UTC95
                Item::Vaseline,
8b8e83329a1datagen2026-10-12 12:01 UTC96
                "A door lock, which works once, and a tub of vaseline behind it.",
8b8e83329a1datagen2026-10-12 12:01 UTC97
            )
8b8e83329a1datagen2026-10-12 12:01 UTC98
        } else {
8b8e83329a1datagen2026-10-12 12:01 UTC99
            (
8b8e83329a1datagen2026-10-12 12:01 UTC100
                Item::Lotion,
8b8e83329a1datagen2026-10-12 12:01 UTC101
                "A door lock, which works once, and a bottle of lotion behind it.",
8b8e83329a1datagen2026-10-12 12:01 UTC102
            )
8b8e83329a1datagen2026-10-12 12:01 UTC103
        };
8b8e83329a1datagen2026-10-12 12:01 UTC104
        self.items.grant(lube);
8b8e83329a1datagen2026-10-12 12:01 UTC105
        self.found(Item::DoorLock, detail)
8b8e83329a1datagen2026-10-12 12:01 UTC106
    }
8b8e83329a1datagen2026-10-12 12:01 UTC107
8b8e83329a1datagen2026-10-12 12:01 UTC108
    fn search_locker(&mut self, first: bool) -> Result<Outcome, Problem> {
8b8e83329a1datagen2026-10-12 12:01 UTC109
        let open = first
8b8e83329a1datagen2026-10-12 12:01 UTC110
            && self.chance(
8b8e83329a1datagen2026-10-12 12:01 UTC111
                self.decision("gregs-locker", "Has Greg left his locker open?"),
8b8e83329a1datagen2026-10-12 12:01 UTC112
                GREGS_LOCKER,
8b8e83329a1datagen2026-10-12 12:01 UTC113
            );
8b8e83329a1datagen2026-10-12 12:01 UTC114
        if open {
8b8e83329a1datagen2026-10-12 12:01 UTC115
            self.items.grant(Item::BabyOil);
8b8e83329a1datagen2026-10-12 12:01 UTC116
            return Ok(self.found(
8b8e83329a1datagen2026-10-12 12:01 UTC117
                Item::BabyOil,
8b8e83329a1datagen2026-10-12 12:01 UTC118
                "Greg has left his locker open. The baby oil is yours now, legally speaking.",
8b8e83329a1datagen2026-10-12 12:01 UTC119
            ));
8b8e83329a1datagen2026-10-12 12:01 UTC120
        }
8b8e83329a1datagen2026-10-12 12:01 UTC121
        self.standing.shame += 3;
8b8e83329a1datagen2026-10-12 12:01 UTC122
        Err(Problem::new(
8b8e83329a1datagen2026-10-12 12:01 UTC123
            StatusCode::UNAVAILABLE_FOR_LEGAL_REASONS,
8b8e83329a1datagen2026-10-12 12:01 UTC124
            "not-your-locker",
8b8e83329a1datagen2026-10-12 12:01 UTC125
            "That locker belongs to Greg. The server cannot serve this request for legal reasons.",
8b8e83329a1datagen2026-10-12 12:01 UTC126
        ))
8b8e83329a1datagen2026-10-12 12:01 UTC127
    }
8b8e83329a1datagen2026-10-12 12:01 UTC128
8b8e83329a1datagen2026-10-12 12:01 UTC129
    /// Searching while caged is noisy, costs the floor turn, and the key only turns up some of
8b8e83329a1datagen2026-10-12 12:01 UTC130
    /// the time. A jammed drawer takes a whole turn to work loose.
3ac624339c98atagen2026-10-13 12:21 UTC131
    pub(super) fn rummage_for_key(&mut self) -> Result<Outcome, Problem> {
3ac624339c98atagen2026-10-13 12:21 UTC132
        self.begin_turn()?;
8b8e83329a1datagen2026-10-12 12:01 UTC133
        self.add_suspicion(1);
8b8e83329a1datagen2026-10-12 12:01 UTC134
        self.maybe_summon_mum();
8b8e83329a1datagen2026-10-12 12:01 UTC135
        if self.here.drawer.jammed {
8b8e83329a1datagen2026-10-12 12:01 UTC136
            self.here.drawer.jammed = false;
8b8e83329a1datagen2026-10-12 12:01 UTC137
            self.notices.push(Notice::DrawerComesLoose);
3ac624339c98atagen2026-10-13 12:21 UTC138
            return Ok(Outcome::empty(StatusCode::NO_CONTENT));
8b8e83329a1datagen2026-10-12 12:01 UTC139
        }
8b8e83329a1datagen2026-10-12 12:01 UTC140
        if !self.chance(
8b8e83329a1datagen2026-10-12 12:01 UTC141
            self.decision("key", "Does the drawer finally give up the cage key?"),
8b8e83329a1datagen2026-10-12 12:01 UTC142
            KEY_IN_DRAWER,
8b8e83329a1datagen2026-10-12 12:01 UTC143
        ) {
8b8e83329a1datagen2026-10-12 12:01 UTC144
            if self.chance(
8b8e83329a1datagen2026-10-12 12:01 UTC145
                self.decision("drawer-jams", "Has the drawer jammed on its runners?"),
8b8e83329a1datagen2026-10-12 12:01 UTC146
                DRAWER_JAMS,
8b8e83329a1datagen2026-10-12 12:01 UTC147
            ) {
8b8e83329a1datagen2026-10-12 12:01 UTC148
                self.here.drawer.jammed = true;
8b8e83329a1datagen2026-10-12 12:01 UTC149
                self.notices.push(Notice::DrawerJammed);
8b8e83329a1datagen2026-10-12 12:01 UTC150
            }
3ac624339c98atagen2026-10-13 12:21 UTC151
            return Ok(Outcome::empty(StatusCode::NO_CONTENT));
8b8e83329a1datagen2026-10-12 12:01 UTC152
        }
8b8e83329a1datagen2026-10-12 12:01 UTC153
        self.items.grant(Item::CageKey);
3ac624339c98atagen2026-10-13 12:21 UTC154
        Ok(Outcome::json(
8b8e83329a1datagen2026-10-12 12:01 UTC155
            StatusCode::OK,
8b8e83329a1datagen2026-10-12 12:01 UTC156
            json!({ "detail": "The key was in the drawer. The cage is off." }),
3ac624339c98atagen2026-10-13 12:21 UTC157
        ))
8b8e83329a1datagen2026-10-12 12:01 UTC158
    }
8b8e83329a1datagen2026-10-12 12:01 UTC159
8b8e83329a1datagen2026-10-12 12:01 UTC160
    pub fn drawer_worth_searching(&self) -> bool {
8b8e83329a1datagen2026-10-12 12:01 UTC161
        !self.here.drawer.searched || self.items.kit.cage
8b8e83329a1datagen2026-10-12 12:01 UTC162
    }
8b8e83329a1datagen2026-10-12 12:01 UTC163
}