atagen

jelq

public

an http based roguelike rpg about jelqing

Star0
Watch0
97c05b741d8f0a39cec7b9e24bf5491f18c819c5
1
ssh://brewery@pls.lobotomise.me:33/atagen/jelq.git
src/game/dispatch.rsRust164 lines5.5 KB
1
use super::{
2
    Floor, Lube, Outcome, Run, Story, Technique,
3
    techniques::{Training, Utility},
4
};
5
use crate::problem::Problem;
6
use axum::http::{StatusCode, header};
7
use serde_json::json;
8
use std::{fmt::Write as _, ops::ControlFlow};
9
10
impl Run {
11
    pub fn jelq(
12
        &mut self,
13
        techniques: &[Technique],
14
        intensity: i32,
15
        lube: Option<Lube>,
16
    ) -> Result<Outcome, Problem> {
17
        self.check_exhausted()?;
18
        if self.online.story == Story::Pending {
19
            return Ok(self.branch_offer());
20
        }
21
        if self.floor == Floor::Forum {
22
            return Ok(Outcome::json(
23
                StatusCode::SEE_OTHER,
24
                json!({ "detail": "Refer to the forum." }),
25
            )
26
            .header(header::LOCATION, super::FORUM_THREAD));
27
        }
28
        if self.items.kit.cage {
29
            return Err(Problem::new(
30
                StatusCode::LOCKED,
31
                "caged",
32
                "The cage is locked. The key is not in the box.",
33
            ));
34
        }
35
        match *techniques {
36
            [Technique::Utility(utility)] => self.utility(utility, lube),
37
            [Technique::Training(training)] => self.single(training, intensity, lube),
38
            [Technique::Training(a), Technique::Training(b)] => self.combo(a, b, intensity, lube),
39
            [_, _] => Err(Problem::new(
40
                StatusCode::BAD_REQUEST,
41
                "combo-invalid",
42
                "Only training techniques can be combined.",
43
            )),
44
            _ => Err(Problem::new(
45
                StatusCode::BAD_REQUEST,
46
                "too-many-techniques",
47
                "Two techniques at most. The server has limits even if you do not.",
48
            )),
49
        }
50
    }
51
52
    pub(super) fn utility(
53
        &mut self,
54
        utility: Utility,
55
        lube: Option<Lube>,
56
    ) -> Result<Outcome, Problem> {
57
        match utility {
58
            Utility::Warmup => return self.warm_up(),
59
            Utility::Ice => return self.ice(),
60
            Utility::Supplement => return self.supplement(),
61
            Utility::Meditate => return self.meditate(),
62
            Utility::Energy => return self.energy(),
63
            Utility::Edge | Utility::Pump => {}
64
        }
65
        self.ready(Technique::Utility(utility), lube)?;
66
        self.check_storage()?;
67
        self.floor_enemy()?;
68
        match utility {
69
            Utility::Edge => self.edge(),
70
            _ => self.pump(),
71
        }
72
    }
73
74
    pub(super) fn single(
75
        &mut self,
76
        training: Training,
77
        intensity: i32,
78
        lube: Option<Lube>,
79
    ) -> Result<Outcome, Problem> {
80
        self.ready(Technique::Training(training), lube)?;
81
        self.check_storage()?;
82
        self.lube_available(lube)?;
83
        self.floor_enemy()?;
84
        self.take_lube(lube)?;
85
        self.chafe(lube, intensity);
86
        self.commit(intensity, lube, 1);
87
        if let ControlFlow::Break(interrupted) = self.mishaps(training, intensity)? {
88
            return Ok(interrupted);
89
        }
90
        if let ControlFlow::Break(interrupted) = self.hazards(intensity)? {
91
            return Ok(interrupted);
92
        }
93
        let outcome = self.roll(training, intensity, lube)?;
94
        Ok(self.gossip(outcome))
95
    }
96
97
    pub(super) fn combo(
98
        &mut self,
99
        a: Training,
100
        b: Training,
101
        intensity: i32,
102
        lube: Option<Lube>,
103
    ) -> Result<Outcome, Problem> {
104
        if a == b {
105
            return Err(Problem::new(
106
                StatusCode::BAD_REQUEST,
107
                "combo-invalid",
108
                "A technique cannot be combined with itself. The server has checked.",
109
            ));
110
        }
111
        self.ready(Technique::Training(a), lube)?;
112
        self.ready(Technique::Training(b), lube)?;
113
        self.check_storage()?;
114
        self.lube_available(lube)?;
115
        self.floor_enemy()?;
116
        self.take_lube(lube)?;
117
        self.chafe(lube, intensity);
118
        self.chafe(lube, intensity);
119
        self.commit(intensity, lube, 2);
120
        for training in [a, b] {
121
            if let ControlFlow::Break(interrupted) = self.mishaps(training, intensity)? {
122
                return Ok(interrupted);
123
            }
124
        }
125
        if let ControlFlow::Break(interrupted) = self.hazards(intensity)? {
126
            return Ok(interrupted);
127
        }
128
129
        let mut statuses = Vec::new();
130
        for training in [a, b] {
131
            let result = self.roll(training, intensity, lube);
132
            if self.ended.is_some() {
133
                return result;
134
            }
135
            let status = match result {
136
                Ok(outcome) => self.gossip(outcome).status(),
137
                Err(problem) => problem.status(),
138
            };
139
            statuses.push((training, status));
140
        }
141
142
        let mut xml = String::from(
143
            "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<D:multistatus xmlns:D=\"DAV:\">\n",
144
        );
145
        for (training, status) in statuses {
146
            let _ = write!(
147
                xml,
148
                "  <D:response>\n    <D:href>{}?technique={}</D:href>\n    <D:status>HTTP/1.1 {} {}</D:status>\n  </D:response>\n",
149
                self.path(""),
150
                training.name(),
151
                status.as_u16(),
152
                crate::problem::reason(status),
153
            );
154
        }
155
        xml.push_str(
156
            "  <D:responsedescription>Each technique has been reported separately.</D:responsedescription>\n</D:multistatus>\n",
157
        );
158
        Ok(Outcome::raw(
159
            StatusCode::MULTI_STATUS,
160
            "application/xml; charset=utf-8",
161
            xml,
162
        ))
163
    }
164
}