atagen

jelq

public

an http based roguelike rpg about jelqing

Star0
Watch0
14de3e1e8dc2a460103dbac0f56b745af96da78e
1
ssh://brewery@pls.lobotomise.me:33/atagen/jelq.git
src/game/kitchen.rsRust132 lines4.7 KB
1
use axum::http::{StatusCode, header};
2
use serde_json::json;
3
4
use super::{
5
    Cause, Floor, Item, Outcome, Run, Story,
6
    balance::{
7
        CAUGHT_MELONED, COCONUT_ODDS, ENERGY_ODDS, KITCHEN_ICE_ODDS, KITCHEN_TELLINGS,
8
        KITCHEN_TOLD, MELON_SHAME, RUPTURE_LINE, SUSPICION_LIMIT, WATERMELON,
9
    },
10
};
11
use crate::problem::Problem;
12
use rand::Rng;
13
14
impl Run {
15
    /// Raid the fridge. It costs the floor turn like anything else, and the household keeps count.
16
    pub fn raid_kitchen(&mut self) -> Result<Outcome, Problem> {
17
        if !self.floor.has_kitchen() {
18
            return Err(Problem::new(
19
                StatusCode::NOT_FOUND,
20
                "no-kitchen",
21
                "There is no kitchen on this floor.",
22
            ));
23
        }
24
        if self.kitchen_tellings >= KITCHEN_TELLINGS {
25
            return Err(Problem::new(
26
                StatusCode::GONE,
27
                "kitchen-off-limits",
28
                "The kitchen is off limits. You have been told twice.",
29
            ));
30
        }
31
        if self.story == Story::Pending {
32
            return Ok(self.branch_offer());
33
        }
34
        self.touch();
35
        self.turn += 1;
36
        self.here.turns += 1;
37
        self.realise();
38
        let was_below = self.suspicion < SUSPICION_LIMIT;
39
        // One draw of 120 keeps the marginals at the documented 1 in 3, 1 in 5 and 1 in 8.
40
        let draw = self.rng.random_range(0..120);
41
        let oil = 120 / COCONUT_ODDS;
42
        let energy = oil + 120 / ENERGY_ODDS;
43
        let ice = energy + 120 / KITCHEN_ICE_ODDS;
44
        let outcome = if self.eq > RUPTURE_LINE && self.rng.random_ratio(WATERMELON.0, WATERMELON.1)
45
        {
46
            self.here.melon_offered = true;
47
            self.melon_offer()
48
        } else if draw < oil {
49
            self.items.grant(Item::CoconutOil);
50
            Ok(Outcome::json(
51
                StatusCode::OK,
52
                json!({ "detail": "A jar of coconut oil, half of it already gone." }),
53
            ))
54
        } else if draw < energy {
55
            self.items.grant(Item::EnergyDrink);
56
            Ok(Outcome::json(
57
                StatusCode::OK,
58
                json!({ "detail": "An energy drink, cold and faintly alarming." }),
59
            ))
60
        } else if draw < ice {
61
            self.items.grant(Item::IcePack);
62
            Ok(Outcome::json(
63
                StatusCode::OK,
64
                json!({ "detail": "An ice pack, buried under the peas." }),
65
            ))
66
        } else {
67
            Ok(Outcome::empty(StatusCode::NO_CONTENT))
68
        };
69
        self.settle(was_below);
70
        let outcome = outcome?;
71
        if self.chance(KITCHEN_TOLD) {
72
            self.kitchen_tellings += 1;
73
            if self.kitchen_tellings >= KITCHEN_TELLINGS {
74
                return Err(Problem::new(
75
                    StatusCode::GONE,
76
                    "kitchen-off-limits",
77
                    "The kitchen is off limits. You have been told twice.",
78
                ));
79
            }
80
            self.notices.push(if self.floor == Floor::Nans {
81
                "Stop raiding the fridge."
82
            } else {
83
                "Stop raiding the kitchen."
84
            });
85
        }
86
        Ok(outcome)
87
    }
88
89
    fn melon_offer(&self) -> Result<Outcome, Problem> {
90
        let commit = self.path("/kitchen/watermelon");
91
        Ok(Outcome::json(
92
            StatusCode::MULTIPLE_CHOICES,
93
            json!({
94
                "detail": "The fridge holds a watermelon. It is exactly the right shape.",
95
                "choices": [
96
                    { "href": commit, "method": "POST", "title": "Commit to the watermelon" },
97
                    { "href": self.path(""), "method": "GET", "title": "Close the fridge" },
98
                ],
99
            }),
100
        )
101
        .header(
102
            header::LINK,
103
            format!(
104
                "<{commit}>; rel=\"alternate\"; title=\"Commit to the watermelon\"; allow=\"POST\""
105
            ),
106
        ))
107
    }
108
109
    /// The watermelon. It empties EQ, keeps the gains, costs shame, and the household may notice.
110
    pub fn commit_melon(&mut self) -> Result<Outcome, Problem> {
111
        if !self.here.melon_offered {
112
            return Err(Problem::new(
113
                StatusCode::CONFLICT,
114
                "no-melon-on-offer",
115
                "There is no watermelon on offer.",
116
            ));
117
        }
118
        self.here.melon_offered = false;
119
        self.reset_eq(0);
120
        self.shame += MELON_SHAME;
121
        self.touch();
122
        if self.chance(CAUGHT_MELONED) {
123
            return Err(self.end(Cause::Meloned));
124
        }
125
        Ok(Outcome::json(
126
            StatusCode::OK,
127
            json!({
128
                "detail": "The watermelon did not survive, and neither did the mood. EQ is gone, the gains are kept, and the shame is considerable.",
129
            }),
130
        ))
131
    }
132
}