a munch adventure
Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.
 
 
 
 

1583 wiersze
54 KiB

  1. (() => {
  2. function checkSuspicion(add = 0) {
  3. const old = getStat("suspicion");
  4. if (add >= 0) {
  5. add *= state.info.awareness.value;
  6. }
  7. changeStat("suspicion", add);
  8. if (getStat("suspicion") >= 100) {
  9. print(["Geta spots you!", "You're snatched up and tossed into the fox's bowl of cereal."]);
  10. goToRoom("in-bowl");
  11. return false;
  12. } else if (getStat("suspicion") >= 75 && old < 75) {
  13. print(["The fox is very suspicious. You're going to get caught if you keep this up..."]);
  14. }
  15. return true;
  16. }
  17. function randomBodyPart() {
  18. const choices = Object.entries(state.player.limbs).filter(([name, status]) => {
  19. return status;
  20. }).map(([name, status]) => name);
  21. return choices[Math.floor(Math.random() * choices.length)];
  22. }
  23. function limbsLost() {
  24. return Object.entries(state.player.limbs).filter(([name, status]) => {
  25. return !status;
  26. }).length;
  27. }
  28. function pickRandom(list) {
  29. return list[Math.floor(Math.random() * list.length)];
  30. }
  31. const word = {
  32. get swallow() { return pickRandom(["swallow", "gulp"]); },
  33. get slimy() { return pickRandom(["slimy", "sloppy", "slick", "glistening"]) },
  34. get disgusting() { return pickRandom(["disgusting", "abhorrent", "rank", "horrific", "nauseating", "sickening", "wretched"]) },
  35. get foul() { return pickRandom(["foul", "rank", "gross"]) },
  36. get fatal() { return pickRandom(["fatal", "deadly"]) },
  37. get painful() { return pickRandom(["painful", "agonizing", "unbearable"]) },
  38. get wet() { return pickRandom(["wet", "damp", "soaking-wet", "drenched", "soaked"]) },
  39. get hot() { return pickRandom(["hot", "sweltering"]) },
  40. get choking() { return pickRandom(["choking", "suffocating", "unbreathable", "thick", "asphyxiating"]) }
  41. }
  42. function statLerp(stat, change, duration) {
  43. // pretty sure this'll be a random id...
  44. const id = new Date().getTime() + Math.random();
  45. const iterations = duration / 1000 * 60;
  46. startTimer({
  47. id: id,
  48. func: () => {
  49. changeStat(stat, change / iterations);
  50. return true;
  51. },
  52. delay: 1000 / 60,
  53. loop: true,
  54. classes: [
  55. ]
  56. });
  57. startTimer({
  58. id: id + "-stopper",
  59. func: () => {
  60. stopTimer(id);
  61. return false;
  62. },
  63. delay: duration,
  64. loop: false,
  65. classes: [
  66. ]
  67. });
  68. }
  69. const limbs = {
  70. head: "head",
  71. leftArm: "left arm",
  72. rightArm: "right arm",
  73. leftLeg: "left leg",
  74. rightLeg: "right leg"
  75. };
  76. stories.push({
  77. "id": "geta-unaware",
  78. "info": {
  79. "name": "Geta's Breakfast",
  80. "desc": "Try to sneak past a fox after a catastrophic shrinking incident.",
  81. "tags": [
  82. "prey",
  83. "fatal",
  84. "oral-vore",
  85. "hard-vore",
  86. "hard-digestion",
  87. "macro-micro"
  88. ]
  89. },
  90. "intro": {
  91. "start": "pepper-grinder",
  92. "setup": () => {
  93. state.info.awareness = {
  94. id: "awareness",
  95. name: "Geta's Awareness",
  96. type: "counter",
  97. value: 1,
  98. get render() {
  99. if (this.value < 1) {
  100. return "Distracted";
  101. } else if (this.value == 1) {
  102. return "Normal"
  103. } else {
  104. return "Alert"
  105. }
  106. }
  107. }
  108. state.geta = {};
  109. state.player.stats.health = { name: "Health", type: "meter", value: 100, min: 0, max: 100, get color() { return "rgb(" + (155 + this.value) + "," + (this.value / 2) + "," + (this.value / 2) + ")" } };
  110. state.player.stats.stamina = { name: "Stamina", type: "meter", value: 100, min: 0, max: 100, get color() { return "rgb(55," + (155 + this.value) + ",55)" }, hidden: true };
  111. state.player.stats.suspicion = { name: "Suspicion", type: "meter", value: 0, min: 0, max: 100, get color() { return "rgb(" + (155 + this.value) + ",100,100)" } };
  112. state.player.stats.mawPos = {
  113. "name": "Struggle", "type": "meter", "value": 0.5, "min": 0, "max": 1, get color() {
  114. return (this.value <= 0.15 || this.value >= 0.85) ? "rgb(255,100,0)" : "rgb(0,255,0)"
  115. }, hidden: true
  116. }
  117. state.player.stats.throatPos = { "name": "Descent", "type": "meter", "value": 0.25, "min": 0, "max": 1, get color() { return "rgb(" + (100 + 155 * this.value) + ",0,0)" }, hidden: true }
  118. state.player.stats.absorption = { "name": "Absorption", "type": "meter", "value": 0, "min": 0, "max": 1, get color() { return "rgb(" + (100 + 155 * this.value) + ",0,0)" }, hidden: true }
  119. state.info.time.value = 60 * 60 * 7 + 60 * 17;
  120. state.player.limbs = {};
  121. state.player.limbs.head = true;
  122. state.player.limbs.leftArm = true;
  123. state.player.limbs.rightArm = true;
  124. state.player.limbs.leftLeg = true;
  125. state.player.limbs.rightLeg = true;
  126. startTimer({
  127. id: "clock",
  128. func: () => {
  129. state.info.time.value += 1;
  130. state.info.time.value %= 86000;
  131. return true;
  132. },
  133. delay: 1000,
  134. loop: true,
  135. classes: [
  136. ]
  137. });
  138. startTimer({
  139. id: "suspicion-decay",
  140. func: () => {
  141. checkSuspicion(-0.1);
  142. return true;
  143. },
  144. delay: 100,
  145. loop: true,
  146. classes: [
  147. "free"
  148. ]
  149. });
  150. startTimer({
  151. id: "timeout",
  152. func: () => {
  153. if (state.info.time.value == 60 * 60 * 7 + 60 * 19) {
  154. print(["The fox is almost done with his breakfast..."]);
  155. }
  156. if (state.info.time.value >= 60 * 60 * 7 + 60 * 20) {
  157. print(["Time's up! In you go."]);
  158. goToRoom("maw");
  159. return false;
  160. }
  161. return true;
  162. },
  163. delay: 1000,
  164. loop: true,
  165. classes: [
  166. "free"
  167. ]
  168. });
  169. startTimer({
  170. id: "geta-action",
  171. func: () => {
  172. const random = Math.random();
  173. if (random < 0.7) {
  174. print(["Geta slurps up a spoonful of cereal."]);
  175. return Math.random() * 3000 + 3000
  176. } else if (random < 0.9) {
  177. state.info.awareness.value = 0.1;
  178. print(["The fox yawns and stretches."]);
  179. startTimer({
  180. id: "yawn-end",
  181. func: () => {
  182. print(["Geta finishes his stretch"]);
  183. state.info.awareness.value = 1;
  184. return true;
  185. },
  186. delay: 5000,
  187. loop: false,
  188. classes: [
  189. "free"
  190. ]
  191. });
  192. return Math.random() * 3000 + 5000
  193. } else {
  194. state.info.awareness.value = 2;
  195. print(["Geta narrows his eyes and looks around the table. Something seems off to him..."]);
  196. startTimer({
  197. id: "squint-end",
  198. func: () => {
  199. print(["He goes back to his breakfast."]);
  200. state.info.awareness.value = 1;
  201. return true;
  202. },
  203. delay: 5000,
  204. loop: false,
  205. classes: [
  206. "free"
  207. ]
  208. });
  209. return Math.random() * 1000 + 6000
  210. }
  211. },
  212. delay: 5000,
  213. loop: true,
  214. classes: [
  215. "free"
  216. ]
  217. });
  218. },
  219. "intro": () => {
  220. print(["<i>\"Urgh...\"</i>, you moan. \"<i>My head...</i>\"",
  221. newline,
  222. "You blink and rub your eyes. You're propped up on something hard and smooth; the ground beneath you is just as uncomfortable. The faint aroma of fried food drifts on the wind. A long moment passes before your eyes clear enough to see &mdash; and when they do clear, you see something most distressing!",
  223. newline,
  224. "You're slumped on a kitchen table with your back to a towering pepper mill. You can't be more than an inch tall; a stray peppercorn is as large as a volleyball.",
  225. ]);
  226. }
  227. },
  228. "sounds": [
  229. "loop/heartbeat.ogg",
  230. "loop/stomach.ogg",
  231. "sfx/absorb.ogg",
  232. "sfx/big-gulp.ogg",
  233. "sfx/digest.ogg",
  234. "sfx/gulp-1.ogg",
  235. "sfx/gulp-2.ogg",
  236. "sfx/gulp-3.ogg",
  237. "sfx/swallow.ogg"
  238. ],
  239. "preload": [
  240. ],
  241. "refresh": () => {
  242. setBackgroundColor(50 - state.player.stats.health.value / 2, 0, 0);
  243. },
  244. "world": {
  245. "pepper-grinder": {
  246. "id": "pepper-grinder",
  247. "name": "Pepper Grinder",
  248. "desc": "You're hiding behind a pepper grinder",
  249. "move": (room) => {
  250. print(["You dart over to the pepper grinder, which looms over you like a greatwood."]);
  251. },
  252. "enter": (room) => {
  253. },
  254. "exit": (room) => {
  255. },
  256. "actions": [
  257. {
  258. name: "Tap",
  259. desc: "Bang on the pepper shaker",
  260. execute: (room) => {
  261. print(["You thump the pepper shaker, making a dull thud."]);
  262. const safe = checkSuspicion(25);
  263. if (safe && getStat("suspicion") > 50) {
  264. print(["Geta leans in to have a closer look. He's going to catch you if you don't move!"]);
  265. startTimer({
  266. id: "pepper-investigate",
  267. func: () => {
  268. if (state.player.location == "pepper-grinder") {
  269. print([
  270. "A massive hand grasps the grinder and shoves it aside; you fall back and land hard, knocking the wind from your lungs. Stars dance in your corners of your vision as Geta's muzzle looms above, his dull-green eyes fixated on your bite-sized body.",
  271. newline,
  272. "He frowns and scoops you up, squeezing you between tree-trunk fingers as he raises you up to his slavering maw."
  273. ]);
  274. goToRoom("hand");
  275. } else {
  276. print(["You evaded the fox."]);
  277. }
  278. },
  279. delay: 3000,
  280. loop: false,
  281. classes: [
  282. "free"
  283. ]
  284. });
  285. }
  286. },
  287. show: [
  288. ],
  289. conditions: [
  290. ]
  291. },
  292. {
  293. name: "Wait",
  294. desc: "Wait for the fox to finish his breakfast. Surely you'll be able to escape after that...right?",
  295. execute: (room) => {
  296. state.info.time.value = 60 * 60 * 7 + 60 * 20;
  297. },
  298. show: [
  299. ],
  300. conditions: [
  301. ]
  302. },
  303. ],
  304. "exits": {
  305. "up": {
  306. "target": "bowl",
  307. "desc": "Walk up to the cereal bowl",
  308. "show": [
  309. ],
  310. "conditions": [
  311. ],
  312. "hooks": [
  313. (room, exit) => {
  314. return checkSuspicion(10);
  315. }
  316. ]
  317. },
  318. "left": {
  319. "target": "table",
  320. "desc": "Run out into the open",
  321. "show": [
  322. ],
  323. "conditions": [
  324. ],
  325. "hooks": [
  326. ]
  327. },
  328. },
  329. "hooks": [
  330. ],
  331. "data": {
  332. "stats": {
  333. }
  334. }
  335. },
  336. "bowl": {
  337. "id": "bowl",
  338. "name": "Behind the Bowl",
  339. "desc": "You're crouched behind Geta's bowl of cereal",
  340. "move": (room) => {
  341. print(["You scurry up to the looming bowl, staying low and out of Geta's sight."]);
  342. },
  343. "enter": (room) => {
  344. },
  345. "exit": (room) => {
  346. },
  347. "actions": [
  348. ],
  349. "exits": {
  350. "ascend": {
  351. "target": "in-bowl",
  352. "desc": "Climb into Geta's cereal",
  353. "show": [
  354. ],
  355. "conditions": [
  356. ],
  357. "hooks": [
  358. ]
  359. },
  360. "down": {
  361. "target": "pepper-grinder",
  362. "desc": "Run back behind the pepper grinder",
  363. "show": [
  364. ],
  365. "conditions": [
  366. ],
  367. "hooks": [
  368. (room, exit) => {
  369. return checkSuspicion(15);
  370. }
  371. ]
  372. },
  373. },
  374. "hooks": [
  375. ],
  376. "data": {
  377. "stats": {
  378. }
  379. }
  380. },
  381. "table": {
  382. "id": "table",
  383. "name": "Table",
  384. "desc": "You're out in the open!",
  385. "move": (room) => {
  386. },
  387. "enter": (room) => {
  388. startTimer({
  389. id: "table-suspicion",
  390. func: () => {
  391. checkSuspicion(1.5);
  392. return true;
  393. },
  394. delay: 100,
  395. loop: true,
  396. classes: [
  397. "free"
  398. ]
  399. });
  400. },
  401. "exit": (room) => {
  402. stopTimer("table-suspicion");
  403. },
  404. "actions": [
  405. ],
  406. "exits": {
  407. "right": {
  408. "target": "pepper-grinder",
  409. "desc": "Run back to cover",
  410. "show": [
  411. ],
  412. "conditions": [
  413. ],
  414. "hooks": [
  415. ]
  416. },
  417. },
  418. "hooks": [
  419. ],
  420. "data": {
  421. "stats": {
  422. }
  423. }
  424. },
  425. "in-bowl": {
  426. "id": "in-bowl",
  427. "name": "Bowl",
  428. "desc": "You're in the cereal bowl...",
  429. "move": (room) => {
  430. print(["Why did you do that?"]);
  431. },
  432. "enter": (room) => {
  433. state.player.stats.suspicion.hidden = true;
  434. stopClassTimers("free");
  435. startTimer({
  436. id: "geta-eat",
  437. func: () => {
  438. if (Math.random() < 0.6) {
  439. print(["Geta scoops up a spoonful of cereal; you narrowly avoid being caught."]);
  440. return true;
  441. } else {
  442. print(["Geta scoops you up and slurps you into his maw."]);
  443. goToRoom("maw");
  444. return false;
  445. }
  446. },
  447. delay: 3000,
  448. loop: true,
  449. classes: [
  450. "free"
  451. ]
  452. });
  453. },
  454. "exit": (room) => {
  455. },
  456. "actions": [
  457. ],
  458. "exits": {
  459. "ascend": {
  460. "target": "bowl",
  461. "desc": "Try to climb back out!",
  462. "show": [
  463. ],
  464. "conditions": [
  465. ],
  466. "hooks": [
  467. (room, exit) => {
  468. print([
  469. "You grab at the rim of the bowl and try to pull yourself out. Alas, your struggles are for naught; Geta easily scoops you up in his spoon and, a heartbeat later, slurps you into his sloppy jaws. You didn't stand a chance."
  470. ]);
  471. goToRoom("maw");
  472. return false;
  473. }
  474. ]
  475. },
  476. },
  477. "hooks": [
  478. ],
  479. "data": {
  480. "stats": {
  481. }
  482. }
  483. },
  484. "hand": {
  485. "id": "hand",
  486. "name": "Geta's Hand",
  487. "desc": "You've been grabbed!",
  488. "move": (room) => {
  489. },
  490. "enter": (room) => {
  491. stopClassTimers("free");
  492. state.player.stats.suspicion.hidden = true;
  493. state.geta.handTicksLeft = 2 + Math.floor(Math.random() * 2);
  494. startTimer({
  495. id: "geta-hand-actions",
  496. func: () => {
  497. if (state.geta.handTicksLeft == 0) {
  498. print(["In you go!"]);
  499. goToRoom("maw");
  500. return false;
  501. } else {
  502. print(["Geta teases you"]);
  503. state.geta.handTicksLeft -= 1;
  504. return Math.random() * 2000 + 4000;
  505. }
  506. },
  507. delay: 5000,
  508. loop: true,
  509. classes: [
  510. ]
  511. });
  512. },
  513. "exit": (room) => {
  514. },
  515. "actions": [
  516. ],
  517. "exits": {
  518. },
  519. "hooks": [
  520. ],
  521. "data": {
  522. "stats": {
  523. }
  524. }
  525. },
  526. "maw": {
  527. "id": "maw",
  528. "name": "Geta's Maw",
  529. "desc": "You've been slurped up into the fox's " + word.foul + " jaws",
  530. "move": (room) => {
  531. },
  532. "enter": (room) => {
  533. state.player.stats.suspicion.hidden = true;
  534. stopClassTimers("free");
  535. state.player.stats.stamina.hidden = false;
  536. state.player.stats.mawPos.hidden = false;
  537. state.geta.slurps = 0;
  538. state.geta.chews = 0;
  539. state.geta.swallowsLeft = 3 + Math.floor(Math.random() * 3);
  540. state.geta.mawMovement = 1;
  541. print(["You slip into Geta's maw; the atmosphere is " + word.disgusting + ". He'll swallow you alive if you slip too far back, but crawl too far forward, and you'll meet his fangs..."])
  542. startTimer({
  543. id: "maw-stamina",
  544. func: () => {
  545. changeStat("stamina", 0.1);
  546. return true;
  547. },
  548. delay: 1000 / 60,
  549. loop: true,
  550. classes: [
  551. "maw-struggle"
  552. ]
  553. });
  554. startTimer({
  555. id: "maw-random-movement",
  556. func: () => {
  557. const time = new Date().getTime();
  558. const movementFactor = (state.geta.mawMovement + limbsLost());
  559. const fastPart = Math.sin(time / 200) / 1600 / 3;
  560. const slowPart = Math.sin(time / 1000) / 1600;
  561. changeStat("mawPos", movementFactor * (fastPart + slowPart));
  562. if (getStat("mawPos") <= 0.02) {
  563. print(["You slip too far back. Geta doesn't even have to try to swallow you like the food you are; you're lost from the world, buried in his hot, tight throat."]);
  564. goToRoom("throat");
  565. return false;
  566. } else if (getStat("mawPos") >= 0.98) {
  567. print(["Geta's jaws close like a falling guillotine's blade. You're crushed like an insect. A sharp gulp drags you down to the fox's guts."]);
  568. playSfx("sfx/swallow.ogg");
  569. changeStat("health", -90);
  570. goToRoom("throat");
  571. state.player.flags.throatSurrender = true;
  572. return false;
  573. }
  574. return true;
  575. },
  576. delay: 1000 / 60,
  577. loop: true,
  578. classes: [
  579. "maw-struggle"
  580. ]
  581. });
  582. startTimer({
  583. id: "maw-struggle",
  584. func: () => {
  585. if (state.geta.swallowsLeft <= 0) {
  586. print(["Geta picks up his bowl of cereal and drinks it down, swallowing you in the process."]);
  587. state.geta.swallowsLeft = -1;
  588. goToRoom("throat");
  589. return false;
  590. }
  591. let choice;
  592. if (Math.random() < 0.2) {
  593. const choices = [
  594. "slosh",
  595. "tilt-back",
  596. "shove",
  597. ];
  598. choice = choices[Math.floor(Math.random() * choices.length)];
  599. } else if (Math.random() > state.geta.slurps / 3) {
  600. choice = "slurp";
  601. } else if (state.geta.chews - Math.floor(Math.random() * 3) < state.geta.slurps) {
  602. choice = "chew";
  603. } else {
  604. choice = "swallow";
  605. }
  606. if (choice == "swallow") {
  607. if (getStat("mawPos") <= 0.15) {
  608. print(["You're too far back. The fox swallows a mouthful of cereal, taking you with it."]);
  609. goToRoom("throat");
  610. return false;
  611. } else {
  612. printRandom([
  613. ["A light swallow drags a lump of chewed-up cereal into Geta's " + word.fatal + " depths."],
  614. ["Geta swallows, dragging you closer to your demise."],
  615. ["Your captor's throat ripples as he gulps down his breakfast."]
  616. ]);
  617. statLerp("mawPos", -0.25, 500);
  618. state.geta.slurps = 0;
  619. state.geta.chews = 0;
  620. state.geta.swallowsLeft -= 1;
  621. return Math.random() * 1500 + 1500;
  622. }
  623. } else if (choice == "slurp") {
  624. statLerp("mawPos", -0.1, 250);
  625. printRandom([
  626. ["A spoonful of cereal slips into the fox's sloppy maw."],
  627. ["Geta slurps up some more of his breakfast."],
  628. ["You're shoved back a bit as Geta slurps up more cereal."]
  629. ]);
  630. state.geta.slurps += 1;
  631. return Math.random() * 1000 + 2500;
  632. } else if (choice == "chew") {
  633. if (getStat("mawPos") >= 0.85) {
  634. const limb = randomBodyPart();
  635. state.player.limbs[limb] = false;
  636. const limbName = limbs[limb];
  637. if (limb == "head") {
  638. print(["Geta's jaws crush down on your head. You die."]);
  639. changeStat("health", -100);
  640. goToRoom("stomach");
  641. } else {
  642. print(["You scream in pain as your " + limbName + " is shattered by the fox's jaws"]);
  643. changeStat("health", -40);
  644. return true;
  645. }
  646. } else {
  647. printRandom([
  648. ["Cruel fangs crush down on the food around you."],
  649. ["Geta chews on his breakfast."],
  650. ["The fox's fangs close with a crackle-crunch of cereal."]
  651. ]);
  652. statLerp("mawPos", Math.random() / 10 - 0.05, 250);
  653. state.geta.chews += 1;
  654. return Math.random() * 500 + 1300;
  655. }
  656. } else if (choice == "slosh") {
  657. print(["Geta's tongue sloshes from side to side, throwing you around his maw like a ship in a storm."]);
  658. state.geta.mawMovement = 3;
  659. startTimer({
  660. id: "maw-slosh-end",
  661. func: () => {
  662. state.geta.mawMovement = 1;
  663. print(["The sloshing ends."]);
  664. return true;
  665. },
  666. delay: 4000,
  667. loop: false,
  668. classes: [
  669. "maw-struggle"
  670. ]
  671. });
  672. return Math.random() * 1500 + 4500;
  673. } else if (choice == "tilt-back") {
  674. print(["Geta tilts his head back, sending rivults of slobber flowing down into that yawning gullet."]);
  675. state.geta.mawMovement = 0.2;
  676. statLerp("mawPos", -1, 4000);
  677. startTimer({
  678. id: "maw-tilt-text",
  679. func: () => {
  680. state.geta.mawMovement = 1;
  681. print(["The fox's muzzle tilts back down as he SWALLOWS hard."]);
  682. statLerp("mawPos", -0.3, 500);
  683. state.geta.swallowsLeft -= 1;
  684. state.geta.slurps = 0;
  685. state.geta.chews = 0;
  686. return true;
  687. },
  688. delay: 4000,
  689. loop: false,
  690. classes: [
  691. "maw-struggle"
  692. ]
  693. });
  694. return 5000 + Math.random() * 1000;
  695. } else if (choice == "shove") {
  696. print(["Geta's tongue lurches forward, shoving you towards the front of his maw!"]);
  697. statLerp("mawPos", 0.2, 500);
  698. return 2000 + Math.random() * 1000;
  699. }
  700. },
  701. delay: 0,
  702. loop: true,
  703. classes: [
  704. "maw-struggle"
  705. ]
  706. });
  707. startTimer({
  708. id: "maw-taunts",
  709. func: () => {
  710. printRandom([
  711. ["\"Did you really think I wouldn't notice you?\""],
  712. ["\"You're going to feel good dying in my guts.\""],
  713. ["\"I could just crush you...but where's the fun in that?\""]
  714. ]);
  715. return Math.random() * 5000 + 5000;
  716. },
  717. delay: 5000,
  718. loop: true,
  719. classes: [
  720. "maw-struggle"
  721. ]
  722. });
  723. },
  724. "exit": (room) => {
  725. state.player.stats.stamina.hidden = true;
  726. state.player.stats.mawPos.hidden = true;
  727. stopClassTimers("maw-struggle");
  728. },
  729. "actions": [
  730. {
  731. name: "Struggle",
  732. desc: "Pull yourself away from the fox's throat! Just don't go too far forward...",
  733. execute: (room) => {
  734. if (getStat("stamina") < 25) {
  735. print(["You're too tired..."]);
  736. } else {
  737. print(["You drag yourself forward"]);
  738. changeStat("stamina", -25);
  739. statLerp("mawPos", 0.15 + Math.random() * 0.05, 250);
  740. }
  741. },
  742. show: [
  743. ],
  744. conditions: [
  745. ]
  746. },
  747. {
  748. name: "Slip Back",
  749. desc: "Slide back towards Geta's gullet",
  750. execute: (room) => {
  751. if (Math.random() * 25 > getStat("stamina")) {
  752. print(["You try to shimmy back an inch or two, but your sore muscles give way; you slide back perilously far!"]);
  753. statLerp("mawPos", -0.3 - Math.random() * 0.25, 250);
  754. }
  755. else if (Math.random() < 0.9) {
  756. print(["You let yourself slip back."]);
  757. statLerp("mawPos", -0.2 - Math.random() * 0.1, 250);
  758. } else {
  759. print(["You lose your grip, sliding back quite far!"]);
  760. statLerp("mawPos", -0.3 - Math.random() * 0.15, 250);
  761. }
  762. },
  763. show: [
  764. ],
  765. conditions: [
  766. ]
  767. },
  768. {
  769. name: "Dive In",
  770. desc: "Throw yourself towards the fox's throat",
  771. execute: (room) => {
  772. print(["Resigned to your fate, you toss yourself into Geta's throat. He seems surprised by your eagerness to submit, but swallows you all the same."]);
  773. goToRoom("throat");
  774. },
  775. show: [
  776. ],
  777. conditions: [
  778. ]
  779. },
  780. ],
  781. "exits": {
  782. },
  783. "hooks": [
  784. ],
  785. "data": {
  786. "stats": {
  787. }
  788. }
  789. },
  790. "throat": {
  791. "id": "throat",
  792. "name": "Geta's Gullet",
  793. "desc": "GULP!",
  794. "move": (room) => {
  795. },
  796. "enter": (room) => {
  797. playSfx("sfx/swallow.ogg");
  798. playLoop("loop/stomach.ogg", 0.3);
  799. state.player.stats.stamina.hidden = false;
  800. state.player.stats.throatPos.hidden = false;
  801. startTimer({
  802. id: "throat-stamina",
  803. func: () => {
  804. changeStat("stamina", 0.03);
  805. return true;
  806. },
  807. delay: 1000 / 60,
  808. loop: true,
  809. classes: [
  810. "throat-struggle"
  811. ]
  812. });
  813. state.geta.throatStage = 1;
  814. startTimer({
  815. id: "throat-stages",
  816. func: () => {
  817. if (state.geta.throatStage / 5 < getStat("throatPos")) {
  818. state.geta.throatStage = Math.ceil(getStat("throatPos") * 5);
  819. switch (state.geta.throatStage) {
  820. case 3:
  821. print(["You're sinking into the fox's chest..."]);
  822. break;
  823. case 4:
  824. print(["Deeper, deeper still..."]);
  825. break;
  826. case 5:
  827. print(["Your grave is just a swallow or two away."]);
  828. break;
  829. default:
  830. break;
  831. }
  832. }
  833. return true;
  834. },
  835. delay: 1000,
  836. loop: true,
  837. classes: [
  838. "throat-struggle"
  839. ]
  840. });
  841. startTimer({
  842. id: "throat-descent",
  843. func: () => {
  844. if (getStat("throatPos") <= 0.01) {
  845. print(["Geta swallows HARD, cramming you back down like the food you are."]);
  846. changeStat("throatPos", 0.1);
  847. statLerp("throatPos", 0.5, 1000);
  848. }
  849. if (getStat("throatPos") >= 0.99) {
  850. goToRoom("stomach");
  851. return false;
  852. }
  853. changeStat("throatPos", state.player.flags.throatSurrender ? 0.0005 : 0.0001);
  854. playLoop("loop/heartbeat.ogg", 0.3 + getStat("throatPos") * 0.7);
  855. return true;
  856. },
  857. delay: 1000 / 60,
  858. loop: true,
  859. classes: [
  860. "throat-struggle"
  861. ]
  862. });
  863. startTimer({
  864. id: "throat-swallows",
  865. func: () => {
  866. const choice = Math.random();
  867. const bonus = state.player.flags.throatSurrender ? 3 : 1
  868. if (choice < 0.7) {
  869. print(["Geta's throat pumps you deeper"]);
  870. playSfx(pickRandom([
  871. "sfx/gulp-1.ogg",
  872. "sfx/gulp-2.ogg",
  873. "sfx/gulp-3.ogg"
  874. ]));
  875. statLerp("throatPos", bonus*0.1, 1250);
  876. return Math.random() * 2000 + 2000;
  877. } else if (choice < 0.85) {
  878. if (getStat("throatPos") < 0.4) {
  879. print(["A finger presses in on you from the outside. Your captor is enjoying himself...but at least it slows your descent a little."]);
  880. statLerp("throatPos", bonus*0.05, 2000);
  881. return Math.random() * 4000 + 2000;
  882. } else {
  883. return Math.random() * 200 + 200;
  884. }
  885. } else {
  886. print(["A crushing swallow grips your body and crams you down deep."]);
  887. playSfx("sfx/big-gulp.ogg");
  888. statLerp("throatPos", bonus*0.3, 1500);
  889. return Math.random() * 2000 + 2000;
  890. }
  891. },
  892. delay: 2000,
  893. loop: true,
  894. classes: [
  895. "throat-struggle"
  896. ]
  897. });
  898. },
  899. "exit": (room) => {
  900. state.player.stats.stamina.hidden = true;
  901. state.player.stats.throatPos.hidden = true;
  902. print(["You slush down into Geta's stomach"]);
  903. stopClassTimers("throat-struggle");
  904. },
  905. "actions": [
  906. {
  907. name: "Struggle",
  908. desc: "Try to climb back out!",
  909. execute: (room) => {
  910. if (Math.random() * 50 > getStat("stamina")) {
  911. print(["You try your best, but your sore muscles are no match."]);
  912. } else {
  913. print(["Your valiant struggles drag you a little closer to freedom."]);
  914. statLerp("throatPos", -0.15, 1000);
  915. changeStat("stamina", -20);
  916. }
  917. },
  918. show: [
  919. (room) => {
  920. return !state.player.flags.throatSurrender;
  921. }
  922. ],
  923. conditions: [
  924. ]
  925. },
  926. {
  927. name: "Give up",
  928. desc: "Dive down into Geta's stomach",
  929. execute: (room) => {
  930. print(["You submit to your predator."]);
  931. state.player.flags.throatSurrender = true;
  932. },
  933. show: [
  934. (room) => {
  935. return !state.player.flags.throatSurrender;
  936. }
  937. ],
  938. conditions: [
  939. ]
  940. },
  941. ],
  942. "exits": {
  943. },
  944. "hooks": [
  945. ],
  946. "data": {
  947. "stats": {
  948. }
  949. }
  950. },
  951. "stomach": {
  952. "id": "stomach",
  953. "name": "Geta's Stomach",
  954. "desc": "Glorp",
  955. "move": (room) => {
  956. },
  957. "enter": (room) => {
  958. playLoop("loop/stomach.ogg");
  959. stopLoop("loop/heartbeat.ogg");
  960. state.geta.digestionStage = 0;
  961. state.geta.acidStrength = 1;
  962. startTimer({
  963. id: "digest-stages",
  964. func: () => {
  965. if (100 - state.geta.digestionStage * 25 - 25 > getStat("health")) {
  966. state.geta.digestionStage = Math.floor((100 - getStat("health")) / 25);
  967. console.log(state.geta.digestionStage);
  968. switch (state.geta.digestionStage) {
  969. case 1:
  970. print(["Your skin begins to tingle."]);
  971. break;
  972. case 2:
  973. print(["The stinging acids work their way into your tender body."]);
  974. break;
  975. case 3:
  976. print(["You're starting to fall apart..."]);
  977. break;
  978. default:
  979. break;
  980. }
  981. }
  982. return true;
  983. },
  984. delay: 1000,
  985. loop: true,
  986. classes: [
  987. "digestion"
  988. ]
  989. });
  990. startTimer({
  991. id: "digest-random",
  992. func: () => {
  993. const choices = [
  994. () => {
  995. const crushed = randomBodyPart();
  996. const name = limbs[crushed];
  997. if (name == "head") {
  998. print(["A powerful fold of muscle grips your head, crushing it like a grape and killing you instantly."]);
  999. changeStat("health", -100);
  1000. return false;
  1001. } else {
  1002. print(["Geta's stomach grips your " + name + " and crushes it with a horrific CRACK"]);
  1003. changeStat("health", -40);
  1004. return true;
  1005. }
  1006. },
  1007. () => {
  1008. printRandom([["Geta squeezes in on his gut with both hands, sloshing you around in the sickly stew of cereal, milk, and enzymatic slime."],
  1009. ["Your organic prison snarls and churns, soaking you in fresh acids and hastening your wretched demise."]]);
  1010. statLerp("health", -10, 2000);
  1011. return true;
  1012. },
  1013. () => {
  1014. if (state.geta.swallowsLeft == 0) {
  1015. print(["A deep series of *glurks* rattles your bones."]);
  1016. startTimer({
  1017. id: "stomach-milk",
  1018. func: () => {
  1019. print(["A torrent of cold milk pours into the fox's stomach."]);
  1020. return false;
  1021. },
  1022. delay: 3000,
  1023. loop: false,
  1024. classes: [
  1025. "digestion"
  1026. ]
  1027. });
  1028. } else if (state.geta.swallowsLeft > 0) {
  1029. print(["Muffled chewing comes from far above. A moment later, you hear a wet *gluk*"]);
  1030. startTimer({
  1031. id: "stomach-cereal",
  1032. func: () => {
  1033. print(["A slimy heap of well-chewed corn flakes splatters down around you."]);
  1034. return false;
  1035. },
  1036. delay: 4000,
  1037. loop: false,
  1038. classes: [
  1039. ]
  1040. });
  1041. } else if (state.geta.swallowsLeft < 0) {
  1042. print(["You hear a few light swallows."]);
  1043. startTimer({
  1044. id: "stomach-coffee",
  1045. func: () => {
  1046. print(["Gouts of hot, bitter coffee pour into the fox's guts."]);
  1047. return false;
  1048. },
  1049. delay: 3000,
  1050. loop: false,
  1051. classes: [
  1052. ]
  1053. });
  1054. }
  1055. return true;
  1056. },
  1057. () => {
  1058. print(["\"You were barely worth eating,\" murmurs the fox. \"So small. So weak.\""]);
  1059. return true;
  1060. }
  1061. ];
  1062. if (choices[Math.floor(Math.random() * choices.length)]()) {
  1063. return Math.random() * 3000 + 3500;
  1064. } else {
  1065. return false;
  1066. }
  1067. },
  1068. delay: 5000,
  1069. loop: true,
  1070. classes: [
  1071. "digestion"
  1072. ]
  1073. });
  1074. startTimer({
  1075. id: "digest",
  1076. func: () => {
  1077. changeStat("health", -0.3 * state.geta.acidStrength);
  1078. if (getStat("health") <= 0) {
  1079. print(["You're gradually digested, merciful oblivion ending your torment in the " + word.disgusting + " depths of your captor..."]);
  1080. goToRoom("digested");
  1081. return false;
  1082. }
  1083. return true;
  1084. },
  1085. delay: 100,
  1086. loop: true,
  1087. classes: [
  1088. "digestion"
  1089. ]
  1090. });
  1091. },
  1092. "exit": (room) => {
  1093. },
  1094. "actions": [
  1095. {
  1096. name: "Squirm",
  1097. desc: "Rub at the walls of the fox's churning stomach",
  1098. execute: (room) => {
  1099. printRandom([
  1100. ["You punch and kick at the walls"],
  1101. ["A powerful churn grabs hold of you, stifling any attempts at struggling"],
  1102. ["Your little thumps and kicks do little to faze your captor"]
  1103. ]);
  1104. if (Math.random() < 0.05) {
  1105. print(["Geta slaps his stomach, slamming your head and throwing you back."]);
  1106. state.player.flags.stunned = true;
  1107. stopTimer("stomach-stun");
  1108. startTimer({
  1109. id: "stomach-stun",
  1110. func: () => {
  1111. state.player.flags.stunned = false;
  1112. return false;
  1113. },
  1114. delay: 3000,
  1115. loop: false,
  1116. classes: [
  1117. "digestion"
  1118. ]
  1119. });
  1120. } else {
  1121. state.player.flags.stunned = true;
  1122. stopTimer("stomach-stun");
  1123. startTimer({
  1124. id: "stomach-stun",
  1125. func: () => {
  1126. state.player.flags.stunned = false;
  1127. return false;
  1128. },
  1129. delay: 2000,
  1130. loop: false,
  1131. classes: [
  1132. "digestion"
  1133. ]
  1134. });
  1135. }
  1136. },
  1137. show: [
  1138. ],
  1139. conditions: [
  1140. (room) => {
  1141. return !state.player.flags.stunned;
  1142. }
  1143. ]
  1144. },
  1145. {
  1146. name: "Beg",
  1147. desc: "Plead for your life",
  1148. execute: (room) => {
  1149. printRandom([
  1150. [
  1151. "\"PLEASE!\" you scream, thumping on the walls of the vulpine's gut. \"Let me out!\"",
  1152. ]
  1153. ])
  1154. if (Math.random() < 0.7) {
  1155. print(["Your pleas fall on deaf ears."]);
  1156. } else {
  1157. printRandom([
  1158. ["\"Shhhh,\" growls Geta, \"you're going to die in me. Stop whimpering.\""],
  1159. ["A long moment passes. \"Poor thing,\" says your captor. \"Shouldn't have gotten so nosy, hmm?\""],
  1160. ["<i>\"No.\"</i>"],
  1161. ["\"You're going to die in there &mdash; and I'm going to enjoy it.\""]
  1162. ])
  1163. }
  1164. state.player.flags.stunned = true;
  1165. stopTimer("stomach-stun");
  1166. startTimer({
  1167. id: "stomach-stun",
  1168. func: () => {
  1169. state.player.flags.stunned = false;
  1170. return false;
  1171. },
  1172. delay: 1000,
  1173. loop: false,
  1174. classes: [
  1175. "digestion"
  1176. ]
  1177. });
  1178. },
  1179. show: [
  1180. ],
  1181. conditions: [
  1182. (room) => {
  1183. return !state.player.flags.stunned;
  1184. }
  1185. ]
  1186. },
  1187. {
  1188. name: "Scream",
  1189. desc: "IT HURTS",
  1190. execute: (room) => {
  1191. printRandom([
  1192. [
  1193. "\"Oh god, oh god, oh god,\" you wail...quivering and quaking as you're digested alive. \"GETA!\""
  1194. ],
  1195. [
  1196. "A blood-curdling scream bellows from your burning lungs."
  1197. ],
  1198. [
  1199. "You let out a hideous wail as the fox digests you alive."
  1200. ]
  1201. ]);
  1202. if (Math.random() < 0.6) {
  1203. print(["Geta doesn't notice."]);
  1204. } else {
  1205. print(["A booming chuckle rocks your body."]);
  1206. printRandom([
  1207. ["\"I hope you're suffering in there.\""],
  1208. ["\"Pathetic little snack.\""],
  1209. ["\"Ready to die?\""],
  1210. ["\"Don't suffocate too soon &mdash; I want you to <i>burn</i>.\""],
  1211. ["\"You get what you deserve.\""],
  1212. ["\"So weak.\""],
  1213. ["\"Enjoy your death.\""]
  1214. ]);
  1215. }
  1216. state.player.flags.stunned = true;
  1217. stopTimer("stomach-stun");
  1218. startTimer({
  1219. id: "stomach-stun",
  1220. func: () => {
  1221. state.player.flags.stunned = false;
  1222. return false;
  1223. },
  1224. delay: 1500,
  1225. loop: false,
  1226. classes: [
  1227. "digestion"
  1228. ]
  1229. });
  1230. },
  1231. show: [
  1232. ],
  1233. conditions: [
  1234. (room) => {
  1235. return !state.player.flags.stunned;
  1236. }
  1237. ]
  1238. },
  1239. ],
  1240. "exits": {
  1241. },
  1242. "hooks": [
  1243. ],
  1244. "data": {
  1245. "stats": {
  1246. }
  1247. }
  1248. },
  1249. "digested": {
  1250. "id": "digested",
  1251. "name": "Geta's Stomach",
  1252. "desc": "You're just mush now",
  1253. "move": (room) => {
  1254. },
  1255. "enter": (room) => {
  1256. stopClassTimers("digestion");
  1257. stopTimer("clock");
  1258. state.player.stats.health.hidden = true;
  1259. state.player.stats.absorption.hidden = false;
  1260. startTimer({
  1261. id: "clock",
  1262. func: () => {
  1263. state.info.time.value += 2;
  1264. state.info.time.value %= 86000;
  1265. return true;
  1266. },
  1267. delay: 1000 / 60,
  1268. loop: true,
  1269. classes: [
  1270. ]
  1271. });
  1272. startTimer({
  1273. id: "passive-absorb",
  1274. func: () => {
  1275. changeStat("absorption", 0.0004);
  1276. if (getStat("absorption") >= 1) {
  1277. goToRoom("absorbed");
  1278. return false;
  1279. }
  1280. return true;
  1281. },
  1282. delay: 1000 / 60,
  1283. loop: true,
  1284. classes: [
  1285. "absorption"
  1286. ]
  1287. });
  1288. startTimer({
  1289. id: "absorbption-random",
  1290. func: () => {
  1291. const result = pickRandom([
  1292. () => {
  1293. print(["A " + word.foul + " belch pours from Geta's maw."]);
  1294. statLerp("absorption", 0.05, 1000);
  1295. },
  1296. () => {
  1297. print(["Powerful muscle grinds down your softening remains."]);
  1298. statLerp("absorption", 0.1, 1000);
  1299. },
  1300. () => {
  1301. print(["The fox kneads on his flattening belly."]);
  1302. statLerp("absorption", 0.1, 1000);
  1303. },
  1304. () => {
  1305. print(["Geta's guts writhe and squeeze, soaking up your digested body and crushing your acid-pitted bones."]);
  1306. statLerp("absorption", 0.2, 1000);
  1307. },
  1308. () => {
  1309. print(["A brutal clench shreds your melting flesh, sealing your fox-fuel fate in seconds."]);
  1310. statLerp("absorption", 1, 2000);
  1311. }
  1312. ])();
  1313. return result ? result : Math.random() * 3000 + 4000;
  1314. },
  1315. delay: 2000,
  1316. loop: true,
  1317. classes: [
  1318. "absorption"
  1319. ]
  1320. });
  1321. playSfx("sfx/digest.ogg");
  1322. },
  1323. "exit": (room) => {
  1324. },
  1325. "actions": [
  1326. {
  1327. name: "Gurgle",
  1328. desc: "Glorp",
  1329. execute: (room) => {
  1330. printRandom([
  1331. ["Grrrrgle"],
  1332. ["Glorp"],
  1333. ["Glrrrrrrnnnnnn..."],
  1334. ["Gwoooooorgle"]
  1335. ]);
  1336. },
  1337. show: [
  1338. ],
  1339. conditions: [
  1340. ]
  1341. },
  1342. ],
  1343. "exits": {
  1344. },
  1345. "hooks": [
  1346. ],
  1347. "data": {
  1348. "stats": {
  1349. }
  1350. }
  1351. },
  1352. "absorbed": {
  1353. "id": "absorbed",
  1354. "name": "Geta's Fat",
  1355. "desc": "You're gone.",
  1356. "move": (room) => {
  1357. },
  1358. "enter": (room) => {
  1359. playSfx("sfx/absorb.ogg");
  1360. stopTimer("clock");
  1361. stopClassTimers("absorption");
  1362. state.player.stats.absorption.hidden = true;
  1363. print(["Your erasure is completed with a deep, drawn-out gurgle; with flesh stripped from bone and life utterly extinguished, there is room left no doubt: Geta has destroyed you. Perhaps your meager contribution to his body will be remembered...but you won't even take long to burn off."]);
  1364. },
  1365. "exit": (room) => {
  1366. },
  1367. "actions": [
  1368. ],
  1369. "exits": {
  1370. },
  1371. "hooks": [
  1372. ],
  1373. "data": {
  1374. "stats": {
  1375. }
  1376. }
  1377. },
  1378. }
  1379. });
  1380. })();