atagen

jelq

public

an http based roguelike rpg about jelqing

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

Blame: src/game/dispatch.rs

8b8e83329a1datagen2026-10-12 12:01 UTC1
use super::{
8b8e83329a1datagen2026-10-12 12:01 UTC2
    Floor, Lube, Outcome, Run, Story, Technique,
8b8e83329a1datagen2026-10-12 12:01 UTC3
    techniques::{Training, Utility},
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
use std::{fmt::Write as _, ops::ControlFlow};
8b8e83329a1datagen2026-10-12 12:01 UTC9
8b8e83329a1datagen2026-10-12 12:01 UTC10
impl Run {
8b8e83329a1datagen2026-10-12 12:01 UTC11
    pub fn jelq(
8b8e83329a1datagen2026-10-12 12:01 UTC12
        &mut self,
8b8e83329a1datagen2026-10-12 12:01 UTC13
        techniques: &[Technique],
8b8e83329a1datagen2026-10-12 12:01 UTC14
        intensity: i32,
8b8e83329a1datagen2026-10-12 12:01 UTC15
        lube: Option<Lube>,
8b8e83329a1datagen2026-10-12 12:01 UTC16
    ) -> Result<Outcome, Problem> {
8b8e83329a1datagen2026-10-12 12:01 UTC17
        self.check_exhausted()?;
8b8e83329a1datagen2026-10-12 12:01 UTC18
        if self.online.story == Story::Pending {
8b8e83329a1datagen2026-10-12 12:01 UTC19
            return Ok(self.branch_offer());
8b8e83329a1datagen2026-10-12 12:01 UTC20
        }
8b8e83329a1datagen2026-10-12 12:01 UTC21
        if self.floor == Floor::Forum {
8b8e83329a1datagen2026-10-12 12:01 UTC22
            return Ok(Outcome::json(
8b8e83329a1datagen2026-10-12 12:01 UTC23
                StatusCode::SEE_OTHER,
8b8e83329a1datagen2026-10-12 12:01 UTC24
                json!({ "detail": "Refer to the forum." }),
8b8e83329a1datagen2026-10-12 12:01 UTC25
            )
8b8e83329a1datagen2026-10-12 12:01 UTC26
            .header(header::LOCATION, super::FORUM_THREAD));
8b8e83329a1datagen2026-10-12 12:01 UTC27
        }
8b8e83329a1datagen2026-10-12 12:01 UTC28
        if self.items.kit.cage {
8b8e83329a1datagen2026-10-12 12:01 UTC29
            return Err(Problem::new(
8b8e83329a1datagen2026-10-12 12:01 UTC30
                StatusCode::LOCKED,
8b8e83329a1datagen2026-10-12 12:01 UTC31
                "caged",
8b8e83329a1datagen2026-10-12 12:01 UTC32
                "The cage is locked. The key is not in the box.",
8b8e83329a1datagen2026-10-12 12:01 UTC33
            ));
8b8e83329a1datagen2026-10-12 12:01 UTC34
        }
8b8e83329a1datagen2026-10-12 12:01 UTC35
        match *techniques {
8b8e83329a1datagen2026-10-12 12:01 UTC36
            [Technique::Utility(utility)] => self.utility(utility, lube),
8b8e83329a1datagen2026-10-12 12:01 UTC37
            [Technique::Training(training)] => self.single(training, intensity, lube),
8b8e83329a1datagen2026-10-12 12:01 UTC38
            [Technique::Training(a), Technique::Training(b)] => self.combo(a, b, intensity, lube),
8b8e83329a1datagen2026-10-12 12:01 UTC39
            [_, _] => Err(Problem::new(
8b8e83329a1datagen2026-10-12 12:01 UTC40
                StatusCode::BAD_REQUEST,
8b8e83329a1datagen2026-10-12 12:01 UTC41
                "combo-invalid",
8b8e83329a1datagen2026-10-12 12:01 UTC42
                "Only training techniques can be combined.",
8b8e83329a1datagen2026-10-12 12:01 UTC43
            )),
8b8e83329a1datagen2026-10-12 12:01 UTC44
            _ => Err(Problem::new(
8b8e83329a1datagen2026-10-12 12:01 UTC45
                StatusCode::BAD_REQUEST,
8b8e83329a1datagen2026-10-12 12:01 UTC46
                "too-many-techniques",
8b8e83329a1datagen2026-10-12 12:01 UTC47
                "Two techniques at most. The server has limits even if you do not.",
8b8e83329a1datagen2026-10-12 12:01 UTC48
            )),
8b8e83329a1datagen2026-10-12 12:01 UTC49
        }
8b8e83329a1datagen2026-10-12 12:01 UTC50
    }
8b8e83329a1datagen2026-10-12 12:01 UTC51
8b8e83329a1datagen2026-10-12 12:01 UTC52
    pub(super) fn utility(
8b8e83329a1datagen2026-10-12 12:01 UTC53
        &mut self,
8b8e83329a1datagen2026-10-12 12:01 UTC54
        utility: Utility,
8b8e83329a1datagen2026-10-12 12:01 UTC55
        lube: Option<Lube>,
8b8e83329a1datagen2026-10-12 12:01 UTC56
    ) -> Result<Outcome, Problem> {
8b8e83329a1datagen2026-10-12 12:01 UTC57
        match utility {
8b8e83329a1datagen2026-10-12 12:01 UTC58
            Utility::Warmup => return self.warm_up(),
8b8e83329a1datagen2026-10-12 12:01 UTC59
            Utility::Ice => return self.ice(),
8b8e83329a1datagen2026-10-12 12:01 UTC60
            Utility::Supplement => return self.supplement(),
8b8e83329a1datagen2026-10-12 12:01 UTC61
            Utility::Meditate => return self.meditate(),
8b8e83329a1datagen2026-10-12 12:01 UTC62
            Utility::Energy => return self.energy(),
8b8e83329a1datagen2026-10-12 12:01 UTC63
            Utility::Edge | Utility::Pump => {}
8b8e83329a1datagen2026-10-12 12:01 UTC64
        }
8b8e83329a1datagen2026-10-12 12:01 UTC65
        self.ready(Technique::Utility(utility), lube)?;
8b8e83329a1datagen2026-10-12 12:01 UTC66
        self.check_storage()?;
8b8e83329a1datagen2026-10-12 12:01 UTC67
        self.floor_enemy()?;
8b8e83329a1datagen2026-10-12 12:01 UTC68
        match utility {
8b8e83329a1datagen2026-10-12 12:01 UTC69
            Utility::Edge => self.edge(),
8b8e83329a1datagen2026-10-12 12:01 UTC70
            _ => self.pump(),
8b8e83329a1datagen2026-10-12 12:01 UTC71
        }
8b8e83329a1datagen2026-10-12 12:01 UTC72
    }
8b8e83329a1datagen2026-10-12 12:01 UTC73
8b8e83329a1datagen2026-10-12 12:01 UTC74
    pub(super) fn single(
8b8e83329a1datagen2026-10-12 12:01 UTC75
        &mut self,
8b8e83329a1datagen2026-10-12 12:01 UTC76
        training: Training,
8b8e83329a1datagen2026-10-12 12:01 UTC77
        intensity: i32,
8b8e83329a1datagen2026-10-12 12:01 UTC78
        lube: Option<Lube>,
8b8e83329a1datagen2026-10-12 12:01 UTC79
    ) -> Result<Outcome, Problem> {
8b8e83329a1datagen2026-10-12 12:01 UTC80
        self.ready(Technique::Training(training), lube)?;
8b8e83329a1datagen2026-10-12 12:01 UTC81
        self.check_storage()?;
8b8e83329a1datagen2026-10-12 12:01 UTC82
        self.lube_available(lube)?;
8b8e83329a1datagen2026-10-12 12:01 UTC83
        self.floor_enemy()?;
8b8e83329a1datagen2026-10-12 12:01 UTC84
        self.take_lube(lube)?;
8b8e83329a1datagen2026-10-12 12:01 UTC85
        self.chafe(lube, intensity);
8b8e83329a1datagen2026-10-12 12:01 UTC86
        self.commit(intensity, lube, 1);
8b8e83329a1datagen2026-10-12 12:01 UTC87
        if let ControlFlow::Break(interrupted) = self.mishaps(training, intensity)? {
8b8e83329a1datagen2026-10-12 12:01 UTC88
            return Ok(interrupted);
8b8e83329a1datagen2026-10-12 12:01 UTC89
        }
8b8e83329a1datagen2026-10-12 12:01 UTC90
        if let ControlFlow::Break(interrupted) = self.hazards(intensity)? {
8b8e83329a1datagen2026-10-12 12:01 UTC91
            return Ok(interrupted);
8b8e83329a1datagen2026-10-12 12:01 UTC92
        }
8b8e83329a1datagen2026-10-12 12:01 UTC93
        let outcome = self.roll(training, intensity, lube)?;
8b8e83329a1datagen2026-10-12 12:01 UTC94
        Ok(self.gossip(outcome))
8b8e83329a1datagen2026-10-12 12:01 UTC95
    }
8b8e83329a1datagen2026-10-12 12:01 UTC96
8b8e83329a1datagen2026-10-12 12:01 UTC97
    pub(super) fn combo(
8b8e83329a1datagen2026-10-12 12:01 UTC98
        &mut self,
8b8e83329a1datagen2026-10-12 12:01 UTC99
        a: Training,
8b8e83329a1datagen2026-10-12 12:01 UTC100
        b: Training,
8b8e83329a1datagen2026-10-12 12:01 UTC101
        intensity: i32,
8b8e83329a1datagen2026-10-12 12:01 UTC102
        lube: Option<Lube>,
8b8e83329a1datagen2026-10-12 12:01 UTC103
    ) -> Result<Outcome, Problem> {
8b8e83329a1datagen2026-10-12 12:01 UTC104
        if a == b {
8b8e83329a1datagen2026-10-12 12:01 UTC105
            return Err(Problem::new(
8b8e83329a1datagen2026-10-12 12:01 UTC106
                StatusCode::BAD_REQUEST,
8b8e83329a1datagen2026-10-12 12:01 UTC107
                "combo-invalid",
8b8e83329a1datagen2026-10-12 12:01 UTC108
                "A technique cannot be combined with itself. The server has checked.",
8b8e83329a1datagen2026-10-12 12:01 UTC109
            ));
8b8e83329a1datagen2026-10-12 12:01 UTC110
        }
8b8e83329a1datagen2026-10-12 12:01 UTC111
        self.ready(Technique::Training(a), lube)?;
8b8e83329a1datagen2026-10-12 12:01 UTC112
        self.ready(Technique::Training(b), lube)?;
8b8e83329a1datagen2026-10-12 12:01 UTC113
        self.check_storage()?;
8b8e83329a1datagen2026-10-12 12:01 UTC114
        self.lube_available(lube)?;
8b8e83329a1datagen2026-10-12 12:01 UTC115
        self.floor_enemy()?;
8b8e83329a1datagen2026-10-12 12:01 UTC116
        self.take_lube(lube)?;
8b8e83329a1datagen2026-10-12 12:01 UTC117
        self.chafe(lube, intensity);
8b8e83329a1datagen2026-10-12 12:01 UTC118
        self.chafe(lube, intensity);
8b8e83329a1datagen2026-10-12 12:01 UTC119
        self.commit(intensity, lube, 2);
8b8e83329a1datagen2026-10-12 12:01 UTC120
        for training in [a, b] {
8b8e83329a1datagen2026-10-12 12:01 UTC121
            if let ControlFlow::Break(interrupted) = self.mishaps(training, intensity)? {
8b8e83329a1datagen2026-10-12 12:01 UTC122
                return Ok(interrupted);
8b8e83329a1datagen2026-10-12 12:01 UTC123
            }
8b8e83329a1datagen2026-10-12 12:01 UTC124
        }
8b8e83329a1datagen2026-10-12 12:01 UTC125
        if let ControlFlow::Break(interrupted) = self.hazards(intensity)? {
8b8e83329a1datagen2026-10-12 12:01 UTC126
            return Ok(interrupted);
8b8e83329a1datagen2026-10-12 12:01 UTC127
        }
8b8e83329a1datagen2026-10-12 12:01 UTC128
8b8e83329a1datagen2026-10-12 12:01 UTC129
        let mut statuses = Vec::new();
8b8e83329a1datagen2026-10-12 12:01 UTC130
        for training in [a, b] {
8b8e83329a1datagen2026-10-12 12:01 UTC131
            let result = self.roll(training, intensity, lube);
8b8e83329a1datagen2026-10-12 12:01 UTC132
            if self.ended.is_some() {
8b8e83329a1datagen2026-10-12 12:01 UTC133
                return result;
8b8e83329a1datagen2026-10-12 12:01 UTC134
            }
8b8e83329a1datagen2026-10-12 12:01 UTC135
            let status = match result {
8b8e83329a1datagen2026-10-12 12:01 UTC136
                Ok(outcome) => self.gossip(outcome).status(),
8b8e83329a1datagen2026-10-12 12:01 UTC137
                Err(problem) => problem.status(),
8b8e83329a1datagen2026-10-12 12:01 UTC138
            };
8b8e83329a1datagen2026-10-12 12:01 UTC139
            statuses.push((training, status));
8b8e83329a1datagen2026-10-12 12:01 UTC140
        }
8b8e83329a1datagen2026-10-12 12:01 UTC141
8b8e83329a1datagen2026-10-12 12:01 UTC142
        let mut xml = String::from(
8b8e83329a1datagen2026-10-12 12:01 UTC143
            "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<D:multistatus xmlns:D=\"DAV:\">\n",
8b8e83329a1datagen2026-10-12 12:01 UTC144
        );
8b8e83329a1datagen2026-10-12 12:01 UTC145
        for (training, status) in statuses {
8b8e83329a1datagen2026-10-12 12:01 UTC146
            let _ = write!(
8b8e83329a1datagen2026-10-12 12:01 UTC147
                xml,
8b8e83329a1datagen2026-10-12 12:01 UTC148
                "  <D:response>\n    <D:href>{}?technique={}</D:href>\n    <D:status>HTTP/1.1 {} {}</D:status>\n  </D:response>\n",
8b8e83329a1datagen2026-10-12 12:01 UTC149
                self.path(""),
8b8e83329a1datagen2026-10-12 12:01 UTC150
                training.name(),
8b8e83329a1datagen2026-10-12 12:01 UTC151
                status.as_u16(),
8b8e83329a1datagen2026-10-12 12:01 UTC152
                crate::problem::reason(status),
8b8e83329a1datagen2026-10-12 12:01 UTC153
            );
8b8e83329a1datagen2026-10-12 12:01 UTC154
        }
8b8e83329a1datagen2026-10-12 12:01 UTC155
        xml.push_str(
8b8e83329a1datagen2026-10-12 12:01 UTC156
            "  <D:responsedescription>Each technique has been reported separately.</D:responsedescription>\n</D:multistatus>\n",
8b8e83329a1datagen2026-10-12 12:01 UTC157
        );
8b8e83329a1datagen2026-10-12 12:01 UTC158
        Ok(Outcome::raw(
8b8e83329a1datagen2026-10-12 12:01 UTC159
            StatusCode::MULTI_STATUS,
8b8e83329a1datagen2026-10-12 12:01 UTC160
            "application/xml; charset=utf-8",
8b8e83329a1datagen2026-10-12 12:01 UTC161
            xml,
8b8e83329a1datagen2026-10-12 12:01 UTC162
        ))
8b8e83329a1datagen2026-10-12 12:01 UTC163
    }
8b8e83329a1datagen2026-10-12 12:01 UTC164
}