an http based roguelike rpg about jelqing
Commit 9374b3933189
tarball5 files changed+73-11
@@ -38,7 +38,8 @@ pub const SELF_REPORT_INFLATION: f64 = 1.5;
3838
pub const MM_PER_INCH: f64 = 25.4;3939
pub const HONEST_TOLERANCE: f64 = 0.06;4040
pub const EXAGGERATION: f64 = 1.0;41
-pub const STORAGE_GIRTH: f64 = 5.0;41
+/// Girth plus a quarter of the length is what the jeans have to hold alongside the extender.42
+pub const STORAGE_BULK: f64 = 6.5;4243
pub const GIRTH_RESPECTED: f64 = 5.0;4344
pub const GIRTH_THICK: f64 = 5.5;4445
pub const FORESKIN_GLIDE: f64 = 1.0;@@ -63,6 +64,8 @@ pub const WINDOW: u32 = 60;
6364
pub const PULLED_MUSCLE: u32 = 12;6465
pub const PULLED_MUSCLE_INTENSITY: i32 = 9;6566
pub const RING_PRIAPISM: u32 = 10;67
+pub const RING_TIGHT_PRIAPISM: u32 = 4;68
+pub const THIN_MARKUP: u32 = 3;6669
pub const SUPPLEMENT_WORKS: u32 = 5;6770
pub const RUPTURE_HOLD: u32 = 250;6871
pub const ULI_ODDS: u32 = 4;@@ -1,7 +1,7 @@
11
use axum::http::{StatusCode, header};22
use serde_json::{Value, json};33
4
-use super::{Item, Outcome, Run, items::SHOP};4
+use super::{Item, Outcome, Run, balance::THIN_MARKUP, items::SHOP};55
use crate::problem::Problem;66
77
fn pump_bro_absent() -> Problem {@@ -13,6 +13,20 @@ fn pump_bro_absent() -> Problem {
1313
}1414
1515
impl Run {16
+ /// Pump-Bro can tell when a customer needs girth, and prices the girth range accordingly.17
+ pub fn price(&self, item: Item) -> Option<u32> {18
+ let girth_range = matches!(19
+ item,20
+ Item::Ring | Item::PumpPro | Item::Supplement | Item::Extender21
+ );22
+ let markup = if girth_range && !self.girth_respected() {23
+ THIN_MARKUP24
+ } else {25
+ 026
+ };27
+ Some(item.price()? + markup)28
+ }29
+1630
pub fn shop_view(&self) -> Result<Value, Problem> {1731
if !self.floor.shop_open() {1832
return Err(pump_bro_absent());@@ -22,14 +36,20 @@ impl Run {
2236
.filter_map(|item| {2337
Some(json!({2438
"item": item.slug(),25
- "price": item.price()?,39
+ "price": self.price(*item)?,2640
"description": item.pitch(),2741
"href": self.path(&format!("/shop/{}", item.slug())),2842
"method": "POST",2943
}))3044
})3145
.collect();32
- Ok(json!({ "merchant": "Pump-Bro", "stock": stock }))46
+ let mut view = json!({ "merchant": "Pump-Bro", "stock": stock });47
+ if !self.girth_respected() {48
+ view["pitch"] = json!(49
+ "Pump-Bro looks you up and down. The girth range has gone up a little, just for you."50
+ );51
+ }52
+ Ok(view)3353
}3454
3555
pub fn buy(&mut self, slug: &str) -> Result<Outcome, Problem> {@@ -46,7 +66,7 @@ impl Run {
4666
let item = Item::parse(slug)4767
.filter(|item| SHOP.contains(item))4868
.ok_or_else(not_for_sale)?;49
- let price = item.price().ok_or_else(not_for_sale)?;69
+ let price = self.price(item).ok_or_else(not_for_sale)?;5070
if item == Item::Pump {5171
return Err(Problem::new(5272
StatusCode::UPGRADE_REQUIRED,@@ -11,7 +11,8 @@ use super::{
1111
FRICTION_DRY, FRICTION_GRIP, FRICTION_HOLD, FRICTION_MAX, FRICTION_MEDITATE, FRICTION_SPIT,1212
GIRTH_THICK, GREED_HOT, GREED_WARM, HOLD_EQ, HOT_EQ, MEDITATION_EQ, OBSERVED, PRIAPISM_EQ,1313
PRIAPISM_TURNS, PULLED_MUSCLE, PULLED_MUSCLE_INTENSITY, REFLECTION, RING_PRIAPISM,14
- RING_RUPTURE_LINE, RUPTURE_HOLD, RUPTURE_LINE, STORAGE_GIRTH, SUSPICION_LIMIT,14
+ RING_RUPTURE_LINE, RING_TIGHT_PRIAPISM, RUPTURE_HOLD, RUPTURE_LINE, STORAGE_BULK,15
+ SUSPICION_LIMIT,1516
},1617
not_extended, round3,1718
state::{MumVisit, Observer, Pending},@@ -321,7 +322,7 @@ impl Run {
321322
}322323
323324
fn check_storage(&self) -> Result<(), Problem> {324
- if self.items.extender && self.girth > STORAGE_GIRTH {325
+ if self.items.extender && self.girth + self.current_length() / 4.0 > STORAGE_BULK {325326
return Err(Problem::new(326327
StatusCode::INSUFFICIENT_STORAGE,327328
"jeans-full",@@ -453,7 +454,11 @@ impl Run {
453454
"ring-priapism",454455
"With the ring still on and everything this warm, will it not go down?",455456
),456
- RING_PRIAPISM,457
+ if self.girth > GIRTH_THICK {458
+ RING_TIGHT_PRIAPISM459
+ } else {460
+ RING_PRIAPISM461
+ },457462
)458463
{459464
self.conditions.priapism_turns = PRIAPISM_TURNS;@@ -185,7 +185,7 @@ fn links(run: &Run) -> String {
185185
.chain(run.here.shopping.then(|| {186186
SHOP.iter()187187
.filter_map(|item| {188
- let price = item.price()?;188
+ let price = run.price(*item)?;189189
Some(format!(190190
"<{}>; rel=\"{REL_BASE}shop-item\"; title=\"{} for {price}\"; allow=\"POST\"",191191
run.path(&format!("/shop/{}", item.slug())),@@ -13,7 +13,7 @@ use crate::{
1313
AppState, Config,1414
game::{1515
Floor, MumVisit, Run, Story,16
- balance::{BRANCH_TURN, STORAGE_GIRTH, SUSPICION_LIMIT},16
+ balance::{BRANCH_TURN, SUSPICION_LIMIT},1717
},1818
router,1919
};@@ -1638,7 +1638,8 @@ async fn a_refused_jelq_leaves_the_lube_alone() {
16381638
let app = seeded_with(Floor::Bedroom, |run| {16391639
run.warmed_up = true;16401640
run.items.extender = true;1641
- run.girth = STORAGE_GIRTH + 1.0;1641
+ run.girth = 6.0;1642
+ run.length = 6.0;16421643
});16431644
let lube = [("content-type", "application/baby-oil")];16441645
let full = send(@@ -2081,3 +2082,36 @@ async fn the_dead_outlive_the_server() {
20812082
let _ = std::fs::remove_file(format!("{}{suffix}", path.display()));20822083
}20832084
}2085
+2086
+#[tokio::test]2087
+async fn pump_bro_charges_the_thin_more_for_girth() {2088
+ for (girth, ring, oil) in [(4.5, 11, 4), (5.2, 8, 4)] {2089
+ let app = seeded_with(Floor::ChangingRoom, |run| run.girth = girth);2090
+ let shop = json(send(&app, "GET", "/runs/cafebabe/shop", &[], "").await).await;2091
+ let price = |slug: &str| {2092
+ shop["stock"]2093
+ .as_array()2094
+ .unwrap()2095
+ .iter()2096
+ .find(|item| item["item"] == slug)2097
+ .unwrap()["price"]2098
+ .as_u64()2099
+ .unwrap()2100
+ };2101
+ assert_eq!(price("cock-ring"), ring, "girth {girth}");2102
+ assert_eq!(price("baby-oil"), oil, "girth {girth}");2103
+ }2104
+}2105
+2106
+#[tokio::test]2107
+async fn a_long_run_fills_the_jeans_before_a_thick_one() {2108
+ let app = seeded_with(Floor::Bedroom, |run| {2109
+ run.warmed_up = true;2110
+ run.items.extender = true;2111
+ run.girth = 4.8;2112
+ run.length = 7.5;2113
+ });2114
+ let lube = [("content-type", "application/baby-oil")];2115
+ let full = send(&app, "JELQ", "/runs/cafebabe?technique=wet", &lube, "").await;2116
+ assert_eq!(full.status(), StatusCode::INSUFFICIENT_STORAGE);2117
+}