an http based roguelike rpg about jelqing
| 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 => "Warms things a good deal. Satisfies the warm-up precondition.", |
| 106 | Self::Ice => "Cools things sharply. Treats a friction burn. Consumes an ice pack.", |
| 107 | Self::Edge => { |
| 108 | "Warms things a little and adds a little girth. Three in a row is a loop." |
| 109 | } |
| 110 | Self::Pump => "Large gains, all temporary. Requires a pump.", |
| 111 | Self::Supplement => "Consumes a supplement.", |
| 112 | Self::Meditate => { |
| 113 | "Cools things a little, sheds 2 friction and 2 suspicion. Taught by the forum. Once per floor." |
| 114 | } |
| 115 | Self::Energy => "+3 stamina. Consumes an energy drink. Tastes like a battery.", |
| 116 | } |
| 117 | } |
| 118 | } |
| 119 | |
| 120 | impl Technique { |
| 121 | pub const ALL: [Self; 11] = [ |
| 122 | Self::Utility(Utility::Warmup), |
| 123 | Self::Utility(Utility::Ice), |
| 124 | Self::Utility(Utility::Edge), |
| 125 | Self::Utility(Utility::Pump), |
| 126 | Self::Utility(Utility::Supplement), |
| 127 | Self::Utility(Utility::Meditate), |
| 128 | Self::Utility(Utility::Energy), |
| 129 | Self::Training(Training::Wet), |
| 130 | Self::Training(Training::Dry), |
| 131 | Self::Training(Training::Stretch), |
| 132 | Self::Training(Training::Uli), |
| 133 | ]; |
| 134 | |
| 135 | pub fn name(self) -> &'static str { |
| 136 | match self { |
| 137 | Self::Training(t) => t.name(), |
| 138 | Self::Utility(u) => u.name(), |
| 139 | } |
| 140 | } |
| 141 | |
| 142 | pub fn parse(name: &str) -> Option<Self> { |
| 143 | Self::ALL.into_iter().find(|t| t.name() == name) |
| 144 | } |
| 145 | |
| 146 | pub fn lubricant(self) -> Option<&'static str> { |
| 147 | match self { |
| 148 | Self::Training(training) => Some(training.profile().lube.name()), |
| 149 | Self::Utility(Utility::Edge) => Some(LubeRule::Optional.name()), |
| 150 | Self::Utility(_) => None, |
| 151 | } |
| 152 | } |
| 153 | |
| 154 | pub fn intensity(self) -> Option<&'static str> { |
| 155 | match self { |
| 156 | Self::Training(_) => Some("1-10"), |
| 157 | Self::Utility(_) => None, |
| 158 | } |
| 159 | } |
| 160 | |
| 161 | pub fn describe(self, known: bool) -> Value { |
| 162 | let training = match self { |
| 163 | Self::Utility(utility) => { |
| 164 | return json!({ |
| 165 | "name": utility.name(), |
| 166 | "effect": utility.effect(), |
| 167 | "lubricant": self.lubricant(), |
| 168 | "locked": !known, |
| 169 | }); |
| 170 | } |
| 171 | Self::Training(training) => training, |
| 172 | }; |
| 173 | let profile = training.profile(); |
| 174 | let lubricant = profile.lube.name(); |
| 175 | json!({ |
| 176 | "name": training.name(), |
| 177 | "dc": profile.dc, |
| 178 | "lubricant": lubricant, |
| 179 | "foreskin": profile.foreskin.map(|(min, max)| json!({ "min": min, "max": max })), |
| 180 | "locked": !known, |
| 181 | }) |
| 182 | } |
| 183 | } |