atagen

jelq

public

an http based roguelike rpg about jelqing

Star0
Watch0
27256acf27800b63fd950b95ecc55b2a2486c1c5
1
ssh://brewery@pls.lobotomise.me:33/atagen/jelq.git
src/game/progress.rsRust203 lines7.2 KB
1
use super::{
2
    Floor, Lube, MumVisit, Notice, Observer, Run, Story,
3
    balance::{
4
        BRANCH_TURN, CAT_TAKES_TOWEL, CHANGING_ROOM_CHILL, EQ_WOBBLE, EXTENDER_GAIN,
5
        FORESKIN_GLIDE, FRICTION_BURN, FRICTION_BURN_AT, FRICTION_COLD, FRICTION_DRY,
6
        FRICTION_GRIP, FRICTION_LOTION, FRICTION_MAX, FRICTION_SPIT, GIRTH_THICK, HOT_EQ, OBSERVED,
7
        PRIAPISM_EQ, PRIAPISM_TURNS, PULLED_MUSCLE, PULLED_MUSCLE_INTENSITY, RING_PRIAPISM,
8
        RING_TIGHT_PRIAPISM, STROKE_EQ, STROKE_EQ_COST, SUSPICION_LIMIT, VIGOUR,
9
    },
10
};
11
use crate::problem::Problem;
12
13
impl Run {
14
    pub(super) fn chafe(&mut self, lube: Option<Lube>, intensity: i32, cold: bool) {
15
        let (base, slip) = match lube {
16
            None => (FRICTION_DRY, 0),
17
            Some(Lube::Spit) => (FRICTION_SPIT, 0),
18
            Some(Lube::Lotion) => (0, 0),
19
            Some(Lube::BabyOil | Lube::CoconutOil) => (0, 1),
20
            Some(Lube::Vaseline) => (0, 2),
21
        };
22
        let vigour = usize::try_from(intensity - 1).map_or(0, |i| VIGOUR[i.min(VIGOUR.len() - 1)]);
23
        let unlubed = matches!(lube, None | Some(Lube::Spit));
24
        let thick = i32::from(unlubed && self.body.girth > GIRTH_THICK);
25
        let glide = i32::from(unlubed && self.body.foreskin.is_some_and(|f| f >= FORESKIN_GLIDE));
26
        let mut friction = (base + vigour + thick - slip - glide).max(0);
27
        if friction > 0
28
            && self
29
                .body
30
                .jelq_grip
31
                .is_some_and(|grip| grip != self.body.grip)
32
        {
33
            friction -= FRICTION_GRIP;
34
        }
35
        if cold {
36
            friction += FRICTION_COLD;
37
        }
38
        if lube == Some(Lube::Lotion) {
39
            friction -= FRICTION_LOTION;
40
        }
41
        self.body.jelq_grip = Some(self.body.grip);
42
        self.body.friction = (self.body.friction + friction).clamp(0, FRICTION_MAX);
43
        if lube == Some(Lube::Lotion) {
44
            if std::mem::take(&mut self.body.conditions.friction_burn) {
45
                self.notices.push(Notice::BurnSoothed);
46
            }
47
        } else if self.body.friction >= FRICTION_BURN_AT
48
            && !self.body.conditions.friction_burn
49
            && self.chance(
50
                self.decision(
51
                    "friction-burn",
52
                    "With the skin this raw, has it finally burned?",
53
                ),
54
                FRICTION_BURN,
55
            )
56
        {
57
            self.body.conditions.friction_burn = true;
58
        }
59
    }
60
61
    pub(super) fn commit(
62
        &mut self,
63
        intensity: i32,
64
        lube: Option<Lube>,
65
        cost: i32,
66
    ) -> Result<(), Problem> {
67
        self.begin_turn()?;
68
        self.step_away();
69
        if self.items.kit.extender {
70
            self.body.length += EXTENDER_GAIN;
71
        }
72
        self.body.stamina -= cost + i32::from(lube == Some(Lube::Lotion));
73
        if self.body.stamina <= 0 {
74
            self.exhaust();
75
        }
76
        let chill = if self.floor == Floor::ChangingRoom {
77
            CHANGING_ROOM_CHILL
78
        } else {
79
            0
80
        };
81
        let wobble = self.oracle.span_int(
82
            self.decision(
83
                "wobble",
84
                "How does the count drift on this stroke, up or down?",
85
            ),
86
            -EQ_WOBBLE,
87
            EQ_WOBBLE,
88
        );
89
        self.body.eq =
90
            (self.body.eq + intensity * STROKE_EQ - STROKE_EQ_COST - chill + wobble).clamp(0, 100);
91
92
        self.make_noise(intensity / 5 + i32::from(lube == Some(Lube::Vaseline)));
93
        if self.floor == Floor::Nans && lube == Some(Lube::CoconutOil) {
94
            self.add_suspicion(2);
95
        }
96
97
        if intensity >= PULLED_MUSCLE_INTENSITY
98
            && !self.body.conditions.pulled_muscle
99
            && self.oracle.chance_not(
100
                self.decision("pulled-muscle", "Do the muscles hold?"),
101
                PULLED_MUSCLE,
102
            )
103
        {
104
            self.body.conditions.pulled_muscle = true;
105
            self.body.stamina = self.body.stamina.min(self.max_stamina());
106
        }
107
        self.settle();
108
        Ok(())
109
    }
110
111
    pub(super) fn make_noise(&mut self, noise: i32) {
112
        let doubled = match self.floor {
113
            Floor::Nans => true,
114
            Floor::ChangingRoom => !self.holds_own_in_the_locker_room(),
115
            _ => false,
116
        };
117
        self.add_suspicion(if doubled { noise * 2 } else { noise });
118
    }
119
120
    pub(super) fn add_suspicion(&mut self, amount: i32) {
121
        self.standing.suspicion = u8::try_from(
122
            (i32::from(self.standing.suspicion) + amount).clamp(0, i32::from(SUSPICION_LIMIT)),
123
        )
124
        .unwrap_or(SUSPICION_LIMIT);
125
    }
126
127
    pub(super) fn settle(&mut self) {
128
        self.maybe_summon_mum();
129
        if let Some(observer) = self.floor.observer()
130
            && self.chance(
131
                self.decision("observed", "Has someone quietly noticed what is going on?"),
132
                OBSERVED,
133
            )
134
        {
135
            self.observed = Some(observer);
136
            self.standing.shame += 1;
137
            if observer == Observer::Cat
138
                && self.chance(
139
                    self.decision("cat-takes-towel", "Has the cat taken the towel?"),
140
                    CAT_TAKES_TOWEL,
141
                )
142
            {
143
                self.here.towel_stolen = true;
144
            }
145
        }
146
        if self.items.kit.ring
147
            && self.body.eq > HOT_EQ
148
            && self.chance(
149
                self.decision(
150
                    "ring-priapism",
151
                    "With the ring still on and everything this warm, will it not go down?",
152
                ),
153
                if self.body.girth > GIRTH_THICK {
154
                    RING_TIGHT_PRIAPISM
155
                } else {
156
                    RING_PRIAPISM
157
                },
158
            )
159
        {
160
            self.body.conditions.priapism_turns = PRIAPISM_TURNS;
161
        }
162
        if self.body.conditions.priapism_turns > 0 {
163
            self.body.conditions.priapism_turns -= 1;
164
            self.body.eq = self.body.eq.max(PRIAPISM_EQ);
165
        }
166
        if self.turn == BRANCH_TURN && self.online.story == Story::Unopened {
167
            self.online.story = Story::Pending;
168
            self.notices.push(Notice::ThreadHasReplies);
169
        }
170
    }
171
172
    pub(super) fn maybe_summon_mum(&mut self) {
173
        let was_below = self.standing.at_turn_start < SUSPICION_LIMIT;
174
        if !self.floor.has_mum() || self.household.mum.is_some() || self.household.just_left {
175
            return;
176
        }
177
        let summoned = was_below && self.standing.suspicion == SUSPICION_LIMIT;
178
        let mut visits = u32::from(self.standing.suspicion) + 1;
179
        if self.here.brother_told {
180
            visits *= 2;
181
        }
182
        if summoned
183
            || self.oracle.ratio(
184
                self.decision(
185
                    "mum-summon",
186
                    "With this much noise in the house, is Mum on her way up?",
187
                ),
188
                visits,
189
                super::balance::MUM_VISIT,
190
            )
191
        {
192
            let errand = self.errand(summoned);
193
            self.notices.push(Notice::MumAtTheDoor(errand.arrival));
194
            let nonce = self.fresh_nonce();
195
            self.household.mum = Some(MumVisit {
196
                errand,
197
                nonce,
198
                strikes: 0,
199
                knocked: false,
200
            });
201
        }
202
    }
203
}