atagen

jelq

public

an http based roguelike rpg about jelqing

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