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.
 
 
 
 

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