function ForestExplore() {
GameObject.call(this, "Explore the Forest");
this.actions.push({
"name": "Explore",
"action": function() {
let outcome = Math.random();
advanceTime(60*30 * (Math.random() * 0.2 + 0.9));
if (outcome < 0.35) {
currentRoom.flags.exit = true;
update(["You find a way back!"]);
} else if (outcome < 0.5) {
startCombat(new Wolf());
} else if (outcome < 0.6) {
startCombat(new AlphaWolf());
} else {
update(["You explore the forest for a while, but don't find anything."]);
}
}
});
this.actions.push({
"name": "Leave",
"action": function() {
moveToByName("East Trail", "You leave the forest");
},
"conditions": [
function(player) {
return currentRoom.flags.exit;
}
]
});
}
function Wolf() {
Creature.call(this, "Wolf", 10, 15, 15);
this.hasName = false;
this.description = function(prefix) { return prefix + " wolf"; };
this.attacks = [];
this.attacks.push(wolfBite(this));
this.attacks.push(wolfHowl(this));
this.attacks.push(wolfTackle(this));
this.attacks.push(wolfTackleBite(this));
this.attacks.push(wolfTackleSwallow(this));
this.attacks.push(grappledStruggle(this));
this.backupAttack = pass(this);
this.struggles = [];
this.struggles.push(new struggle(this));
this.struggles.push(new submit(this));
this.digests = [];
this.digests.push(wolfDigest(this));
this.digests.push(wolfBelch(this));
this.flags.stage = "combat";
this.startCombat = function(player) {
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 hungry."];
};
this.finishCombat = function() {
if (this.flags.stage == "combat")
return [this.description("The") + " knocks you to the ground. You bash your head on a rock and black out."];
else if (this.flags.stage == "oral")
return ["You fall limp in " + this.description("the") + "'s roiling guts, melting away to feed the mangy predator for a good, long time..."];
};
this.status = function(player) {
return [];
};
}
function AlphaWolf() {
Creature.call(this, "Alpha Wolf", 20, 20, 20);
this.hasName = false;
this.description = function(prefix) { return prefix + " alpha wolf"; };
this.attacks = [];
this.attacks.push(wolfBite(this));
this.attacks.push(wolfHowl(this));
this.attacks.push(wolfTackle(this));
this.attacks.push(wolfTackleBite(this));
this.attacks.push(wolfTackleSwallow(this));
this.attacks.push(wolfSwallow(this));
this.attacks.push(grappledStruggle(this));
this.attacks.push(grappledReverse(this));
this.backupAttack = pass(this);
this.struggles = [];
this.struggles.push(new struggle(this));
this.struggles.push(new submit(this));
this.digests = [];
this.digests.push(wolfDigest(this));
this.digests.push(wolfBelch(this));
this.flags.stage = "combat";
this.startCombat = function(player) {
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."];
};
this.finishCombat = function() {
if (this.flags.stage == "combat")
return [this.description("The") + " knocks you to the ground. You bash your head on a rock and black out."];
else if (this.flags.stage == "oral")
return ["You fall limp in " + this.description("the") + "'s roiling guts, melting away to feed the mangy predator for a good, long time..."];
};
this.status = function(player) {
return [];
};
}
function wolfBite(attacker) {
return {
attackPlayer: function(defender){
let damage = attack(attacker, defender, attacker.str);
return [attacker.description("The") + " jumps at you, biting for " + damage + " damage"];
},
requirements: [
function(attacker, defender) {
return attacker.flags.stage == "combat";
},
function(attacker, defender) {
return !attacker.flags.grappled && !defender.flags.grappled;
}
],
priority: 1,
weight: function(attacker, defender) { return 1 + defender.health/defender.maxHealth; }
};
}
function wolfHowl(attacker) {
return {
attackPlayer: function(defender){
attacker.statBuffs.push(new StatBuff("str", 1.25));
return [attacker.description("The") + " backs up and lets out a long, wailing howl.",newline,"It seems emboldened."];
},
requirements: [
function(attacker, defender) {
return attacker.flags.stage == "combat";
},
function(attacker, defender) {
return !attacker.flags.grappled && !defender.flags.grappled;
}
],
priority: 1,
weight: function(attacker, defender) { return 0.25; }
};
}
function wolfTackle(attacker) {
return {
attackPlayer: function(defender){
defender.flags.grappled = true;
return [attacker.description("The") + " leaps on top of you, pinning you to the ground!"];
},
requirements: [
function(attacker, defender) {
return attacker.flags.stage == "combat";
},
function(attacker, defender) {
return !attacker.flags.grappled && !defender.flags.grappled;
}
],
priority: 1,
weight: function(attacker, defender) { return 1.25 - defender.health/defender.maxHealth; }
};
}
function wolfTackleBite(attacker) {
return {
attackPlayer: function(defender){
let damage = attack(attacker, defender, attacker.str * 1.5);
return pickRandom([
["Pain shoots through your arm as " + attacker.description("the") + " bites it for " + damage + " damage!"],
["You struggle against " + attacker.description("the") + " as it bites your shoulder for " + damage + " damage."],
[attacker.description("The") + "'s claws dig into your legs for " + damage + " damage."]
]);
},
requirements: [
function(attacker, defender) {
return attacker.flags.stage == "combat";
},
function(attacker, defender) {
return !attacker.flags.grappled && defender.flags.grappled;
}
],
priority: 1,
weight: function(attacker, defender) { return 1 + defender.health/defender.maxHealth; }
};
}
function wolfTackleSwallow(attacker) {
return {
attackPlayer: function(defender){
attacker.flags.stage = "oral";
changeMode("eaten");
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."];
},
conditions: [
function(attacker, defender) {
return defender.prefs.prey && defender.prefs.vore.oral > 0;
}
],
requirements: [
function(attacker, defender) {
return attacker.flags.stage == "combat";
},
function(attacker, defender) {
return !attacker.flags.grappled && defender.flags.grappled;
}
],
priority: 1,
weight: function(attacker, defender) { return 1; }
};
}
function wolfSwallow(attacker) {
return {
attackPlayer: function(defender){
let success = statCheck(attacker, defender, "dex") || defender.stamina == 0;
if (success) {
attacker.flags.stage = "oral";
changeMode("eaten");
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. Glrp, glllpkh, gulp - and you're in its throat, thrashing and struggling as you plunge into the greedy beast's sloppy stomach."];
} else {
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."];
}
},
conditions: [
function(attacker, defender) {
return defender.prefs.prey && defender.prefs.vore.oral > 0;
}
],
requirements: [
function(attacker, defender) {
return attacker.flags.stage == "combat";
},
function(attacker, defender) {
return !attacker.flags.grappled && !defender.flags.grappled;
}
],
priority: 1,
weight: function(attacker, defender) { return 1; }
};
}
function wolfDigest(attacker) {
return {
digest: function(defender){
let damage = attack(attacker, defender, attacker.str * 3);
return [attacker.description("The") + "'s churning guts wear you down."];
},
requirements: [
function(attacker, defender) {
return attacker.flags.stage == "oral";
}
],
priority: 1,
weight: function(attacker, defender) { return 1; },
gameover: function() { return "Digested by " + attacker.description("a"); }
};
}
function wolfBelch(attacker) {
return {
digest: function(defender){
defender.stamina -= 50;
let damage = attack(attacker, defender, attacker.str * 2);
return [attacker.description("The") + " lets out a crass BELCH, draining air from its snarling gut and squeezing you even tighter than before."];
},
requirements: [
function(attacker, defender) {
return attacker.flags.stage == "oral";
}
],
priority: 1,
weight: function(attacker, defender) { return 1; },
gameover: function() { return "Reduced to a belch by " + attacker.description("a"); }
};
}