atagen

jelq

public

an http based roguelike rpg about jelqing

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