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

404 lines
12 KiB

  1. function ForestExplore() {
  2. GameObject.call(this, "Explore the Forest");
  3. this.actions.push({
  4. "name": "Explore",
  5. "action": function() {
  6. let outcome = Math.random();
  7. advanceTime(60*30 * (Math.random() * 0.2 + 0.9));
  8. if (outcome < 0.35) {
  9. currentRoom.flags.exit = true;
  10. update(["You find a way back!"]);
  11. } else if (outcome < 0.5) {
  12. startCombat(new Wolf());
  13. } else if (outcome < 0.6) {
  14. startCombat(new AlphaWolf());
  15. } else if (outcome < 0.75) {
  16. startCombat(new Anaconda());
  17. } else {
  18. update(["You explore the forest for a while, but don't find anything."]);
  19. }
  20. }
  21. });
  22. this.actions.push({
  23. "name": "Leave",
  24. "action": function() {
  25. moveToByName("East Trail", "You leave the forest");
  26. },
  27. "conditions": [
  28. function(player) {
  29. return currentRoom.flags.exit;
  30. }
  31. ]
  32. });
  33. }
  34. function Wolf() {
  35. Creature.call(this, "Wolf", 10, 15, 15);
  36. this.hasName = false;
  37. this.description = function(prefix) { return prefix + " wolf"; };
  38. this.attacks = [];
  39. this.attacks.push(wolfBite(this));
  40. this.attacks.push(wolfHowl(this));
  41. this.attacks.push(wolfTackle(this));
  42. this.attacks.push(wolfTackleBite(this));
  43. this.attacks.push(wolfTackleSwallow(this));
  44. this.attacks.push(grappledStruggle(this));
  45. this.backupAttack = pass(this);
  46. this.struggles = [];
  47. this.struggles.push(new struggle(this));
  48. this.struggles.push(new submit(this));
  49. this.digests = [];
  50. this.digests.push(wolfDigest(this));
  51. this.digests.push(wolfBelch(this));
  52. this.flags.stage = "combat";
  53. this.startCombat = function(player) {
  54. return ["A snapping twig grabs your attention. You turn and find yourself facing a large, mangy wolf. The cur stands at least half your height at the shoulder, and it looks <i>hungry.</i>"];
  55. };
  56. this.finishCombat = function() {
  57. if (this.flags.stage == "combat")
  58. return [this.description("The") + " knocks you to the ground. You bash your head on a rock and black out."];
  59. else if (this.flags.stage == "oral")
  60. return ["You fall limp in " + this.description("the") + "'s roiling guts, melting away to feed the mangy predator for a good, long time..."];
  61. };
  62. this.status = function(player) {
  63. return [];
  64. };
  65. }
  66. function AlphaWolf() {
  67. Creature.call(this, "Alpha Wolf", 20, 20, 20);
  68. this.hasName = false;
  69. this.description = function(prefix) { return prefix + " alpha wolf"; };
  70. this.attacks = [];
  71. this.attacks.push(wolfBite(this));
  72. this.attacks.push(wolfHowl(this));
  73. this.attacks.push(wolfTackle(this));
  74. this.attacks.push(wolfTackleBite(this));
  75. this.attacks.push(wolfTackleSwallow(this));
  76. this.attacks.push(wolfSwallow(this));
  77. this.attacks.push(grappledStruggle(this));
  78. this.attacks.push(grappledReverse(this));
  79. this.backupAttack = pass(this);
  80. this.struggles = [];
  81. this.struggles.push(new struggle(this));
  82. this.struggles.push(new submit(this));
  83. this.digests = [];
  84. this.digests.push(wolfDigest(this));
  85. this.digests.push(wolfBelch(this));
  86. this.flags.stage = "combat";
  87. this.startCombat = function(player) {
  88. return ["A low growl sends a chill up your spine. You turn around slowly, coming face-to-face with a massive, snarling wolf. Nearly six feet tall at the shoulder, the beast is eyeing you up as a snack."];
  89. };
  90. this.finishCombat = function() {
  91. if (this.flags.stage == "combat")
  92. return [this.description("The") + " knocks you to the ground. You bash your head on a rock and black out."];
  93. else if (this.flags.stage == "oral")
  94. return ["You fall limp in " + this.description("the") + "'s roiling guts, melting away to feed the mangy predator for a good, long time..."];
  95. };
  96. this.status = function(player) {
  97. return [];
  98. };
  99. }
  100. function wolfBite(attacker) {
  101. return {
  102. attackPlayer: function(defender){
  103. let damage = attack(attacker, defender, attacker.str);
  104. return [attacker.description("The") + " jumps at you, biting for " + damage + " damage"];
  105. },
  106. requirements: [
  107. function(attacker, defender) {
  108. return attacker.flags.stage == "combat";
  109. },
  110. function(attacker, defender) {
  111. return !attacker.flags.grappled && !defender.flags.grappled;
  112. }
  113. ],
  114. priority: 1,
  115. weight: function(attacker, defender) { return 1 + defender.health/defender.maxHealth; }
  116. };
  117. }
  118. function wolfHowl(attacker) {
  119. return {
  120. attackPlayer: function(defender){
  121. attacker.statBuffs.push(new StatBuff("str", 1.25));
  122. return [attacker.description("The") + " backs up and lets out a long, wailing howl.",newline,"It seems emboldened."];
  123. },
  124. requirements: [
  125. function(attacker, defender) {
  126. return attacker.flags.stage == "combat";
  127. },
  128. function(attacker, defender) {
  129. return !attacker.flags.grappled && !defender.flags.grappled;
  130. }
  131. ],
  132. priority: 1,
  133. weight: function(attacker, defender) { return 0.25; }
  134. };
  135. }
  136. function wolfTackle(attacker) {
  137. return {
  138. attackPlayer: function(defender){
  139. defender.flags.grappled = true;
  140. return [attacker.description("The") + " leaps on top of you, pinning you to the ground!"];
  141. },
  142. requirements: [
  143. function(attacker, defender) {
  144. return attacker.flags.stage == "combat";
  145. },
  146. function(attacker, defender) {
  147. return !attacker.flags.grappled && !defender.flags.grappled;
  148. }
  149. ],
  150. priority: 1,
  151. weight: function(attacker, defender) { return 1.25 - defender.health/defender.maxHealth; }
  152. };
  153. }
  154. function wolfTackleBite(attacker) {
  155. return {
  156. attackPlayer: function(defender){
  157. let damage = attack(attacker, defender, attacker.str * 1.5);
  158. return pickRandom([
  159. ["Pain shoots through your arm as " + attacker.description("the") + " bites it for " + damage + " damage!"],
  160. ["You struggle against " + attacker.description("the") + " as it bites your shoulder for " + damage + " damage."],
  161. [attacker.description("The") + "'s claws dig into your legs for " + damage + " damage."]
  162. ]);
  163. },
  164. requirements: [
  165. function(attacker, defender) {
  166. return attacker.flags.stage == "combat";
  167. },
  168. function(attacker, defender) {
  169. return !attacker.flags.grappled && defender.flags.grappled;
  170. }
  171. ],
  172. priority: 1,
  173. weight: function(attacker, defender) { return 1 + defender.health/defender.maxHealth; }
  174. };
  175. }
  176. function wolfTackleSwallow(attacker) {
  177. return {
  178. attackPlayer: function(defender){
  179. attacker.flags.stage = "oral";
  180. changeMode("eaten");
  181. return ["You struggle against " + attacker.description("the") + ", but it's not enough - its greedy jaws envelop your head, then your shoulders. The hungry beast swallows you down in seconds, cramming you into its hot, slimy stomach."];
  182. },
  183. conditions: [
  184. function(attacker, defender) {
  185. return defender.prefs.prey && defender.prefs.vore.oral > 0;
  186. }
  187. ],
  188. requirements: [
  189. function(attacker, defender) {
  190. return attacker.flags.stage == "combat";
  191. },
  192. function(attacker, defender) {
  193. return !attacker.flags.grappled && defender.flags.grappled;
  194. }
  195. ],
  196. priority: 1,
  197. weight: function(attacker, defender) { return 1; }
  198. };
  199. }
  200. function wolfSwallow(attacker) {
  201. return {
  202. attackPlayer: function(defender){
  203. let success = statCheck(attacker, defender, "dex") || defender.stamina == 0;
  204. if (success) {
  205. attacker.flags.stage = "oral";
  206. changeMode("eaten");
  207. return [attacker.description("The") + " charges, closing the gap in the blink of an eye and jamming your upper body into its massive, drool-slathered maw. <i>Glrp, glllpkh, gulp</i> - and you're in its throat, thrashing and struggling as you plunge into the greedy beast's sloppy stomach."];
  208. } else {
  209. return [attacker.description("The") + " lunges at you, racing up with jaws splayed wide open. You leap to the side, barely avoiding the greedy beast's maw as it barrels past, growling and snapping in frustration."];
  210. }
  211. },
  212. conditions: [
  213. function(attacker, defender) {
  214. return defender.prefs.prey && defender.prefs.vore.oral > 0;
  215. }
  216. ],
  217. requirements: [
  218. function(attacker, defender) {
  219. return attacker.flags.stage == "combat";
  220. },
  221. function(attacker, defender) {
  222. return !attacker.flags.grappled && !defender.flags.grappled;
  223. }
  224. ],
  225. priority: 1,
  226. weight: function(attacker, defender) { return 1; }
  227. };
  228. }
  229. function wolfDigest(attacker) {
  230. return {
  231. digest: function(defender){
  232. let damage = attack(attacker, defender, attacker.str * 3);
  233. return [attacker.description("The") + "'s churning guts wear you down."];
  234. },
  235. requirements: [
  236. function(attacker, defender) {
  237. return attacker.flags.stage == "oral";
  238. }
  239. ],
  240. priority: 1,
  241. weight: function(attacker, defender) { return 1; },
  242. gameover: function() { return "Digested by " + attacker.description("a"); }
  243. };
  244. }
  245. function wolfBelch(attacker) {
  246. return {
  247. digest: function(defender){
  248. defender.stamina -= 50;
  249. let damage = attack(attacker, defender, attacker.str * 2);
  250. return [attacker.description("The") + " lets out a crass <i>BELCH</i>, draining air from its snarling gut and squeezing you even tighter than before."];
  251. },
  252. requirements: [
  253. function(attacker, defender) {
  254. return attacker.flags.stage == "oral";
  255. }
  256. ],
  257. priority: 1,
  258. weight: function(attacker, defender) { return 1; },
  259. gameover: function() { return "Reduced to a belch by " + attacker.description("a"); }
  260. };
  261. }
  262. function Anaconda() {
  263. Creature.call(this, "Anaconda", 30, 10, 20);
  264. this.hasName = false;
  265. this.description = function(prefix) { return prefix + " anaconda"; };
  266. this.flags.state = "combat";
  267. this.flags.oral = {};
  268. this.flags.grapple = {};
  269. let attacker = this;
  270. this.attacks = [];
  271. // hiss at player
  272. this.attacks.push({
  273. attackPlayer: function(defender) {
  274. return pickRandom([
  275. ["The anaconda raises its head and hisses"],
  276. ["The hulking serpent narrows its eyes and hisses at you"]
  277. ]);
  278. },
  279. requirements: [
  280. function(attacker, defender) {
  281. return attacker.flags.state == "combat";
  282. }
  283. ],
  284. priority: 1,
  285. weight: function(attacker, defender) { return 1; }
  286. });
  287. // slap player with tail
  288. this.attacks.push({
  289. attackPlayer: function(defender) {
  290. if (statHealthCheck(attacker, defender, "dex")) {
  291. let damage = attack(attacker, defender, "str");
  292. return ["The snake's tail whips around, smacking you for " + damage + " damage!"];
  293. } else {
  294. return ["The serpent's tail lashes at you, but you manage to stay out of its way."];
  295. }
  296. },
  297. requirements: [
  298. function(attacker, defender) {
  299. return attacker.flags.state == "combat";
  300. }
  301. ],
  302. priority: 1,
  303. weight: function(attacker, defender) { return 1; }
  304. });
  305. // grab player with tail
  306. this.attacks.push({
  307. attackPlayer: function(defender) {
  308. if (statHealthCheck(attacker, defender, "dex")) {
  309. let damage = attack(attacker, defender, "str");
  310. return ["The snake's tail whips around and grabs you! A tight embrace of smooth, cold scales grips your entire upper body, a lazy <i>clench</i> of muscle suppressing your meek struggles."];
  311. } else {
  312. return ["The anaconda tries to snatch you up in its tail. You dodge out of the way."];
  313. }
  314. },
  315. requirements: [
  316. function(attacker, defender) {
  317. return attacker.flags.state == "combat";
  318. }
  319. ],
  320. priority: 1,
  321. weight: function(attacker, defender) { return 4 - 4 * defender.healthPercentage(); }
  322. });
  323. //
  324. /** PLAYER ATTACKS **/
  325. this.playerAttacks = [];
  326. // pass in combat
  327. this.playerAttacks.push(
  328. function(attacker) {
  329. return {
  330. name: "Pass",
  331. desc: "Do nothing",
  332. attack: function(defender) {
  333. return ["You do nothing."];
  334. },
  335. requirements: [
  336. function(attacker, defender) {
  337. return defender.flags.state == "combat";
  338. }
  339. ]
  340. };
  341. }
  342. );
  343. }