atagen

jelq

public

an http based roguelike rpg about jelqing

Star0
Watch0
cddf59e37d5f7b2a7e0f8b644252196caf5a7e97
1
ssh://brewery@pls.lobotomise.me:33/atagen/jelq.git
src/game/techniques.rsRust170 lines4.8 KB
1
use serde_json::{Value, json};
2
3
use super::lube::LubeRule;
4
5
/// Techniques that roll for gains.
6
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
7
pub enum Training {
8
    Wet,
9
    Dry,
10
    Stretch,
11
    Uli,
12
}
13
14
/// Techniques that change EQ or spend an item without rolling.
15
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
16
pub enum Utility {
17
    Warmup,
18
    Ice,
19
    Edge,
20
    Pump,
21
    Supplement,
22
    Meditate,
23
    Energy,
24
}
25
26
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
27
pub enum Technique {
28
    Training(Training),
29
    Utility(Utility),
30
}
31
32
pub struct Profile {
33
    pub(crate) dc: i32,
34
    pub(crate) length: f64,
35
    pub(crate) girth: f64,
36
    /// Minimum and maximum foreskin the technique tolerates. A minimum above zero means it is used.
37
    pub(crate) foreskin: Option<(f64, f64)>,
38
    pub(crate) foreskin_growth: f64,
39
    pub(crate) lube: LubeRule,
40
}
41
42
impl Training {
43
    pub fn name(self) -> &'static str {
44
        match self {
45
            Self::Wet => "wet",
46
            Self::Dry => "dry",
47
            Self::Stretch => "stretch",
48
            Self::Uli => "uli",
49
        }
50
    }
51
52
    pub fn profile(self) -> Profile {
53
        match self {
54
            Self::Wet => Profile {
55
                dc: 10,
56
                length: 0.010,
57
                girth: 0.005,
58
                foreskin: None,
59
                foreskin_growth: 0.0,
60
                lube: LubeRule::Required,
61
            },
62
            Self::Dry => Profile {
63
                dc: 12,
64
                length: 0.008,
65
                girth: 0.003,
66
                foreskin: Some((0.8, 2.0)),
67
                foreskin_growth: 0.01,
68
                lube: LubeRule::Forbidden,
69
            },
70
            Self::Stretch => Profile {
71
                dc: 11,
72
                length: 0.015,
73
                girth: 0.0,
74
                foreskin: Some((0.0, 1.8)),
75
                foreskin_growth: 0.03,
76
                lube: LubeRule::Optional,
77
            },
78
            Self::Uli => Profile {
79
                dc: 15,
80
                length: 0.002,
81
                girth: 0.020,
82
                foreskin: None,
83
                foreskin_growth: 0.0,
84
                lube: LubeRule::Optional,
85
            },
86
        }
87
    }
88
}
89
90
impl Utility {
91
    pub fn name(self) -> &'static str {
92
        match self {
93
            Self::Warmup => "warmup",
94
            Self::Ice => "ice",
95
            Self::Edge => "edge",
96
            Self::Pump => "pump",
97
            Self::Supplement => "supplement",
98
            Self::Meditate => "meditate",
99
            Self::Energy => "energy",
100
        }
101
    }
102
103
    fn effect(self) -> &'static str {
104
        match self {
105
            Self::Warmup => "EQ +25. Satisfies the warm-up precondition.",
106
            Self::Ice => "EQ -40. Treats a friction burn. Consumes an ice pack.",
107
            Self::Edge => "EQ +15 and a little girth. Three in a row is a loop.",
108
            Self::Pump => "Large gains, all temporary. Requires a pump.",
109
            Self::Supplement => "Consumes a supplement.",
110
            Self::Meditate => "EQ -10, sheds 2 friction. Taught by the forum. Once per floor.",
111
            Self::Energy => "+3 stamina. Consumes an energy drink. Tastes like a battery.",
112
        }
113
    }
114
}
115
116
impl Technique {
117
    pub const ALL: [Self; 11] = [
118
        Self::Utility(Utility::Warmup),
119
        Self::Utility(Utility::Ice),
120
        Self::Utility(Utility::Edge),
121
        Self::Utility(Utility::Pump),
122
        Self::Utility(Utility::Supplement),
123
        Self::Utility(Utility::Meditate),
124
        Self::Utility(Utility::Energy),
125
        Self::Training(Training::Wet),
126
        Self::Training(Training::Dry),
127
        Self::Training(Training::Stretch),
128
        Self::Training(Training::Uli),
129
    ];
130
131
    pub fn name(self) -> &'static str {
132
        match self {
133
            Self::Training(t) => t.name(),
134
            Self::Utility(u) => u.name(),
135
        }
136
    }
137
138
    pub fn parse(name: &str) -> Option<Self> {
139
        Self::ALL.into_iter().find(|t| t.name() == name)
140
    }
141
142
    pub fn lubricant(self) -> Option<&'static str> {
143
        match self {
144
            Self::Training(training) => Some(training.profile().lube.name()),
145
            Self::Utility(_) => None,
146
        }
147
    }
148
149
    pub fn describe(self, known: bool) -> Value {
150
        let training = match self {
151
            Self::Utility(utility) => {
152
                return json!({
153
                    "name": utility.name(),
154
                    "effect": utility.effect(),
155
                    "locked": !known,
156
                });
157
            }
158
            Self::Training(training) => training,
159
        };
160
        let profile = training.profile();
161
        let lubricant = profile.lube.name();
162
        json!({
163
            "name": training.name(),
164
            "dc": profile.dc,
165
            "lubricant": lubricant,
166
            "foreskin": profile.foreskin.map(|(min, max)| json!({ "min": min, "max": max })),
167
            "locked": !known,
168
        })
169
    }
170
}