a munch adventure
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

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