atagen

jelq

public

an http based roguelike rpg about jelqing

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