big steppy
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 

7206 строки
187 KiB

  1. "use strict";
  2. /*jshint browser: true*/
  3. /*jshint devel: true*/
  4. let version = "v1.1.2";
  5. let errored = false;
  6. window.onerror = function (msg, source, lineno, colno, error) {
  7. //opens a popup if the game encounters an error
  8. if (!errored) {
  9. errored = true;
  10. alert(
  11. "An error occurred! Please press F12 to open the dev tools, then click the 'Console' tab and send any errors shown there to chemicalcrux\n\nScreenshotting the text and line number of the error would be great.\n\nAlso include the browser information that gets logged below it.\n\nThe error might also show up here: " +
  12. msg +
  13. " at " +
  14. lineno +
  15. "," +
  16. colno
  17. );
  18. console.log(navigator.userAgent);
  19. }
  20. };
  21. //generates initial conditions and sets up variables
  22. let started = false;
  23. const fillPeriod = 1000 / 60;
  24. const strollingEnum = {
  25. Standing: 0,
  26. Strolling: 1,
  27. Jogging: 2,
  28. Running: 3,
  29. };
  30. let strolling = strollingEnum.Standing;
  31. let unit = "metric";
  32. let numbers = "words";
  33. let verbose = true;
  34. let flat = false;
  35. let text_verbosity = "verbose";
  36. let autoVerbose = true;
  37. const textFadeChoices = {
  38. stays: {
  39. name: "Text Stays",
  40. animation: "none",
  41. next: "dims",
  42. },
  43. dims: {
  44. name: "Text Dims",
  45. animation: "log-dim 15s linear",
  46. next: "fades",
  47. },
  48. fades: {
  49. name: "Text Fades",
  50. animation: "log-fade 20s linear",
  51. next: "stays",
  52. },
  53. };
  54. let textFade = textFadeChoices["stays"];
  55. let newline = " ";
  56. let victims = {};
  57. let macro =
  58. //macro controls every customizable part of the players body
  59. {
  60. shrunkPrey: null,
  61. fastDigestFactor: 1,
  62. fastDigestTimer: null,
  63. pauseDigest: false,
  64. walkSpeed: 1,
  65. growthPoints: 0,
  66. orgasm: false,
  67. afterglow: false,
  68. arousal: 0,
  69. edge: 0,
  70. maleSpurt: 0,
  71. femaleSpurt: 0,
  72. scale: 1,
  73. pawScale: 1,
  74. assScale: 1,
  75. dickScale: 1,
  76. ballScale: 1,
  77. vaginaScale: 1,
  78. wombScale: 1,
  79. breastScale: 1,
  80. tailScale: 1,
  81. wingScale: 1,
  82. muskScale: 1,
  83. stenchScale: 1,
  84. breathScale: 1,
  85. magicScale: 1,
  86. tailDensity: 1000,
  87. dickDensity: 1000,
  88. ballDensity: 1000,
  89. breastDensity: 1000,
  90. assDensity: 1000, //this is only used for automatic growth function
  91. wombDensity: 1000, //this is only used for automatic growth function
  92. pawDensity: 1000, //this is only used for automatic growth function
  93. breathStyle: "cone",
  94. scaling: function (value, scale, factor) {
  95. return value * Math.pow(scale, factor);
  96. },
  97. get height() {
  98. return this.scaling(this.baseHeight, this.scale, 1);
  99. },
  100. get mass() {
  101. return this.scaling(this.baseMass, this.scale, 3);
  102. },
  103. get pawLength() {
  104. return this.scaling(this.basePawLength * this.pawScale, this.scale, 1);
  105. },
  106. get pawWidth() {
  107. return this.scaling(this.basePawWidth * this.pawScale, this.scale, 1);
  108. },
  109. get pawArea() {
  110. return this.pawLength * this.pawWidth;
  111. },
  112. get analVoreArea() {
  113. return this.scaling(
  114. Math.pow(this.baseAnalVoreDiameter * this.assScale, 2),
  115. this.scale,
  116. 2
  117. );
  118. },
  119. get assArea() {
  120. return this.scaling(this.baseAssArea * this.assScale, this.scale, 2);
  121. },
  122. get handLength() {
  123. return this.scaling(this.baseHandLength, this.scale, 1);
  124. },
  125. get handWidth() {
  126. return this.scaling(this.baseHandWidth, this.scale, 1);
  127. },
  128. get handArea() {
  129. return this.handLength * this.handWidth;
  130. },
  131. get wingLength() {
  132. return this.scaling(this.baseWingLength, this.scale * this.wingScale, 1);
  133. },
  134. get wingWidth() {
  135. return this.scaling(this.baseWingWidth, this.scale * this.wingScale, 1);
  136. },
  137. get wingArea() {
  138. return this.wingLength * this.wingWidth;
  139. },
  140. footOnlyDesc: function (plural = false, capital = false) {
  141. let result = "";
  142. switch (this.footType) {
  143. case "paw":
  144. result = plural ? "paws" : "paw";
  145. break;
  146. case "hoof":
  147. result = plural ? "hooves" : "hoof";
  148. break;
  149. case "foot":
  150. result = plural ? "feet" : "foot";
  151. break;
  152. case "avian":
  153. result = plural ? "avian feet" : "avian foot";
  154. break;
  155. }
  156. return capital
  157. ? result.charAt(0).toUpperCase() + result.slice(1)
  158. : result;
  159. },
  160. footDesc: function (plural = false, capital = false, possessive = false) {
  161. let result = "";
  162. if (!this.footWear) {
  163. return this.footOnlyDesc(plural, capital);
  164. }
  165. if (!this.footSockWorn && !this.footShoeWorn) {
  166. return this.footOnlyDesc(plural, capital);
  167. } else if (this.footShoeWorn) {
  168. switch (this.footShoe) {
  169. case "shoe":
  170. result = plural ? "shoes" : "shoe";
  171. break;
  172. case "boot":
  173. result = plural ? "boots" : "boot";
  174. break;
  175. case "trainer":
  176. result = plural ? "trainers" : "trainer";
  177. break;
  178. case "sandal":
  179. result = plural ? "sandals" : "sandal";
  180. break;
  181. case "heel":
  182. return plural ? "high heels" : "high heel";
  183. break;
  184. case "croc":
  185. return plural ? "crocs" : "croc";
  186. break;
  187. }
  188. } else if (this.footSockWorn) {
  189. switch (this.footSock) {
  190. case "sock":
  191. result = "socked " + this.footOnlyDesc(plural, false);
  192. break;
  193. case "stocking":
  194. result = "stocking-wrapped " + this.footOnlyDesc(plural, false);
  195. break;
  196. }
  197. }
  198. if (possessive) {
  199. result = " your " + result;
  200. }
  201. return capital
  202. ? result.charAt(0).toUpperCase() + result.slice(1)
  203. : result;
  204. },
  205. toeNoShoeDesc: function (plural = false, capital = false) {
  206. let result = "";
  207. if (!this.footSockWorn) {
  208. return this.toeOnlyDesc(plural, capital);
  209. } else if (this.footSockWorn) {
  210. switch (this.footSock) {
  211. case "sock":
  212. result = "socked " + this.toeOnlyDesc(plural, false);
  213. }
  214. }
  215. return capital
  216. ? result.charAt(0).toUpperCase() + result.slice(1)
  217. : result;
  218. },
  219. toeOnlyDesc: function (plural = false, capital = false) {
  220. let result = "";
  221. switch (this.footType) {
  222. case "paw":
  223. result = plural ? "toes" : "toe";
  224. break;
  225. case "hoof":
  226. result = plural ? "hooves" : "hoof";
  227. break;
  228. case "foot":
  229. result = plural ? "toes" : "toe";
  230. break;
  231. case "avian":
  232. result = plural ? "talons" : "talon";
  233. break;
  234. }
  235. return capital
  236. ? result.charAt(0).toUpperCase() + result.slice(1)
  237. : result;
  238. },
  239. toeDesc: function (plural = false, capital = false, possessive = false) {
  240. let result = "";
  241. if (!this.footWear) {
  242. return this.toeOnlyDesc(plural, capital);
  243. }
  244. if (!this.footSockWorn && !this.footShoeWorn) {
  245. return this.toeOnlyDesc(plural, capital);
  246. } else if (this.footShoeWorn) {
  247. switch (this.footShoe) {
  248. case "shoe":
  249. result = plural ? "treads" : "tread";
  250. break;
  251. case "boot":
  252. result = plural ? "treads" : "tread";
  253. break;
  254. case "trainer":
  255. result = plural ? "treads" : "tread";
  256. break;
  257. case "sandal":
  258. result = plural ? "treads" : "tread";
  259. break;
  260. case "heel":
  261. return plural ? "treads" : "tread";
  262. break;
  263. case "croc":
  264. return plural ? "treads" : "tread";
  265. break;
  266. }
  267. } else if (this.footSockWorn) {
  268. switch (this.footSock) {
  269. case "sock":
  270. result = "socked " + this.toeOnlyDesc(plural, false);
  271. break;
  272. case "stocking":
  273. result = "stocking-wrapped " + this.footOnlyDesc(plural, false);
  274. break;
  275. }
  276. }
  277. if (possessive) {
  278. result = "your " + result;
  279. }
  280. return capital
  281. ? result.charAt(0).toUpperCase() + result.slice(1)
  282. : result;
  283. },
  284. soleNoShoeDesc: function (plural = false, capital = false) {
  285. let result = "";
  286. if (!this.footSockWorn) {
  287. return this.soleOnlyDesc(plural, capital);
  288. } else if (this.footSockWorn) {
  289. switch (this.footSock) {
  290. case "sock":
  291. result = "socked " + this.soleOnlyDesc(plural, false);
  292. }
  293. }
  294. return capital
  295. ? result.charAt(0).toUpperCase() + result.slice(1)
  296. : result;
  297. },
  298. soleOnlyDesc: function (plural = false, capital = false) {
  299. let result = "";
  300. switch (this.footType) {
  301. case "paw":
  302. result = plural ? "pads" : "pads";
  303. break;
  304. case "hoof":
  305. result = plural
  306. ? pickString("frogs", "soles")
  307. : pickString("frog", "sole");
  308. break;
  309. case "foot":
  310. result = plural ? "soles" : "sole";
  311. break;
  312. case "avian":
  313. result = plural ? "pads" : "pads";
  314. break;
  315. }
  316. return capital
  317. ? result.charAt(0).toUpperCase() + result.slice(1)
  318. : result;
  319. },
  320. soleDesc: function (plural = false, capital = false, possessive = false) {
  321. let result = "";
  322. if (!this.footWear) {
  323. return this.soleOnlyDesc(plural, capital);
  324. }
  325. if (!this.footSockWorn && !this.footShoeWorn) {
  326. return this.soleOnlyDesc(plural, capital);
  327. } else if (this.footShoeWorn) {
  328. switch (this.footShoe) {
  329. case "shoe":
  330. result = plural ? "heels" : "heel";
  331. break;
  332. case "boot":
  333. result = plural ? "heels" : "heel";
  334. break;
  335. case "trainer":
  336. result = plural ? "heels" : "heel";
  337. break;
  338. case "sandal":
  339. result = plural ? "heels" : "heel";
  340. break;
  341. case "heel":
  342. return plural ? "soles" : "sole";
  343. break;
  344. case "croc":
  345. return plural ? "heels" : "heel";
  346. break;
  347. }
  348. } else if (this.footSockWorn) {
  349. switch (this.footSock) {
  350. case "sock":
  351. result = "socked " + this.soleOnlyDesc(plural, false);
  352. break;
  353. case "stocking":
  354. result = "stocking-wrapped " + this.soleOnlyDesc(plural, false);
  355. break;
  356. }
  357. }
  358. if (possessive) {
  359. result = "your " + result;
  360. }
  361. return capital
  362. ? result.charAt(0).toUpperCase() + result.slice(1)
  363. : result;
  364. },
  365. shoeDesc: function (plural, capital) {
  366. let result = "";
  367. switch (this.footShoe) {
  368. case "shoe":
  369. result = plural ? "shoes" : "shoe";
  370. break;
  371. case "boot":
  372. result = plural ? "boots" : "boot";
  373. break;
  374. case "trainer":
  375. result = plural ? "trainers" : "trainer";
  376. break;
  377. case "sandal":
  378. result = plural ? "sandals" : "sandal";
  379. break;
  380. case "heel":
  381. return plural ? "high heels" : "high heel";
  382. break;
  383. case "croc":
  384. return plural ? "crocs" : "croc";
  385. break;
  386. }
  387. return capital
  388. ? result.charAt(0).toUpperCase() + result.slice(1)
  389. : result;
  390. },
  391. sockDesc: function (plural, capital) {
  392. let result = "";
  393. switch (this.footSock) {
  394. case "sock":
  395. result = plural ? "socks" : "sock";
  396. break;
  397. case "stocking":
  398. result = plural ? "stockings" : "stocking";
  399. break;
  400. }
  401. return capital
  402. ? result.charAt(0).toUpperCase() + result.slice(1)
  403. : result;
  404. },
  405. jawDesc: function (plural = false, capital = false) {
  406. let result = "";
  407. switch (this.jawType) {
  408. case "jaw":
  409. result = plural ? "jaws" : "jaw";
  410. break;
  411. case "beak":
  412. result = "beak";
  413. break;
  414. }
  415. return capital
  416. ? result.charAt(0).toUpperCase() + result.slice(1)
  417. : result;
  418. },
  419. biteDesc: function (plural = false, capital = false) {
  420. let result = "";
  421. switch (this.jawType) {
  422. case "jaw":
  423. result = plural ? "crushes" : "crush";
  424. break;
  425. case "beak":
  426. result = plural ? "slices" : "slice";
  427. break;
  428. }
  429. return capital
  430. ? result.charAt(0).toUpperCase() + result.slice(1)
  431. : result;
  432. },
  433. teethDesc: function (plural = false, capital = false) {
  434. let result = "";
  435. switch (this.jawType) {
  436. case "jaw":
  437. result = plural ? "fangs" : "fang";
  438. break;
  439. case "beak":
  440. result = "beak";
  441. break;
  442. }
  443. return capital
  444. ? result.charAt(0).toUpperCase() + result.slice(1)
  445. : result;
  446. },
  447. get preyGrowthFactor() {
  448. if (macro.growthScaleWithSize) {
  449. return this.basePreyGrowthFactor * Math.pow(this.scale, 1);
  450. //this breaks once you get to the size of a planet
  451. } else {
  452. return this.basePreyGrowthFactor;
  453. }
  454. },
  455. get tailLength() {
  456. return this.scaling(this.baseTailLength * this.tailScale, this.scale, 1);
  457. },
  458. get tailDiameter() {
  459. return this.scaling(
  460. this.baseTailDiameter * this.tailScale,
  461. this.scale,
  462. 1
  463. );
  464. },
  465. get tailStretchDiameter() {
  466. return this.scaling(
  467. this.tailStretchiness * this.baseTailDiameter * this.tailScale,
  468. this.scale,
  469. 1
  470. );
  471. },
  472. get tailGirth() {
  473. return Math.pow(this.tailDiameter / 2, 2) * Math.PI;
  474. },
  475. get tailStretchGirth() {
  476. return Math.pow(this.tailStretchDiameter / 2, 2) * Math.PI;
  477. },
  478. get tailArea() {
  479. return this.tailLength * this.tailDiameter;
  480. },
  481. get tailVolume() {
  482. return this.tailGirth * this.tailLength;
  483. },
  484. get tailMass() {
  485. return this.tailVolume * this.tailDensity;
  486. },
  487. get tailDesc() {
  488. return this.tailType + " " + (this.tailCount > 1 ? "tails" : "tail");
  489. },
  490. get tailNoDesc() {
  491. return this.tailCount > 1 ? "tails" : "tail";
  492. },
  493. get arousalDickFactor() {
  494. //this scales the size of the dick based on arousal, and is not directly related to arousalFactor(multiplier on arousal you gain from actions)
  495. let factor = 1;
  496. if (!this.arousalEnabled || this.arousal < 25) {
  497. factor = 0.5;
  498. } else if (this.arousal < 75) {
  499. factor = 0.5 + (this.arousal - 25) / 100;
  500. }
  501. return factor;
  502. },
  503. get dickLength() {
  504. return this.scaling(
  505. this.baseDickLength * this.dickScale * this.arousalDickFactor,
  506. this.scale,
  507. 1
  508. );
  509. },
  510. get dickDiameter() {
  511. return this.scaling(
  512. this.baseDickDiameter * this.dickScale * this.arousalDickFactor,
  513. this.scale,
  514. 1
  515. );
  516. },
  517. get dickGirth() {
  518. return Math.pow(this.dickDiameter / 2, 2) * Math.PI;
  519. },
  520. get dickStretchGirth() {
  521. return this.dickGirth * this.dickStretchiness * this.dickStretchiness;
  522. },
  523. get dickArea() {
  524. return (this.dickLength * this.dickDiameter * Math.PI) / 2;
  525. },
  526. get dickVolume() {
  527. return this.dickLength * Math.pow(this.dickDiameter / 2, 2) * Math.PI;
  528. },
  529. get dickMass() {
  530. return this.dickVolume * this.dickDensity;
  531. },
  532. get ballDiameter() {
  533. return this.scaling(
  534. this.baseBallDiameter * this.ballScale,
  535. this.scale,
  536. 1
  537. );
  538. },
  539. get ballArea() {
  540. return 2 * Math.PI * Math.pow(this.ballDiameter / 2, 2);
  541. },
  542. get ballVolume() {
  543. let radius = this.ballDiameter / 2;
  544. return (4 / 3) * Math.PI * Math.pow(radius, 3);
  545. },
  546. get ballMass() {
  547. let volume = this.ballVolume;
  548. return volume * this.ballDensity;
  549. },
  550. get cumVolume() {
  551. let vol = this.scaling(this.baseCumVolume / 1000, this.scale, 3);
  552. return this.scaling(vol, this.dickScale, 2);
  553. },
  554. get vaginaLength() {
  555. return this.scaling(
  556. this.baseVaginaLength * this.vaginaScale,
  557. this.scale,
  558. 1
  559. );
  560. },
  561. get vaginaWidth() {
  562. return this.scaling(
  563. this.baseVaginaWidth * this.vaginaScale,
  564. this.scale,
  565. 1
  566. );
  567. },
  568. get vaginaArea() {
  569. return this.vaginaLength * this.vaginaWidth;
  570. },
  571. get vaginaStretchArea() {
  572. return (
  573. this.vaginaStretchiness *
  574. this.vaginaStretchiness *
  575. this.vaginaLength *
  576. this.vaginaWidth
  577. );
  578. },
  579. // this isn't how biology works but I'll leave it in
  580. get vaginaVolume() {
  581. return this.vaginaArea * this.vaginaWidth;
  582. },
  583. get wombVolume() {
  584. return this.scaling(this.baseWombVolume, this.wombScale * this.scale, 3);
  585. },
  586. get femcumVolume() {
  587. let vol = this.scaling(this.baseFemcumVolume / 1000, this.scale, 3);
  588. return this.scaling(vol, this.vaginaScale, 2);
  589. },
  590. get lactationVolume() {
  591. return this.milkStorage.limit * this.lactationFactor;
  592. },
  593. get breastDiameter() {
  594. return this.scaling(
  595. this.baseBreastDiameter * this.breastScale,
  596. this.scale,
  597. 1
  598. );
  599. },
  600. get breastStretchDiameter() {
  601. return this.scaling(
  602. this.breastStretchiness * this.baseBreastDiameter * this.breastScale,
  603. this.scale,
  604. 1
  605. );
  606. },
  607. get breastArea() {
  608. return 2 * Math.PI * Math.pow(this.breastDiameter / 2, 2);
  609. },
  610. get breastStretchArea() {
  611. return 2 * Math.PI * Math.pow(this.breastStretchDiameter / 2, 2);
  612. },
  613. get breastVolume() {
  614. let radius = this.breastDiameter / 2;
  615. return (4 / 3) * Math.PI * Math.pow(radius, 3);
  616. },
  617. get breastMass() {
  618. let volume = this.breastVolume;
  619. return volume * this.breastDensity;
  620. },
  621. get droolVolume() {
  622. return this.scaling(this.droolBaseVolume / 1000, this.scale, 3);
  623. },
  624. digest: function (owner, organ, time = 15, auto = true) {
  625. // we now have an explicit no-auto-digest flag, but
  626. // some saves will wind up a time of 0 anyway, so I'll
  627. // just leave this here to keep that from breaking things
  628. if (auto && time != 0) {
  629. setTimeout(function () {
  630. owner.digest(owner, organ, time);
  631. }, (time * 1000) / organ.stages / macro.fastDigestFactor);
  632. }
  633. if (macro.pauseDigest) {
  634. return;
  635. }
  636. let count = Math.min(organ.contents.length, organ.maxDigest);
  637. let container = organ.contents.pop();
  638. organ.contents.unshift(new Container());
  639. if (container.count == 0) return;
  640. do_digestion(owner, organ, container);
  641. },
  642. get scatDigestFactor() {
  643. if (this.scatScaleWithSize) {
  644. return this.baseScatDigestFactor * this.scale;
  645. } else {
  646. return this.baseScatDigestFactor;
  647. }
  648. },
  649. stomach: {
  650. name: "stomach",
  651. setup: function (owner) {
  652. this.owner = owner;
  653. for (let i = 0; i < this.stages; i++)
  654. this.contents.push(new Container());
  655. owner.digest(owner, this, owner.oralDigestTime, owner.oralDigestAuto);
  656. },
  657. feed: function (prey) {
  658. this.feedFunc(prey, this, this.owner);
  659. },
  660. feedFunc: function (prey, self, owner) {
  661. this.contents[0] = this.contents[0].merge(prey);
  662. },
  663. describeDigestion: function (container) {
  664. return describe("stomach", container, this.owner, verbose, flat);
  665. },
  666. fill: function (owner, container) {
  667. if (owner.gasEnabled)
  668. owner.gasStorage.amount +=
  669. (container.sum_property("mass") * owner.gasDigestFactor) / 1e4;
  670. if (owner.scatEnabled) {
  671. owner.scatStorage.amount +=
  672. (container.sum_property("mass") * owner.scatDigestFactor) / 1e3;
  673. owner.scatStorage.victims =
  674. owner.scatStorage.victims.merge(container);
  675. }
  676. },
  677. get description() {
  678. let prey = new Container();
  679. this.contents.forEach(function (x) {
  680. prey = prey.merge(x);
  681. });
  682. if (verbose || flat) {
  683. prey = flatten(prey);
  684. }
  685. if (prey.count == 0) {
  686. return "Your belly is flat, growling and gurgling for want of prey.";
  687. } else {
  688. if (macro.brutality > 0) {
  689. return (
  690. "Your belly churns and bubbles as it works to melt " +
  691. prey.describeSimple(verbose || flat) +
  692. " down to chyme."
  693. );
  694. } else {
  695. return (
  696. "Your belly sloshes with the weight of " +
  697. prey.describeSimple(verbose || flat) +
  698. " trapped within."
  699. );
  700. }
  701. }
  702. },
  703. contents: [],
  704. stages: 3,
  705. },
  706. tail: {
  707. name: "tail",
  708. setup: function (owner) {
  709. this.owner = owner;
  710. for (let i = 0; i < this.stages; i++)
  711. this.contents.push(new Container());
  712. owner.digest(owner, this, owner.tailDigestTime, owner.tailDigestAuto);
  713. },
  714. feed: function (prey) {
  715. this.feedFunc(prey, this, this.owner);
  716. },
  717. feedFunc: function (prey, self, owner) {
  718. this.contents[0] = this.contents[0].merge(prey);
  719. },
  720. describeMove: function (container) {
  721. return describe(
  722. "tail-to-stomach",
  723. container,
  724. this.owner,
  725. verbose,
  726. flat
  727. );
  728. },
  729. describeDigestion: function (container) {
  730. return describe("tail", container, this.owner, verbose, flat);
  731. },
  732. fill: function (owner, container) {
  733. if (owner.gasEnabled)
  734. owner.gasStorage.amount +=
  735. (container.sum_property("mass") * owner.gasDigestFactor) / 1e3;
  736. if (owner.scatEnabled) {
  737. owner.scatStorage.amount +=
  738. (container.sum_property("mass") * owner.scatDigestFactor) / 1e3;
  739. owner.scatStorage.victims =
  740. owner.scatStorage.victims.merge(container);
  741. }
  742. },
  743. get description() {
  744. let prey = new Container();
  745. this.contents.forEach(function (x) {
  746. prey = prey.merge(x);
  747. });
  748. if (verbose || flat) {
  749. prey = flatten(prey);
  750. }
  751. if (prey.count == 0) {
  752. return (
  753. "Your " +
  754. this.owner.tailDesc +
  755. " " +
  756. (this.owner.tailCount > 1 ? "are" : "is") +
  757. " empty."
  758. );
  759. } else {
  760. if (this.owner.tailVoreToStomach) {
  761. return (
  762. "Your " +
  763. this.owner.tailDesc +
  764. " " +
  765. (this.owner.tailCount > 1
  766. ? "clench and squeeze around "
  767. : "clenches and squeezes around ") +
  768. prey.describeSimple(verbose || flat) +
  769. ", working them deeper and deeper inside."
  770. );
  771. } else if (macro.brutality > 0) {
  772. return (
  773. "Your " +
  774. this.owner.tailDesc +
  775. " " +
  776. (this.owner.tailCount > 1 ? "groans" : "groan") +
  777. " ominously as " +
  778. (this.owner.tailCount > 1 ? "they gurgle" : "it gurgles") +
  779. " around " +
  780. prey.describeSimple(verbose || flat) +
  781. ", slowly absorbing them into your musky depths."
  782. );
  783. } else {
  784. return (
  785. "Your " +
  786. this.owner.tailDesc +
  787. " " +
  788. (this.owner.tailCount > 1 ? "bulge" : "bulges") +
  789. " with " +
  790. prey.describeSimple(verbose || flat) +
  791. "."
  792. );
  793. }
  794. }
  795. },
  796. contents: [],
  797. stages: 3,
  798. },
  799. bowels: {
  800. name: "bowels",
  801. setup: function (owner) {
  802. this.owner = owner;
  803. for (let i = 0; i < this.stages; i++)
  804. this.contents.push(new Container());
  805. owner.digest(owner, this, owner.analDigestTime, owner.analDigestAuto);
  806. },
  807. feed: function (prey) {
  808. this.feedFunc(prey, this, this.owner);
  809. },
  810. feedFunc: function (prey, self, owner) {
  811. this.contents[0] = this.contents[0].merge(prey);
  812. },
  813. describeMove: function (container) {
  814. return describe(
  815. "bowels-to-stomach",
  816. container,
  817. this.owner,
  818. verbose,
  819. flat
  820. );
  821. },
  822. describeDigestion: function (container) {
  823. return describe("bowels", container, this.owner, verbose, flat);
  824. },
  825. fill: function (owner, container) {
  826. if (owner.gasEnabled)
  827. owner.gasStorage.amount +=
  828. (container.sum_property("mass") * owner.gasDigestFactor) / 1e3;
  829. if (owner.scatEnabled) {
  830. owner.scatStorage.amount +=
  831. (container.sum_property("mass") * owner.scatDigestFactor) / 1e3;
  832. owner.scatStorage.victims =
  833. owner.scatStorage.victims.merge(container);
  834. }
  835. },
  836. get description() {
  837. let prey = new Container();
  838. this.contents.forEach(function (x) {
  839. prey = prey.merge(x);
  840. });
  841. if (verbose || flat) {
  842. prey = flatten(prey);
  843. }
  844. if (prey.count == 0) {
  845. return "Your bowels are empty.";
  846. } else {
  847. if (macro.brutality > 0) {
  848. return (
  849. "Your bowels groan ominously as they clench around " +
  850. prey.describeSimple(verbose || flat) +
  851. ", slowly absorbing them into your musky depths."
  852. );
  853. } else {
  854. return (
  855. "Your bowels bulge with " +
  856. prey.describeSimple(verbose || flat) +
  857. "."
  858. );
  859. }
  860. }
  861. },
  862. contents: [],
  863. stages: 3,
  864. },
  865. get femcumDigestFactor() {
  866. if (this.femcumScaleWithSize) {
  867. return this.baseFemcumDigestFactor * this.scale;
  868. } else {
  869. return this.baseFemcumDigestFactor;
  870. }
  871. },
  872. womb: {
  873. name: "womb",
  874. setup: function (owner) {
  875. this.owner = owner;
  876. for (let i = 0; i < this.stages; i++)
  877. this.contents.push(new Container());
  878. owner.digest(
  879. owner,
  880. this,
  881. owner.unbirthDigestTime,
  882. owner.unbirthDigestAuto
  883. );
  884. },
  885. feed: function (prey) {
  886. this.feedFunc(prey, this, this.owner);
  887. },
  888. feedFunc: function (prey, self, owner) {
  889. this.contents[0] = this.contents[0].merge(prey);
  890. },
  891. describeDigestion: function (container, vol) {
  892. return describe("womb", container, this.owner, verbose, flat).replace(
  893. "$VOLUME",
  894. volume(vol, unit, false)
  895. );
  896. },
  897. fill: function (owner, container) {
  898. let amount =
  899. (container.sum_property("mass") * owner.femcumDigestFactor) / 1e3;
  900. owner.femcumStorage.amount += amount;
  901. return amount;
  902. },
  903. get description() {
  904. let prey = new Container();
  905. this.contents.forEach(function (x) {
  906. prey = prey.merge(x);
  907. });
  908. if (verbose || flat) {
  909. prey = flatten(prey);
  910. }
  911. if (prey.count == 0) {
  912. return "Your lower belly is flat.";
  913. } else {
  914. if (macro.brutality > 0) {
  915. return (
  916. "Your womb tingles as its rhythmically grinds down on " +
  917. prey.describeSimple(verbose || flat) +
  918. ", turning them soft and wet as they start to dissolve into femcum."
  919. );
  920. } else {
  921. return (
  922. "Your womb clenches around " +
  923. prey.describeSimple(verbose || flat) +
  924. "."
  925. );
  926. }
  927. }
  928. },
  929. contents: [],
  930. stages: 3,
  931. },
  932. get cumDigestFactor() {
  933. if (this.cumScaleWithSize) {
  934. return this.baseCumDigestFactor * this.scale;
  935. } else {
  936. return this.baseCumDigestFactor;
  937. }
  938. },
  939. balls: {
  940. name: "balls",
  941. setup: function (owner) {
  942. this.owner = owner;
  943. for (let i = 0; i < this.stages; i++)
  944. this.contents.push(new Container());
  945. owner.digest(owner, this, owner.cockDigestTime, owner.cockDigestAuto);
  946. },
  947. feed: function (prey) {
  948. this.feedFunc(prey, this, this.owner);
  949. },
  950. feedFunc: function (prey, self, owner) {
  951. this.contents[0] = this.contents[0].merge(prey);
  952. },
  953. describeDigestion: function (container, vol) {
  954. return describe("balls", container, this.owner, verbose, flat).replace(
  955. "$VOLUME",
  956. volume(vol, unit, false)
  957. );
  958. },
  959. fill: function (owner, container) {
  960. let amount =
  961. (container.sum_property("mass") * owner.cumDigestFactor) / 1e3;
  962. owner.cumStorage.amount += amount;
  963. return amount;
  964. },
  965. get description() {
  966. let prey = new Container();
  967. this.contents.forEach(function (x) {
  968. prey = prey.merge(x);
  969. });
  970. if (verbose || flat) {
  971. prey = flatten(prey);
  972. }
  973. if (prey.count == 0) {
  974. return "Your balls are smooth.";
  975. } else {
  976. if (macro.brutality > 0) {
  977. return (
  978. "Your balls slosh and bulge as they work to convert " +
  979. prey.describeSimple(verbose || flat) +
  980. " into hot cum."
  981. );
  982. } else {
  983. return (
  984. "Your balls slosh about, loaded down with " +
  985. prey.describeSimple(verbose || flat) +
  986. "."
  987. );
  988. }
  989. }
  990. },
  991. contents: [],
  992. stages: 3,
  993. },
  994. get milkDigestFactor() {
  995. if (this.milkScaleWithSize) {
  996. return this.baseMilkDigestFactor * this.scale;
  997. } else {
  998. return this.baseMilkDigestFactor;
  999. }
  1000. },
  1001. breasts: {
  1002. name: "breasts",
  1003. setup: function (owner) {
  1004. this.owner = owner;
  1005. for (let i = 0; i < this.stages; i++)
  1006. this.contents.push(new Container());
  1007. owner.digest(
  1008. owner,
  1009. this,
  1010. owner.breastDigestTime,
  1011. owner.breastDigestAuto
  1012. );
  1013. },
  1014. feed: function (prey) {
  1015. this.feedFunc(prey, this, this.owner);
  1016. },
  1017. feedFunc: function (prey, self, owner) {
  1018. this.contents[0] = this.contents[0].merge(prey);
  1019. },
  1020. describeDigestion: function (container, vol) {
  1021. return describe(
  1022. "breasts",
  1023. container,
  1024. this.owner,
  1025. verbose,
  1026. flat
  1027. ).replace("$VOLUME", volume(vol, unit, false));
  1028. },
  1029. fill: function (owner, container) {
  1030. if (macro.lactationEnabled) {
  1031. let amount =
  1032. (container.sum_property("mass") * owner.milkDigestFactor) / 1e3;
  1033. owner.milkStorage.amount += amount;
  1034. return amount;
  1035. }
  1036. },
  1037. get description() {
  1038. let prey = new Container();
  1039. this.contents.forEach(function (x) {
  1040. prey = prey.merge(x);
  1041. });
  1042. if (verbose || flat) {
  1043. prey = flatten(prey);
  1044. }
  1045. if (prey.count == 0) {
  1046. return "Your breasts are smooth.";
  1047. } else {
  1048. if (macro.brutality > 0) {
  1049. return (
  1050. "Your breasts slosh from side to side, " +
  1051. prey.describeSimple(verbose || flat) +
  1052. " slowly digesting into creamy milk."
  1053. );
  1054. } else {
  1055. return (
  1056. "Your breasts bulge with " +
  1057. prey.describeSimple(verbose || flat) +
  1058. "."
  1059. );
  1060. }
  1061. }
  1062. },
  1063. contents: [],
  1064. stages: 3,
  1065. },
  1066. get pissDigestFactor() {
  1067. if (this.pissScaleWithSize) {
  1068. return this.basePissDigestFactor * this.scale;
  1069. } else {
  1070. return this.basePissDigestFactor;
  1071. }
  1072. },
  1073. bladder: {
  1074. name: "bladder",
  1075. setup: function (owner) {
  1076. this.owner = owner;
  1077. for (let i = 0; i < this.stages; i++)
  1078. this.contents.push(new Container());
  1079. owner.digest(
  1080. owner,
  1081. this,
  1082. owner.bladderDigestTime,
  1083. owner.bladderDigestAuto
  1084. );
  1085. },
  1086. feed: function (prey) {
  1087. this.feedFunc(prey, this, this.owner);
  1088. },
  1089. feedFunc: function (prey, self, owner) {
  1090. this.contents[0] = this.contents[0].merge(prey);
  1091. },
  1092. describeDigestion: function (container, vol) {
  1093. return describe(
  1094. "bladder",
  1095. container,
  1096. this.owner,
  1097. verbose,
  1098. flat
  1099. ).replace("$VOLUME", volume(vol, unit, false));
  1100. },
  1101. fill: function (owner, container) {
  1102. let amount =
  1103. (container.sum_property("mass") * owner.pissDigestFactor) / 1e3;
  1104. owner.pissStorage.amount += amount;
  1105. return amount;
  1106. },
  1107. get description() {
  1108. let prey = new Container();
  1109. this.contents.forEach(function (x) {
  1110. prey = prey.merge(x);
  1111. });
  1112. if (verbose || flat) {
  1113. prey = flatten(prey);
  1114. }
  1115. if (prey.count == 0) {
  1116. return "Your bladder has nobody in it.";
  1117. } else {
  1118. if (macro.brutality > 0) {
  1119. return (
  1120. "Your bladder bulges, " +
  1121. prey.describeSimple(verbose || flat) +
  1122. " dissolving in your acrid piss."
  1123. );
  1124. } else {
  1125. return (
  1126. "Your bladder bulges with " +
  1127. prey.describeSimple(verbose || flat) +
  1128. "."
  1129. );
  1130. }
  1131. }
  1132. },
  1133. contents: [],
  1134. stages: 3,
  1135. },
  1136. souls: {
  1137. name: "souls",
  1138. setup: function (owner) {
  1139. this.owner = owner;
  1140. for (let i = 0; i < this.stages; i++)
  1141. this.contents.push(new Container());
  1142. owner.digest(owner, this, owner.soulDigestTime, owner.soulDigestAuto);
  1143. },
  1144. feed: function (prey) {
  1145. this.feedFunc(prey, this, this.owner);
  1146. },
  1147. feedFunc: function (prey, self, owner) {
  1148. if (get_living_prey(prey.sum()) > 0)
  1149. this.contents[0] = this.contents[0].merge(prey);
  1150. },
  1151. describeDigestion: function (container) {
  1152. return describe("soul-digest", container, this.owner, verbose, flat);
  1153. },
  1154. fill: function (owner, container) {
  1155. add_victim_people("soul-digest", container);
  1156. },
  1157. get description() {
  1158. let prey = new Container();
  1159. this.contents.forEach(function (x) {
  1160. prey = prey.merge(x);
  1161. });
  1162. let souls = get_living_prey(prey.sum());
  1163. if (souls == 0) {
  1164. return "Your depths hold no souls.";
  1165. } else {
  1166. if (macro.brutality > 0) {
  1167. return (
  1168. "Your depths bubble and boil with energy, slowly digesting " +
  1169. (souls > 1 ? souls + " souls." : "a lonely soul")
  1170. );
  1171. } else {
  1172. return (
  1173. "You feel " +
  1174. (souls > 1 ? souls + " souls " : "a soul ") +
  1175. "trapped in your depths."
  1176. );
  1177. }
  1178. }
  1179. },
  1180. contents: [],
  1181. stages: 3,
  1182. },
  1183. goo: {
  1184. name: "goo",
  1185. setup: function (owner) {
  1186. this.owner = owner;
  1187. for (let i = 0; i < this.stages; i++)
  1188. this.contents.push(new Container());
  1189. if (owner.gooDigestion) {
  1190. owner.digest(owner, this, owner.gooDigestTime, owner.gooDigestAuto);
  1191. }
  1192. },
  1193. feed: function (prey) {
  1194. this.feedFunc(prey, this, this.owner);
  1195. },
  1196. feedFunc: function (prey, self, owner) {
  1197. this.contents[0] = this.contents[0].merge(prey);
  1198. },
  1199. describeDigestion: function (container) {
  1200. add_victim_people("goo", container);
  1201. return describe("goo-digest", container, this.owner, verbose, flat);
  1202. },
  1203. fill: function (owner, container) {},
  1204. get description() {
  1205. let prey = new Container();
  1206. this.contents.forEach(function (x) {
  1207. prey = prey.merge(x);
  1208. });
  1209. if (verbose || flat) {
  1210. prey = flatten(prey);
  1211. }
  1212. if (prey.count == 0) {
  1213. return "You contain no prey.";
  1214. } else {
  1215. if (macro.gooDigestion) {
  1216. return (
  1217. "Your gooey body contains " +
  1218. prey.describeSimple(verbose || flat) +
  1219. ", gradually absorbing them into your bulk."
  1220. );
  1221. } else {
  1222. return (
  1223. "Your gooey body contains " +
  1224. prey.describeSimple(verbose || flat) +
  1225. "."
  1226. );
  1227. }
  1228. }
  1229. },
  1230. contents: [],
  1231. stages: 3,
  1232. },
  1233. get breathArea() {
  1234. return this.scaling(
  1235. this.baseBreathArea,
  1236. macro.breathScale * this.scale,
  1237. 2
  1238. );
  1239. },
  1240. pawsVore: {
  1241. name: "paws",
  1242. setup: function (owner) {
  1243. this.owner = owner;
  1244. for (let i = 0; i < this.stages; i++)
  1245. this.contents.push(new Container());
  1246. owner.digest(owner, this, owner.pawDigestTime, owner.pawDigestAuto);
  1247. },
  1248. feed: function (prey) {
  1249. this.feedFunc(prey, this, this.owner);
  1250. },
  1251. feedFunc: function (prey, self, owner) {
  1252. this.contents[0] = this.contents[0].merge(prey);
  1253. },
  1254. describeDigestion: function (container) {
  1255. return describe("paws", container, this.owner, verbose, flat);
  1256. },
  1257. fill: function (owner, container) {},
  1258. get description() {
  1259. let prey = new Container();
  1260. this.contents.forEach(function (x) {
  1261. prey = prey.merge(x);
  1262. });
  1263. if (verbose || flat) {
  1264. prey = flatten(prey);
  1265. }
  1266. if (prey.count == 0) {
  1267. return (
  1268. "Your " + this.owner.footOnlyDesc(true) + " don't contain any prey."
  1269. );
  1270. } else {
  1271. return (
  1272. "Your " +
  1273. this.owner.footOnlyDesc(true) +
  1274. " have enveloped " +
  1275. prey.describeSimple(verbose || flat)
  1276. );
  1277. }
  1278. },
  1279. contents: [],
  1280. stages: 3,
  1281. },
  1282. crop: {
  1283. name: "crop",
  1284. setup: function (owner) {
  1285. this.owner = owner;
  1286. for (let i = 0; i < this.stages; i++)
  1287. this.contents.push(new Container());
  1288. owner.digest(
  1289. owner,
  1290. this,
  1291. owner.cropTransferTime,
  1292. owner.cropTransferAuto
  1293. );
  1294. },
  1295. feed: function (prey) {
  1296. this.feedFunc(prey, this, this.owner);
  1297. },
  1298. feedFunc: function (prey, self, owner) {
  1299. this.contents[0] = this.contents[0].merge(prey);
  1300. },
  1301. describeDigestion: function (container) {
  1302. return describe("crop-transfer", container, this.owner, verbose, flat);
  1303. },
  1304. describeMove: function (container) {
  1305. return describe("crop-transfer", container, this.owner, verbose, flat);
  1306. },
  1307. fill: function (owner, container) {},
  1308. get description() {
  1309. let prey = new Container();
  1310. this.contents.forEach(function (x) {
  1311. prey = prey.merge(x);
  1312. });
  1313. if (verbose || flat) {
  1314. prey = flatten(prey);
  1315. }
  1316. if (prey.count == 0) {
  1317. return "Your crop don't contain any prey.";
  1318. } else {
  1319. return (
  1320. "Your crop bulges with " +
  1321. prey.describeSimple(verbose || flat) +
  1322. "."
  1323. );
  1324. }
  1325. },
  1326. contents: [],
  1327. stages: 3,
  1328. },
  1329. wings: {
  1330. name: "wings",
  1331. setup: function (owner) {
  1332. this.owner = owner;
  1333. for (let i = 0; i < this.stages; i++)
  1334. this.contents.push(new Container());
  1335. owner.digest(owner, this, owner.wingDigestTime, owner.wingDigestAuto);
  1336. },
  1337. feed: function (prey) {
  1338. this.feedFunc(prey, this, this.owner);
  1339. },
  1340. feedFunc: function (prey, self, owner) {
  1341. this.contents[0] = this.contents[0].merge(prey);
  1342. },
  1343. describeMove: function (container) {
  1344. return describe(
  1345. "wings-to-stomach",
  1346. container,
  1347. this.owner,
  1348. verbose,
  1349. flat
  1350. );
  1351. },
  1352. describeDigestion: function (container) {
  1353. return describe("wings", container, this.owner, verbose, flat);
  1354. },
  1355. fill: function (owner, container) {
  1356. // no-op
  1357. },
  1358. get description() {
  1359. let prey = new Container();
  1360. this.contents.forEach(function (x) {
  1361. prey = prey.merge(x);
  1362. });
  1363. if (verbose || flat) {
  1364. prey = flatten(prey);
  1365. }
  1366. if (prey.count == 0) {
  1367. return (
  1368. "Your don't have anyone trapped in your " +
  1369. macro.wingDesc +
  1370. " wings."
  1371. );
  1372. } else {
  1373. if (macro.brutality > 0) {
  1374. return (
  1375. "Your " +
  1376. macro.wingDesc +
  1377. " wings bulge as they squeeze in on " +
  1378. prey.describeSimple(verbose || flat) +
  1379. ", slowly breaking them down."
  1380. );
  1381. } else {
  1382. return (
  1383. "Your " +
  1384. macro.wingDesc +
  1385. " wings bulge with " +
  1386. prey.describeSimple(verbose || flat) +
  1387. "."
  1388. );
  1389. }
  1390. }
  1391. },
  1392. contents: [],
  1393. stages: 3,
  1394. },
  1395. // holding spots
  1396. pouch: {
  1397. name: "pouch",
  1398. container: new Container(),
  1399. get description() {
  1400. let prey = this.container;
  1401. if (verbose || flat) {
  1402. prey = flatten(prey);
  1403. }
  1404. if (this.container.count == 0) return "Your pouch is empty";
  1405. else
  1406. return (
  1407. "Your pouch contains " +
  1408. this.container.describeSimple(verbose || flat)
  1409. );
  1410. },
  1411. add: function (victims) {
  1412. this.container = this.container.merge(victims);
  1413. },
  1414. },
  1415. sheath: {
  1416. name: "sheath",
  1417. container: new Container(),
  1418. get description() {
  1419. if (this.container.count == 0) return "Your sheath is empty";
  1420. else
  1421. return (
  1422. "Your sheath contains " +
  1423. this.container.describeSimple(verbose || flat)
  1424. );
  1425. },
  1426. add: function (victims) {
  1427. this.container = this.container.merge(victims);
  1428. },
  1429. },
  1430. foreskin: {
  1431. name: "foreskin",
  1432. container: new Container(),
  1433. get description() {
  1434. if (this.container.count == 0)
  1435. return "Your foreskin is wrapped tightly around your shaft.";
  1436. else
  1437. return (
  1438. "Your foreskin bulges with " +
  1439. this.container.describeSimple(verbose || flat)
  1440. );
  1441. },
  1442. add: function (victims) {
  1443. this.container = this.container.merge(victims);
  1444. },
  1445. },
  1446. cleavage: {
  1447. name: "cleavage",
  1448. container: new Container(),
  1449. get description() {
  1450. if (this.container.count == 0)
  1451. return "Your breasts don't have anyone stuck between them";
  1452. else
  1453. return (
  1454. "Your cleavage contains " +
  1455. this.container.describeSimple(verbose || flat)
  1456. );
  1457. },
  1458. add: function (victims) {
  1459. this.container = this.container.merge(victims);
  1460. },
  1461. },
  1462. shoeTrapped: new Container(),
  1463. sockTrapped: new Container(),
  1464. shoe: {
  1465. name: "shoe",
  1466. container: new Container(),
  1467. get description() {
  1468. if (this.container.count == 0)
  1469. return "Your " + macro.shoeDesc(true) + " are empty.";
  1470. else
  1471. return (
  1472. "Your " +
  1473. macro.shoeDesc(true) +
  1474. " contain " +
  1475. this.container.describeSimple(verbose || flat)
  1476. );
  1477. },
  1478. add: function (victims) {
  1479. this.container = this.container.merge(victims);
  1480. },
  1481. },
  1482. sock: {
  1483. name: "sock",
  1484. container: new Container(),
  1485. get description() {
  1486. if (this.container.count == 0)
  1487. return "Your " + macro.sockDesc(true) + " are empty.";
  1488. else
  1489. return (
  1490. "Your " +
  1491. macro.sockDesc(true) +
  1492. " contain " +
  1493. this.container.describeSimple(verbose || flat)
  1494. );
  1495. },
  1496. add: function (victims) {
  1497. this.container = this.container.merge(victims);
  1498. },
  1499. },
  1500. paws: {
  1501. name: "paws",
  1502. container: new Container(),
  1503. get description() {
  1504. if (this.container.count == 0)
  1505. return (
  1506. "You don't have anyone stuck between your " +
  1507. this.owner.toeDesc(true)
  1508. );
  1509. else
  1510. return (
  1511. "You have " +
  1512. this.container.describeSimple(verbose || flat) +
  1513. " wedged between your " +
  1514. this.owner.toeDesc(true)
  1515. );
  1516. },
  1517. add: function (victims) {
  1518. this.container = this.container.merge(victims);
  1519. },
  1520. },
  1521. init: function () {
  1522. this.stomach.setup(this);
  1523. this.bowels.setup(this);
  1524. this.tail.setup(this);
  1525. this.womb.setup(this);
  1526. this.balls.setup(this);
  1527. this.breasts.setup(this);
  1528. this.bladder.setup(this);
  1529. this.souls.setup(this);
  1530. this.goo.setup(this);
  1531. this.pawsVore.setup(this);
  1532. this.crop.setup(this);
  1533. this.wings.setup(this);
  1534. this.cumStorage.owner = this;
  1535. this.femcumStorage.owner = this;
  1536. this.milkStorage.owner = this;
  1537. this.gasStorage.owner = this;
  1538. this.pissStorage.owner = this;
  1539. this.scatStorage.owner = this;
  1540. this.paws.owner = this;
  1541. if (this.analVoreToStomach) {
  1542. this.bowels.moves = this.stomach;
  1543. }
  1544. if (this.tailVoreToStomach) {
  1545. this.tail.moves = this.stomach;
  1546. }
  1547. if (this.wingVoreToStomach) {
  1548. this.wings.moves = this.stomach;
  1549. }
  1550. this.crop.moves = this.stomach;
  1551. if (this.maleParts) this.fillCum(this);
  1552. if (this.femaleParts) this.fillFemcum(this);
  1553. if (this.lactationEnabled && this.hasBreasts) this.fillBreasts(this);
  1554. this.quenchExcess(this);
  1555. if (this.gasEnabled) this.fillGas(this);
  1556. if (this.pissEnabled) this.fillPiss(this);
  1557. if (this.scatEnabled) this.fillScat(this);
  1558. },
  1559. fillCum: function (self) {
  1560. self.cumStorage.amount +=
  1561. (self.cumStorage.limit * self.baseCumProduction * fillPeriod) / 1000;
  1562. if (self.cumStorage.amount > self.cumStorage.limit)
  1563. self.arouse(1 * (self.cumStorage.amount / self.cumStorage.limit - 1));
  1564. setTimeout(function () {
  1565. self.fillCum(self);
  1566. }, fillPeriod);
  1567. },
  1568. fillFemcum: function (self) {
  1569. self.femcumStorage.amount +=
  1570. (self.femcumStorage.limit * self.baseFemcumProduction * fillPeriod) /
  1571. 1000;
  1572. if (self.femcumStorage.amount > self.femcumStorage.limit)
  1573. self.arouse(
  1574. 1 * (self.femcumStorage.amount / self.femcumStorage.limit - 1)
  1575. );
  1576. setTimeout(function () {
  1577. self.fillFemcum(self);
  1578. }, fillPeriod);
  1579. },
  1580. fillBreasts: function (self) {
  1581. self.milkStorage.amount +=
  1582. (self.milkStorage.limit * self.baseLactationProduction * fillPeriod) /
  1583. 1000;
  1584. if (self.milkStorage.amount > self.milkStorage.limit) {
  1585. breast_milk(self.milkStorage.amount - self.milkStorage.limit / 2);
  1586. }
  1587. if (self.milkStorage.amount > self.milkStorage.limit) {
  1588. self.milkStorage.amount = self.milkStorage.limit;
  1589. }
  1590. setTimeout(function () {
  1591. self.fillBreasts(self);
  1592. }, fillPeriod);
  1593. },
  1594. fillGas: function (self) {
  1595. self.gasStorage.amount +=
  1596. (self.gasStorage.limit * self.baseGasProduction * fillPeriod) / 1000;
  1597. let ratio = self.gasStorage.amount / self.gasStorage.limit;
  1598. if ((ratio > 1 && Math.random() * 100 < ratio) || ratio > 2) {
  1599. let amount = self.gasStorage.amount - (self.gasStorage.limit * 3) / 4;
  1600. if (self.belchEnabled && self.fartEnabled) {
  1601. if (Math.random() < 0.5) belch(amount, false);
  1602. else fart(amount, false);
  1603. } else if (self.belchEnabled) {
  1604. belch(amount, false);
  1605. } else if (self.fartEnabled) {
  1606. fart(amount, false);
  1607. }
  1608. }
  1609. setTimeout(function () {
  1610. self.fillGas(self);
  1611. }, fillPeriod);
  1612. },
  1613. get urethraDiameter() {
  1614. return this.scaling(this.baseUrethraDiameter, this.scale, 1);
  1615. },
  1616. get urethraStretchDiameter() {
  1617. return this.urethraDiameter * this.urethraStretchiness;
  1618. },
  1619. get urethraStretchArea() {
  1620. return (
  1621. ((this.urethraStretchDiameter * this.urethraStretchDiameter) / 4) *
  1622. Math.PI
  1623. );
  1624. },
  1625. fillPiss: function (self) {
  1626. self.pissStorage.amount +=
  1627. (self.pissStorage.limit * self.basePissProduction * fillPeriod) / 1000;
  1628. if (self.pissStorage.amount > self.pissStorage.limit * 2)
  1629. piss(self.pissStorage.amount, false);
  1630. setTimeout(function () {
  1631. self.fillPiss(self);
  1632. }, fillPeriod);
  1633. },
  1634. fillScat: function (self) {
  1635. self.scatStorage.amount +=
  1636. (self.scatStorage.limit * self.baseScatProduction * fillPeriod) / 1000;
  1637. if (self.scatStorage.amount > self.scatStorage.limit * 2)
  1638. scat(self.scatStorage.amount, false);
  1639. setTimeout(function () {
  1640. self.fillScat(self);
  1641. }, fillPeriod);
  1642. },
  1643. cumStorage: {
  1644. amount: 0,
  1645. get limit() {
  1646. return this.owner.ballVolume * this.owner.cumStorageScale * 2;
  1647. },
  1648. },
  1649. femcumStorage: {
  1650. amount: 0,
  1651. get limit() {
  1652. return this.owner.wombVolume * this.owner.femcumStorageScale;
  1653. },
  1654. },
  1655. milkStorage: {
  1656. amount: 0,
  1657. get limit() {
  1658. return this.owner.breastVolume * 2 * this.owner.milkStorageScale;
  1659. },
  1660. },
  1661. gasStorage: {
  1662. amount: 0,
  1663. get limit() {
  1664. return (
  1665. (Math.pow(this.owner.scale, 3) / 1000) * this.owner.gasStorageScale
  1666. );
  1667. },
  1668. },
  1669. pissStorage: {
  1670. amount: 0,
  1671. get limit() {
  1672. return (
  1673. (Math.pow(this.owner.scale, 3) / 5000) * this.owner.pissStorageScale
  1674. );
  1675. },
  1676. },
  1677. scatStorage: {
  1678. amount: 0,
  1679. victims: new Container(),
  1680. get limit() {
  1681. return (
  1682. (Math.pow(this.owner.scale, 3) / 1000) * this.owner.scatStorageScale
  1683. );
  1684. },
  1685. },
  1686. get pawStenchArea() {
  1687. return this.pawArea * this.basePawStenchArea * this.stenchScale;
  1688. },
  1689. get assStenchArea() {
  1690. return this.assArea * this.baseAssStenchArea * this.stenchScale;
  1691. },
  1692. get gasDigestFactor() {
  1693. if (this.gasScaleWithSize) {
  1694. return this.baseGasDigestFactor * this.scale;
  1695. } else {
  1696. return this.baseGasDigestFactor;
  1697. }
  1698. },
  1699. arouse: function (amount) {
  1700. if (!this.arousalEnabled) return;
  1701. if (this.afterglow) return;
  1702. if (this.orgasm) amount /= 5;
  1703. this.arousal += amount * this.arousalFactor;
  1704. if (this.arousal >= 200) {
  1705. this.arousal = 200;
  1706. if (!this.orgasm) {
  1707. this.orgasm = true;
  1708. update(
  1709. ["You shudder as ecstasy races up your spine", newline],
  1710. false
  1711. );
  1712. if (this.maleParts) {
  1713. this.maleOrgasm(this);
  1714. if (this.sheath.container.count > 0) sheath_crush();
  1715. if (this.foreskin.container.count > 0) foreskin_crush();
  1716. }
  1717. if (this.femaleParts) {
  1718. this.femaleOrgasm(this);
  1719. }
  1720. if (!this.maleParts && !this.femaleParts) {
  1721. this.nullOrgasm(this);
  1722. }
  1723. }
  1724. }
  1725. },
  1726. quench: function (amount) {
  1727. if (!this.arousalEnabled) return;
  1728. this.arousal -= amount;
  1729. if (this.arousal <= 100) {
  1730. if (this.orgasm) {
  1731. this.orgasm = false;
  1732. this.afterglow = true;
  1733. }
  1734. }
  1735. if (this.arousal < 0) {
  1736. this.arousal = 0;
  1737. this.afterglow = false;
  1738. }
  1739. },
  1740. quenchExcess: function (self) {
  1741. if (self.arousalEnabled) {
  1742. if (self.arousal > 100 && !self.orgasm) {
  1743. self.arousal = Math.max(100, self.arousal - 1);
  1744. self.edge += (Math.sqrt(self.arousal - 100) / 500) * macro.edgeFactor;
  1745. self.edge = Math.min(1, self.edge);
  1746. if (self.maleParts)
  1747. self.maleSpurt +=
  1748. (((self.arousal - 100) / 100 + Math.random()) / 25) * self.edge;
  1749. if (self.femaleParts)
  1750. self.femaleSpurt +=
  1751. (((self.arousal - 100) / 100 + Math.random()) / 25) * self.edge;
  1752. if (self.maleSpurt > 1) {
  1753. male_spurt(macro.cumVolume * (0.1 + Math.random() / 10), false);
  1754. self.maleSpurt = 0;
  1755. }
  1756. if (self.femaleSpurt > 1) {
  1757. female_spurt(
  1758. macro.femcumVolume * (0.1 + Math.random() / 10),
  1759. false
  1760. );
  1761. self.femaleSpurt = 0;
  1762. }
  1763. } else if (self.orgasm) {
  1764. self.quench(1);
  1765. } else if (self.afterglow) {
  1766. self.quench(0.5);
  1767. self.edge = Math.max(0, self.edge - 0.01);
  1768. }
  1769. }
  1770. setTimeout(function () {
  1771. self.quenchExcess(self);
  1772. }, 200);
  1773. },
  1774. maleOrgasm: function (self, times = 0) {
  1775. if (!this.arousalEnabled) return;
  1776. if (self.orgasm) {
  1777. let spurt = Math.min(this.cumVolume, this.cumStorage.amount);
  1778. if (spurt == this.cumVolume) {
  1779. let excess = this.cumStorage.amount - this.cumVolume;
  1780. spurt += (excess * 3) / 4;
  1781. }
  1782. this.cumStorage.amount -= spurt;
  1783. male_orgasm(spurt, false);
  1784. setTimeout(function () {
  1785. self.maleOrgasm(self);
  1786. }, 5000);
  1787. }
  1788. },
  1789. femaleOrgasm: function (self) {
  1790. if (!this.arousalEnabled) return;
  1791. if (this.orgasm) {
  1792. let spurt = Math.min(this.femcumVolume, this.femcumStorage.amount);
  1793. if (spurt == this.femcumVolume) {
  1794. let excess = this.femcumStorage.amount - this.femcumVolume;
  1795. spurt += (excess * 3) / 4;
  1796. }
  1797. this.femcumStorage.amount -= spurt;
  1798. female_orgasm(spurt, false);
  1799. setTimeout(function () {
  1800. self.femaleOrgasm(self);
  1801. }, 5000);
  1802. }
  1803. },
  1804. nullOrgasm: function (self) {
  1805. if (!this.arousalEnabled) return;
  1806. if (this.orgasm) {
  1807. setTimeout(function () {
  1808. self.nullOrgasm(self);
  1809. }, 2000);
  1810. }
  1811. },
  1812. get totalMass() {
  1813. let base = Math.pow(this.scale, 3) * this.baseMass;
  1814. if (this.hasTail) {
  1815. base += this.tailMass * this.tailCount;
  1816. }
  1817. if (this.maleParts) {
  1818. base += this.dickMass;
  1819. base += this.ballMass * 2;
  1820. }
  1821. if (this.hasBreasts) {
  1822. base += this.breastMass * 2;
  1823. }
  1824. return base;
  1825. },
  1826. get description() {
  1827. let result = [];
  1828. let line =
  1829. "You are " +
  1830. (macro.name == "" ? "" : macro.name + ", ") +
  1831. "a " +
  1832. length(macro.height, unit, true) +
  1833. " tall " +
  1834. macro.species +
  1835. ". You weigh " +
  1836. mass(macro.mass, unit) +
  1837. ".";
  1838. result.push(line);
  1839. result.push(macro.stomach.description);
  1840. if (this.analVore) {
  1841. result.push(macro.bowels.description);
  1842. }
  1843. if (this.hasTail) {
  1844. line =
  1845. "Your " +
  1846. macro.describeTail +
  1847. (macro.tailCount > 1
  1848. ? " tails sway as you walk. "
  1849. : " tail sways as you walk. ");
  1850. if (this.tailMaw) {
  1851. line +=
  1852. macro.tailCount > 1
  1853. ? "Their maws are drooling"
  1854. : "Its maw is drooling";
  1855. }
  1856. result.push(line);
  1857. if (this.tailMaw) {
  1858. result.push(this.tail.description);
  1859. }
  1860. }
  1861. if (this.arousalEnabled) {
  1862. if (this.afterglow) {
  1863. result.push("You're basking in the afterglow of a powerful orgasm.");
  1864. } else if (this.orgasm) {
  1865. result.push("You're cumming!");
  1866. } else if (this.arousal < 25) {
  1867. result.push("You're not at all aroused.");
  1868. } else if (this.arousal < 75) {
  1869. result.push("You're feeling a little aroused.");
  1870. } else if (this.arousal < 150) {
  1871. result.push("You're feeling aroused.");
  1872. } else if (this.arousal < 200) {
  1873. result.push("You're on the edge of an orgasm!");
  1874. }
  1875. }
  1876. if (this.maleParts) {
  1877. if (this.hasSheath && this.arousal < 75) {
  1878. line =
  1879. "Your " +
  1880. this.describeDick +
  1881. " cock is hidden away in your bulging sheath, with two " +
  1882. mass(macro.ballMass, unit, true) +
  1883. ", " +
  1884. length(macro.ballDiameter, unit, true) +
  1885. " wide balls hanging beneath.";
  1886. } else {
  1887. line =
  1888. "Your " +
  1889. this.describeDick +
  1890. " cock hangs from your hips, with two " +
  1891. mass(macro.ballMass, unit, true) +
  1892. ", " +
  1893. length(macro.ballDiameter, unit, true) +
  1894. " wide balls hanging beneath.";
  1895. }
  1896. result.push(line);
  1897. result.push(macro.balls.description);
  1898. }
  1899. if (this.femaleParts) {
  1900. line =
  1901. "Your " +
  1902. this.describeVagina +
  1903. " slit peeks out from between your legs.";
  1904. result.push(line);
  1905. result.push(macro.womb.description);
  1906. }
  1907. if (this.hasBreasts) {
  1908. line =
  1909. "You have two " +
  1910. length(this.breastDiameter, unit, true) +
  1911. " wide breasts that weigh " +
  1912. mass(macro.breastMass, unit) +
  1913. " apiece.";
  1914. if (this.lactationEnabled) {
  1915. line +=
  1916. " They slosh with " +
  1917. volume(this.milkStorage.amount, unit, false) +
  1918. " of creamy milk.";
  1919. }
  1920. if (this.cleavage.container.count > 0)
  1921. line +=
  1922. " Between them are " +
  1923. this.cleavage.container.describeSimple(verbose || flat) +
  1924. ".";
  1925. result.push(line);
  1926. if (this.breastVore) {
  1927. result.push(this.breasts.description);
  1928. }
  1929. }
  1930. if (this.soulVoreEnabled) {
  1931. result.push(this.souls.description);
  1932. }
  1933. if (this.wingVoreEnabled) {
  1934. result.push(this.wings.description);
  1935. }
  1936. if (this.hasPouch) {
  1937. result.push(this.pouch.description);
  1938. }
  1939. line =
  1940. "Your two " +
  1941. length(macro.pawLength, unit, true) +
  1942. " by " +
  1943. length(macro.pawWidth, unit, true) +
  1944. " " +
  1945. this.footDesc(true) +
  1946. " shake the earth.";
  1947. if (this.footShoeWorn && this.shoe.container.count > 0) {
  1948. line +=
  1949. " Within " +
  1950. (this.shoe.container.count > 1 ? "are" : "is") +
  1951. " " +
  1952. this.shoe.container.describeSimple(verbose || flat);
  1953. if (this.footSockWorn && this.sock.container.count > 0) {
  1954. line +=
  1955. " and " +
  1956. this.sock.container.describeSimple(verbose || flat) +
  1957. " in your socks.";
  1958. }
  1959. } else if (this.footSockWorn && this.sock.container.count > 0) {
  1960. line +=
  1961. " Within " +
  1962. (this.sock.container.count > 1 ? "are" : "is") +
  1963. " " +
  1964. this.sock.container.describeSimple(verbose || flat);
  1965. }
  1966. if (this.paws.container.count > 0) {
  1967. line +=
  1968. " You have " +
  1969. this.paws.container.describeSimple(verbose || flat) +
  1970. " wedged between your " +
  1971. macro.toeDesc(true);
  1972. }
  1973. result.push(line);
  1974. if (this.gooMolten) {
  1975. result.push(this.goo.description);
  1976. }
  1977. if (this.pawVoreEnabled) {
  1978. result.push(this.pawsVore.description);
  1979. }
  1980. return result;
  1981. },
  1982. get describeTail() {
  1983. return (
  1984. (this.tailCount > 1 ? this.tailCount + " " : "") +
  1985. length(this.tailLength, unit, true) +
  1986. " long " +
  1987. this.tailType
  1988. );
  1989. },
  1990. get describeDick() {
  1991. let state = "";
  1992. if (!this.arousalEnabled) {
  1993. state = "limp";
  1994. } else if (this.orgasm) {
  1995. state = "spurting";
  1996. } else {
  1997. if (this.arousal < 25) {
  1998. state = "limp";
  1999. } else if (this.arousal < 75) {
  2000. state = "swelling";
  2001. } else if (this.arousal < 100) {
  2002. state = "erect";
  2003. } else if (this.arousal < 150) {
  2004. state = "erect, throbbing";
  2005. } else if (this.arousal < 200) {
  2006. state = "erect, throbbing, pre-soaked";
  2007. }
  2008. }
  2009. return (
  2010. length(this.dickLength, unit, true) +
  2011. " long " +
  2012. state +
  2013. " " +
  2014. this.dickType +
  2015. " " +
  2016. pickString("cock", "shaft", "rod", "member", "dick")
  2017. );
  2018. },
  2019. get describeVagina() {
  2020. let state = "";
  2021. if (!this.arousalEnabled) {
  2022. state = "";
  2023. } else if (this.orgasm) {
  2024. state = " gushing, quivering";
  2025. } else {
  2026. if (this.arousal < 25) {
  2027. state = "";
  2028. } else if (this.arousal < 75) {
  2029. state = " moist";
  2030. } else if (this.arousal < 100) {
  2031. state = " glistening";
  2032. } else if (this.arousal < 150) {
  2033. state = " dripping";
  2034. } else if (this.arousal < 200) {
  2035. state = " dripping, quivering";
  2036. }
  2037. }
  2038. return length(this.vaginaLength, unit, true) + " long" + state;
  2039. },
  2040. };
  2041. //
  2042. //------END OF MACRO FUCTION-----------------------------------------------------------------------------------------------
  2043. //
  2044. const biomeEnum = {
  2045. City: {
  2046. enabled: "cityEnabled",
  2047. biomeSize: [1000, 5000], //[min,max] Note: this is the distance you will walk until getting to the end of the biome
  2048. biomeWeights: {
  2049. //Weights determine if and how often you run into something while inside of a biome
  2050. House: 0.1,
  2051. Car: 0.07,
  2052. Bus: 0.02,
  2053. Business: 0.075,
  2054. Train: 0.005,
  2055. Tram: 0.01,
  2056. "Parking Garage": 0.003,
  2057. "Small Skyscraper": 0.05,
  2058. "Large Skyscraper": 0.05,
  2059. City: 0.00005,
  2060. },
  2061. },
  2062. Downtown: {
  2063. enabled: "downtownEnabled",
  2064. biomeSize: [1000, 5000], //[min,max] Note: this is the distance you will walk until getting to the end of the biome
  2065. biomeWeights: {
  2066. //Weights determine if and how often you run into something while inside of a biome
  2067. Car: 0.1,
  2068. Bus: 0.05,
  2069. Tram: 0.03,
  2070. Business: 0.075,
  2071. "Parking Garage": 0.003,
  2072. "Small Skyscraper": 0.06,
  2073. City: 0.00005,
  2074. },
  2075. },
  2076. Rural: {
  2077. enabled: "ruralEnabled",
  2078. biomeSize: [4000, 8000], //[min,max] Note: this is the distance you will walk until getting to the end of the biome
  2079. biomeWeights: {
  2080. //Weights determine if and how often you run into something while inside of a biome
  2081. Cow: 0.005,
  2082. House: 0.1,
  2083. Barn: 0.08,
  2084. Car: 0.1,
  2085. Train: 0.002,
  2086. Business: 0.075,
  2087. Ranch: 0.01,
  2088. Airstrip: 0.002,
  2089. Airport: 0.002,
  2090. Town: 0.00001,
  2091. },
  2092. },
  2093. Suburb: {
  2094. enabled: "suburbEnabled",
  2095. biomeSize: [2000, 7000], //[min,max] Note: this is the distance you will walk until getting to the end of the biome
  2096. biomeWeights: {
  2097. //Weights determine if and how often you run into something while inside of a biome
  2098. House: 0.1,
  2099. Car: 0.07,
  2100. Bus: 0.01,
  2101. Town: 0.00001,
  2102. },
  2103. },
  2104. };
  2105. let biome = biomeEnum.City; //starting biome(this will be overwritten by player selection as soon as game starts)
  2106. let biomeSize = 3000; // size of starting biome(this will be overwritten by player selection as soon as game starts)
  2107. let position = 0; //declares variable and starts player at 0 as they have not taken a step yet
  2108. function updateBiome(forceNew = false, specifyBiome) {
  2109. //handles stepping between biomes
  2110. if (macro.height > 1e12 || macro.changingBiomes == false) {
  2111. //stops function from running once it stops being relevant
  2112. return;
  2113. }
  2114. let strideSize = macro.height * 0.4; //adjust step size based on height
  2115. position += strideSize; //adds distance from step into total disance traveled through biome
  2116. if (position > biomeSize || forceNew == true) {
  2117. //if player steps out of biome, generates a new one
  2118. position = 0;
  2119. let oldBiome = biome;
  2120. let biomeTemp = biome; //defines biomeTemp for latrer use, what it is set to does not matter
  2121. if (specifyBiome == undefined) {
  2122. biomeTemp = pickString(
  2123. biomeEnum.City,
  2124. biomeEnum.Suburb,
  2125. biomeEnum.Rural,
  2126. biomeEnum.Downtown
  2127. ); //if a biome is not force into this function, it picks a random biome
  2128. } else {
  2129. //otherwise it sets the new biome to the selected one
  2130. biomeTemp = specifyBiome;
  2131. }
  2132. if (macro[biomeTemp.enabled] == false) {
  2133. //checks that the biome selected is actually enabled and if it is not, reruns the function
  2134. updateBiome(true); //side effect of this order is that if the user selects an invalid biome
  2135. return;
  2136. }
  2137. biome = biomeTemp; //if biome passes all checks to allow creation, sets it as biome player is in
  2138. generateBiome(); //assigns a size to new biome
  2139. if (oldBiome !== biome) {
  2140. //only alerts player if the biome type actually changed
  2141. look(true);
  2142. }
  2143. }
  2144. }
  2145. function generateBiome() {
  2146. //creates the biome in accordance with its specific settings(only controls size now but needs to be a seperate function due to way game starts)
  2147. let offset = biome.biomeSize[0]; //Math.random generates a random value from 0-1. biome.biomeSize denotes min and max size for each type of biome
  2148. let multiplier = biome.biomeSize[1] - offset; //if Math.random generated 0, we need the min value, so min value becomes offset. if it is 1, we need
  2149. biomeSize = Math.random() * multiplier + offset; // max value so we multiply 1 by the (maxvalue - minvalue)+minvalue to cap out at max value.
  2150. }
  2151. function look(onlyBiome = false) {
  2152. //onlyBiome means don't include player description when looking at surroundings
  2153. let playerDesc = macro.description;
  2154. let areaDesc = "";
  2155. if (macro.height > 1e12) areaDesc = "You're pretty much everywhere at once.";
  2156. else if (macro.height > 1e6)
  2157. areaDesc =
  2158. "You're " +
  2159. (strolling ? "strolling" : "standing") +
  2160. "...on pretty much everything at once.";
  2161. else
  2162. switch (biome) {
  2163. case biomeEnum.Rural:
  2164. areaDesc =
  2165. "You're " +
  2166. (strolling ? "strolling" : "standing") +
  2167. " amongst rural farmhouses and expansive ranches. Cattle are milling about at your feet.";
  2168. break;
  2169. case biomeEnum.Suburb:
  2170. areaDesc =
  2171. "You're " +
  2172. (strolling ? "striding" : "standing") +
  2173. " through the winding roads of a suburb.";
  2174. break;
  2175. case biomeEnum.City:
  2176. if (macro.height < 6) {
  2177. areaDesc =
  2178. "You are " +
  2179. (strolling ? "strolling" : "standing") +
  2180. " in the street of a city. Several " +
  2181. (macro.victimsHuman ? "humans" : "people") +
  2182. " have noticed your intimidating presence and are beginning to run.";
  2183. break;
  2184. } else if (macro.height < 24) {
  2185. areaDesc =
  2186. "Your broad frame fills the street of the city you are terrorizing. Your presence has caused a pileup of vehicles trying to escape.";
  2187. break;
  2188. } else if (macro.height < 100) {
  2189. areaDesc =
  2190. "You are too large for the city streets you are " +
  2191. (strolling ? "strolling through." : "standing in.") +
  2192. " Your hulking frame scrapes against building after building, leaving a clear indicator of your path. Gridlock is starting to set in, with people honking and trying to drive away on the sidewalks.";
  2193. break;
  2194. } else if (macro.height < 500) {
  2195. areaDesc =
  2196. "You are " +
  2197. (strolling ? "strolling through" : "looming over") +
  2198. " a bustling city. Your mammoth frame is on par with the few nearby skyscrapers. You forge your own path, leaving a swath of demolished buildings. Panic has fully gripped the city; the streets are filled with vehicles, all immobile.";
  2199. break;
  2200. } else if (macro.height < 2500) {
  2201. areaDesc =
  2202. "You are " +
  2203. (strolling ? "strolling over" : "looming over") +
  2204. " a city in the midst of chaos. Your colossal bulk blots out the sky, and makes the couple of remaining skyscrapers look small in comparison. You can clearly see the imprints of your " +
  2205. macro.footDesc(true) +
  2206. ". Traffic is gridlocked as far as you can see.";
  2207. break;
  2208. } else {
  2209. areaDesc =
  2210. "You're terrorizing the streets of a city. Heavy traffic, worsened by your rampage, is everywhere.";
  2211. break;
  2212. }
  2213. case biomeEnum.Downtown:
  2214. if (macro.height < 6) {
  2215. areaDesc =
  2216. "You are " +
  2217. (strolling ? "strolling" : "standing") +
  2218. " in packed downtown streets. Several " +
  2219. (macro.victimsHuman ? "humans" : "people") +
  2220. " have noticed your intimidating presence and are beginning to run.";
  2221. break;
  2222. } else if (macro.height < 24) {
  2223. areaDesc =
  2224. "Your broad frame fills the street of the city center. Your presence has caused a pileup of vehicles trying to escape.";
  2225. break;
  2226. } else if (macro.height < 100) {
  2227. areaDesc =
  2228. "You are too large for the city streets you are " +
  2229. (strolling ? "strolling through." : "standing in.") +
  2230. " Your hulking frame scrapes against building after building, leaving a clear indicator of your path. Gridlock is starting to set in, with people honking and trying to drive away on the sidewalks.";
  2231. break;
  2232. } else if (macro.height < 500) {
  2233. areaDesc =
  2234. "You are " +
  2235. (strolling ? "strolling through" : "looming over") +
  2236. " a bustling city. Your mammoth frame is on par with the glittering skyscrapers that surround you. You forge your own path, leaving a swath of demolished buildings. Panic has fully gripped the city; the streets are filled with vehicles, all immobile.";
  2237. break;
  2238. } else if (macro.height < 2500) {
  2239. areaDesc =
  2240. "You are " +
  2241. (strolling ? "strolling over" : "looming over") +
  2242. " a city in the midst of chaos. Your colossal bulk blots out the sky, and makes the remaining skyscrapers look small in comparison. You can clearly see the imprints of your " +
  2243. macro.footDesc(true) +
  2244. ". Traffic is gridlocked as far as you can see, and farther.";
  2245. break;
  2246. } else {
  2247. areaDesc =
  2248. "You're lurking amongst the skyscrapers of downtown. The streets are packed, and the buildings are practically begging you to knock them over.";
  2249. break;
  2250. }
  2251. }
  2252. if (onlyBiome == true) {
  2253. update([areaDesc, newline]);
  2254. } else {
  2255. let desc = playerDesc.concat([newline, areaDesc, newline]);
  2256. update(desc);
  2257. }
  2258. }
  2259. function toggle_auto(e) {
  2260. switch (
  2261. strolling //Changes how fast player is moving, if player is running, sets player back to standing
  2262. ) {
  2263. case strollingEnum.Standing:
  2264. strolling = strollingEnum.Strolling;
  2265. e.target.innerText = "Status: Strolling";
  2266. update(["You start walking.", newline]);
  2267. break;
  2268. case strollingEnum.Strolling:
  2269. strolling = strollingEnum.Jogging;
  2270. e.target.innerText = "Status: Jogging";
  2271. update(["You start jogging.", newline]);
  2272. break;
  2273. case strollingEnum.Jogging:
  2274. strolling = strollingEnum.Running;
  2275. e.target.innerText = "Status: Running";
  2276. update(["You start running.", newline]);
  2277. break;
  2278. case strollingEnum.Running:
  2279. strolling = strollingEnum.Standing;
  2280. e.target.innerText = "Status: Standing";
  2281. update(["You stop running..", newline]);
  2282. break;
  2283. }
  2284. // strolling = !strolling;
  2285. // e.target.innerText = "Status: " + (strolling ? "Strolling" : "Standing");
  2286. //if (strolling)
  2287. // update(["You start walking.",newline]);
  2288. //else
  2289. // update(["You stop walking.",newline]);
  2290. //this is the old code where strolling is defined as true and false(strolling is now referencing an Enum) should probably be ripped out if this ever makes it onto the main Repo
  2291. }
  2292. function toggle_units(e) {
  2293. switch (unit) {
  2294. case "metric":
  2295. unit = "SI";
  2296. break;
  2297. case "SI":
  2298. unit = "customary";
  2299. break;
  2300. case "customary":
  2301. unit = "US";
  2302. break;
  2303. case "US":
  2304. unit = "approx";
  2305. break;
  2306. case "approx":
  2307. unit = "metric";
  2308. break;
  2309. }
  2310. e.target.innerText =
  2311. "Units:\n" + unit.charAt(0).toUpperCase() + unit.slice(1);
  2312. update();
  2313. }
  2314. function toggle_units_options(e) {
  2315. switch (unit) {
  2316. case "metric":
  2317. unit = "SI";
  2318. break;
  2319. case "SI":
  2320. unit = "customary";
  2321. break;
  2322. case "customary":
  2323. unit = "US";
  2324. break;
  2325. case "US":
  2326. unit = "metric";
  2327. break;
  2328. }
  2329. e.target.innerText =
  2330. "Units:\n" + unit.charAt(0).toUpperCase() + unit.slice(1);
  2331. updateAllPreviews();
  2332. }
  2333. function toggle_numbers(e) {
  2334. switch (numbers) {
  2335. case "full":
  2336. numbers = "prefix";
  2337. break;
  2338. case "prefix":
  2339. numbers = "words";
  2340. break;
  2341. case "words":
  2342. numbers = "scientific";
  2343. break;
  2344. case "scientific":
  2345. numbers = "full";
  2346. break;
  2347. }
  2348. e.target.innerText =
  2349. "Numbers: " + numbers.charAt(0).toUpperCase() + numbers.slice(1);
  2350. update();
  2351. }
  2352. function toggle_verbose(e) {
  2353. switch (text_verbosity) {
  2354. case "verbose":
  2355. text_verbosity = "concise";
  2356. e.target.innerText = "Concise Text";
  2357. verbose = false;
  2358. flat = true;
  2359. break;
  2360. case "concise":
  2361. text_verbosity = "simple";
  2362. e.target.innerText = "Simple Text";
  2363. verbose = false;
  2364. flat = false;
  2365. break;
  2366. case "simple":
  2367. text_verbosity = "verbose";
  2368. e.target.innerText = "Verbose Text";
  2369. verbose = true;
  2370. flat = false;
  2371. break;
  2372. }
  2373. }
  2374. function toggle_arousal(e) {
  2375. macro.arousalEnabled = !macro.arousalEnabled;
  2376. e.target.innerText = macro.arousalEnabled ? "Arousal On" : "Arousal Off";
  2377. if (macro.arousalEnabled) {
  2378. document.getElementById("arousal").style.display = "block";
  2379. document.getElementById("edge").style.display = "block";
  2380. document.querySelector("#arousalMeter").style.display = "inline-block";
  2381. document.querySelector("#orgasmMeter").style.display = "inline-block";
  2382. document.querySelector("#edgeMeter").style.display = "inline-block";
  2383. } else {
  2384. document.getElementById("arousal").style.display = "none";
  2385. document.getElementById("edge").style.display = "none";
  2386. document.querySelector("#arousalMeter").style.display = "none";
  2387. document.querySelector("#orgasmMeter").style.display = "none";
  2388. document.querySelector("#edgeMeter").style.display = "none";
  2389. }
  2390. macro.orgasm = false;
  2391. macro.afterglow = false;
  2392. enable_victim("cum-flood", "Flooded by cum");
  2393. enable_victim("femcum-flood", "Flooded by femcum");
  2394. }
  2395. // lists out total people
  2396. function summarize(sum, fatal = true) {
  2397. let word;
  2398. let count = get_living_prey(sum);
  2399. if (fatal && macro.brutality > 0) word = count != 1 ? "kills" : "kill";
  2400. else if (!fatal && macro.brutality > 0) word = "prey";
  2401. else word = count != 1 ? "victims" : "victim";
  2402. return "<b>(" + count + " " + word + ")</b>";
  2403. }
  2404. function getOnePrey(biome, area, sameSize = true) {
  2405. if (macro.shrunkPrey != null) {
  2406. return getPrey(biome, area, sameSize);
  2407. }
  2408. let weights = getWeights(biome, area);
  2409. let potential = [];
  2410. for (let key in weights) {
  2411. if (weights.hasOwnProperty(key)) {
  2412. potential.push(key);
  2413. }
  2414. }
  2415. let potAreas = [];
  2416. potential.forEach(function (x) {
  2417. potAreas.push([x, things[x].area]);
  2418. });
  2419. potAreas = potAreas.sort(function (x, y) {
  2420. return y[1] - x[1];
  2421. });
  2422. for (let i = 0; i < potAreas.length; i++) {
  2423. let x = potAreas[i];
  2424. if (x[1] < area) {
  2425. return new Container([new things[x[0]][x[0]](1)]);
  2426. }
  2427. }
  2428. if (sameSize) return new Container([new things["Person"]["Person"](1)]);
  2429. else return new Container();
  2430. }
  2431. //set weights(how often a thing is encountered)
  2432. function getWeights(region, area) {
  2433. let weights = {};
  2434. if (area > things["Planet"].area) {
  2435. weights = {
  2436. Planet: 1.47e-3,
  2437. Star: 1.7713746e-3,
  2438. "Solar System": 4e-4,
  2439. Galaxy: 0.1,
  2440. Cluster: 0.5,
  2441. Universe: 1,
  2442. Multiverse: 1,
  2443. Timeline: 1,
  2444. Pantheon: 1,
  2445. Reality: 1,
  2446. };
  2447. } else if (area > things["Town"].area) {
  2448. weights = {
  2449. Town: 0.001,
  2450. City: 0.0005,
  2451. Continent: 0.5,
  2452. };
  2453. } else {
  2454. try {
  2455. weights = region.biomeWeights;
  2456. } catch (err) {
  2457. weights = {
  2458. House: 0.1,
  2459. Car: 0.07,
  2460. Bus: 0.02,
  2461. Tram: 0.02,
  2462. Train: 0.005,
  2463. Business: 0.075,
  2464. "Parking Garage": 0.003,
  2465. "Small Skyscraper": 0.05,
  2466. "Large Skyscraper": 0.025,
  2467. Town: 0.00001,
  2468. City: 0.00005,
  2469. Continent: 0.0005,
  2470. Planet: 0.0001,
  2471. };
  2472. }
  2473. if (!macro.victimsNoPeople) {
  2474. if (macro.victimsHuman) {
  2475. weights["Human"] = 0.017;
  2476. } else {
  2477. weights["Person"] = 0.017;
  2478. }
  2479. }
  2480. if (macro.victimsMilitary) {
  2481. if (macro.height < 500) {
  2482. weights["Soldier"] = 0.08;
  2483. weights["Tank"] = 0.07;
  2484. weights["Artillery"] = 0.06;
  2485. (weights["Military Helicopter"] = 0.05), (weights["Squad"] = 0.04);
  2486. (weights["Platoon"] = 0.2),
  2487. (weights["Company"] = 0.3),
  2488. (weights["Battalion"] = 0.4),
  2489. (weights["Brigade"] = 0.5);
  2490. } else if (macro.height < 5000) {
  2491. weights["Tank"] = 0.0002;
  2492. weights["Artillery"] = 0.001;
  2493. weights["Squad"] = 0.0001;
  2494. (weights["Platoon"] = 0.0005),
  2495. (weights["Company"] = 0.001),
  2496. (weights["Battalion"] = 0.002),
  2497. (weights["Brigade"] = 0.003);
  2498. (weights["Division"] = 0.002),
  2499. (weights["Tank Division"] = 0.001),
  2500. (weights["Army"] = 0.001);
  2501. } else {
  2502. (weights["Division"] = 0.02),
  2503. (weights["Tank Division"] = 0.01),
  2504. (weights["Army"] = 0.01);
  2505. }
  2506. }
  2507. if (macro.victimsMicros) {
  2508. weights["Micro"] = 0.001;
  2509. }
  2510. if (macro.victimsMacros) {
  2511. weights["Macro"] = 0.0001;
  2512. }
  2513. }
  2514. if (macro.singleVictimType != "Disabled") {
  2515. weights = {};
  2516. weights[macro.singleVictimType] = 0.25;
  2517. }
  2518. return weights;
  2519. }
  2520. function getPrey(region, area, sameSize = false) {
  2521. if (macro.shrunkPrey != null) {
  2522. let prey = macro.shrunkPrey;
  2523. macro.shrunkPrey = null;
  2524. return prey;
  2525. }
  2526. let weights = getWeights(region, area);
  2527. var prey = fill_area(area, weights);
  2528. if (prey.count == 0 && sameSize) return getOnePrey(biome, area, true);
  2529. return prey;
  2530. }
  2531. function digest_all(organ, active = false) {
  2532. let prey = new Container();
  2533. for (let i = 0; i < organ.stages; i++) {
  2534. prey = prey.merge(organ.contents[i]);
  2535. organ.contents[i] = new Container();
  2536. }
  2537. if (prey.count == 0) {
  2538. return;
  2539. }
  2540. do_digestion(organ.owner, organ, prey, active);
  2541. }
  2542. function do_digestion(owner, organ, container, active = false) {
  2543. if (organ.moves != undefined) {
  2544. organ.moves.feed(container);
  2545. let sound = getSound("insert", container.sum_property("mass"));
  2546. let line = organ.describeMove(container);
  2547. let summary = summarize(container.sum(), false);
  2548. update([line, summary, newline], active);
  2549. return;
  2550. }
  2551. grow_automatic(container.sum_property("mass"), organ.name);
  2552. let digested = container.sum();
  2553. for (let key in victims[organ.name]) {
  2554. if (
  2555. victims[organ.name].hasOwnProperty(key) &&
  2556. digested.hasOwnProperty(key)
  2557. ) {
  2558. victims["digested"][key] += digested[key];
  2559. victims[organ.name][key] -= digested[key];
  2560. }
  2561. }
  2562. let sound = getSound("digest", container.sum_property("mass"));
  2563. let vol = organ.fill(owner, container);
  2564. let line = organ.describeDigestion(container, vol);
  2565. let lethal =
  2566. macro.brutality != 0 && (!macro.soulVoreEnabled || organ.name === "souls");
  2567. let summary = summarize(container.sum(), lethal);
  2568. if (macro.soulVoreEnabled && organ.name != "souls") {
  2569. owner.souls.feed(container);
  2570. let soulCount = container.sum()["Person"];
  2571. let soulLine = "";
  2572. if (soulCount > 0)
  2573. soulLine =
  2574. "Their " +
  2575. (soulCount == 1 ? "soul is" : "souls are") +
  2576. " trapped in your depths!";
  2577. else soulLine = "No souls, though...";
  2578. update([sound, line, summary, soulLine, newline], active);
  2579. } else {
  2580. update([sound, line, summary, newline], active);
  2581. }
  2582. }
  2583. function digest_stomach() {
  2584. digest_all(macro.stomach, true);
  2585. }
  2586. function digest_tail() {
  2587. digest_all(macro.tail, true);
  2588. }
  2589. function digest_anal() {
  2590. digest_all(macro.bowels, true);
  2591. }
  2592. function digest_cock() {
  2593. digest_all(macro.balls, true);
  2594. }
  2595. function digest_breast() {
  2596. digest_all(macro.breasts, true);
  2597. }
  2598. function digest_unbirth() {
  2599. digest_all(macro.womb, true);
  2600. }
  2601. function digest_soul() {
  2602. digest_all(macro.souls, true);
  2603. }
  2604. function digest_bladder() {
  2605. digest_all(macro.bladder, true);
  2606. }
  2607. function digest_goo() {
  2608. digest_all(macro.goo, true);
  2609. }
  2610. function digest_paws() {
  2611. digest_all(macro.pawsVore, true);
  2612. }
  2613. function digest_wings() {
  2614. digest_all(macro.wings, true);
  2615. }
  2616. function crop_swallow() {
  2617. digest_all(macro.crop, true);
  2618. }
  2619. function feed() {
  2620. let area = macro.handArea;
  2621. let prey = getPrey(biome, area, macro.sameSizeOralVore);
  2622. let linesummary = summarize(prey.sum(), false);
  2623. let people = get_living_prey(prey.sum());
  2624. let preyMass = prey.sum_property("mass");
  2625. let sound = getSound("swallow", preyMass);
  2626. let line = "";
  2627. if (macro.cropEnabled) {
  2628. macro.crop.feed(prey);
  2629. line = describe("crop-swallow", prey, macro, verbose, flat);
  2630. } else {
  2631. macro.stomach.feed(prey);
  2632. line = describe("eat", prey, macro, verbose, flat);
  2633. }
  2634. add_victim_people("eaten", prey);
  2635. update([sound, line, linesummary, newline]);
  2636. macro.arouse(5);
  2637. if (macro.droolEnabled) {
  2638. drool();
  2639. }
  2640. }
  2641. function chew() {
  2642. let area = macro.handArea;
  2643. let prey = getPrey(biome, area, macro.sameSizeOralVore);
  2644. let line = describe("chew", prey, macro, verbose, flat);
  2645. let linesummary = summarize(prey.sum(), false);
  2646. let people = get_living_prey(prey.sum());
  2647. let preyMass = prey.sum_property("mass");
  2648. let sound = getSound("chew", preyMass);
  2649. add_victim_people("chew", prey);
  2650. macro.stomach.feed(prey);
  2651. update([sound, line, linesummary, newline]);
  2652. macro.arouse(10);
  2653. if (macro.droolEnabled) {
  2654. drool();
  2655. }
  2656. }
  2657. function drool() {
  2658. let vol = macro.droolVolume * (Math.random() / 5 + 0.9);
  2659. let area = Math.pow(vol, 2 / 3);
  2660. let prey = getPrey(biome, area);
  2661. if (prey.count == 0) {
  2662. return;
  2663. }
  2664. let line = describe("drool", prey, macro, verbose, flat).replace(
  2665. "$VOLUME",
  2666. volume(vol, unit, false)
  2667. );
  2668. let linesummary = summarize(prey.sum(), true);
  2669. let people = get_living_prey(prey.sum());
  2670. let preyMass = prey.sum_property("mass");
  2671. let sound = getSound("drip", preyMass);
  2672. add_victim_people("drool", prey);
  2673. update([sound, line, linesummary, newline]);
  2674. }
  2675. function hand_crush(active = true) {
  2676. let area = macro.handArea;
  2677. let prey = getOnePrey(biome, area, macro.sameSizeStomp);
  2678. let line = describe("hand-crush", prey, macro, verbose, flat);
  2679. let linesummary = summarize(prey.sum(), true);
  2680. let people = get_living_prey(prey.sum());
  2681. let preyMass = prey.sum_property("mass");
  2682. let sound = getSound("crush", preyMass);
  2683. add_victim_people("stomped", prey);
  2684. update([sound, line, linesummary, newline], active);
  2685. macro.arouse(5);
  2686. }
  2687. function foot_crush(active = true) {
  2688. let area = macro.pawArea;
  2689. let prey = getOnePrey(biome, area, macro.sameSizeStomp);
  2690. let line = describe("foot-crush", prey, macro, verbose, flat);
  2691. let linesummary = summarize(prey.sum(), true);
  2692. let people = get_living_prey(prey.sum());
  2693. let preyMass = prey.sum_property("mass");
  2694. let sound = getSound("crush", preyMass);
  2695. add_victim_people("stomped", prey);
  2696. update([sound, line, linesummary, newline], active);
  2697. updateBiome(false);
  2698. macro.arouse(5);
  2699. }
  2700. function stomp(active = true) {
  2701. if (macro.gooMolten && !macro.footShoeWorn && !macro.footSockWorn) {
  2702. stomp_goo();
  2703. return;
  2704. }
  2705. let area = macro.pawArea;
  2706. let prey = getPrey(biome, area, macro.sameSizeStomp);
  2707. let line = describe("stomp", prey, macro, verbose, flat);
  2708. let linesummary = summarize(prey.sum(), true);
  2709. let people = get_living_prey(prey.sum());
  2710. let preyMass = prey.sum_property("mass");
  2711. let sound = getSound("crush", preyMass);
  2712. add_victim_people("stomped", prey);
  2713. update([sound, line, linesummary, newline], active);
  2714. updateBiome(false);
  2715. macro.arouse(5);
  2716. stomp_wedge(active);
  2717. if (macro.stenchEnabled && macro.basePawStenchArea > 0) {
  2718. paw_stench(active);
  2719. }
  2720. }
  2721. function stomp_wedge(active = true) {
  2722. if (macro.footType == "hoof") return;
  2723. let area = 0;
  2724. if (!macro.footWear || (!macro.footSockWorn && !macro.footShoeWorn))
  2725. area = macro.pawArea / 10;
  2726. else if (macro.footShoeWorn) area = macro.pawArea / 25;
  2727. else area = macro.pawArea / 50;
  2728. let prey = getPrey(biome, area, false);
  2729. if (prey.count == 0) return;
  2730. let line = describe("stomp-wedge", prey, macro, verbose, flat);
  2731. let linesummary = summarize(prey.sum(), false);
  2732. let people = get_living_prey(prey.sum());
  2733. let preyMass = prey.sum_property("mass");
  2734. let sound = getSound("crush", preyMass);
  2735. macro.paws.add(prey);
  2736. add_victim_people("stomped", prey);
  2737. update([sound, line, linesummary, newline], active);
  2738. }
  2739. function stomp_goo() {
  2740. let area = macro.pawArea;
  2741. let prey = getPrey(biome, area, macro.sameSizeStomp);
  2742. let line = describe("stomp-goo", prey, macro, verbose, flat);
  2743. let linesummary = summarize(prey.sum(), false);
  2744. let people = get_living_prey(prey.sum());
  2745. let preyMass = prey.sum_property("mass");
  2746. let sound = getSound("goo", preyMass);
  2747. macro.goo.feed(prey);
  2748. update([sound, line, linesummary, newline]);
  2749. macro.arouse(5);
  2750. if (macro.stenchEnabled) {
  2751. paw_stench();
  2752. }
  2753. }
  2754. function flex_toes() {
  2755. let prey = new Container();
  2756. if (!macro.footWear || (!macro.footSockWorn && !macro.footShoeWorn)) {
  2757. prey = macro.paws.container;
  2758. macro.paws.container = new Container();
  2759. } else if (macro.footSockWorn && macro.footShoeWorn) {
  2760. prey = macro.shoe.container.merge(macro.sock.container);
  2761. if (macro.brutality > 0) {
  2762. macro.shoe.container = new Container();
  2763. macro.sock.container = new Container();
  2764. }
  2765. } else if (macro.footSockWorn) {
  2766. prey = macro.sock.container;
  2767. if (macro.brutality > 0) {
  2768. macro.sock.container = new Container();
  2769. }
  2770. } else if (macro.footShoeWorn) {
  2771. prey = macro.shoe.container;
  2772. if (macro.brutality > 0) {
  2773. macro.shoe.container = new Container();
  2774. }
  2775. }
  2776. let line = describe("flex-toes", prey, macro, verbose, flat);
  2777. let linesummary = summarize(prey.sum(), true);
  2778. let people = get_living_prey(prey.sum());
  2779. let preyMass = prey.sum_property("mass");
  2780. let sound = getSound("crush", preyMass);
  2781. add_victim_people("flex-toes", prey);
  2782. update([sound, line, linesummary, newline]);
  2783. }
  2784. function paw_stench() {
  2785. let area = macro.pawStenchArea;
  2786. let prey = getPrey(biome, area);
  2787. let line = describe("paw-stench", prey, macro, verbose, flat);
  2788. let linesummary = summarize(prey.sum(), true);
  2789. let people = get_living_prey(prey.sum());
  2790. if (get_living_prey(prey.sum()) == 0) return;
  2791. let preyMass = prey.sum_property("mass");
  2792. add_victim_people("paw-stench", prey);
  2793. update([line, linesummary, newline]);
  2794. macro.arouse(5);
  2795. }
  2796. function grind(active = true) {
  2797. let area = macro.assArea / 2;
  2798. if (macro.maleParts) area += macro.dickArea;
  2799. if (macro.femaleParts) area += macro.vaginaArea;
  2800. let prey = getPrey(biome, area);
  2801. let line = describe("grind", prey, macro, verbose, flat);
  2802. let linesummary = summarize(prey.sum(), true);
  2803. let people = get_living_prey(prey.sum());
  2804. let preyMass = prey.sum_property("mass");
  2805. let sound = getSound("crush", preyMass);
  2806. add_victim_people("humped", prey);
  2807. update([sound, line, linesummary, newline]);
  2808. macro.arouse(20);
  2809. if (macro.maleMuskEnabled) {
  2810. male_musk((area * macro.baseMaleMuskArea * macro.muskScale) / 2, active);
  2811. }
  2812. if (macro.femaleMuskEnabled) {
  2813. female_musk(area * macro.baseFemaleMuskArea * macro.muskScale, active);
  2814. }
  2815. }
  2816. function ass_grind(active = true) {
  2817. let area = macro.assArea / 2;
  2818. let prey = getPrey(biome, area);
  2819. let line = describe("ass-grind", prey, macro, verbose, flat);
  2820. let linesummary = summarize(prey.sum(), true);
  2821. let people = get_living_prey(prey.sum());
  2822. let preyMass = prey.sum_property("mass");
  2823. let sound = getSound("crush", preyMass);
  2824. add_victim_people("ass-ground", prey);
  2825. update([sound, line, linesummary, newline]);
  2826. macro.arouse(15);
  2827. if (macro.maleMuskEnabled) {
  2828. male_musk((area * macro.baseMaleMuskArea * macro.muskScale) / 2, active);
  2829. }
  2830. if (macro.femaleMuskEnabled) {
  2831. female_musk(area * macro.baseFemaleMuskArea * macro.muskScale, active);
  2832. }
  2833. }
  2834. function anal_vore() {
  2835. let area = macro.analVoreArea;
  2836. let prey = getOnePrey(biome, area, macro.sameSizeAnalVore);
  2837. let line = describe("anal-vore", prey, macro, verbose, flat);
  2838. let linesummary = summarize(prey.sum(), false);
  2839. let people = get_living_prey(prey.sum());
  2840. let preyMass = prey.sum_property("mass");
  2841. let sound = getSound("insert", preyMass);
  2842. macro.bowels.feed(prey);
  2843. add_victim_people("anal-vore", prey);
  2844. update([sound, line, linesummary, newline]);
  2845. macro.arouse(20);
  2846. }
  2847. function sit() {
  2848. if (macro.gooMolten) {
  2849. sit_goo();
  2850. return;
  2851. }
  2852. let area = macro.assArea;
  2853. let crushed = getPrey(biome, area, macro.sameSizeStomp);
  2854. let line = describe("ass-crush", crushed, macro, verbose, flat);
  2855. let linesummary = summarize(crushed.sum(), true);
  2856. let people = get_living_prey(crushed.sum());
  2857. let crushedMass = crushed.sum_property("mass");
  2858. let sound = getSound("crush", crushedMass);
  2859. update([sound, line, linesummary, newline]);
  2860. add_victim_people("ass-crush", crushed);
  2861. macro.arouse(5);
  2862. if (macro.stenchEnabled && macro.baseAssStenchArea > 0) {
  2863. ass_stench();
  2864. }
  2865. }
  2866. function sit_goo() {
  2867. let area = macro.assArea;
  2868. let prey = getPrey(biome, area, macro.sameSizeStomp);
  2869. let line = describe("ass-goo", prey, macro, verbose, flat);
  2870. let linesummary = summarize(prey.sum(), false);
  2871. let people = get_living_prey(prey.sum());
  2872. let crushedMass = prey.sum_property("mass");
  2873. let sound = getSound("goo", crushedMass);
  2874. macro.goo.feed(prey);
  2875. update([sound, line, linesummary, newline]);
  2876. macro.arouse(15);
  2877. if (macro.stenchEnabled && macro.baseAssStenchArea > 0) {
  2878. ass_stench();
  2879. }
  2880. }
  2881. function ass_stench() {
  2882. let area = macro.assStenchArea;
  2883. let prey = getPrey(biome, area);
  2884. let line = describe("ass-stench", prey, macro, verbose, flat);
  2885. let linesummary = summarize(prey.sum(), true);
  2886. let people = get_living_prey(prey.sum());
  2887. if (prey.sum()["Person"] == undefined) return;
  2888. let preyMass = prey.sum_property("mass");
  2889. add_victim_people("ass-stench", prey);
  2890. update([line, linesummary, newline]);
  2891. macro.arouse(5);
  2892. }
  2893. function cleavage_stuff() {
  2894. let area = macro.handArea;
  2895. let prey = getPrey(biome, area);
  2896. let line = describe("cleavage-stuff", prey, macro, verbose, flat);
  2897. let linesummary = summarize(prey.sum(), false);
  2898. let people = get_living_prey(prey.sum());
  2899. macro.cleavage.add(prey);
  2900. let preyMass = prey.sum_property("mass");
  2901. let sound = getSound("insert", preyMass);
  2902. update([sound, line, linesummary, newline]);
  2903. macro.arouse(10);
  2904. }
  2905. function cleavage_crush() {
  2906. let prey = macro.cleavage.container;
  2907. macro.cleavage.container = new Container();
  2908. let line = describe("cleavage-crush", prey, macro, verbose, flat);
  2909. let linesummary = summarize(prey.sum(), true);
  2910. let people = get_living_prey(prey.sum());
  2911. let preyMass = prey.sum_property("mass");
  2912. let sound = getSound("crush", preyMass);
  2913. add_victim_people("cleavage-crush", prey);
  2914. update([sound, line, linesummary, newline]);
  2915. macro.arouse(preyMass > 0 ? 20 : 10);
  2916. }
  2917. function cleavage_drop() {
  2918. let prey = macro.cleavage.container;
  2919. macro.cleavage.container = new Container();
  2920. let line = describe("cleavage-drop", prey, macro, verbose, flat);
  2921. let linesummary = summarize(prey.sum(), true);
  2922. let people = get_living_prey(prey.sum());
  2923. let preyMass = prey.sum_property("mass");
  2924. let sound = getSound("drop", preyMass);
  2925. add_victim_people("cleavage-drop", prey);
  2926. update([sound, line, linesummary, newline]);
  2927. macro.arouse(preyMass > 0 ? 15 : 5);
  2928. }
  2929. function cleavage_absorb() {
  2930. let prey = macro.cleavage.container;
  2931. macro.cleavage.container = new Container();
  2932. let line = describe("cleavage-absorb", prey, macro, verbose, flat);
  2933. let linesummary = summarize(prey.sum(), true);
  2934. let people = get_living_prey(prey.sum());
  2935. let preyMass = prey.sum_property("mass");
  2936. let sound = getSound("insert", preyMass);
  2937. add_victim_people("cleavage-absorb", prey);
  2938. update([sound, line, linesummary, newline]);
  2939. macro.arouse(preyMass > 0 ? 15 : 5);
  2940. if (preyMass > 0) {
  2941. grow_automatic(preyMass, "breasts");
  2942. }
  2943. }
  2944. function breast_toy() {
  2945. let prey = macro.cleavage.container;
  2946. let line = describe("breast-toy", prey, macro, verbose, flat);
  2947. let linesummary = summarize(prey.sum(), false);
  2948. let people = get_living_prey(prey.sum());
  2949. let preyMass = prey.sum_property("mass");
  2950. let sound = getSound("insert", preyMass);
  2951. update([sound, line, linesummary, newline]);
  2952. macro.arouse(15);
  2953. }
  2954. function breast_crush() {
  2955. let area = macro.breastArea;
  2956. let prey = getPrey(biome, area, macro.sameSizeStomp);
  2957. let line = describe("breast-crush", prey, macro, verbose, flat);
  2958. let linesummary = summarize(prey.sum(), true);
  2959. let people = get_living_prey(prey.sum());
  2960. let preyMass = prey.sum_property("mass");
  2961. let sound = getSound("crush", preyMass);
  2962. add_victim_people("breast-crush", prey);
  2963. update([sound, line, linesummary, newline]);
  2964. if (
  2965. macro.lactationEnabled &&
  2966. macro.milkStorage.amount / macro.milkStorage.limit > 0.5
  2967. ) {
  2968. let amount = Math.min(
  2969. macro.lactationVolume,
  2970. (macro.milkStorage.amount / macro.milkStorage.limit - 0.5) *
  2971. macro.milkStorage.limit
  2972. );
  2973. breast_milk(amount);
  2974. }
  2975. macro.arouse(10);
  2976. }
  2977. function breast_vore() {
  2978. // todo nipple areas?
  2979. let area = macro.breastStretchArea / 4;
  2980. let prey = getPrey(biome, area, macro.sameSizeBreastVore);
  2981. let line = describe("breast-vore", prey, macro, verbose, flat);
  2982. let linesummary = summarize(prey.sum(), false);
  2983. let people = get_living_prey(prey.sum());
  2984. let preyMass = prey.sum_property("mass");
  2985. let sound = getSound("insert", preyMass);
  2986. add_victim_people("breast-vore", prey);
  2987. macro.breasts.feed(prey);
  2988. update([sound, line, linesummary, newline]);
  2989. if (
  2990. macro.lactationEnabled &&
  2991. macro.milkStorage.amount / macro.milkStorage.limit > 0.5
  2992. ) {
  2993. let amount = Math.min(
  2994. macro.lactationVolume,
  2995. (macro.milkStorage.amount / macro.milkStorage.limit - 0.5) *
  2996. macro.milkStorage.limit
  2997. );
  2998. breast_milk(amount);
  2999. }
  3000. macro.arouse(10);
  3001. }
  3002. function breast_milk(vol, active = true) {
  3003. if (vol == undefined) {
  3004. vol = Math.min(macro.lactationVolume, macro.milkStorage.amount);
  3005. }
  3006. macro.milkStorage.amount -= vol;
  3007. let area = Math.pow(vol, 2 / 3);
  3008. let prey = getPrey(biome, area);
  3009. let line = describe("breast-milk", prey, macro, verbose, flat).replace(
  3010. "$VOLUME",
  3011. volume(vol, unit, false)
  3012. );
  3013. let linesummary = summarize(prey.sum(), true);
  3014. let people = get_living_prey(prey.sum());
  3015. let preyMass = prey.sum_property("mass");
  3016. let sound = getSound("liquid", preyMass);
  3017. add_victim_people("milk-flood", prey);
  3018. update([sound, line, linesummary, newline], active);
  3019. macro.arouse(20);
  3020. }
  3021. function unbirth() {
  3022. let area = macro.vaginaStretchArea;
  3023. let prey = getPrey(biome, area, macro.sameSizeUnbirth);
  3024. let line = describe("unbirth", prey, macro, verbose, flat);
  3025. let linesummary = summarize(prey.sum(), false);
  3026. let people = get_living_prey(prey.sum());
  3027. let preyMass = prey.sum_property("mass");
  3028. let sound = getSound("insert", preyMass);
  3029. macro.womb.feed(prey);
  3030. add_victim_people("unbirth", prey);
  3031. update([sound, line, linesummary, newline]);
  3032. macro.arouse(20);
  3033. }
  3034. function slit_toy() {
  3035. let prey = macro.womb.contents[0].merge(macro.womb.contents[1]);
  3036. let line = describe("slit-toy", prey, macro, verbose, flat);
  3037. let linesummary = summarize(prey.sum(), false);
  3038. let people = get_living_prey(prey.sum());
  3039. let preyMass = prey.sum_property("mass");
  3040. let sound = getSound("insert", preyMass);
  3041. update([sound, line, linesummary, newline]);
  3042. macro.arouse(15);
  3043. }
  3044. function sheath_stuff() {
  3045. let area = Math.min(macro.handArea, macro.dickArea);
  3046. let prey = getPrey(biome, area);
  3047. let line = describe("sheath-stuff", prey, macro, verbose, flat);
  3048. let linesummary = summarize(prey.sum(), false);
  3049. let people = get_living_prey(prey.sum());
  3050. let preyMass = prey.sum_property("mass");
  3051. let sound = getSound("insert", preyMass);
  3052. macro.sheath.add(prey);
  3053. update([sound, line, linesummary, newline]);
  3054. macro.arouse(15);
  3055. }
  3056. function sheath_toy() {
  3057. let prey = macro.sheath.container;
  3058. let line = describe("sheath-toy", prey, macro, verbose, flat);
  3059. let linesummary = summarize(prey.sum(), false);
  3060. let people = get_living_prey(prey.sum());
  3061. let preyMass = prey.sum_property("mass");
  3062. let sound = getSound("insert", preyMass);
  3063. update([sound, line, linesummary, newline]);
  3064. macro.arouse(15);
  3065. }
  3066. function sheath_clench() {
  3067. let prey = macro.sheath.container;
  3068. macro.sheath.container = new Container();
  3069. let line = describe("sheath-clench", prey, macro, verbose, flat);
  3070. let linesummary = summarize(prey.sum(), true);
  3071. let people = get_living_prey(prey.sum());
  3072. let preyMass = prey.sum_property("mass");
  3073. let sound = getSound("crush", preyMass);
  3074. add_victim_people("sheath-crush", prey);
  3075. update([sound, line, linesummary, newline]);
  3076. macro.arouse(45);
  3077. }
  3078. function sheath_crush() {
  3079. let prey = macro.sheath.container;
  3080. macro.sheath.container = new Container();
  3081. let line = describe("sheath-crush", prey, macro, verbose, flat);
  3082. let linesummary = summarize(prey.sum(), true);
  3083. let people = get_living_prey(prey.sum());
  3084. let preyMass = prey.sum_property("mass");
  3085. let sound = getSound("crush", preyMass);
  3086. add_victim_people("sheath-crush", prey);
  3087. update([sound, line, linesummary, newline]);
  3088. macro.arouse(45);
  3089. }
  3090. function sheath_absorb() {
  3091. let prey = macro.sheath.container;
  3092. macro.sheath.container = new Container();
  3093. let line = describe("sheath-absorb", prey, macro, verbose, flat);
  3094. let linesummary = summarize(prey.sum(), true);
  3095. let people = get_living_prey(prey.sum());
  3096. let preyMass = prey.sum_property("mass");
  3097. let sound = getSound("insert", preyMass);
  3098. add_victim_people("sheath-absorb", prey);
  3099. update([sound, line, linesummary, newline]);
  3100. if (preyMass > 0) {
  3101. grow_automatic(preyMass, "cock");
  3102. }
  3103. macro.arouse(45);
  3104. }
  3105. function foreskin_stuff() {
  3106. let area = Math.min(macro.handArea, macro.dickArea);
  3107. let prey = getPrey(biome, area);
  3108. let line = describe("foreskin-stuff", prey, macro, verbose, flat);
  3109. let linesummary = summarize(prey.sum(), false);
  3110. let people = get_living_prey(prey.sum());
  3111. let preyMass = prey.sum_property("mass");
  3112. let sound = getSound("insert", preyMass);
  3113. macro.foreskin.add(prey);
  3114. update([sound, line, linesummary, newline]);
  3115. macro.arouse(15);
  3116. }
  3117. function foreskin_toy() {
  3118. let prey = macro.foreskin.container;
  3119. let line = describe("foreskin-toy", prey, macro, verbose, flat);
  3120. let linesummary = summarize(prey.sum(), false);
  3121. let people = get_living_prey(prey.sum());
  3122. let preyMass = prey.sum_property("mass");
  3123. let sound = getSound("insert", preyMass);
  3124. update([sound, line, linesummary, newline]);
  3125. macro.arouse(15);
  3126. }
  3127. function foreskin_clench() {
  3128. let prey = macro.foreskin.container;
  3129. macro.foreskin.container = new Container();
  3130. let line = describe("foreskin-clench", prey, macro, verbose, flat);
  3131. let linesummary = summarize(prey.sum(), true);
  3132. let people = get_living_prey(prey.sum());
  3133. let preyMass = prey.sum_property("mass");
  3134. let sound = getSound("crush", preyMass);
  3135. add_victim_people("foreskin-crush", prey);
  3136. update([sound, line, linesummary, newline]);
  3137. macro.arouse(45);
  3138. }
  3139. function foreskin_crush() {
  3140. let prey = macro.foreskin.container;
  3141. macro.foreskin.container = new Container();
  3142. let line = describe("foreskin-crush", prey, macro, verbose, flat);
  3143. let linesummary = summarize(prey.sum(), true);
  3144. let people = get_living_prey(prey.sum());
  3145. let preyMass = prey.sum_property("mass");
  3146. let sound = getSound("crush", preyMass);
  3147. add_victim_people("foreskin-crush", prey);
  3148. update([sound, line, linesummary, newline]);
  3149. macro.arouse(45);
  3150. }
  3151. function foreskin_absorb() {
  3152. let prey = macro.foreskin.container;
  3153. macro.foreskin.container = new Container();
  3154. let line = describe("foreskin-absorb", prey, macro, verbose, flat);
  3155. let linesummary = summarize(prey.sum(), true);
  3156. let people = get_living_prey(prey.sum());
  3157. let preyMass = prey.sum_property("mass");
  3158. let sound = getSound("insert", preyMass);
  3159. add_victim_people("foreskin-absorb", prey);
  3160. update([sound, line, linesummary, newline]);
  3161. if (preyMass > 0) {
  3162. grow_automatic(preyMass, "cock");
  3163. }
  3164. macro.arouse(45);
  3165. }
  3166. function cockslap(active = true) {
  3167. let area = macro.dickArea;
  3168. let prey = getPrey(biome, area);
  3169. let line = describe("cockslap", prey, macro, verbose, flat);
  3170. let linesummary = summarize(prey.sum(), true);
  3171. let people = get_living_prey(prey.sum());
  3172. let preyMass = prey.sum_property("mass");
  3173. let sound = getSound("crush", preyMass);
  3174. add_victim_people("cock-slap", prey);
  3175. update([sound, line, linesummary, newline]);
  3176. macro.arouse(15);
  3177. if (macro.maleMuskEnabled) {
  3178. male_musk((area * macro.baseMaleMuskArea * macro.muskScale) / 2, active);
  3179. }
  3180. }
  3181. function cock_vore(active = true) {
  3182. let area = macro.dickStretchGirth;
  3183. let prey = getPrey(biome, area, macro.sameSizeCockVore);
  3184. let line = describe("cock-vore", prey, macro, verbose, flat);
  3185. let linesummary = summarize(prey.sum(), false);
  3186. let people = get_living_prey(prey.sum());
  3187. let preyMass = prey.sum_property("mass");
  3188. let sound = getSound("insert", preyMass);
  3189. macro.balls.feed(prey);
  3190. add_victim_people("cock-vore", prey);
  3191. update([sound, line, linesummary, newline]);
  3192. macro.arouse(20);
  3193. if (macro.maleMuskEnabled) {
  3194. male_musk((area * macro.baseMaleMuskArea * macro.muskScale) / 2, active);
  3195. }
  3196. }
  3197. function ball_smother(active = true) {
  3198. let area = macro.ballArea * 2;
  3199. let prey = getPrey(biome, area);
  3200. let line = describe("ball-smother", prey, macro, verbose, flat);
  3201. let linesummary = summarize(prey.sum(), true);
  3202. let people = get_living_prey(prey.sum());
  3203. let preyMass = prey.sum_property("mass");
  3204. let sound = getSound("crush", preyMass);
  3205. add_victim_people("ball-smother", prey);
  3206. update([sound, line, linesummary, newline]);
  3207. macro.arouse(10);
  3208. if (macro.maleMuskEnabled) {
  3209. male_musk(area * macro.baseMaleMuskArea * macro.muskScale, active);
  3210. }
  3211. }
  3212. function male_musk(area, active = true) {
  3213. let prey = getPrey(biome, area);
  3214. let line = describe("male-musk", prey, macro, verbose, flat);
  3215. let linesummary = summarize(prey.sum(), true);
  3216. let people = get_living_prey(prey.sum());
  3217. if (get_living_prey(prey.sum()) == 0) return;
  3218. let preyMass = prey.sum_property("mass");
  3219. add_victim_people("male-musk", prey);
  3220. update([line, linesummary, newline], active);
  3221. }
  3222. function male_spurt(vol, active = true) {
  3223. let area = Math.pow(vol, 2 / 3);
  3224. let prey = getPrey(biome, area);
  3225. let line = describe("male-spurt", prey, macro, verbose, flat, vol).replace(
  3226. "$VOLUME",
  3227. volume(vol, unit, true)
  3228. );
  3229. let linesummary = summarize(prey.sum(), true);
  3230. let people = get_living_prey(prey.sum());
  3231. let preyMass = prey.sum_property("mass");
  3232. let sound = getSound("drip", preyMass);
  3233. add_victim_people("cum-flood", prey);
  3234. update([sound, line, linesummary, newline], active);
  3235. if (macro.maleMuskEnabled) {
  3236. male_spurt_musk(area * macro.baseMaleMuskArea * macro.muskScale, active);
  3237. }
  3238. }
  3239. function male_spurt_musk(area, active = true) {
  3240. let prey = getPrey(biome, area);
  3241. let line = describe("male-spurt-musk", prey, macro, verbose, flat);
  3242. let linesummary = summarize(prey.sum(), true);
  3243. let people = get_living_prey(prey.sum());
  3244. if (get_living_prey(prey.sum()) == 0) return;
  3245. let preyMass = prey.sum_property("mass");
  3246. add_victim_people("male-spurt-musk", prey);
  3247. update([line, linesummary, newline], active);
  3248. macro.arouse(5);
  3249. }
  3250. function male_orgasm(vol, active = true) {
  3251. let area = Math.pow(vol, 2 / 3);
  3252. let prey = getPrey(biome, area);
  3253. let line = describe("male-orgasm", prey, macro, verbose, flat, vol).replace(
  3254. "$VOLUME",
  3255. volume(vol, unit, true)
  3256. );
  3257. let linesummary = summarize(prey.sum(), true);
  3258. let people = get_living_prey(prey.sum());
  3259. let preyMass = prey.sum_property("mass");
  3260. let sound = getSound("liquid", preyMass);
  3261. add_victim_people("cum-flood", prey);
  3262. update([sound, line, linesummary, newline], active);
  3263. if (macro.maleMuskEnabled) {
  3264. male_orgasm_musk(area * macro.baseMaleMuskArea * macro.muskScale, active);
  3265. }
  3266. }
  3267. function male_orgasm_musk(area, active = true) {
  3268. let prey = getPrey(biome, area);
  3269. let line = describe("male-orgasm-musk", prey, macro, verbose, flat);
  3270. let linesummary = summarize(prey.sum(), true);
  3271. let people = get_living_prey(prey.sum());
  3272. if (get_living_prey(prey.sum()) == 0) return;
  3273. let preyMass = prey.sum_property("mass");
  3274. add_victim_people("male-orgasm-musk", prey);
  3275. update([line, linesummary, newline], active);
  3276. macro.arouse(5);
  3277. }
  3278. function female_musk(area, active = true) {
  3279. let prey = getPrey(biome, area);
  3280. let line = describe("female-musk", prey, macro, verbose, flat);
  3281. let linesummary = summarize(prey.sum(), true);
  3282. let people = get_living_prey(prey.sum());
  3283. if (get_living_prey(prey.sum()) == 0) return;
  3284. let preyMass = prey.sum_property("mass");
  3285. add_victim_people("female-musk", prey);
  3286. update([line, linesummary, newline], active);
  3287. macro.arouse(5);
  3288. }
  3289. function female_spurt(vol, active = true) {
  3290. let area = Math.pow(vol, 2 / 3);
  3291. let prey = getPrey(biome, area);
  3292. let line = describe("female-spurt", prey, macro, verbose, flat).replace(
  3293. "$VOLUME",
  3294. volume(vol, unit, false)
  3295. );
  3296. let linesummary = summarize(prey.sum(), true);
  3297. let people = get_living_prey(prey.sum());
  3298. let preyMass = prey.sum_property("mass");
  3299. let sound = getSound("drip", preyMass);
  3300. add_victim_people("femcum-flood", prey);
  3301. update([sound, line, linesummary, newline], active);
  3302. if (macro.femaleMuskEnabled) {
  3303. female_spurt_musk(
  3304. area * macro.baseFemaleMuskArea * macro.muskScale,
  3305. active
  3306. );
  3307. }
  3308. }
  3309. function female_spurt_musk(area, active = true) {
  3310. let prey = getPrey(biome, area);
  3311. let line = describe("female-spurt-musk", prey, macro, verbose, flat);
  3312. let linesummary = summarize(prey.sum(), true);
  3313. let people = get_living_prey(prey.sum());
  3314. if (get_living_prey(prey.sum()) == 0) return;
  3315. let preyMass = prey.sum_property("mass");
  3316. add_victim_people("female-spurt-musk", prey);
  3317. update([line, linesummary, newline], active);
  3318. macro.arouse(5);
  3319. }
  3320. function female_orgasm(vol, active = true) {
  3321. let area = Math.pow(vol, 2 / 3);
  3322. let prey = getPrey(biome, area);
  3323. let line = describe("female-orgasm", prey, macro, verbose, flat).replace(
  3324. "$VOLUME",
  3325. volume(vol, unit, false)
  3326. );
  3327. let linesummary = summarize(prey.sum(), true);
  3328. let people = get_living_prey(prey.sum());
  3329. let preyMass = prey.sum_property("mass");
  3330. let sound = getSound("liquid", preyMass);
  3331. add_victim_people("femcum-flood", prey);
  3332. update([sound, line, linesummary, newline], active);
  3333. if (macro.femaleMuskEnabled) {
  3334. female_orgasm_musk(
  3335. area * macro.baseFemaleMuskArea * macro.muskScale,
  3336. active
  3337. );
  3338. }
  3339. }
  3340. function female_orgasm_musk(area, active = true) {
  3341. let prey = getPrey(biome, area);
  3342. let line = describe("female-orgasm-musk", prey, macro, verbose, flat);
  3343. let linesummary = summarize(prey.sum(), true);
  3344. let people = get_living_prey(prey.sum());
  3345. if (get_living_prey(prey.sum()) == 0) return;
  3346. let preyMass = prey.sum_property("mass");
  3347. add_victim_people("female-orgasm-musk", prey);
  3348. update([line, linesummary, newline], active);
  3349. macro.arouse(5);
  3350. }
  3351. function tail_slap() {
  3352. let area = macro.tailArea * macro.tailCount;
  3353. let prey = getPrey(biome, area);
  3354. let line = describe("tail-slap", prey, macro, verbose, flat);
  3355. let linesummary = summarize(prey.sum(), true);
  3356. let people = get_living_prey(prey.sum());
  3357. let preyMass = prey.sum_property("mass");
  3358. let sound = getSound("crush", preyMass);
  3359. add_victim_people("tail-slap", prey);
  3360. update([sound, line, linesummary, newline]);
  3361. macro.arouse(5);
  3362. }
  3363. function tail_vore_only() {
  3364. tail_vore(1);
  3365. }
  3366. function tail_vore_one() {
  3367. tail_vore(1);
  3368. }
  3369. function tail_vore_some() {
  3370. tail_vore(Math.floor(Math.random() * macro.tailCount) + 1);
  3371. }
  3372. function tail_vore_all() {
  3373. tail_vore(macro.tailCount);
  3374. }
  3375. function tail_vore(count) {
  3376. let lines = [];
  3377. let totalPrey = new Container();
  3378. if (count <= 3) {
  3379. for (let i = 0; i < count; i++) {
  3380. let area = macro.tailStretchGirth;
  3381. let prey = getPrey(biome, area, macro.sameSizeTailVore);
  3382. totalPrey = totalPrey.merge(prey);
  3383. let line = describe("tail-vore", prey, macro, verbose, flat);
  3384. lines.push(line);
  3385. }
  3386. } else {
  3387. let area = macro.tailStretchGirth;
  3388. let i = 0;
  3389. for (i = 0; i < 10 && i < count; i++) {
  3390. let prey = getPrey(biome, area, macro.sameSizeTailVore);
  3391. for (var key in prey.contents) {
  3392. if (prey.contents.hasOwnProperty(key)) {
  3393. prey.contents[key].multiply(Math.ceil((count - i) / 10));
  3394. }
  3395. }
  3396. totalPrey = totalPrey.merge(prey);
  3397. }
  3398. let line = describe("tails-vore", totalPrey, macro, verbose, flat).replace(
  3399. "$COUNT",
  3400. macro.tailCount
  3401. );
  3402. lines.push(line);
  3403. }
  3404. let linesummary = summarize(totalPrey.sum(), false);
  3405. lines.push(linesummary);
  3406. lines.push(newline);
  3407. let people = get_living_prey(totalPrey.sum());
  3408. let preyMass = totalPrey.sum_property("mass");
  3409. let sound = getSound("swallow", preyMass);
  3410. macro.tail.feed(totalPrey);
  3411. add_victim_people("tail-vore", totalPrey);
  3412. update([sound].concat(lines));
  3413. macro.arouse(5);
  3414. }
  3415. function pouch_stuff() {
  3416. let area = macro.handArea;
  3417. let prey = getPrey(biome, area);
  3418. let line = describe("pouch-stuff", prey, macro, verbose, flat);
  3419. let linesummary = summarize(prey.sum(), false);
  3420. let people = get_living_prey(prey.sum());
  3421. let preyMass = prey.sum_property("mass");
  3422. let sound = getSound("insert", preyMass);
  3423. macro.pouch.add(prey);
  3424. update([sound, line, linesummary, newline]);
  3425. macro.arouse(5);
  3426. }
  3427. function pouch_rub() {
  3428. let prey = macro.pouch.container;
  3429. let line = describe("pouch-rub", prey, macro, verbose, flat);
  3430. let linesummary = summarize(prey.sum(), false);
  3431. update([line, linesummary, newline]);
  3432. }
  3433. function pouch_eat() {
  3434. let prey = macro.pouch.container;
  3435. macro.pouch.container = new Container();
  3436. let line = describe("pouch-eat", prey, macro, verbose, flat);
  3437. let linesummary = summarize(prey.sum(), false);
  3438. let people = get_living_prey(prey.sum());
  3439. let preyMass = prey.sum_property("mass");
  3440. let sound = getSound("swallow", preyMass);
  3441. macro.stomach.feed(prey);
  3442. add_victim_people("eaten", prey);
  3443. update([sound, line, linesummary, newline]);
  3444. macro.arouse(5);
  3445. }
  3446. function pouch_absorb() {
  3447. let prey = macro.pouch.container;
  3448. macro.pouch.container = new Container();
  3449. let line = describe("pouch-absorb", prey, macro, verbose, flat);
  3450. let linesummary = summarize(prey.sum(), false);
  3451. let people = get_living_prey(prey.sum());
  3452. let preyMass = prey.sum_property("mass");
  3453. let sound = getSound("insert", preyMass);
  3454. macro.stomach.feed(prey);
  3455. add_victim_people("pouch-absorb", prey);
  3456. update([sound, line, linesummary, newline]);
  3457. macro.arouse(25);
  3458. }
  3459. function soul_vore() {
  3460. let area = macro.height * macro.height;
  3461. let prey = getPrey(biome, area);
  3462. let line = describe("soul-vore", prey, macro, verbose, flat);
  3463. let linesummary = summarize(prey.sum(), false);
  3464. let people = get_living_prey(prey.sum());
  3465. let preyMass = prey.sum_property("mass");
  3466. let sound = getSound("swallow", preyMass);
  3467. macro.souls.feed(prey);
  3468. update([sound, line, linesummary, newline]);
  3469. macro.arouse(15);
  3470. }
  3471. function soul_absorb_paw() {
  3472. let prey = getPrey(biome, macro.pawArea, macro.sameSizeStomp);
  3473. let line = describe("soul-absorb-paw", prey, macro, verbose, flat);
  3474. let linesummary = summarize(prey.sum(), true);
  3475. let people = get_living_prey(prey.sum());
  3476. let preyMass = prey.sum_property("mass");
  3477. let sound = getSound("crush", preyMass);
  3478. add_victim_people("soul-paw", prey);
  3479. update([sound, line, linesummary, newline]);
  3480. macro.arouse(25);
  3481. }
  3482. function belch(vol, active = true) {
  3483. if (vol == undefined) {
  3484. vol = Math.min(macro.gasStorage.amount, macro.gasStorage.limit / 3);
  3485. }
  3486. macro.gasStorage.amount -= vol;
  3487. let area = Math.pow(vol, 2 / 3);
  3488. let prey = getPrey(biome, area);
  3489. let line = describe("belch", prey, macro, verbose, flat).replace(
  3490. "$VOLUME",
  3491. volume(vol, unit, false)
  3492. );
  3493. let linesummary = summarize(prey.sum(), true);
  3494. let people = get_living_prey(prey.sum());
  3495. let preyMass = prey.sum_property("mass");
  3496. let sound = getSound("belch", preyMass);
  3497. add_victim_people("gas-belch", prey);
  3498. update([sound, line, linesummary, newline], active);
  3499. }
  3500. function fart(vol, active = true) {
  3501. if (vol == undefined) {
  3502. vol = Math.min(macro.gasStorage.amount, macro.gasStorage.limit / 2);
  3503. }
  3504. macro.gasStorage.amount -= vol;
  3505. let area = Math.pow(vol, 2 / 3);
  3506. let prey = getPrey(biome, area);
  3507. let line = describe("fart", prey, macro, verbose, flat).replace(
  3508. "$VOLUME",
  3509. volume(vol, unit, false)
  3510. );
  3511. let linesummary = summarize(prey.sum(), true);
  3512. let people = get_living_prey(prey.sum());
  3513. let preyMass = prey.sum_property("mass");
  3514. let sound = getSound("fart", preyMass);
  3515. add_victim_people("gas-fart", prey);
  3516. update([sound, line, linesummary, newline], active);
  3517. }
  3518. function wear_shoes() {
  3519. macro.shoe.container = macro.shoe.container.merge(macro.paws.container);
  3520. let line = describe(
  3521. "wear-shoe",
  3522. macro.shoe.container.merge(macro.paws.container, flat),
  3523. macro,
  3524. verbose
  3525. );
  3526. macro.paws.container = new Container();
  3527. let summary = summarize(macro.shoe.container.sum(), false);
  3528. macro.footShoeWorn = true;
  3529. footwearUpdate();
  3530. macro.paws.container = macro.shoeTrapped;
  3531. macro.shoeTrapped = new Container();
  3532. update([line, summary, newline]);
  3533. }
  3534. function remove_shoes() {
  3535. macro.footShoeWorn = false;
  3536. macro.shoeTrapped = macro.paws.container;
  3537. macro.paws.container = new Container();
  3538. let line = describe(
  3539. "remove-shoe",
  3540. macro.shoe.container,
  3541. macro,
  3542. verbose,
  3543. flat
  3544. );
  3545. let summary = summarize(macro.shoe.container.sum(), false);
  3546. footwearUpdate();
  3547. update([line, summary, newline]);
  3548. if (macro.stenchEnabled) {
  3549. remove_shoes_stench();
  3550. }
  3551. }
  3552. function remove_shoes_stench() {
  3553. let area = macro.pawStenchArea * 2;
  3554. let prey = getPrey(biome, area);
  3555. let line = describe("paw-stench", prey, macro, verbose, flat);
  3556. let linesummary = summarize(prey.sum(), true);
  3557. let people = get_living_prey(prey.sum());
  3558. if (get_living_prey(prey.sum()) == 0) return;
  3559. let preyMass = prey.sum_property("mass");
  3560. add_victim_people("paw-stench", prey);
  3561. update([line, linesummary, newline]);
  3562. macro.arouse(5);
  3563. }
  3564. function wear_socks() {
  3565. macro.sock.container = macro.sock.container.merge(macro.paws.container);
  3566. let line = describe("wear-sock", macro.sock.container, macro, verbose, flat);
  3567. macro.paws.container = new Container();
  3568. let summary = summarize(macro.sock.container.sum(), false);
  3569. macro.footSockWorn = true;
  3570. macro.paws.container = macro.sockTrapped;
  3571. macro.sockTrapped = new Container();
  3572. footwearUpdate();
  3573. update([line, summary, newline]);
  3574. }
  3575. function remove_socks() {
  3576. macro.footSockWorn = false;
  3577. macro.sockTrapped = macro.paws.container;
  3578. macro.paws.container = new Container();
  3579. let line = describe(
  3580. "remove-sock",
  3581. macro.sock.container,
  3582. macro,
  3583. verbose,
  3584. flat
  3585. );
  3586. let summary = summarize(macro.sock.container.sum(), false);
  3587. footwearUpdate();
  3588. update([line, summary, newline]);
  3589. if (macro.stenchEnabled) {
  3590. remove_socks_stench();
  3591. }
  3592. }
  3593. function remove_socks_stench() {
  3594. let area = macro.pawStenchArea * 2;
  3595. let prey = getPrey(biome, area);
  3596. let line = describe("paw-stench", prey, macro, verbose, flat);
  3597. let linesummary = summarize(prey.sum(), true);
  3598. let people = get_living_prey(prey.sum());
  3599. if (get_living_prey(prey.sum()) == 0) return;
  3600. let preyMass = prey.sum_property("mass");
  3601. add_victim_people("paw-stench", prey);
  3602. update([line, linesummary, newline]);
  3603. macro.arouse(5);
  3604. }
  3605. function stuff_shoes() {
  3606. let prey = getPrey(biome, macro.pawArea / 5, false);
  3607. macro.shoe.add(prey);
  3608. let line = describe("stuff-shoe", prey, macro, verbose, flat);
  3609. let summary = summarize(prey.sum(), false);
  3610. update([line, summary, newline]);
  3611. }
  3612. function stuff_socks() {
  3613. let prey = getPrey(biome, macro.pawArea / 5, false);
  3614. macro.sock.add(prey);
  3615. let line = describe("stuff-sock", prey, macro, verbose, flat);
  3616. let summary = summarize(prey.sum(), false);
  3617. update([line, summary, newline]);
  3618. }
  3619. function dump_shoes() {
  3620. let prey = macro.shoe.container;
  3621. macro.shoe.container = new Container();
  3622. let line = describe("dump-shoe", prey, macro, verbose, flat);
  3623. let summary = summarize(prey.sum(), false);
  3624. update([line, summary, newline]);
  3625. }
  3626. function dump_socks() {
  3627. let prey = macro.sock.container;
  3628. macro.sock.container = new Container();
  3629. let line = describe("dump-sock", prey, macro, verbose, flat);
  3630. let summary = summarize(prey.sum(), false);
  3631. update([line, summary, newline]);
  3632. }
  3633. function footwearUpdate() {
  3634. disable_button("wear_shoes");
  3635. disable_button("remove_shoes");
  3636. disable_button("wear_socks");
  3637. disable_button("remove_socks");
  3638. disable_button("stuff_shoes");
  3639. disable_button("dump_shoes");
  3640. disable_button("stuff_socks");
  3641. disable_button("dump_socks");
  3642. if (macro.footShoeEnabled) {
  3643. if (macro.footShoeWorn) {
  3644. enable_button("remove_shoes");
  3645. } else {
  3646. enable_button("stuff_shoes");
  3647. enable_button("dump_shoes");
  3648. enable_button("wear_shoes");
  3649. }
  3650. }
  3651. if (macro.footSockEnabled) {
  3652. if (!macro.footShoeEnabled || !macro.footShoeWorn) {
  3653. if (macro.footSockWorn) {
  3654. enable_button("remove_socks");
  3655. } else {
  3656. enable_button("wear_socks");
  3657. }
  3658. }
  3659. if (!macro.footSockWorn) {
  3660. enable_button("stuff_socks");
  3661. enable_button("dump_socks");
  3662. }
  3663. }
  3664. }
  3665. function piss(vol, active = true) {
  3666. if (vol == undefined) {
  3667. vol = macro.pissStorage.amount;
  3668. }
  3669. macro.pissStorage.amount -= vol;
  3670. let area = Math.pow(vol, 2 / 3);
  3671. let prey = getPrey(biome, area);
  3672. let line = describe("piss", prey, macro, verbose, flat).replace(
  3673. "$VOLUME",
  3674. volume(vol, unit, false)
  3675. );
  3676. let linesummary = summarize(prey.sum(), true);
  3677. let people = get_living_prey(prey.sum());
  3678. let preyMass = prey.sum_property("mass");
  3679. let sound = getSound("liquid", preyMass);
  3680. add_victim_people("piss", prey);
  3681. update([sound, line, linesummary, newline], active);
  3682. macro.arouse(20);
  3683. if (macro.stenchEnabled && macro.basePissStenchArea > 0) {
  3684. piss_stench(area * macro.basePissStenchArea * macro.stenchScale, active);
  3685. }
  3686. }
  3687. function piss_stench(area, active = true) {
  3688. let prey = getPrey(biome, area);
  3689. let line = describe("piss-stench", prey, macro, verbose, flat);
  3690. let linesummary = summarize(prey.sum(), true);
  3691. let people = get_living_prey(prey.sum());
  3692. if (get_living_prey(prey.sum()) == 0) return;
  3693. let preyMass = prey.sum_property("mass");
  3694. add_victim_people("piss-stench", prey);
  3695. update([line, linesummary, newline], active);
  3696. macro.arouse(5);
  3697. }
  3698. function bladder_vore() {
  3699. let prey = getPrey(
  3700. biome,
  3701. macro.urethraStretchArea,
  3702. macro.sameSizeBladderVore
  3703. );
  3704. let line = describe("bladder-vore", prey, macro, verbose, flat);
  3705. let linesummary = summarize(prey.sum(), false);
  3706. let people = get_living_prey(prey.sum());
  3707. let preyMass = prey.sum_property("mass");
  3708. let sound = getSound("insert", preyMass);
  3709. add_victim_people("bladder-vore", prey);
  3710. macro.bladder.feed(prey);
  3711. update([sound, line, linesummary, newline]);
  3712. macro.arouse(20);
  3713. }
  3714. function scat(vol, active = true) {
  3715. if (vol == undefined) {
  3716. vol = macro.scatStorage.amount;
  3717. }
  3718. let area = Math.pow(vol, 2 / 3) / 2;
  3719. let scatLength = Math.pow(vol, 1 / 3) * 4;
  3720. let prey = getPrey(biome, area);
  3721. let line = describe("scat", prey, macro, verbose, flat)
  3722. .replace("$MASS", mass(vol * 1000, unit, true))
  3723. .replace("$LENGTH", length(scatLength, unit, true));
  3724. let linesummary = summarize(prey.sum(), true);
  3725. let people = get_living_prey(prey.sum());
  3726. let preyMass = prey.sum_property("mass");
  3727. let sound = getSound("scat", preyMass);
  3728. macro.scatStorage.victims = new Container();
  3729. add_victim_people("scat", prey);
  3730. update([sound, line, linesummary, newline], active);
  3731. macro.scatStorage.amount -= vol;
  3732. macro.arouse(50);
  3733. if (macro.stenchEnabled && macro.baseScatStenchArea > 0) {
  3734. scat_stench(area * macro.baseScatStenchArea * macro.stenchScale, active);
  3735. }
  3736. }
  3737. function scat_stench(area) {
  3738. let prey = getPrey(biome, area);
  3739. let line = describe("scat-stench", prey, macro, verbose, flat);
  3740. let linesummary = summarize(prey.sum(), true);
  3741. let people = get_living_prey(prey.sum());
  3742. if (get_living_prey(prey.sum()) == 0) return;
  3743. let preyMass = prey.sum_property("mass");
  3744. add_victim_people("scat-stench", prey);
  3745. update([line, linesummary, newline]);
  3746. macro.arouse(5);
  3747. }
  3748. function setButton(button, state) {
  3749. if (state) {
  3750. enable_button(button);
  3751. } else {
  3752. disable_button(button);
  3753. }
  3754. }
  3755. function gooButtons(molten) {
  3756. setButton("melt", !molten);
  3757. setButton("solidify", molten);
  3758. setButton("flood", molten);
  3759. if (macro.oralVore) {
  3760. setButton("goo_stomach_pull", molten);
  3761. setButton("goo_stomach_push", molten);
  3762. }
  3763. if (macro.analVore) {
  3764. setButton("goo_bowels_pull", molten);
  3765. setButton("goo_bowels_push", molten);
  3766. }
  3767. if (macro.femaleParts) {
  3768. setButton("goo_womb_pull", molten);
  3769. setButton("goo_womb_push", molten);
  3770. }
  3771. if (macro.maleParts) {
  3772. setButton("goo_balls_pull", molten);
  3773. setButton("goo_balls_push", molten);
  3774. }
  3775. if (macro.hasBreasts) {
  3776. setButton("goo_breasts_pull", molten);
  3777. setButton("goo_breasts_push", molten);
  3778. }
  3779. if (macro.pawVoreEnabled) {
  3780. setButton("goo_paws_pull", molten);
  3781. setButton("goo_paws_push", molten);
  3782. }
  3783. if (macro.hasTail) {
  3784. setButton("goo_tail_pull", molten);
  3785. setButton("goo_tail_push", molten);
  3786. }
  3787. if (macro.gooDigestManual) {
  3788. setButton("digest_goo", molten);
  3789. }
  3790. }
  3791. function melt() {
  3792. macro.gooMolten = true;
  3793. gooButtons(macro.gooMolten);
  3794. let prey = new Container();
  3795. prey = prey.merge(macro.paws.container);
  3796. macro.paws.container = new Container();
  3797. if (macro.footSockWorn) {
  3798. prey = prey.merge(macro.sock.container);
  3799. macro.sock.container = new Container();
  3800. } else if (macro.footShoeWorn) {
  3801. prey = prey.merge(macro.shoe.container);
  3802. macro.shoe.container = new Container();
  3803. }
  3804. let line = describe("melt", prey, macro, verbose, flat);
  3805. macro.goo.feed(prey);
  3806. update([line, newline]);
  3807. }
  3808. function flood() {
  3809. let area = Math.pow(macro.totalMass / 1000, 2 / 3);
  3810. let prey = getPrey(biome, area, macro.sameSizeStomp);
  3811. let line = describe("flood", prey, macro, verbose, flat);
  3812. let linesummary = summarize(prey.sum(), false);
  3813. let people = get_living_prey(prey.sum());
  3814. let preyMass = prey.sum_property("mass");
  3815. let sound = getSound("goo", preyMass);
  3816. macro.goo.feed(prey);
  3817. update([sound, line, linesummary, newline]);
  3818. macro.arouse(5);
  3819. }
  3820. function solidify() {
  3821. macro.gooMolten = false;
  3822. gooButtons(macro.gooMolten);
  3823. let prey = new Container();
  3824. for (let i = 0; i < macro.goo.contents.length; i++) {
  3825. prey = prey.merge(macro.goo.contents[i]);
  3826. macro.goo.contents[i] = new Container();
  3827. }
  3828. let line = describe("solidify", prey, macro, verbose, flat);
  3829. let linesummary = summarize(prey.sum(), true);
  3830. let people = get_living_prey(prey.sum());
  3831. let preyMass = prey.sum_property("mass");
  3832. let sound = getSound("insert", preyMass);
  3833. if (macro.gooDigestion) {
  3834. update([sound, line, linesummary, newline]);
  3835. add_victim_people("goo", prey);
  3836. } else {
  3837. update([sound, line, newline]);
  3838. }
  3839. }
  3840. function vomit() {
  3841. let prey = new Container();
  3842. for (let i = 0; i < macro.stomach.contents.length; i++) {
  3843. prey = prey.merge(macro.stomach.contents[i]);
  3844. macro.stomach.contents[i] = new Container();
  3845. }
  3846. let line = describe("vomit", prey, macro, verbose, flat);
  3847. let linesummary = summarize(prey.sum(), true);
  3848. let preyMass = prey.sum_property("mass");
  3849. let sound = getSound("vomit", preyMass);
  3850. update([sound, line, linesummary, newline]);
  3851. add_victim_people("vomit", prey);
  3852. }
  3853. function move_prey(from, to) {
  3854. let prey = new Container();
  3855. for (let i = 0; i < from.contents.length; i++) {
  3856. prey = prey.merge(from.contents[i]);
  3857. from.contents[i] = new Container();
  3858. }
  3859. to.feed(prey);
  3860. return prey;
  3861. }
  3862. function goo_move_prey(from, to, name) {
  3863. let prey = move_prey(from, to);
  3864. let line = describe(name, prey, macro, verbose, flat);
  3865. let linesummary = summarize(prey.sum(), false);
  3866. let preyMass = prey.sum_property("mass");
  3867. let sound = getSound("goo", preyMass);
  3868. update([sound, line, linesummary, newline]);
  3869. }
  3870. function goo_stomach_pull() {
  3871. return goo_move_prey(macro.stomach, macro.goo, "goo-stomach-pull");
  3872. }
  3873. function goo_stomach_push() {
  3874. return goo_move_prey(macro.goo, macro.stomach, "goo-stomach-push");
  3875. }
  3876. function goo_bowels_pull() {
  3877. return goo_move_prey(macro.bowels, macro.goo, "goo-bowels-pull");
  3878. }
  3879. function goo_bowels_push() {
  3880. return goo_move_prey(macro.goo, macro.bowels, "goo-bowels-push");
  3881. }
  3882. function goo_womb_pull() {
  3883. return goo_move_prey(macro.womb, macro.goo, "goo-womb-pull");
  3884. }
  3885. function goo_womb_push() {
  3886. return goo_move_prey(macro.goo, macro.womb, "goo-womb-push");
  3887. }
  3888. function goo_balls_pull() {
  3889. return goo_move_prey(macro.balls, macro.goo, "goo-balls-pull");
  3890. }
  3891. function goo_balls_push() {
  3892. return goo_move_prey(macro.goo, macro.balls, "goo-balls-push");
  3893. }
  3894. function goo_breasts_pull() {
  3895. return goo_move_prey(macro.breasts, macro.goo, "goo-breasts-pull");
  3896. }
  3897. function goo_breasts_push() {
  3898. return goo_move_prey(macro.goo, macro.breasts, "goo-breasts-push");
  3899. }
  3900. function goo_tail_pull() {
  3901. return goo_move_prey(macro.tail, macro.goo, "goo-tail-pull");
  3902. }
  3903. function goo_tail_push() {
  3904. return goo_move_prey(macro.goo, macro.tail, "goo-tail-push");
  3905. }
  3906. function goo_paws_pull() {
  3907. return goo_move_prey(macro.pawsVore, macro.goo, "goo-paws-pull");
  3908. }
  3909. function goo_paws_push() {
  3910. return goo_move_prey(macro.goo, macro.pawsVore, "goo-paws-push");
  3911. }
  3912. function paw_vore() {
  3913. let prey = new Container();
  3914. let lines = [];
  3915. if (
  3916. (!macro.footShoeEnabled || !macro.footShoeWorn) &&
  3917. (!macro.footSockEnabled || !macro.footSockWorn)
  3918. ) {
  3919. let area = macro.pawArea;
  3920. prey = prey.merge(getPrey(biome, area, macro.sameSizePawVore));
  3921. lines.push(describe("paw-vore", prey, macro, verbose, flat));
  3922. }
  3923. if (macro.paws.container.count > 0) {
  3924. prey = prey.merge(macro.paws.container);
  3925. lines.push(
  3926. describe("paw-vore-toes", macro.paws.container, macro, verbose, flat)
  3927. );
  3928. macro.paws.container = new Container();
  3929. }
  3930. if (
  3931. macro.shoe.container.count > 0 &&
  3932. macro.footShoeWorn &&
  3933. (!macro.footSockEnabled || !macro.footSockWorn)
  3934. ) {
  3935. prey = prey.merge(macro.shoe.container);
  3936. lines.push(
  3937. describe("paw-vore-toes", macro.shoe.container, macro, verbose, flat)
  3938. );
  3939. macro.shoe.container = new Container();
  3940. }
  3941. if (macro.sock.container.count > 0 && macro.footSockWorn) {
  3942. prey = prey.merge(macro.sock.container);
  3943. lines.push(
  3944. describe("paw-vore-toes", macro.sock.container, macro, verbose, flat)
  3945. );
  3946. macro.sock.container = new Container();
  3947. }
  3948. if (lines.length == 0) {
  3949. if (macro.footSockWorn) {
  3950. update([
  3951. "Your " +
  3952. macro.footOnlyDesc(true) +
  3953. " have no prey to absorb in your socks.",
  3954. newline,
  3955. ]);
  3956. } else if (macro.footShoeWorn) {
  3957. update([
  3958. "Your " +
  3959. macro.footOnlyDesc(true) +
  3960. " have no prey to absorb in your " +
  3961. macro.footDesc(true) +
  3962. ".",
  3963. newline,
  3964. ]);
  3965. } else {
  3966. update(["Nothing happens...", newline]);
  3967. }
  3968. return;
  3969. }
  3970. let linesummary = summarize(prey.sum(), false);
  3971. let people = get_living_prey(prey.sum());
  3972. let preyMass = prey.sum_property("mass");
  3973. let sound = getSound("insert", preyMass);
  3974. macro.pawsVore.feed(prey);
  3975. add_victim_people("paw-vore", prey);
  3976. update([sound].concat(lines).concat([linesummary, newline]));
  3977. macro.arouse(5);
  3978. }
  3979. function breath(type, style) {
  3980. let area = macro.breathArea;
  3981. let prey = new Container();
  3982. if (style == "line") {
  3983. area *= (Math.log10(macro.scale) + 1) * 10;
  3984. prey = getOnePrey(biome, area, true);
  3985. } else if (style == "cone") {
  3986. prey = getPrey(biome, area, true);
  3987. }
  3988. let line = describe("breath-" + type, prey, macro, verbose, flat);
  3989. let linesummary = summarize(prey.sum(), true);
  3990. let preyMass = prey.sum_property("mass");
  3991. let sound = getSound("breath", preyMass);
  3992. update([sound, line, linesummary, newline]);
  3993. add_victim_people("breath-" + type, prey);
  3994. macro.arouse(5);
  3995. }
  3996. function breath_fire() {
  3997. breath("fire", macro.breathStyle);
  3998. }
  3999. function breath_ice() {
  4000. breath("ice", macro.breathStyle);
  4001. }
  4002. function breath_electric() {
  4003. breath("electric", macro.breathStyle);
  4004. }
  4005. function breath_smoke() {
  4006. breath("smoke", macro.breathStyle);
  4007. }
  4008. function breath_radiation() {
  4009. breath("radiation", macro.breathStyle);
  4010. }
  4011. function breath_foul() {
  4012. breath("foul", macro.breathStyle);
  4013. }
  4014. function breath_line() {
  4015. macro.breathStyle = "line";
  4016. update(["You prepare to exhale a focused line of breath!", newline]);
  4017. }
  4018. function breath_cone() {
  4019. macro.breathStyle = "cone";
  4020. update(["You prepare to exhale a broad cone of breath!", newline]);
  4021. }
  4022. function magic_shrink() {
  4023. let prey = new Container();
  4024. prey = getPrey(
  4025. biome,
  4026. macro.magicScale * macro.height * macro.height * 100,
  4027. true
  4028. );
  4029. macro.shrunkPrey = prey;
  4030. macro.shrunkPrey.mod_property("mass", (x) => x / 1e2);
  4031. let line = describe("magic-shrink", prey, macro, false, flat);
  4032. let linesummary = summarize(prey.sum(), false);
  4033. let preyMass = prey.sum_property("mass");
  4034. let sound = getSound("magic", preyMass);
  4035. update([sound, line, linesummary, newline]);
  4036. return;
  4037. }
  4038. function magic_fast_digestion() {
  4039. let line = "You infuse your depths with power, speeding your digestion.";
  4040. if (macro.fastDigestTimer) {
  4041. clearTimeout(macro.fastDigestTimer);
  4042. }
  4043. macro.fastDigestFactor = Math.log10(macro.magicScale) * 3;
  4044. macro.fastDigestTimer = setTimeout(function () {
  4045. macro.fastDigestFactor = 1;
  4046. macro.fastDigestTimer = null;
  4047. update(["The digestion magic wears off...", newline]);
  4048. }, 30000);
  4049. update([line, newline]);
  4050. }
  4051. function magic_pause_digestion() {
  4052. let line;
  4053. if (macro.pauseDigest) {
  4054. line = "You end the spell, and your body resumes its work.";
  4055. } else {
  4056. line = "Your magic halts your digestive processes.";
  4057. }
  4058. macro.pauseDigest = !macro.pauseDigest;
  4059. update([line, newline]);
  4060. }
  4061. function magic_arousal() {
  4062. let line = "Ooo";
  4063. if (macro.maleParts && macro.femaleParts) {
  4064. }
  4065. update([line, newline]);
  4066. macro_arousal_execute(macro.magicScale * 100, macro.magicScale * 100);
  4067. }
  4068. function macro_arousal_execute(remaining, max) {
  4069. if (remaining > 0) {
  4070. macro.arouse((2 * remaining) / max);
  4071. setTimeout(() => macro_arousal_execute(remaining - 1, max), 25);
  4072. }
  4073. }
  4074. function magic_fill_sexual() {
  4075. let line = "Full up!";
  4076. update([line, newline]);
  4077. macro_fill_sexual_execute(macro.magicScale * 100, macro.magicScale * 100);
  4078. }
  4079. function macro_fill_sexual_execute(remaining, max) {
  4080. if (macro.maleParts) {
  4081. macro.cumStorage.amount +=
  4082. (macro.cumStorage.limit * 0.02 * remaining) / max;
  4083. }
  4084. if (macro.femaleParts) {
  4085. macro.femcumStorage.amount +=
  4086. (macro.femcumStorage.limit * 0.02 * remaining) / max;
  4087. }
  4088. if (remaining > 0) {
  4089. setTimeout(() => macro_fill_sexual_execute(remaining - 1, max), 25);
  4090. }
  4091. }
  4092. function wings_flap() {
  4093. let area = macro.wingArea * 2;
  4094. let prey = getPrey(biome, area, false);
  4095. let line = describe("wings-flap", prey, macro, verbose, flat);
  4096. let linesummary = summarize(prey.sum(), true);
  4097. let people = get_living_prey(prey.sum());
  4098. let preyMass = prey.sum_property("mass");
  4099. let sound = getSound("breath", preyMass);
  4100. add_victim_people("wings-flap", prey);
  4101. update([sound, line, linesummary, newline]);
  4102. }
  4103. function wings_vore() {
  4104. let area = macro.wingArea * 2;
  4105. let prey = getPrey(biome, area, false);
  4106. let line = describe("wings-vore", prey, macro, verbose, flat);
  4107. let linesummary = summarize(prey.sum(), true);
  4108. let people = get_living_prey(prey.sum());
  4109. let preyMass = prey.sum_property("mass");
  4110. let sound = getSound("insert", preyMass);
  4111. macro.wings.feed(prey);
  4112. add_victim_people("wings-vore", prey);
  4113. update([sound, line, linesummary, newline]);
  4114. }
  4115. function cooldown_start(name) {
  4116. let button = document.querySelector("#" + "button-action-" + name);
  4117. if (button.dataset.free) {
  4118. return;
  4119. }
  4120. let parent = button.parentElement;
  4121. let category = parent.id.replace("actions-", "");
  4122. Array.from(parent.children).forEach(function (x) {
  4123. x.disabled = true;
  4124. x.classList.add("action-button-disabled");
  4125. });
  4126. cooldown(category, 100, 100);
  4127. }
  4128. function cooldown(category, time, timestart) {
  4129. if (time <= 0) {
  4130. cooldown_end(category);
  4131. } else {
  4132. let button = document.getElementById("action-part-" + category);
  4133. let amount = Math.round(((timestart - time) / timestart) * 100);
  4134. let unselect = dark ? "#111" : "#ddd";
  4135. let select = dark ? "#444" : "#555";
  4136. button.style.setProperty(
  4137. "background",
  4138. "linear-gradient(to right, " +
  4139. select +
  4140. " 0%, " +
  4141. select +
  4142. " " +
  4143. amount +
  4144. "%, " +
  4145. unselect +
  4146. " " +
  4147. amount +
  4148. "%, " +
  4149. unselect +
  4150. " 100%"
  4151. );
  4152. setTimeout(function () {
  4153. cooldown(category, time - 1, timestart);
  4154. }, 20);
  4155. }
  4156. }
  4157. function cooldown_end(category) {
  4158. let button = document.getElementById("action-part-" + category);
  4159. button.style.setProperty("background", null);
  4160. let parent = document.querySelector("#actions-" + category);
  4161. Array.from(parent.children).forEach(function (x) {
  4162. x.disabled = false;
  4163. x.classList.remove("action-button-disabled");
  4164. });
  4165. }
  4166. function transformNumbers(line, fixed = undefined) {
  4167. return line
  4168. .toString()
  4169. .replace(/[0-9]+(\.[0-9]+)?(e\+[0-9]+)?/g, function (text) {
  4170. return number(text, numbers, fixed);
  4171. });
  4172. }
  4173. function update(lines = [], active = true) {
  4174. let log = active
  4175. ? document.getElementById("log")
  4176. : document.getElementById("react-log");
  4177. let oldHeight = log.scrollHeight;
  4178. lines.forEach(function (x) {
  4179. let line = document.createElement("div");
  4180. line.innerHTML = transformNumbers(x);
  4181. log.appendChild(line);
  4182. });
  4183. if (lines.length > 0) {
  4184. log.scrollTop = log.scrollHeight;
  4185. let deltaHeight = log.scrollHeight - oldHeight;
  4186. if (deltaHeight / window.innerHeight >= 0.2 && verbose && autoVerbose) {
  4187. update(["Switching to concise text!", newline], false);
  4188. autoVerbose = false;
  4189. let button = document.querySelector("#button-option-toggle_verbose");
  4190. toggle_verbose({ target: button });
  4191. }
  4192. }
  4193. document.getElementById("height").innerHTML =
  4194. "Height: " + transformNumbers(length(macro.height, unit));
  4195. document.getElementById("mass").innerHTML =
  4196. "Mass: " + transformNumbers(mass(macro.totalMass, unit));
  4197. if (macro.difficulty > 0) {
  4198. document.getElementById("growth-points").innerHTML =
  4199. "Growth points: " + macro.growthPoints;
  4200. }
  4201. applyPercentage("arousal", 150 - macro.arousal * 1.5);
  4202. applyPercentage("orgasm", 150 - (macro.arousal - 100) * 1.5);
  4203. applyPercentage("edge", 150 - macro.edge * 150);
  4204. stylePercentage("cum", macro.cumStorage);
  4205. stylePercentage("femcum", macro.femcumStorage);
  4206. stylePercentage("milk", macro.milkStorage);
  4207. stylePercentage("gas", macro.gasStorage);
  4208. stylePercentage("piss", macro.pissStorage);
  4209. stylePercentage("scat", macro.scatStorage);
  4210. }
  4211. function applyPercentage(name, meterPos) {
  4212. meterPos = meterPos < 0 ? 0 : meterPos;
  4213. document
  4214. .querySelector("#" + name + "Meter .fill")
  4215. .style.setProperty(
  4216. "transform",
  4217. "translate(0px, " + Math.round(meterPos) + "px)"
  4218. );
  4219. let meter = document.querySelector("#" + name + "Meter");
  4220. if (meterPos == 0) {
  4221. meter.classList.add("shaking");
  4222. } else {
  4223. meter.classList.remove("shaking");
  4224. }
  4225. }
  4226. function stylePercentage(name, storage) {
  4227. document.getElementById(name).innerHTML =
  4228. name + ": " + transformNumbers(volume(storage.amount, unit, false), 2);
  4229. let meterPos = 150 - (storage.amount / storage.limit) * 150;
  4230. applyPercentage(name, meterPos);
  4231. }
  4232. function pick_move() {
  4233. let moving = false;
  4234. let walkSpeed = macro.walkSpeed;
  4235. let stepTime = 0;
  4236. switch (strolling) {
  4237. case strollingEnum.Standing:
  4238. moving = false;
  4239. break;
  4240. case strollingEnum.Strolling:
  4241. stepTime = 1 * (1 / walkSpeed) * 2000 * (1 + Math.log10(macro.scale));
  4242. moving = true;
  4243. break;
  4244. case strollingEnum.Jogging:
  4245. stepTime =
  4246. (1 / 2) * (1 / walkSpeed) * 2000 * (1 + Math.log10(macro.scale));
  4247. moving = true;
  4248. break;
  4249. case strollingEnum.Running:
  4250. stepTime =
  4251. (1 / 3) * (1 / walkSpeed) * 2000 * (1 + Math.log10(macro.scale));
  4252. moving = true;
  4253. break;
  4254. }
  4255. setTimeout(pick_move, stepTime);
  4256. if (!moving) {
  4257. return;
  4258. }
  4259. stomp(false);
  4260. }
  4261. //Growth
  4262. //Automatic Growth
  4263. function grow_automatic(preyMass, part) {
  4264. if (macro.automaticGrowthEnabled == true) {
  4265. let preyMassBody = preyMass * macro.preyGrowthFactor;
  4266. if (part === "tail" && macro.tailGrowthFactor > 0) {
  4267. preyMassBody =
  4268. (1 - macro.tailGrowthFactor) * macro.preyGrowthFactor * preyMass; //if growth factor is greater than 1, this function will behave oddly
  4269. grow_tail(
  4270. macro.tailGrowthFactor * macro.preyGrowthFactor * preyMass,
  4271. false
  4272. );
  4273. } else if (part === "cock" && macro.cockGrowthFactor > 0) {
  4274. preyMassBody =
  4275. (1 - macro.cockGrowthFactor) * macro.preyGrowthFactor * preyMass; //if growth factor is greater than 1, this function will behave oddly
  4276. grow_dick(
  4277. macro.cockGrowthFactor * macro.preyGrowthFactor * preyMass,
  4278. false
  4279. );
  4280. } else if (part === "balls" && macro.ballGrowthFactor > 0) {
  4281. preyMassBody =
  4282. (1 - macro.ballGrowthFactor) * macro.preyGrowthFactor * preyMass; //if growth factor is greater than 1, this function will behave oddly
  4283. grow_balls(
  4284. macro.ballGrowthFactor * macro.preyGrowthFactor * preyMass,
  4285. false
  4286. );
  4287. } else if (part === "bowels" && macro.assGrowthFactor > 0) {
  4288. preyMassBody =
  4289. (1 - macro.assGrowthFactor) * macro.preyGrowthFactor * preyMass; //if growth factor is greater than 1, this function will behave oddly
  4290. grow_ass(
  4291. macro.assGrowthFactor * macro.preyGrowthFactor * preyMass,
  4292. false
  4293. );
  4294. } else if (part === "breasts" && macro.breastGrowthFactor > 0) {
  4295. let preyMassBody =
  4296. (1 - macro.breastGrowthFactor) * macro.preyGrowthFactor * preyMass; //if growth factor is greater than 1, this function will behave oddly
  4297. grow_breasts(
  4298. macro.breastGrowthFactor * macro.preyGrowthFactor * preyMass,
  4299. false
  4300. );
  4301. } else if (part === "womb") {
  4302. if (macro.wombGrowthFactor > 0) {
  4303. preyMassBody =
  4304. (1 - macro.wombGrowthFactor) * macro.preyGrowthFactor * preyMass; //if growth factor is greater than 1, this function will behave oddly
  4305. grow_womb(
  4306. macro.wombGrowthFactor * macro.preyGrowthFactor * preyMass,
  4307. false
  4308. );
  4309. }
  4310. if (macro.vaginaGrowthFactor > 0) {
  4311. preyMassBody =
  4312. (1 - macro.vaginaGrowthFactor) *
  4313. macro.preyGrowthFactor *
  4314. preyMassBody; //if growth factor is greater than 1, this function will behave oddly
  4315. grow_vagina(
  4316. macro.vaginaGrowthFactor * macro.preyGrowthFactor * preyMass,
  4317. false
  4318. );
  4319. }
  4320. } else if (part === "paws" && macro.pawGrowthFactor > 0) {
  4321. preyMassBody =
  4322. (1 - macro.pawGrowthFactor) * macro.preyGrowthFactor * preyMassBody; // if growth factor is greater than 1, this function will behave oddly
  4323. grow_paws(
  4324. macro.pawGrowthFactor * macro.preyGrowthFactor * preyMass,
  4325. false
  4326. );
  4327. } else if (part === "souls" && macro.soulGrowthFactor > 0) {
  4328. preyMassBody = 0; //keeps body growth from running
  4329. grow(preyMass * macro.soulGrowthFactor, false);
  4330. } else if (part === "goo" && macro.gooGrowthFactor > 0) {
  4331. preyMassBody = 0; //keeps body growth from running
  4332. grow(preyMass * macro.gooGrowthFactor, false);
  4333. //Body, runs after organ specific growth so organ specific growth factor kicks in. Doesn't run after goo or soul related growth
  4334. }
  4335. if (preyMassBody > 0) {
  4336. grow(preyMassBody, false);
  4337. }
  4338. }
  4339. }
  4340. //Manual Growth
  4341. function grow_part_pick(id) {
  4342. document
  4343. .querySelector(".growth-part-active")
  4344. .classList.remove("growth-part-active");
  4345. document.querySelector("#" + id).classList.add("growth-part-active");
  4346. }
  4347. function grow_pick(times) {
  4348. const select = document.querySelector("#growth-part-select");
  4349. const chosenPart = select.value;
  4350. if (macro.difficulty > 0 && macro.growthPoints < (times - 1) * 10) {
  4351. update([
  4352. "You need " + times * 10 + " growth points to grow that much.",
  4353. newline,
  4354. ]);
  4355. } else {
  4356. if (macro.difficulty > 0) {
  4357. macro.growthPoints -= (times - 1) * 10;
  4358. }
  4359. times /= 10;
  4360. switch (chosenPart) {
  4361. case "body":
  4362. grow(times);
  4363. break;
  4364. case "paws":
  4365. grow_paws(times);
  4366. break;
  4367. case "tail":
  4368. grow_tail(times);
  4369. break;
  4370. case "ass":
  4371. grow_ass(times);
  4372. break;
  4373. case "dick":
  4374. grow_dick(times);
  4375. break;
  4376. case "balls":
  4377. grow_balls(times);
  4378. break;
  4379. case "slit":
  4380. grow_vagina(times);
  4381. break;
  4382. case "womb":
  4383. grow_womb(times);
  4384. break;
  4385. case "breasts":
  4386. grow_breasts(times);
  4387. break;
  4388. case "wings":
  4389. grow_wings(times);
  4390. break;
  4391. case "musk":
  4392. grow_musk(times);
  4393. break;
  4394. case "stench":
  4395. grow_stench(times);
  4396. break;
  4397. case "breath":
  4398. grow_breath(times);
  4399. break;
  4400. case "magic":
  4401. grow_magic(times);
  4402. break;
  4403. }
  4404. }
  4405. }
  4406. function grow(factor = 1, simpleCalc = true) {
  4407. let oldHeight = macro.height;
  4408. let oldMass = macro.mass;
  4409. if (simpleCalc == true) {
  4410. macro.scale *= factor;
  4411. } else {
  4412. macro.scale = Math.pow((macro.mass + factor) / macro.baseMass, 1 / 3);
  4413. }
  4414. let heightDelta = macro.height - oldHeight;
  4415. let massDelta = macro.mass - oldMass;
  4416. update([
  4417. pickString(
  4418. "Power surges through you",
  4419. "Your body surges upward",
  4420. "Your muscles fight for space",
  4421. "Energy flows into you",
  4422. "You feel your body expand",
  4423. "Your surroundings appear to shink",
  4424. "Your muscles tense",
  4425. "You almost lose your balance",
  4426. "A warm sensation fills you",
  4427. "You feel \
  4428. a buzz of power"
  4429. ) +
  4430. " as you grow " +
  4431. length(heightDelta, unit) +
  4432. " taller and gain " +
  4433. mass(massDelta, unit) +
  4434. " of mass.",
  4435. newline,
  4436. ]);
  4437. }
  4438. function grow_paws(factor, simpleCalc = true) {
  4439. let oldArea = macro.pawArea;
  4440. if (simpleCalc == true) {
  4441. macro.pawScale *= factor;
  4442. } else {
  4443. let volumeChangerPart =
  4444. (Math.pow(macro.pawWidth, 2) * macro.pawLength * macro.pawDensity +
  4445. factor) /
  4446. (3 * macro.pawDensity);
  4447. //mass = volume*density. Since we know what we want our mass to be, we can figure out how much volume the final paw should have
  4448. let scaleChangerPart =
  4449. (3 * volumeChangerPart) /
  4450. (Math.pow(macro.basePawWidth, 2) * macro.basePawLength);
  4451. macro.pawScale = Math.pow(scaleChangerPart, 1 / 3) / macro.scale;
  4452. // volume = 1/3 basewidth^2 * baselength *scale^3 *pawscale^3
  4453. }
  4454. let areaDelta = macro.pawArea - oldArea;
  4455. update([
  4456. pickString(
  4457. "Power surges through you",
  4458. "Energy flows into you",
  4459. "You feel your " + macro.footDesc(true) + " expand",
  4460. "Your muscles tense",
  4461. "A warm sensation fills you",
  4462. "You feel a buzz of power"
  4463. ) +
  4464. " as your \
  4465. " +
  4466. macro.footOnlyDesc(true) +
  4467. pickString(
  4468. " grow,",
  4469. " push the ground apart,",
  4470. " sink deeper into the soil,"
  4471. ) +
  4472. " gaining " +
  4473. area(areaDelta, unit, false) +
  4474. " of area.",
  4475. newline,
  4476. ]);
  4477. }
  4478. function grow_tail(factor, simpleCalc = true) {
  4479. let oldLength = macro.tailLength;
  4480. let oldMass = macro.tailMass;
  4481. if (simpleCalc == true) {
  4482. macro.tailScale *= factor;
  4483. } else {
  4484. let volumeChangerPart =
  4485. (macro.tailMass + factor / macro.tailCount) / macro.tailDensity;
  4486. let scaleChangerPart =
  4487. volumeChangerPart /
  4488. (Math.pow(macro.baseTailDiameter / 2, 2) *
  4489. Math.PI *
  4490. macro.baseTailLength *
  4491. Math.pow(macro.scale, 3));
  4492. macro.tailScale = Math.pow(scaleChangerPart, 1 / 3);
  4493. // (tailVolume/((macro.baseTailDiameter/2)^2 * Math.PI * macro.baseTailLength * macro.scale^3)) = macro.tailScale^3
  4494. }
  4495. let lengthDelta = macro.tailLength - oldLength;
  4496. let massDelta = macro.tailMass - oldMass;
  4497. update([
  4498. pickString(
  4499. "Power surges through you",
  4500. "Energy flows into you",
  4501. "You feel your tail twitch",
  4502. "Your muscles tense",
  4503. "Your balance shifts",
  4504. "A warm sensation fills you",
  4505. "You feel a buzz of power"
  4506. ) +
  4507. " as your " +
  4508. macro.tailType +
  4509. " tail grows " +
  4510. length(lengthDelta, unit, false) +
  4511. " longer and gains " +
  4512. mass(massDelta, unit, false) +
  4513. " of mass.",
  4514. newline,
  4515. ]);
  4516. }
  4517. function grow_dick(factor, simpleCalc = true) {
  4518. let oldLength = macro.dickLength;
  4519. let oldMass = macro.dickMass;
  4520. if (simpleCalc == true) {
  4521. macro.dickScale *= factor;
  4522. } else {
  4523. let volumeChangerPart = (macro.dickMass + factor) / macro.dickDensity;
  4524. let scaleChangerPart =
  4525. volumeChangerPart /
  4526. (Math.pow(macro.baseDickDiameter / 2, 2) *
  4527. Math.PI *
  4528. Math.pow(macro.scale, 3) *
  4529. macro.baseDickLength *
  4530. Math.pow(macro.arousalDickFactor, 3));
  4531. macro.dickScale = Math.pow(scaleChangerPart, 1 / 3);
  4532. // dickScale^3 = volume/ pi * baseDickRadius^2 * macro.scale^3 * baseDickLength * arousalDickFactor^3
  4533. }
  4534. let lengthDelta = macro.dickLength - oldLength;
  4535. let massDelta = macro.dickMass - oldMass;
  4536. update([
  4537. pickString(
  4538. "Power surges through you",
  4539. "Energy flows into you",
  4540. "You feel your cock throb",
  4541. "Your muscles tense",
  4542. "You feel your loins buzz with energy",
  4543. "A warm sensation fills you",
  4544. "You feel a buzz of power"
  4545. ) +
  4546. " as your " +
  4547. macro.dickType +
  4548. " cock grows " +
  4549. length(lengthDelta, unit, false) +
  4550. " longer and gains " +
  4551. mass(massDelta, unit, false) +
  4552. " of mass.",
  4553. newline,
  4554. ]);
  4555. }
  4556. function grow_balls(factor, simpleCalc = true) {
  4557. let oldDiameter = macro.ballDiameter;
  4558. let oldMass = macro.ballMass;
  4559. if (simpleCalc == true) {
  4560. macro.ballScale *= factor;
  4561. } else {
  4562. let volumeChangerPart = (macro.ballMass + factor) / macro.ballDensity;
  4563. let scaleChangerPart = Math.pow((6 * volumeChangerPart) / Math.PI, 1 / 3);
  4564. macro.ballScale = scaleChangerPart / (macro.baseBallDiameter * macro.scale);
  4565. // (6 * volume / pi)^1/3 = base ball diam * scale *ballScale
  4566. }
  4567. let diameterDelta = macro.ballDiameter - oldDiameter;
  4568. let massDelta = macro.ballMass - oldMass;
  4569. update([
  4570. pickString(
  4571. "Power surges through you",
  4572. "Energy flows into you",
  4573. "You feel an unfamiliar weight in your sack",
  4574. "You sack pushes your thighs further apart",
  4575. "Your muscles tense",
  4576. "You feel your loins buzz with energy",
  4577. "You feel a buzz of power",
  4578. "A warm sensation fills you"
  4579. ) +
  4580. " as your balls swell by " +
  4581. length(diameterDelta, unit, false) +
  4582. ", gaining " +
  4583. mass(massDelta, unit, false) +
  4584. " of mass apiece.",
  4585. newline,
  4586. ]);
  4587. }
  4588. function grow_breasts(factor, simpleCalc = true) {
  4589. let oldDiameter = macro.breastDiameter;
  4590. let oldMass = macro.breastMass;
  4591. if (simpleCalc == true) {
  4592. macro.breastScale *= factor;
  4593. } else {
  4594. let volumeChangerPart = (factor + macro.breastMass) / macro.breastDensity;
  4595. let scaleChangerPart = Math.pow((6 * volumeChangerPart) / Math.PI, 1 / 3);
  4596. macro.breastScale =
  4597. scaleChangerPart / (macro.baseBreastDiameter * macro.scale);
  4598. // (6 * volume / pi)^1/3 = base ball diam * scale * ballScale
  4599. }
  4600. let diameterDelta = macro.breastDiameter - oldDiameter;
  4601. let massDelta = macro.breastMass - oldMass;
  4602. update([
  4603. pickString(
  4604. "Power surges through you",
  4605. "Energy flows into you",
  4606. "You feel an unfamilliar weight on your chest",
  4607. "Your balance shifts",
  4608. "Your muscles tense",
  4609. "You feel a buzz of power",
  4610. "A warm sensation fills you"
  4611. ) +
  4612. " as your breasts swell by " +
  4613. length(diameterDelta, unit, false) +
  4614. ", gaining " +
  4615. mass(massDelta, unit, false) +
  4616. " of mass apiece.",
  4617. newline,
  4618. ]);
  4619. }
  4620. function grow_vagina(factor, simpleCalc = true) {
  4621. let oldLength = macro.vaginaLength;
  4622. if (simpleCalc == true) {
  4623. macro.vaginaScale *= factor;
  4624. } else {
  4625. let volumeChangerPart =
  4626. (macro.vaginaVolume * macro.wombDensity + factor) / macro.wombDensity;
  4627. let scaleChangerPart =
  4628. volumeChangerPart /
  4629. (Math.pow(macro.baseVaginaWidth, 2) * macro.baseVaginaLength);
  4630. macro.vaginaScale = Math.pow(scaleChangerPart, 1 / 3) / macro.scale;
  4631. //vaginaVolume = baseVaginaWidth^2 * baseVaginaLength * (vaginaScale * macro.scale)^3
  4632. }
  4633. let lengthDelta = macro.vaginaLength - oldLength;
  4634. update([
  4635. pickString(
  4636. "Power surges through you",
  4637. "Energy flows into you",
  4638. "You feel your loins buzz with energy",
  4639. "Your muscles tense",
  4640. "You feel a buzz of power",
  4641. "A warm sensation fills you"
  4642. ) +
  4643. " as your moist slit expands by " +
  4644. length(lengthDelta, unit, false) +
  4645. ".",
  4646. newline,
  4647. ]);
  4648. }
  4649. function grow_womb(factor, simpleCalc = true) {
  4650. let oldVolume = macro.wombVolume;
  4651. if (simpleCalc == true) {
  4652. macro.wombScale *= factor;
  4653. } else {
  4654. let volumeChangerPart =
  4655. (macro.wombVolume * macro.wombDensity + factor) / macro.wombDensity;
  4656. let scaleChangerPart = volumeChangerPart / macro.baseWombVolume;
  4657. macro.wombScale = Math.pow(scaleChangerPart, 1 / 3) / macro.scale;
  4658. //wombVolume = baseWombVolume * (wombScale * macro.scale)^3
  4659. }
  4660. let volumeDelta = macro.wombVolume - oldVolume;
  4661. update([
  4662. pickString(
  4663. "Power surges through you",
  4664. "Energy flows into you",
  4665. "You feel your loins buzz with energy",
  4666. "You feel your muscles tense",
  4667. "You feel a buzz of power",
  4668. "A warm sensation fills you"
  4669. ) +
  4670. " as your womb grows larger, gaining " +
  4671. volume(volumeDelta, unit, false) +
  4672. " of capacity.",
  4673. newline,
  4674. ]);
  4675. }
  4676. function grow_ass(factor, simpleCalc = true) {
  4677. let oldDiameter = Math.pow(macro.assArea, 1 / 2);
  4678. if (simpleCalc == true) {
  4679. macro.assScale *= factor;
  4680. } else {
  4681. macro.assScale = macro.assScale + factor / macro.mass; //this is a hack, but the commented out block below doesn't work
  4682. //This Code is broken and I dont know why:
  4683. //let radiusPart = Math.pow((macro.assArea/(4 * Math.PI)), 1/2);
  4684. //let volumeChangerPart = (preyMassPart + (((4 * Math.PI)/3) * Math.pow(radiusPart, 3) * macro.assDensity) / macro.assDensity);
  4685. //volume=(mass1+mass2)/density. Mass2 is calcualted from volume*density this is modeling the ass as a sphere(2 hemispheres)
  4686. //let scaleChangerPart = ((Math.pow(((3/(4 * Math.PI)) * volumeChangerPart), 2/3) * 4 * Math.PI) / (macro.baseAssArea * Math.pow(macro.scale, 2)));
  4687. //macro.assScale = scaleChangerPart;
  4688. //V=4/3((baseassArea*scale^2*AssScale)/4pi)^3/2
  4689. }
  4690. let diameterDelta = Math.pow(macro.assArea, 1 / 2) - oldDiameter;
  4691. update([
  4692. pickString(
  4693. "Power surges through you",
  4694. "Energy flows into you",
  4695. "You feel your rear fill with power",
  4696. "You feel your rear plump out",
  4697. "You feel your rear expand",
  4698. "Your muscles tense",
  4699. "Your balance shifts",
  4700. "You feel a buzz of power",
  4701. "A warm sensation fills you"
  4702. ) +
  4703. " as your ass swells by " +
  4704. length(diameterDelta, unit, false) +
  4705. ".",
  4706. newline,
  4707. ]);
  4708. }
  4709. function grow_wings(factor, simpleCalc = true) {
  4710. let oldLength = macro.wingLength;
  4711. if (simpleCalc == true) {
  4712. macro.wingScale *= factor;
  4713. } else {
  4714. macro.wingScale = macro.wingScale + factor / macro.mass;
  4715. }
  4716. let lengthDelta = macro.wingLength - oldLength;
  4717. update([
  4718. pickString(
  4719. "Power surges through you",
  4720. "Energy flows into you",
  4721. "Your back muscles fight for space",
  4722. "Your muscles tense",
  4723. "A crackling fills the air",
  4724. "Your balance shifts",
  4725. "You feel a buzz of power",
  4726. "A warm sensation fills you"
  4727. ) +
  4728. " as your " +
  4729. macro.wingDesc +
  4730. " wings grow, gaining " +
  4731. length(2 * lengthDelta, unit, false) +
  4732. " of wingspan.",
  4733. newline,
  4734. ]);
  4735. }
  4736. function grow_musk(factor, simpleCalc = true) {
  4737. let oldScale = macro.muskScale;
  4738. if (simpleCalc == true) {
  4739. macro.muskScale *= factor;
  4740. } else {
  4741. macro.muskScale = macro.muskScale + factor / Math.pow(macro.mass, 1 / 3);
  4742. }
  4743. let scaleDelta = macro.muskScale - oldScale;
  4744. update([
  4745. pickString(
  4746. "Power surges through you",
  4747. "Energy flows into you",
  4748. "A crackling fills the air",
  4749. "Your balance shifts",
  4750. "You feel a buzz of power",
  4751. "A warm sensation fills you"
  4752. ) + " as your musk thickens, growing more potent.",
  4753. newline,
  4754. ]);
  4755. }
  4756. function grow_stench(factor, simpleCalc = true) {
  4757. let oldScale = macro.muskScale;
  4758. if (simpleCalc == true) {
  4759. macro.stenchScale *= factor;
  4760. } else {
  4761. macro.stenchScale =
  4762. macro.stenchScale + factor / Math.pow(macro.mass, 1 / 3);
  4763. }
  4764. let scaleDelta = macro.stenchScale - oldScale;
  4765. update([
  4766. pickString(
  4767. "Power surges through you",
  4768. "Energy flows into you",
  4769. "A crackling fills the air",
  4770. "Your balance shifts",
  4771. "You feel a buzz of power",
  4772. "A warm sensation fills you"
  4773. ) + " as your stench thickens, growing more potent.",
  4774. newline,
  4775. ]);
  4776. }
  4777. function grow_breath(factor, simpleCalc = true) {
  4778. let oldScale = macro.breathScale;
  4779. if (simpleCalc == true) {
  4780. macro.breathScale *= factor;
  4781. } else {
  4782. macro.breathScale =
  4783. macro.breathScale + factor / Math.pow(macro.mass, 1 / 3);
  4784. }
  4785. let scaleDelta = macro.breathScale - oldScale;
  4786. update([
  4787. pickString(
  4788. "Power surges through you",
  4789. "Energy flows into you",
  4790. "A crackling fills the air",
  4791. "Your balance shifts",
  4792. "You feel a buzz of power",
  4793. "A warm sensation fills you"
  4794. ) + " as your breath weapon grows more potent.",
  4795. newline,
  4796. ]);
  4797. }
  4798. function grow_magic(factor, simpleCalc = true) {
  4799. let oldScale = macro.magicScale;
  4800. if (simpleCalc == true) {
  4801. macro.magicScale *= factor;
  4802. } else {
  4803. macro.magicScale = macro.magicScale + factor / Math.pow(macro.mass, 1 / 3);
  4804. }
  4805. let scaleDelta = macro.magicScale - oldScale;
  4806. update([
  4807. pickString(
  4808. "Power surges through you",
  4809. "Energy flows into you",
  4810. "A crackling fills the air",
  4811. "Your balance shifts",
  4812. "You feel a buzz of power",
  4813. "A warm sensation fills you"
  4814. ) + " as your magical powers grow.",
  4815. newline,
  4816. ]);
  4817. }
  4818. function resetSettings() {
  4819. document.forms.namedItem("custom-species-form").reset();
  4820. reset_visible_groups();
  4821. updateAllPreviews();
  4822. }
  4823. function loadPreset() {
  4824. resetSettings();
  4825. let select = document.getElementById("character-presets");
  4826. loadSettings(presets[select.selectedIndex]);
  4827. }
  4828. function grabFormData(form, warnings, panels, buttons, stats, parts) {
  4829. // verify that this input box is in something we enabled
  4830. let parent = form.parentElement;
  4831. while (true) {
  4832. if (parent.id == "custom-species") {
  4833. break;
  4834. }
  4835. if (parent.classList.contains("reveal-if-active")) {
  4836. let sib = parent.previousSibling.previousSibling;
  4837. if (!sib.checked) {
  4838. return;
  4839. }
  4840. }
  4841. parent = parent.parentElement;
  4842. }
  4843. if (form.hasAttribute("data-warning")) {
  4844. warnings.push(form.getAttribute("data-warning"));
  4845. }
  4846. if (form.hasAttribute("data-buttons")) {
  4847. let text = form.getAttribute("data-buttons");
  4848. text.split(",").forEach(function (token) {
  4849. buttons.push(token);
  4850. });
  4851. }
  4852. if (form.hasAttribute("data-panels")) {
  4853. let text = form.getAttribute("data-panels");
  4854. text.split(",").forEach(function (token) {
  4855. panels.push(token);
  4856. });
  4857. }
  4858. if (form.hasAttribute("data-stats")) {
  4859. let text = form.getAttribute("data-stats");
  4860. text.split(",").forEach(function (token) {
  4861. stats.push(token);
  4862. });
  4863. }
  4864. if (form.hasAttribute("data-parts")) {
  4865. let text = form.getAttribute("data-parts");
  4866. text.split(",").forEach(function (token) {
  4867. parts.push(token);
  4868. });
  4869. }
  4870. }
  4871. // if diff is true, only record settings that are
  4872. // different from the defaults!
  4873. function generateSettings(diff = false) {
  4874. let form = document.forms.namedItem("custom-species-form");
  4875. let settings = {};
  4876. let warnings = [];
  4877. let panels = [];
  4878. let buttons = [];
  4879. let stats = [];
  4880. let parts = [];
  4881. for (let i = 0; i < form.length; i++) {
  4882. let value = form[i].value == "" ? form[i].placeholder : form[i].value;
  4883. if (form[i].type == "text") settings[form[i].name] = value;
  4884. else if (form[i].type == "number") {
  4885. if (form[i].dataset.unit == "percentage") {
  4886. settings[form[i].name] = parseFloat(value) / 100;
  4887. } else if (form[i].dataset.unit == "volume") {
  4888. settings[form[i].name] = parseFloat(value) / 1000;
  4889. } else {
  4890. settings[form[i].name] = parseFloat(value);
  4891. }
  4892. } else if (form[i].type == "checkbox") {
  4893. settings[form[i].name] = form[i].checked;
  4894. if (form[i].checked) {
  4895. grabFormData(form[i], warnings, panels, buttons, stats, parts);
  4896. }
  4897. } else if (form[i].type == "radio") {
  4898. let name = form[i].name;
  4899. if (form[i].checked) {
  4900. settings[name] = form[i].value;
  4901. grabFormData(form[i], warnings, panels, buttons, stats, parts);
  4902. }
  4903. } else if (form[i].type == "select-one") {
  4904. settings[form[i].name] = form[i][form[i].selectedIndex].value;
  4905. grabFormData(
  4906. form[i][form[i].selectedIndex],
  4907. warnings,
  4908. panels,
  4909. buttons,
  4910. stats,
  4911. parts
  4912. );
  4913. }
  4914. }
  4915. if (diff) {
  4916. options.forEach((panel) => {
  4917. recurseDeletePanel(settings, panel);
  4918. });
  4919. }
  4920. return {
  4921. settings: settings,
  4922. warnings: warnings,
  4923. panels: panels,
  4924. buttons: buttons,
  4925. stats: stats,
  4926. parts: parts,
  4927. };
  4928. }
  4929. function recurseDeletePanel(settings, panel) {
  4930. if (panel.id && panel.optional && !settings[panel.id]) {
  4931. delete settings[panel.id];
  4932. }
  4933. panel.entries.forEach((option) => {
  4934. if (option.type == "subcategory") {
  4935. if (
  4936. settings[option.id] == option.default ||
  4937. (!settings[option.id] && option.default === undefined)
  4938. ) {
  4939. delete settings[option.id];
  4940. }
  4941. recurseDeletePanel(settings, option);
  4942. } else if (settings[option.id] == undefined) {
  4943. delete settings[option.id];
  4944. } else if (
  4945. option.type == "checkbox" &&
  4946. !settings[option.id] &&
  4947. option.default === undefined
  4948. ) {
  4949. delete settings[option.id];
  4950. } else {
  4951. if (option.unit == "percentage") {
  4952. if (settings[option.id] * 100 == option.default)
  4953. delete settings[option.id];
  4954. } else if (option.unit == "volume") {
  4955. if (settings[option.id] * 1000 == option.default)
  4956. delete settings[option.id];
  4957. } else if (settings[option.id] == option.default && option.id != "name") {
  4958. delete settings[option.id];
  4959. }
  4960. }
  4961. });
  4962. }
  4963. function clearExport() {
  4964. document.getElementById("export-area").value = "";
  4965. }
  4966. function exportSettings() {
  4967. let settings = generateSettings(true)["settings"];
  4968. document.getElementById("export-area").value = JSON.stringify(settings);
  4969. }
  4970. function importSettings() {
  4971. try {
  4972. let text = document.getElementById("export-area").value;
  4973. if (text == "") {
  4974. return;
  4975. }
  4976. let settings = JSON.parse(text);
  4977. resetSettings();
  4978. loadSettings(settings);
  4979. } catch (err) {
  4980. alert("Bad character data!");
  4981. }
  4982. }
  4983. function updateCustomCharacters() {
  4984. let select = document.querySelector("#custom-characters");
  4985. select.innerHTML = "";
  4986. let saves = JSON.parse(storage.getItem("custom-characters"));
  4987. let names = Object.entries(saves).map(function ([name, contents]) {
  4988. return name;
  4989. });
  4990. names.sort(function (x, y) {
  4991. return x.localeCompare(y);
  4992. });
  4993. if (Object.keys(saves).length == 0) {
  4994. let none = document.createElement("option");
  4995. none.innerText = "No characters to load";
  4996. select.appendChild(none);
  4997. return;
  4998. } else {
  4999. names.forEach(function (name) {
  5000. let entry = document.createElement("option");
  5001. entry.value = name;
  5002. entry.innerText = name;
  5003. select.appendChild(entry);
  5004. });
  5005. }
  5006. }
  5007. function saveSettings() {
  5008. let storage = window.localStorage;
  5009. let settings = generateSettings()["settings"];
  5010. let saves = JSON.parse(storage.getItem("custom-characters"));
  5011. saves[settings.name] = settings;
  5012. storage.setItem("custom-characters", JSON.stringify(saves));
  5013. updateCustomCharacters();
  5014. }
  5015. function deleteSettings() {
  5016. let select = document.querySelector("#custom-characters");
  5017. let name = select.options[select.selectedIndex].value;
  5018. let settings = JSON.parse(storage.getItem("custom-characters"));
  5019. if (settings[name] != undefined && confirm("Really delete " + name + "?")) {
  5020. let settings = JSON.parse(storage.getItem("custom-characters"));
  5021. delete settings[name];
  5022. localStorage.setItem("custom-characters", JSON.stringify(settings));
  5023. updateCustomCharacters();
  5024. }
  5025. }
  5026. function loadAutosave() {
  5027. if (window.localStorage.getItem("autosave") == null) return;
  5028. loadSettings(JSON.parse(window.localStorage.getItem("autosave")));
  5029. }
  5030. function loadSettings(settings = null) {
  5031. if (settings == null) {
  5032. let storage = window.localStorage;
  5033. let select = document.querySelector("#custom-characters");
  5034. let name = select.options[select.selectedIndex].value;
  5035. settings = JSON.parse(storage.getItem("custom-characters"))[name];
  5036. if (settings == undefined) {
  5037. return;
  5038. }
  5039. }
  5040. migrate(settings);
  5041. reset_visible_groups();
  5042. let form = document.forms.namedItem("custom-species-form");
  5043. for (let i = 0; i < form.length; i++) {
  5044. if (settings[form[i].name] != undefined) {
  5045. if (form[i].type == "text") form[i].value = settings[form[i].name];
  5046. else if (form[i].type == "number") {
  5047. if (form[i].dataset.unit == "percentage") {
  5048. form[i].value = settings[form[i].name] * 100;
  5049. } else if (form[i].dataset.unit == "volume") {
  5050. form[i].value = settings[form[i].name] * 1000;
  5051. } else {
  5052. form[i].value = settings[form[i].name];
  5053. }
  5054. } else if (form[i].type == "checkbox") {
  5055. form[i].checked = settings[form[i].name];
  5056. options.forEach((option) => {
  5057. if (
  5058. option.group &&
  5059. option.group != "main" &&
  5060. option.id == form[i].name &&
  5061. settings[form[i].name]
  5062. ) {
  5063. document.querySelector(
  5064. "#group-toggle-" + option.group
  5065. ).checked = true;
  5066. }
  5067. });
  5068. } else if (form[i].type == "radio") {
  5069. let name = form[i].name;
  5070. form[i].checked = settings[name] == form[i].value;
  5071. } else if (form[i].type == "select-one") {
  5072. for (let j = 0; j < form[i].length; j++) {
  5073. if (form[i][j].value == settings[form[i].name]) {
  5074. form[i].selectedIndex = j;
  5075. break;
  5076. }
  5077. }
  5078. }
  5079. }
  5080. }
  5081. updateAllPreviews();
  5082. update_visible_groups();
  5083. }
  5084. function add_victim_people(category, prey) {
  5085. victims[category]["people"] += get_living_prey(prey.sum());
  5086. macro.growthPoints +=
  5087. (get_living_prey(prey.sum()) * 100) / (1 + Math.log10(macro.scale));
  5088. }
  5089. function enable_victim(category) {
  5090. victims[category] = {};
  5091. victims[category]["people"] = 0;
  5092. }
  5093. function enable_button(name) {
  5094. document.getElementById("button-action-" + name).style.display = "inline";
  5095. }
  5096. function disable_button(name) {
  5097. document.getElementById("button-action-" + name).style.display = "none";
  5098. }
  5099. function enable_panel(name) {
  5100. document.getElementById("action-part-" + name).style.display = "inline";
  5101. }
  5102. function enable_stat(name) {
  5103. document.getElementById(name).style.display = "block";
  5104. document.querySelector("#" + name + "Meter").style.display = "inline-block";
  5105. }
  5106. function enable_growth_part(name) {
  5107. document.querySelector("#option-growth-" + name).style.display = "block";
  5108. }
  5109. function disable_button(name) {
  5110. document.getElementById("button-action-" + name).style.display = "none";
  5111. }
  5112. function disable_panel(name) {
  5113. document.getElementById("action-part-" + name).style.display = "none";
  5114. }
  5115. function startGame(e) {
  5116. if (started) return;
  5117. started = true;
  5118. window.localStorage.setItem(
  5119. "autosave",
  5120. JSON.stringify(generateSettings()["settings"])
  5121. );
  5122. let info = generateSettings();
  5123. let settings = info["settings"];
  5124. let warns = info["warnings"];
  5125. info["panels"].forEach(function (panel) {
  5126. enable_panel(panel);
  5127. });
  5128. info["buttons"].forEach(function (button) {
  5129. enable_button(button);
  5130. });
  5131. info["stats"].forEach(function (stat) {
  5132. enable_stat(stat);
  5133. });
  5134. info["parts"].forEach(function (part) {
  5135. enable_growth_part(part);
  5136. });
  5137. for (var key in settings) {
  5138. if (settings.hasOwnProperty(key)) {
  5139. macro[key] = settings[key];
  5140. }
  5141. }
  5142. registerActions();
  5143. registerOptions();
  5144. if (!macro.hasTail) {
  5145. macro.tailCount = 0;
  5146. }
  5147. victim_keys.forEach(function (key) {
  5148. enable_victim(key.replace("victim-", ""));
  5149. });
  5150. enable_growth_part("paws");
  5151. document.querySelector(".game-area").style.display = "grid";
  5152. document.getElementById("log").style.display = "inline";
  5153. document.getElementById("react-log").style.display = "inline";
  5154. document.getElementById("character-build-area").style.display = "none";
  5155. document.getElementById("action-panel").style.display = "flex";
  5156. enable_panel("options");
  5157. enable_panel("body");
  5158. enable_panel("paws");
  5159. enable_button("stomp");
  5160. enable_button("hand_crush");
  5161. enable_button("foot_crush");
  5162. enable_button("sit");
  5163. enable_button("grind");
  5164. enable_button("ass_grind");
  5165. if (macro.footType != "hoof") enable_button("flex_toes");
  5166. enable_growth_part("body");
  5167. enable_growth_part("ass");
  5168. if (macro.arousalEnabled) {
  5169. document.querySelector("#arousalMeter").style.display = "inline-block";
  5170. document.querySelector("#orgasmMeter").style.display = "inline-block";
  5171. document.querySelector("#edgeMeter").style.display = "inline-block";
  5172. }
  5173. if (macro.oralVore) {
  5174. if (macro.brutality > 0) {
  5175. enable_button("chew");
  5176. }
  5177. }
  5178. if (macro.tailCount > 0) {
  5179. enable_panel("tails");
  5180. if (macro.tailMaw) {
  5181. if (macro.tailCount > 1) {
  5182. enable_button("tail_vore_one");
  5183. if (macro.tailCount > 2) {
  5184. enable_button("tail_vore_some");
  5185. }
  5186. enable_button("tail_vore_all");
  5187. } else {
  5188. enable_button("tail_vore_only");
  5189. }
  5190. }
  5191. }
  5192. if (macro.hasPouch) {
  5193. if (macro.oralVore) {
  5194. enable_button("pouch_eat");
  5195. }
  5196. }
  5197. if (macro.footWear) {
  5198. macro.footShoeWorn = macro.footShoeEnabled;
  5199. macro.footSockWorn = macro.footSockEnabled;
  5200. footwearUpdate();
  5201. }
  5202. if (macro.gooEnabled) {
  5203. macro.gooMolten = false;
  5204. }
  5205. document.getElementById("button-option-toggle_arousal").innerHTML =
  5206. macro.arousalEnabled ? "Arousal On" : "Arousal Off";
  5207. if (!macro.arousalEnabled) {
  5208. document.getElementById("arousal").style.display = "none";
  5209. document.getElementById("edge").style.display = "none";
  5210. }
  5211. document.getElementById("button-option-toggle_units").innerText =
  5212. "Units:\n" + unit.charAt(0).toUpperCase() + unit.slice(1); //sets units button to display selected unit on start
  5213. if (macro.victimsHuman) {
  5214. // eh this is ok
  5215. things["Person"]["Person"] = Human;
  5216. }
  5217. if (macro.victimsMacros) {
  5218. contents_insert("Town", "Macro", 2, 5);
  5219. contents_insert("City", "Macro", 5, 20);
  5220. contents_insert("Continent", "Macro", 100, 300);
  5221. }
  5222. macro.init();
  5223. switch (
  5224. macro.defaultBiome //sets starting biome as defined by player
  5225. ) {
  5226. case "City":
  5227. biome = biomeEnum.City;
  5228. break;
  5229. case "Downtown":
  5230. biome = biomeEnum.Downtown;
  5231. break;
  5232. case "Suburb":
  5233. biome = biomeEnum.Suburb;
  5234. break;
  5235. case "Rural":
  5236. biome = biomeEnum.Rural;
  5237. break;
  5238. }
  5239. generateBiome();
  5240. update(warns);
  5241. if (warns.length > 0) {
  5242. update([newline]);
  5243. }
  5244. document.getElementById("actions-body").style.display = "flex";
  5245. document.getElementById("stat-container").style.display = "flex";
  5246. repeatUpdate();
  5247. window.scroll(0, 0);
  5248. }
  5249. function repeatUpdate() {
  5250. update();
  5251. setTimeout(repeatUpdate, fillPeriod);
  5252. }
  5253. function actionTab(e) {
  5254. let name = e.target.id;
  5255. let target = "actions-" + name.replace(/action-part-/, "");
  5256. document
  5257. .querySelectorAll(".action-part-button.active")
  5258. .forEach(function (element) {
  5259. element.classList.remove("active");
  5260. });
  5261. document.querySelectorAll(".action-tab").forEach(function (element) {
  5262. element.style.display = "none";
  5263. });
  5264. e.target.classList.add("active");
  5265. document.getElementById(target).style.display = "flex";
  5266. }
  5267. function showStats() {
  5268. let lines = [];
  5269. let total = 0;
  5270. for (var key in victims) {
  5271. if (victims.hasOwnProperty(key)) {
  5272. if (victims[key]["people"] > 0) {
  5273. lines.push([
  5274. victims[key]["people"] + " " + describeVictim("victim-" + key, macro),
  5275. victims[key]["people"],
  5276. ]);
  5277. total += victims[key]["people"];
  5278. }
  5279. }
  5280. }
  5281. // sort in descending order of kills/victims
  5282. lines = lines.sort(function (x, y) {
  5283. if (x[1] == y[1]) {
  5284. return 0;
  5285. } else {
  5286. return x[1] > y[1] ? -1 : 1;
  5287. }
  5288. });
  5289. lines = lines.map(function (x) {
  5290. return x[0];
  5291. });
  5292. if (macro.brutality > 0) {
  5293. lines.splice(0, 0, "Kills:");
  5294. } else {
  5295. lines.splice(0, 0, "Victims:");
  5296. }
  5297. lines.push("Total: " + total);
  5298. lines.push(newline);
  5299. update(lines);
  5300. }
  5301. function performAction(name) {
  5302. if (name != "magic_shrink" && macro.magicShrinkAuto) {
  5303. magic_shrink();
  5304. }
  5305. window[name]();
  5306. }
  5307. function registerActions() {
  5308. let buttons = document.querySelectorAll("[id^='button-action']");
  5309. buttons.forEach(function (button) {
  5310. let name = button.id;
  5311. name = name.replace(/button-action-/, "");
  5312. if (macro.difficulty > 0) {
  5313. button.addEventListener("click", function () {
  5314. cooldown_start(name);
  5315. performAction(name);
  5316. });
  5317. } else {
  5318. button.addEventListener("click", function () {
  5319. performAction(name);
  5320. });
  5321. }
  5322. });
  5323. }
  5324. function registerOptions() {
  5325. let buttons = document.querySelectorAll("[id^='button-option']");
  5326. buttons.forEach(function (button) {
  5327. let name = button.id;
  5328. name = name.replace(/button-option-/, "");
  5329. button.addEventListener("click", function (e) {
  5330. window[name](e);
  5331. });
  5332. });
  5333. }
  5334. function updateAllPreviews() {
  5335. document.querySelectorAll(".preview").forEach(function (prev) {
  5336. let name = prev.id.replace("Preview", "");
  5337. updatePreview(name);
  5338. });
  5339. }
  5340. function updatePreview(name) {
  5341. let scale = document.getElementById("scale").value;
  5342. if (scale == "") scale = document.getElementById("scale").placeholder;
  5343. let element = document.getElementById(name);
  5344. if (element == undefined) return;
  5345. let value = element.value;
  5346. let unitType = document.getElementById(name).dataset.unit;
  5347. if (value == "") value = document.getElementById(name).placeholder;
  5348. let result = "";
  5349. if (unitType == undefined) return;
  5350. if (unitType == "length") result = length(value * scale, unit);
  5351. else if (unitType == "area") result = area(value * scale * scale, unit);
  5352. else if (unitType == "volume")
  5353. result = volume((value * scale * scale * scale) / 1000, unit);
  5354. else if (unitType == "mass")
  5355. result = mass(value * scale * scale * scale, unit);
  5356. else if (unitType == "percentage") result = value + "%";
  5357. document.getElementById(name + "Preview").innerHTML = result;
  5358. }
  5359. function toggleTextFade() {
  5360. textFade = textFadeChoices[textFade.next];
  5361. const button = document.querySelector("#button-option-toggleTextFade");
  5362. button.innerText = textFade.name;
  5363. document
  5364. .querySelectorAll(".log")
  5365. .forEach((log) =>
  5366. log.style.setProperty("--fade-animation", textFade.animation)
  5367. );
  5368. }
  5369. function debugLog() {
  5370. console.log("Your character settings:");
  5371. console.log(JSON.stringify(generateSettings()["settings"]));
  5372. console.log("Current macro state:");
  5373. console.log(
  5374. JSON.stringify(macro, function (key, value) {
  5375. if (key == "owner") {
  5376. return "owner";
  5377. } else {
  5378. return value;
  5379. }
  5380. })
  5381. );
  5382. alert(
  5383. 'Debug info has been logged to console. Press F12, click "Console", and copy all the text'
  5384. );
  5385. }
  5386. window.addEventListener("load", function (event) {
  5387. (function () {
  5388. let storage = window.localStorage;
  5389. if (storage.getItem("dark-mode") != null) {
  5390. setDarkMode(storage.getItem("dark-mode") === "true");
  5391. }
  5392. })();
  5393. if (storage.getItem("custom-characters") == undefined) {
  5394. storage.setItem("custom-characters", JSON.stringify({}));
  5395. }
  5396. // this migrates the old single custom character slot over
  5397. if (storage.getItem("settings") != undefined) {
  5398. let character = JSON.parse(storage.getItem("settings"));
  5399. let saves = JSON.parse(storage.getItem("custom-characters"));
  5400. saves[character.name] = character;
  5401. localStorage.setItem("custom-characters", JSON.stringify(saves));
  5402. localStorage.removeItem("settings");
  5403. }
  5404. updateCustomCharacters();
  5405. document.querySelectorAll(".version").forEach(function (x) {
  5406. x.innerText = "Version: " + version;
  5407. });
  5408. construct_options();
  5409. construct_panels();
  5410. document
  5411. .querySelector("#save-version")
  5412. .setAttribute("placeholder", migrations.length);
  5413. document.querySelectorAll("input[type='number']").forEach(function (x) {
  5414. x.addEventListener("input", function () {
  5415. updatePreview(x.id);
  5416. });
  5417. });
  5418. updateAllPreviews();
  5419. document.querySelector("#scale").addEventListener("input", updateAllPreviews);
  5420. presets.sort(function (x, y) {
  5421. let xp = x.priority === undefined ? 0 : x.priority;
  5422. let yp = y.priority === undefined ? 0 : y.priority;
  5423. if (xp != yp) {
  5424. return yp - xp;
  5425. } else {
  5426. return x.name.localeCompare(y.name);
  5427. }
  5428. });
  5429. let category_list = document.getElementById("character-preset-categories");
  5430. presetCategories.forEach((name) => {
  5431. let opt = document.createElement("option");
  5432. opt.innerHTML = name;
  5433. opt.value = name;
  5434. category_list.appendChild(opt);
  5435. });
  5436. category_list.addEventListener("change", updatePresets);
  5437. let list = document.getElementById("character-presets");
  5438. for (let i = 0; i < presets.length; i++) {
  5439. let opt = document.createElement("option");
  5440. opt.innerHTML = presets[i]["name"];
  5441. opt.dataset.category = presets[i].category || "default";
  5442. opt.value = i;
  5443. list.appendChild(opt);
  5444. }
  5445. updatePresets();
  5446. register_buttons();
  5447. update_visible_groups();
  5448. setTimeout(pick_move, 2000);
  5449. });
  5450. function updatePresets(e) {
  5451. const list = document.getElementById("character-presets");
  5452. const category_list = document.getElementById("character-preset-categories");
  5453. Array.from(list.options).forEach((x) => {
  5454. if (x.dataset.category == category_list.value) {
  5455. x.style.display = "block";
  5456. } else {
  5457. x.style.display = "none";
  5458. }
  5459. });
  5460. if (list.selectedOptions[0].style.display == "none") {
  5461. for (let i = 0; i < list.options.length; i++) {
  5462. if (list.options[i].style.display != "none") {
  5463. list.selectedIndex = i;
  5464. break;
  5465. }
  5466. }
  5467. }
  5468. }
  5469. function reset_visible_groups() {
  5470. groups.forEach((group) => {
  5471. document.querySelector("#group-toggle-" + group).checked = false;
  5472. });
  5473. update_visible_groups();
  5474. }
  5475. function update_visible_groups() {
  5476. groups.forEach((group) => {
  5477. const state = document.querySelector("#group-toggle-" + group).checked;
  5478. document.querySelectorAll(".sheet-group-" + group).forEach((category) => {
  5479. if (state) category.style.display = "";
  5480. else category.style.display = "none";
  5481. });
  5482. });
  5483. }
  5484. function register_buttons() {
  5485. document.querySelectorAll(".action-part-button").forEach(function (element) {
  5486. element.addEventListener("click", actionTab);
  5487. });
  5488. document.getElementById("button-look").addEventListener("click", look);
  5489. document.getElementById("button-stats").addEventListener("click", showStats);
  5490. document
  5491. .getElementById("button-dark-mode-options")
  5492. .addEventListener("click", toggleDarkMode);
  5493. document.querySelectorAll(".growth-part").forEach(function (button) {
  5494. button.addEventListener("select", function () {
  5495. grow_part_pick(button.id);
  5496. });
  5497. });
  5498. document
  5499. .getElementById("button-growth-1.1")
  5500. .addEventListener("click", function () {
  5501. grow_pick(11);
  5502. });
  5503. document
  5504. .getElementById("button-growth-1.5")
  5505. .addEventListener("click", function () {
  5506. grow_pick(15);
  5507. });
  5508. document
  5509. .getElementById("button-growth-2")
  5510. .addEventListener("click", function () {
  5511. grow_pick(20);
  5512. });
  5513. document
  5514. .getElementById("button-growth-5")
  5515. .addEventListener("click", function () {
  5516. grow_pick(50);
  5517. });
  5518. document
  5519. .getElementById("button-growth-20")
  5520. .addEventListener("click", function () {
  5521. grow_pick(200);
  5522. });
  5523. document
  5524. .getElementById("button-growth-100")
  5525. .addEventListener("click", function () {
  5526. grow_pick(1000);
  5527. });
  5528. document
  5529. .getElementById("button-load-preset")
  5530. .addEventListener("click", loadPreset);
  5531. document
  5532. .getElementById("button-export-clear")
  5533. .addEventListener("click", clearExport);
  5534. document
  5535. .getElementById("button-export-preset")
  5536. .addEventListener("click", exportSettings);
  5537. document
  5538. .getElementById("button-import-preset")
  5539. .addEventListener("click", importSettings);
  5540. document
  5541. .getElementById("button-reset-custom")
  5542. .addEventListener("click", resetSettings);
  5543. document
  5544. .getElementById("button-load-autosave")
  5545. .addEventListener("click", loadAutosave);
  5546. document
  5547. .getElementById("button-units-options")
  5548. .addEventListener("click", toggle_units_options);
  5549. // note to self - the anonymous function is so that
  5550. // loadSettings doesn't receive the mouseEvent!
  5551. document
  5552. .getElementById("button-load-custom")
  5553. .addEventListener("click", function () {
  5554. loadSettings();
  5555. });
  5556. document
  5557. .getElementById("button-save-custom")
  5558. .addEventListener("click", function () {
  5559. saveSettings();
  5560. });
  5561. document
  5562. .getElementById("button-delete-custom")
  5563. .addEventListener("click", function () {
  5564. deleteSettings();
  5565. });
  5566. document.getElementById("button-start").addEventListener("click", startGame);
  5567. }
  5568. function render_text_option(li, option) {
  5569. let input = document.createElement("input");
  5570. input.setAttribute("autocomplete", "off");
  5571. input.setAttribute("id", option.id);
  5572. input.setAttribute("name", option.id);
  5573. input.setAttribute("type", "text");
  5574. if (option.default) {
  5575. input.setAttribute("placeholder", option.default);
  5576. }
  5577. let label = document.createElement("label");
  5578. label.setAttribute("for", option.id);
  5579. label.innerText = option.name;
  5580. li.appendChild(label);
  5581. li.appendChild(input);
  5582. }
  5583. function render_number_option(li, option, type) {
  5584. let input = document.createElement("input");
  5585. input.setAttribute("autocomplete", "off");
  5586. input.setAttribute("id", option.id);
  5587. input.setAttribute("name", option.id);
  5588. input.setAttribute("type", "number");
  5589. if (type == "int") {
  5590. input.setAttribute("step", "1");
  5591. input.setAttribute("pattern", "\\d*");
  5592. } else if (type == "float") {
  5593. input.setAttribute("step", "any");
  5594. }
  5595. if (option.default) {
  5596. input.setAttribute("placeholder", option.default);
  5597. }
  5598. let label = document.createElement("label");
  5599. label.setAttribute("for", option.id);
  5600. label.innerText = option.name;
  5601. if (option.tooltip != undefined) {
  5602. label.classList.add("has-tooltip");
  5603. label.setAttribute("title", option.tooltip);
  5604. }
  5605. li.appendChild(label);
  5606. li.appendChild(input);
  5607. if (option.unit) {
  5608. input.setAttribute("data-unit", option.unit);
  5609. let unit = document.createElement("div");
  5610. unit.classList.add("preview");
  5611. unit.id = option.id + "Preview";
  5612. li.appendChild(unit);
  5613. }
  5614. }
  5615. function render_float_option(li, option) {
  5616. render_number_option(li, option, "float");
  5617. }
  5618. function render_int_option(li, option) {
  5619. render_number_option(li, option, "int");
  5620. }
  5621. //sets up style for "radio" in features.js
  5622. function render_radio_option(options_div, option) {
  5623. option.choices.forEach(function (choice) {
  5624. let li = document.createElement("li");
  5625. let input = document.createElement("input");
  5626. input.setAttribute("autocomplete", "off");
  5627. input.setAttribute("id", option.id + "-" + choice.value);
  5628. input.setAttribute("name", option.id);
  5629. input.setAttribute("value", choice.value);
  5630. input.setAttribute("type", "radio");
  5631. if (option.default == choice.value) {
  5632. input.setAttribute("checked", true);
  5633. }
  5634. let label = document.createElement("label");
  5635. label.setAttribute("for", option.id + "-" + choice.value);
  5636. label.innerText = choice.name;
  5637. label.classList.add("solo");
  5638. if (choice.tooltip) {
  5639. label.classList.add("has-tooltip");
  5640. label.title = choice.tooltip;
  5641. }
  5642. attach_form_data(input, choice);
  5643. li.appendChild(input);
  5644. li.appendChild(label);
  5645. options_div.appendChild(li);
  5646. });
  5647. }
  5648. //sets up style for "checkbox" in features.js
  5649. function render_checkbox_option(li, option) {
  5650. let input = document.createElement("input");
  5651. input.setAttribute("autocomplete", "off");
  5652. input.setAttribute("id", option.id);
  5653. input.setAttribute("name", option.id);
  5654. input.setAttribute("type", "checkbox");
  5655. if (option.default) {
  5656. input.setAttribute("checked", true);
  5657. }
  5658. let label = document.createElement("label");
  5659. label.setAttribute("for", option.id);
  5660. label.innerText = option.name;
  5661. label.classList.add("solo");
  5662. attach_form_data(input, option);
  5663. if (option.tooltip != undefined) {
  5664. label.classList.add("has-tooltip");
  5665. label.setAttribute("title", option.tooltip);
  5666. }
  5667. li.appendChild(input);
  5668. li.appendChild(label);
  5669. }
  5670. function render_select_option(li, option) {
  5671. let label = document.createElement("label");
  5672. label.setAttribute("for", option.id);
  5673. label.innerText = option.name;
  5674. let select = document.createElement("select");
  5675. select.setAttribute("id", option.id);
  5676. select.setAttribute("name", option.id);
  5677. option.choices.forEach(function (choice) {
  5678. let sub_option = document.createElement("option");
  5679. sub_option.innerText = choice.name;
  5680. sub_option.setAttribute("value", choice.value);
  5681. if (option.default == choice.value) {
  5682. sub_option.defaultSelected = true;
  5683. }
  5684. select.appendChild(sub_option);
  5685. });
  5686. if (option.tooltip != undefined) {
  5687. label.classList.add("has-tooltip");
  5688. label.setAttribute("title", option.tooltip);
  5689. }
  5690. li.appendChild(label);
  5691. li.appendChild(select);
  5692. }
  5693. function render_subcategory_option(li, option) {
  5694. let sub_div = document.createElement("div");
  5695. sub_div.classList.add("custom-category-sub");
  5696. let sub_ul = document.createElement("ul");
  5697. sub_ul.classList.add("flex-outer-sub");
  5698. let sub_input = document.createElement("input");
  5699. sub_input.classList.add("custom-header-checkbox");
  5700. sub_input.id = option.id;
  5701. sub_input.setAttribute("name", option.id);
  5702. sub_input.setAttribute("type", "checkbox");
  5703. if (option.default === true) {
  5704. sub_input.setAttribute("checked", true);
  5705. }
  5706. let sub_label = document.createElement("label");
  5707. sub_label.classList.add("custom-header");
  5708. sub_label.setAttribute("for", option.id);
  5709. sub_label.innerText = option.name;
  5710. sub_label.classList.add("solo");
  5711. let sub_div_inner = document.createElement("div");
  5712. sub_div_inner.classList.add("reveal-if-active");
  5713. sub_ul.appendChild(sub_input);
  5714. sub_ul.appendChild(sub_label);
  5715. sub_ul.appendChild(sub_div_inner);
  5716. option.entries.forEach(function (option) {
  5717. let li = document.createElement("li");
  5718. render_option(sub_div_inner, li, option);
  5719. sub_div_inner.appendChild(li);
  5720. });
  5721. attach_form_data(sub_input, option);
  5722. sub_div.appendChild(sub_ul);
  5723. li.appendChild(sub_div);
  5724. }
  5725. function render_label(li, option) {
  5726. let div = document.createElement("div");
  5727. div.classList.add("custom-label");
  5728. div.textContent = option.name;
  5729. if (option.tooltip != undefined) {
  5730. div.classList.add("has-tooltip");
  5731. div.setAttribute("title", option.tooltip);
  5732. }
  5733. li.appendChild(div);
  5734. }
  5735. function render_option(root_div, li, option) {
  5736. if (option.type == "text") {
  5737. render_text_option(li, option);
  5738. }
  5739. if (option.type == "float") {
  5740. render_float_option(li, option);
  5741. }
  5742. if (option.type == "int") {
  5743. render_int_option(li, option);
  5744. }
  5745. if (option.type == "radio") {
  5746. render_radio_option(root_div, option);
  5747. // we added n li elements; we need to skip the default one
  5748. return;
  5749. }
  5750. if (option.type == "checkbox") {
  5751. render_checkbox_option(li, option);
  5752. }
  5753. if (option.type == "select") {
  5754. render_select_option(li, option);
  5755. }
  5756. if (option.type == "subcategory") {
  5757. render_subcategory_option(li, option);
  5758. }
  5759. if (option.type == "label") {
  5760. render_label(li, option);
  5761. }
  5762. root_div.appendChild(li);
  5763. }
  5764. function render_category(root, category) {
  5765. let name = category.name;
  5766. let cat_id = category.id;
  5767. let cat_div = document.createElement("div");
  5768. cat_div.classList.add("custom-category");
  5769. let header;
  5770. if (category.optional) {
  5771. header = document.createElement("label");
  5772. let input = document.createElement("input");
  5773. input.classList.add("custom-header-checkbox");
  5774. input.setAttribute("type", "checkbox");
  5775. input.id = category.id;
  5776. input.name = category.id;
  5777. cat_div.appendChild(input);
  5778. header.classList.add("custom-header");
  5779. header.setAttribute("for", category.id);
  5780. attach_form_data(input, category);
  5781. } else {
  5782. header = document.createElement("div");
  5783. header.classList.add("custom-header-static");
  5784. }
  5785. if (category.group) {
  5786. cat_div.classList.add("sheet-group-" + category.group);
  5787. }
  5788. header.innerText = name;
  5789. let options_div = document.createElement("div");
  5790. if (category.optional) {
  5791. options_div.classList.add("reveal-if-active");
  5792. }
  5793. category.entries.forEach(function (option) {
  5794. let li = document.createElement("li");
  5795. render_option(options_div, li, option);
  5796. });
  5797. cat_div.appendChild(header);
  5798. cat_div.appendChild(options_div);
  5799. root.appendChild(cat_div);
  5800. }
  5801. function construct_options() {
  5802. let group_holder = document.getElementById("group-button-holder");
  5803. groups.forEach((group) => {
  5804. const label = document.createElement("label");
  5805. const input = document.createElement("input");
  5806. input.setAttribute("autocomplete", "off");
  5807. input.setAttribute("id", "group-toggle-" + group);
  5808. input.setAttribute("name", "group-toggle-" + group);
  5809. input.setAttribute("type", "checkbox");
  5810. label.setAttribute("for", "group-toggle-" + group);
  5811. label.innerText = groupInfo[group].name;
  5812. label.classList.add("group-toggle");
  5813. input.addEventListener("input", update_visible_groups);
  5814. label.classList.add("solo");
  5815. group_holder.appendChild(input);
  5816. group_holder.appendChild(label);
  5817. group_holder.appendChild(document.createElement("br"));
  5818. });
  5819. let root = document.getElementById("character-flex-outer");
  5820. options.forEach(function (category) {
  5821. render_category(root, category);
  5822. });
  5823. groups.forEach((group) => {
  5824. let div = document.createElement("div");
  5825. div.classList.add("group-banner");
  5826. div.classList.add("sheet-group-" + group);
  5827. div.innerText = groupInfo[group].name;
  5828. root.appendChild(div);
  5829. });
  5830. }
  5831. function attach_form_data(element, data) {
  5832. if (data.warning != undefined) {
  5833. element.setAttribute("data-warning", data.warning);
  5834. }
  5835. if (data.panels != undefined) {
  5836. element.setAttribute("data-panels", data.panels.join(","));
  5837. }
  5838. if (data.buttons != undefined) {
  5839. element.setAttribute("data-buttons", data.buttons.join(","));
  5840. }
  5841. if (data.stats != undefined) {
  5842. element.setAttribute("data-stats", data.stats.join(","));
  5843. }
  5844. if (data.parts != undefined) {
  5845. element.setAttribute("data-parts", data.parts.join(","));
  5846. }
  5847. }
  5848. function construct_panels() {
  5849. let root = document.getElementById("action-panel");
  5850. let panelList = document.createElement("div");
  5851. panelList.classList.add("action-part-container");
  5852. root.appendChild(panelList);
  5853. Object.entries(panels).forEach(function ([name, contents]) {
  5854. let buttons = document.createElement("div");
  5855. buttons.classList.add("action-tab");
  5856. buttons.id = "actions-" + name;
  5857. let panel_button = document.createElement("button");
  5858. panel_button.classList.add("action-part-button");
  5859. panel_button.id = "action-part-" + name;
  5860. panel_button.innerText = contents.name;
  5861. panelList.appendChild(panel_button);
  5862. contents.buttons.forEach(function (action) {
  5863. let button = document.createElement("button");
  5864. button.classList.add("action-button");
  5865. if (contents.type == "options") {
  5866. button.id = "button-option-" + action.target;
  5867. } else {
  5868. button.id = "button-action-" + action.target;
  5869. }
  5870. button.innerText = action.name;
  5871. if (action.default) {
  5872. button.style.display = "inline";
  5873. }
  5874. buttons.appendChild(button);
  5875. });
  5876. root.appendChild(buttons);
  5877. });
  5878. }