atagen

jelq

public

an http based roguelike rpg about jelqing

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