From 854683dda669eb21cd03cbbd2117574ffdde6bf9 Mon Sep 17 00:00:00 2001 From: Fen Dweller Date: Mon, 12 Mar 2018 11:07:26 -0400 Subject: [PATCH] Common enemies can now pin and devour the player --- combat.js | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- feast.js | 34 +++++++++++-------- vore.js | 14 ++++++-- 3 files changed, 130 insertions(+), 18 deletions(-) diff --git a/combat.js b/combat.js index aaff6ef..9170844 100644 --- a/combat.js +++ b/combat.js @@ -6,6 +6,14 @@ function attack(attacker, defender, baseDamage) { return damage; } +function isNormal(entity) { + return entity.grappled != true; +} + +function isGrappled(entity) { + return entity.grappled == true; +} + function punchAttack(attacker) { return { name: "Punch", @@ -15,7 +23,9 @@ function punchAttack(attacker) { }, attackPlayer: function(defender) { return "The " + attacker.description() + " punches you for " + attack(attacker, defender, attacker.str) + " damage"; - } + }, requirements: [ + function(attacker, defender) { return isNormal(attacker) && isNormal(defender); } + ] }; } @@ -28,6 +38,92 @@ function flankAttack(attacker) { }, attackPlayer: function(defender) { return "The " + attacker.description() + " runs past you, then turns and hits you for " + attack(attacker, defender, attacker.str) + " damage"; + }, requirements: [ + function(attacker, defender) { return isNormal(attacker) && isNormal(defender); } + ] + }; +} + +function grapple(attacker) { + return { + name: "Grapple", + desc: "Try to grab your opponent", + attack: function(defender) { + let success = Math.random() < 0.5; + if (success) { + defender.grappled = true; + return "You charge at the " + defender.description() + ", tackling them and knocking them to the ground."; + } else { + return "You charge at the " + defender.description() + ", but they dodge out of the way!"; + } + }, + attackPlayer: function(defender) { + let success = Math.random() < 0.5; + if (success) { + defender.grappled = true; + return "The " + attacker.description() + " lunges at you, pinning you to the floor!"; + } else { + return "The " + attacker.description() + " tries to tackle you, but you deftly avoid them."; + } + }, + requirements: [ + function(attacker, defender) { return isNormal(attacker) && isNormal(defender); } + ] + }; +} + +function grappleDevour(attacker) { + return { + name: "Devour", + desc: "Try to consume your grappled opponent", + attack: function(defender) { + let success = Math.random() < 0.25 + (1 - defender.health / defender.maxHealth) * 0.75; + if (success) { + attacker.stomach.feed(defender); + defender.grappled = false; + changeMode("explore"); + return "You open your jaws wide, stuffing the " + defender.description() + "'s head into your gullet and greedily wolfing them down. Delicious."; + } else { + return "Your jaws open wide, but the " + defender.description() + " manages to avoid becoming " + attacker.species + " chow."; + } + }, + attackPlayer: function(defender) { + let success = Math.random() < 0.5 + (1 - defender.health / defender.maxHealth)*0.5 && Math.random() < 0.5; + if(success) { + defender.grappled = false; + changeMode("eaten"); + return "The " + attacker.description() + " forces your head into their sloppy jaws, devouring you despite your frantic struggles. Glp."; + } else { + return "The " + attacker.description() + " tries to swallow you down, but you manage to resist their hunger."; + } + }, requirements: [ + function(attacker, defender) { return isNormal(attacker) && isGrappled(defender); } + ] + }; +} + +function grappleRelease(attacker) { + return { + name: "Release", + desc: "Release your opponent", + attack: function(defender) { + defender.grappled = false; + return "You throw the " + defender.description() + " back, dealing " + attack(attacker, defender, attacker.str*1.5) + " damage"; + }, requirements: [ + function(attacker, defender) { return isNormal(attacker) && isGrappled(defender); } + ] + }; +} + +function pass(attacker) { + return { + name: "Pass", + desc: "You can't do anything!", + attack: function(defender) { + return "You do nothing."; + }, + attackPlayer: function(defender) { + return "The " + attacker.description() + " does nothing."; } }; } @@ -46,7 +142,7 @@ function devourPlayer(attacker) { changeMode("eaten"); return "The voracious " + attacker.description() + " pins you down and devours you in seconds."; } - } + }; } function leer(attacker) { diff --git a/feast.js b/feast.js index 961361c..1adeaa1 100644 --- a/feast.js +++ b/feast.js @@ -11,6 +11,7 @@ let time = 9*60*60; let newline = " "; let player = new Player(); +let playerAttacks = []; let respawnRoom; @@ -20,6 +21,11 @@ let prefs = { } }; +function filterValid(options, attacker, defender) { + let filtered = options.filter(option => option.conditions == undefined || option.conditions.reduce((result, test) => result && test(prefs), true)); + return filtered.filter(option => option.requirements == undefined || option.requirements.reduce((result, test) => result && test(attacker, defender), true)); +} + function round(number, digits) { return Math.round(number * Math.pow(10,digits)) / Math.pow(10,digits); } @@ -96,11 +102,16 @@ function updateCombat() { list.removeChild(list.firstChild); } - for (let i = 0; i < player.attacks.length; i++) { + playerAttacks = filterValid(player.attacks, player, currentFoe); + + if (playerAttacks.length == 0) + playerAttacks = [player.backupAttack]; + + for (let i = 0; i < playerAttacks.length; i++) { let li = document.createElement("li"); let button = document.createElement("button"); button.classList.add("combat-button"); - button.innerHTML = player.attacks[i].name; + button.innerHTML = playerAttacks[i].name; button.addEventListener("click", function() { attackClicked(i); } ); button.addEventListener("mouseover", function() { attackHovered(i); } ); button.addEventListener("mouseout", function() { document.getElementById("combat-desc").innerHTML = ""; } ); @@ -248,6 +259,7 @@ function generateSettings() { function applySettings(settings) { player.name = settings.name; + player.species = settings.species; for (let key in settings) { if (settings.hasOwnProperty(key)) { @@ -309,22 +321,19 @@ function respawn(respawnRoom) { } function startCombat(opponent) { - changeMode("combat"); currentFoe = opponent; + changeMode("combat"); update(["Oh shit it's a " + opponent.description()]); } function attackClicked(index) { - update([player.attacks[index].attack(currentFoe)]); + update([playerAttacks[index].attack(currentFoe)]); if (currentFoe.health <= 0) { update(["The " + currentFoe.description() + " falls to the ground!"]); startDialog(new FallenFoe(currentFoe)); - } else { - let attacks = currentFoe.attacks.filter(attack => attack.conditions == undefined || attack.conditions.reduce((result, test) => result && test(prefs), true)); - attacks = attacks.filter(attack => attack.requirements == undefined || attack.requirements.reduce((result, test) => result && test(currentFoe, player), true)); - - let attack = pick(attacks); + } else if (mode == "combat") { + let attack = pick(filterValid(currentFoe.attacks, currentFoe, player)); if (attack == null) { attack = currentFoe.backupAttack; @@ -344,7 +353,7 @@ function attackClicked(index) { } function attackHovered(index) { - document.getElementById("combat-desc").innerHTML = player.attacks[index].desc; + document.getElementById("combat-desc").innerHTML = playerAttacks[index].desc; } function struggleClicked(index) { @@ -357,10 +366,7 @@ function struggleClicked(index) { if (result.escape) { changeMode("explore"); } else { - let digests = currentFoe.digests.filter(digest => digest.conditions == undefined || digest.conditions.reduce((result, test) => result && test(prefs), true)); - digests = digests.filter(digest => digest.requirements == undefined || digest.requirements.reduce((result, test) => result && test(currentFoe, player), true)); - - let digest = pick(digests); + let digest = pick(filterValid(currentFoe.digests, currentFoe, player)); if (digest == null) { digest = currentFoe.backupDigest; diff --git a/vore.js b/vore.js index 3ba4a8d..61bf4ca 100644 --- a/vore.js +++ b/vore.js @@ -29,7 +29,12 @@ function Player(name = "Player") { this.attacks.push(new punchAttack(this)); this.attacks.push(new flankAttack(this)); + this.attacks.push(new grapple(this)); + this.attacks.push(new grappleDevour(this)); + this.attacks.push(new grappleRelease(this)); + + this.backupAttack = new pass(this); this.str = 15; this.dex = 15; this.con = 15; @@ -53,6 +58,11 @@ function Anthro() { this.attacks.push(new punchAttack(this)); this.attacks.push(new flankAttack(this)); + this.attacks.push(new grapple(this)); + + this.attacks.push(new grappleDevour(this)); + + this.backupAttack = new pass(this); this.struggles = []; @@ -269,7 +279,7 @@ function plead(predator) { name: "Plead", desc: "Ask very, very nicely for the predator to let you go. More effective if you haven't hurt your predator.", struggle: function(player) { - let escape = Math.random() < predator.health / predator.maxHealth; + let escape = Math.random() < predator.health / predator.maxHealth && Math.random() < 0.33; if (escape) { return { @@ -291,7 +301,7 @@ function struggle(predator) { name: "Struggle", desc: "Try to squirm free. More effective if you've hurt your predator.", struggle: function(player) { - let escape = Math.random() > predator.health / predator.maxHealth; + let escape = Math.random() > predator.health / predator.maxHealth && Math.random() < 0.33; if (escape) { return {