Skip to content
Snippets Groups Projects
fAnimal.js 42.2 KiB
Newer Older
brickode's avatar
brickode committed

brickode's avatar
brickode committed
/**
 * @param {App.Entity.SlaveState} slave
 * @param {string} type
brickode's avatar
brickode committed
 */
App.Interact.fAnimal = function(slave, type) {
	const frag = new DocumentFragment();
	const {He, he, him, His, his, girl} = getPronouns(slave);
brickode's avatar
brickode committed
	/** @enum {string} */
	const Acts = {
		VAGINAL: "vaginal",
		ANAL: "anal",
		ORAL: "oral",
	};
	const vaginal = Acts.VAGINAL;
	const anal = Acts.ANAL;
	const oral = Acts.ORAL;
	const approvingFetishes = ["masochist", "humiliation", "perverted", "sinful"];	// not strictly fetishes, but approvingFetishesAndBehavioralQuirksAndSexualQuirks doesn't have the same ring to it
	const animal = V.active[type];

	let fetishDesc;
	let act;
	let hole;
	let orifice = [];
	const anAnimal = animal.articleAn ? `an ${animal.name}` : `a ${animal.name}`;

	if (slave.assignment === Job.FUCKTOY || slave.assignment === Job.MASTERSUITE) {
brickode's avatar
brickode committed
		if (slave.toyHole === "pussy") {
			act = vaginal;
brickode's avatar
brickode committed
		} else if (slave.toyHole === "ass") {
			act = anal;
brickode's avatar
brickode committed
		} else if (slave.toyHole === "mouth") {
			act = oral;
brickode's avatar
brickode committed
		} else {
			if (canDoVaginal(slave)) {
				act = vaginal;
brickode's avatar
brickode committed
			} else if (canDoAnal(slave)) {
				act = anal;
brickode's avatar
brickode committed
			} else {
				act = oral;
brickode's avatar
brickode committed
			}
brickode's avatar
brickode committed
		}
	} else if (canDoVaginal(slave)) {
		act = vaginal;
brickode's avatar
brickode committed
	} else if (canDoAnal(slave)) {
		act = anal;
brickode's avatar
brickode committed
	} else {
		act = oral;
	const slaveApproves = () =>
		approvingFetishes.includes(slave.fetish) ||
		approvingFetishes.includes(slave.sexualQuirk) ||
		approvingFetishes.includes(slave.behavioralQuirk) ||
		slave.fetish === "buttslut" && act === anal ||
		slave.fetish === "cumslut" && act === oral ||
		slave.sexualQuirk === "gagfuck queen" && act === oral;
	switch (act) {
		case oral:
			orifice = ["mouth", "throat"];
			break;
		case vaginal:
			orifice = ["pussy", "cunt"];
			hole = 0;
			break;
		case anal:
			orifice = ["asshole", "rectum"];
			hole = 1;
			break;
		default:
			throw new Error(`Unexpected act type '${act}' in fAnimal()`);
	}

	if (slave.fetish === "cumslut" && act === oral) {
brickode's avatar
brickode committed
		fetishDesc = `getting to drink more cum`;
	} else if (slave.fetish === "humiliation") {
		fetishDesc = `committing such a humiliating act`;
	} else if (slave.fetish === "buttslut" && act === anal) {
brickode's avatar
brickode committed
		fetishDesc = `getting to take a cock up ${his} ass`;
	} else if (slave.fetish === "masochist") {
		fetishDesc = `committing such a painful act`;
	} else if (slave.sexualQuirk === "perverted") {
		fetishDesc = `committing such a perverted act`;
	} else if (slave.sexualQuirk === "gagfuck queen" && act === oral) {
brickode's avatar
brickode committed
		fetishDesc = `getting to suck more dick`;
	} else if (slave.behavioralQuirk === "sinful") {
		fetishDesc = `committing such a sinful act`;
	}

	const mainDiv = App.UI.DOM.appendNewElement("div", frag);

	mainDiv.append(intro(), consummation(), completion(), sexEffects());
brickode's avatar
brickode committed

	if (V.postSexCleanUp) {
brickode's avatar
brickode committed
		mainDiv.append(cleanUp());
brickode's avatar
brickode committed
	}
	// MARK: Intro Functions
brickode's avatar
brickode committed
	function intro() {
		const mainSpan = document.createElement("span");

		const r = [];
brickode's avatar
brickode committed

		if (canWalk(slave)) {
			r.push(`You call ${him} over and`);
		} else {
			r.push(`You order another slave to bring ${slave.slaveName} over. Once ${he} is situated, you`);
		}

		r.push(`tell ${him} you want to watch ${him} ${act === oral ?
			`suck off` :
			act === vaginal ?
				`get fucked by` :
				`get fucked in the ass by`} ${anAnimal}. `);
brickode's avatar
brickode committed

		if (slave.fetish === "mindbroken") {
brickode's avatar
brickode committed
			r.push(`${slave.slaveName} nods ${his} head dumbly, ${his} eyes vacant${!canSee(slave) ? ` as always` : ``}. `);
brickode's avatar
brickode committed
		}

		mainSpan.append(r.join(' '));

		if (slave.fetish !== "mindbroken") {
			if (slave.devotion > 50) {
				mainSpan.append(introDevoted());
			} else if (slave.devotion > 20) {
				mainSpan.append(introNondevoted());
			} else if (slave.devotion >= -20) {
				mainSpan.append(introNonresistant());
			} else {
				mainSpan.append(introResistant());
			}
		}

brickode's avatar
brickode committed
		return mainSpan;



		function introDevoted() {
			const mainSpan = document.createElement("span");

			if (act === oral) {
				if (slaveApproves()) {
					mainSpan.append(`${slave.slaveName}'s face visibly brightens at the prospect of ${fetishDesc}, even if it's an animal${slave.fetish === "cumslut" ? `'s cum` : ` that ${he} has to suck off`}. `);
brickode's avatar
brickode committed
				} else {
					mainSpan.append(`${slave.slaveName} visibly blanches at the thought of having to suck down an animal's cum, but ${he} is so devoted to you that ${he} reluctantly agrees. `);
brickode's avatar
brickode committed
				}
			} else {
				if ((act === vaginal && slave.vagina > 0) || (act === anal && slave.anus > 0)) {
					if (slaveApproves()) {
						mainSpan.append(`${slave.slaveName}'s face visibly brightens at the thought of ${fetishDesc}, even if the dick is an animal's. `);
					} else {
						mainSpan.append(`${slave.slaveName} looks visibly disturbed, but is so attentive to your will that ${he} agrees. `);
					}
brickode's avatar
brickode committed
				} else {
					if (slaveApproves()) {
						mainSpan.append(`${slave.slaveName}'s face visibly brightens at the thought of ${fetishDesc}, although ${he} seems a bit hesitant at the thought of giving ${his} virginity to an animal. `);
					} else {
						mainSpan.append(`${slave.slaveName} looks visibly shaken at the thought of having ${his} precious ${!canDoVaginal(slave) ? `anal ` : ``}virginity taken by an animal, but is so attentive to your will that ${he} ultimately agrees. `);
					}
brickode's avatar
brickode committed

		function introNondevoted() {
			const mainSpan = document.createElement("span");
brickode's avatar
brickode committed

			if (act === oral) {
				if (slaveApproves()) {
					mainSpan.append(`${slave.slaveName} isn't too keen on the idea of sucking off an animal, but the idea of ${fetishDesc} is enough to get ${him} to comply. `);
				} else {
					mainSpan.append(`${slave.slaveName} tries in vain to conceal ${his} horror at the thought of blowing an animal, but quickly regains ${his} composure. `);
				}
			} else {
				if ((act === vaginal && slave.vagina > 0) || (act === anal && slave.anus > 0)) {
					if (slaveApproves()) {
						mainSpan.append(`${slave.slaveName} doesn't seem terribly keen on the idea of fucking an animal, but the thought of ${fetishDesc} seems to be enough to win ${him} over. `);
					} else {
						mainSpan.append(`${slave.slaveName} tries in vain to conceal ${his} horror at the thought of fucking an animal, but quickly regains ${his} composure. `);
				} else {
					if (slaveApproves()) {
						mainSpan.append(`${slave.slaveName} clearly has some reservations about having ${his} ${act === anal ? `anal ` : ``}virginity taken by ${anAnimal}, but the thought of ${fetishDesc} is enough to make agree to comply. `);
					} else {
						mainSpan.append(`${slave.slaveName} tries in vain to conceal ${his} horror at the thought of having ${his} precious ${act === anal ? `rosebud` : `pearl`} taken by a beast, but quickly regains ${his} composure. `);
					}
brickode's avatar
brickode committed

		function introNonresistant() {
			const mainSpan = document.createElement("span");
brickode's avatar
brickode committed

			if (act === oral) {
				if (slaveApproves()) {
					mainSpan.append(`${slave.slaveName} looks disgusted at the thought of sucking off an animal at first, but the thought of the ${fetishDesc} that comes with it seems to spark a small flame of lust in ${him}. `);
brickode's avatar
brickode committed
				} else {
					mainSpan.append(`${slave.slaveName} tries in vain to conceal ${his} horror at the thought of blowing an animal${canWalk(slave) ? `, and only the threat of worse punishment keeps ${him} from running away as fast as ${he} can` : ``}. `);
brickode's avatar
brickode committed
				}
			} else {
				if ((act === vaginal && slave.vagina > 0) || (act === anal && slave.anus > 0)) {
					if (slaveApproves()) {
						mainSpan.append(`${slave.slaveName} looks disgusted at the thought of fucking an animal at first, but the thought of the ${fetishDesc} that comes with it seems to spark a small flame of lust in ${him}. `);
					} else {
						mainSpan.append(`${slave.slaveName} tries in vain to conceal ${his} horror at the thought of fucking an animal${canWalk(slave) ? `, and only the threat of worse punishment keeps ${him} from running away as fast as ${he} can` : ``}. `);
brickode's avatar
brickode committed
				} else {
					if (slaveApproves()) {
						mainSpan.append(`${slave.slaveName} clearly has some reservations about having ${his} ${act === anal ? `anal ` : ``}virginity taken by ${anAnimal}, but the thought of ${fetishDesc} is enough to make agree to comply. `);
					} else {
						mainSpan.append(`${slave.slaveName} tries in vain to conceal ${his} horror at the thought of having ${his} precious ${act === anal ? `rosebud` : `pearl`} taken by a beast${canWalk(slave) ? `, and only the threat of worse punishment keeps ${him} from running away as fast as ${he} can` : ``}. `);
					}
brickode's avatar
brickode committed

		function introResistant() {
			const mainSpan = document.createElement("span");
brickode's avatar
brickode committed

			mainSpan.append(`${slave.slaveName}'s face contorts into a mixture of ${slave.devotion < -50 ? `hatred, anger, and disgust` : `anger and disgust`}, ${canWalk(slave) ?
				`and only the threat of far worse punishment is enough to prevent ${him} from running out of the room` :
				`but ${he} knows ${he} is powerless to stop you`}. `);
brickode's avatar
brickode committed




	// MARK: Consummation Functions

	function consummation() {
		if (slave.devotion > 50) {
			return consummationDevoted();
		} else if (slave.devotion > 20) {
			return consummationNondevoted();
		} else if (slave.devotion > -20) {
			return consummationNonresistant();
			return consummationResistant();
		function consummationDevoted() {
			const
				mainSpan = document.createElement("span"),
				r = [];
			if (act === oral) {
				r.push(`You have ${him} kneel on the floor before calling in the ${animal.name}. The beast slowly saunters up to the slave where ${he} waits, showing little concern when the slave reaches out and begins masturbating it to begin the process of getting the animal hard. Once the ${animal.name} is hard enough, ${slave.slaveName} takes its cock and begins to give it a few tentative licks before finally putting it in ${his} mouth. `);
				r.push(`You have ${him} ${slave.clothes !== "no clothing" ? `take off ${his} clothes and ` : ``}get on the floor, ass in the air, before calling in the ${animal.name}. The beast slowly saunters up to the slave, where it takes only a few short moments for its animal brain to realize that what it is standing behind is a warm hole that needs to be filled with seed. `);
			}

			switch (animal) {
				case V.active.canine:
					consummationDevotedCanine(act);
					break;
				case V.active.hooved:
					consummationDevotedHooved(act);
					break;
				case V.active.feline:
					consummationDevotedFeline(act);
					break;
				default:
					throw new Error(`Unexpected animal type '${animal}' in consummationDevoted()`);
			}

			if (act !== oral) {
				mainSpan.append(virginityCheck(act));
			}

			function consummationDevotedCanine(type) {
				if (type === oral) {
					if (slaveApproves()) {
						r.push(`The slave seems to quickly get over the fact that the dick currently in ${his} mouth belongs to a canine as ${his} more carnal desires kick in. `);
					} else {
						r.push(`The slave visibly gags as the unfamiliar texture of ${anAnimal}'s cock fills it, then gives a groan as the beast thrusts, filling ${his} throat. `);
					if (canWalk(slave)) {
						r.push(`The canine clambers up to mount ${slave.slaveName}, eliciting a squeal from the ${girl} as its claws dig into ${his} flesh. `);
					} else {
						r.push(`The canine takes a few curious sniffs, then lines up its large cock with ${slave.slaveName}'s ${act === vaginal ? `pussy` : `asshole`}. `);
					}
					r.push(`It takes a few tries, but the ${animal.name} finally manages to sink its cock into ${his} ${slaveApproves() && act === vaginal ? `wet ` : ``}${act === vaginal ? `cunt` : `asshole`} and begin to hammer away in the way that only canines can. `);
				}
			function consummationDevotedHooved(type) {
				if (type === oral) {
					if (slaveApproves()) {
						r.push(`The slave seems to quickly get over the fact that dick currently in ${his} mouth is not a human one as ${his} more carnal desires kick in. `);
					} else {
						r.push(`The slave visibly gags as the unfamiliar texture of ${anAnimal}'s cock fills it, then gives a groan as the beast thrusts, stretching ${his} poor throat to the limit. `);
					r.push(`${slave.slaveName} gives a long, drawn-out moan as the huge phallus fills ${his} ${act === vaginal ? `pussy` : `asshole`} nearly to its breaking point. `);
			function consummationDevotedFeline(type) {
				if (type === oral) {
					if (slaveApproves()) {
						r.push(`The slave seems to quickly get over the fact that dick currently in ${his} mouth belongs to ${anAnimal} as ${his} more carnal desires kick in. `);
						r.push(`The slave visibly gags as the unfamiliar texture of ${anAnimal}'s cock fills it, then gives a groan as the beast thrusts, the barbs on its cock rubbing the inside of ${his} mouth raw. `);
					r.push(`${slave.slaveName} gives a squeal of pain as the barbed cock makes its way into ${his} ${act === vaginal ? `pussy` : `asshole`}. `);
brickode's avatar
brickode committed

			mainSpan.append(r.join(' '));
brickode's avatar
brickode committed

		function consummationNondevoted() {
			const
				mainSpan = document.createElement("span"),
				r = [];
brickode's avatar
brickode committed

			if (act === oral) {
				r.push(`You tell ${him} to kneel on the floor before calling in the ${animal.name}. The beast slowly saunters up to the slave where ${he} waits, showing little concern when the slave hesitantly reaches out and begins masturbating it to begin the process of getting the animal hard. Once the ${animal.name} is hard enough, ${slave.slaveName} takes its cock, and, after taking a moment to steel ${his} resolve, begins to give it a few reluctant licks before putting it in ${his} mouth. `);
			} else {
				r.push(`You tell ${him} to ${slave.clothes !== "no clothing" ? `take off ${his} clothes and ` : ``}get on the floor, ass in the air, before calling in the ${animal.name}. The beast slowly saunters up to the slave, where it takes only a few seconds for its animal brain to realize that what it is standing behind is a warm hole that needs to be filled with seed. `);
			}
			switch (animal) {
				case V.active.canine:
					consummationNondevotedCanine(act);
					break;
				case V.active.hooved:
					consummationNondevotedHooved(act);
					break;
				case V.active.feline:
					consummationNondevotedFeline(act);
					break;
				default:
					throw new Error(`Unexpected animal type '${animal}' in consummationDevoted()`);
			}
			if (act !== oral) {
				mainSpan.append(virginityCheck(act));
			}
			function consummationNondevotedCanine(type) {
				if (type === oral) {
					if (slaveApproves()) {
						r.push(`Though the slave still seems to have some reservations about sucking off an animal, ${he} seems to forget that the cock in ${his} mouth belongs to ${anAnimal} soon enough, once ${his} carnal desires kick in. `);
						r.push(`The slave visibly gags as the unfamiliar texture of ${anAnimal}'s cock fills it, and you get the feeling ${he} is beginning to reevaluate just how much ${he} wants to avoid punishment. `);
					if (canWalk(slave)) {
						r.push(`The canine clambers up to mount ${slave.slaveName}, eliciting a squeal from the ${girl} as its claws dig into ${his} flesh. `);
					} else {
						r.push(`The canine takes a few curious sniffs, then lines up its large cock with ${slave.slaveName}'s ${act === vaginal ? `pussy` : `asshole`}. `);
					}
					r.push(`It takes a few tries, but the ${animal.name} finally manages to sink its cock into ${his} ${slaveApproves() && act === vaginal ? `wet ` : ``}${act === vaginal ? `cunt` : `asshole`} and begin to hammer away in the way that only canines can. `);
				}
			function consummationNondevotedHooved(type) {
				if (type === oral) {
					if (slaveApproves()) {
						r.push(`Though the slave still seems to have some reservations about sucking off ${anAnimal}, ${he} seems to forget that the cock in ${his} mouth isn't human soon enough, once ${his} carnal desires kick in. `);
						r.push(`The slave visibly gags as the unfamiliar texture of ${anAnimal}'s cock fills it, and you get the feeling ${he} is beginning to reevaluate just how much ${he} wants to avoid punishment. `);
					r.push(`${slave.slaveName} gives a long, drawn-out groan as the huge phallus fills ${his} ${act === vaginal ? `pussy` : `asshole`} nearly to its breaking point. `);
			function consummationNondevotedFeline(type) {
				if (type === oral) {
					if (slaveApproves()) {
						r.push(`Though the slave still seems to have some reservations about sucking off an animal, ${he} seems to forget that the cock in ${his} mouth belongs to a feline soon enough, once ${his} carnal desires kick in. `);
					} else {
						r.push(`The slave visibly gags as the unfamiliar texture of ${anAnimal}'s barbed dick fills it, and you get the feeling ${he} is beginning to reevaluate just how much ${he} wants to avoid punishment. `);
					r.push(`${slave.slaveName} gives a squeal of pain as the barbed cock makes its way into ${his} ${act === vaginal ? `pussy` : `asshole`}. `);
brickode's avatar
brickode committed

			mainSpan.append(r.join(' '));
brickode's avatar
brickode committed

		function consummationNonresistant() {
			const
				mainSpan = document.createElement("span"),
				r = [];
brickode's avatar
brickode committed

			if (act === oral) {
				r.push(`You force ${him} to kneel on the floor before calling in the ${animal.name}. The beast slowly saunters up to the slave where ${he} waits, showing little concern when the slave reluctantly reaches out and begins masturbating it to begin the process of getting the animal hard. Once the ${animal.name} is hard enough, ${slave.slaveName} takes its cock and begins to give it a few tentative licks before finally putting it in ${his} mouth. `);
			} else {
				r.push(`You force ${him} to ${slave.clothes !== "no clothing" ? `take off ${his} clothes and ` : ``}get on the floor, ass in the air, before calling in the ${animal.name}. The beast slowly saunters up to the slave, where it takes only a few short moments for its animal brain to realize that what it is standing behind is a warm hole that needs to be filled with seed. `);
			}
			switch (animal) {
				case V.active.canine:
					consummationNonresistantCanine(act);
					break;
				case V.active.hooved:
					consummationNonresistantHooved(act);
					break;
				case V.active.feline:
					consummationNonresistantFeline(act);
					break;
				default:
					throw new Error(`Unexpected animal type '${animal}' in consummationNonresistant()`);
			}
			if (act !== oral) {
				mainSpan.append(virginityCheck(act));
			}
			function consummationNonresistantCanine(type) {
				if (type === oral) {
					if (slaveApproves()) {
						r.push(`Though the slave still seems to have some reservations about sucking off an animal, ${he} seems to forget that the cock in ${his} mouth belongs to ${anAnimal} soon enough, once ${his} carnal desires kick in. `);
						r.push(`The slave visibly gags as the unfamiliar texture of ${anAnimal}'s cock fills it, and you get the feeling ${he} is beginning to reevaluate just how much ${he} wants to avoid punishment. `);
					if (canWalk(slave)) {
						r.push(`The canine clambers up to mount ${slave.slaveName}, eliciting a squeal from the ${girl} as its claws dig into ${his} flesh. `);
					} else {
						r.push(`The canine takes a few curious sniffs, then lines up its large cock with ${slave.slaveName}'s ${act === vaginal ? `pussy` : `asshole`}. `);
					}
					r.push(`It takes a few tries, but the ${animal.name} finally manages to sink its cock into ${his} ${slaveApproves() && act === vaginal ? `wet ` : ``}${act === vaginal ? `cunt` : `asshole`} and begin to hammer away in the way that only canines can. `);
				}
			function consummationNonresistantHooved(type) {
				if (type === oral) {
					if (slaveApproves()) {
						r.push(`Though the slave still seems to have some reservations about sucking off ${anAnimal}, ${he} seems to forget that the cock in ${his} mouth isn't human soon enough, once ${his} carnal desires kick in. `);
						r.push(`The slave visibly gags as the unfamiliar texture of ${anAnimal}'s cock fills it, and you get the feeling ${he} is beginning to reevaluate just how much ${he} wants to avoid punishment. `);
					r.push(`${slave.slaveName} gives a long, drawn-out groan as the huge phallus fills ${his} ${act === vaginal ? `pussy` : `asshole`} nearly to its breaking point. `);
			function consummationNonresistantFeline(type) {
				if (type === oral) {
					if (slaveApproves()) {
						r.push(`Though the slave still seems to have some reservations about sucking off an animal, ${he} seems to forget that the cock in ${his} mouth belongs to a feline soon enough, once ${his} carnal desires kick in. `);
					} else {
						r.push(`The slave visibly gags as the unfamiliar texture of ${anAnimal}'s barbed dick fills it, and you get the feeling ${he} is beginning to reevaluate just how much ${he} wants to avoid punishment. `);
					r.push(`${slave.slaveName} gives a squeal of pain as the barbed cock makes its way into ${his} ${act === vaginal ? `pussy` : `asshole`}. `);
brickode's avatar
brickode committed

			mainSpan.append(r.join(' '));
brickode's avatar
brickode committed

		function consummationResistant() {
			const
				mainSpan = document.createElement("span"),
				r = [];
brickode's avatar
brickode committed

			if (act === oral) {
				r.push(`You have to physically force ${him} to kneel on the floor before calling in the ${animal.name}. The beast slowly saunters up to the slave where ${he} is restrained, showing little concern when another slave reaches out and begins masturbating it to begin the process of getting the animal hard. Once the ${animal.name} is hard enough, the slave takes its cock and lines it up with ${slave.slaveName}'s mouth. The animal needs no prompting, and thrusts itself into ${his} ring-gagged mouth. `);
			} else {
				r.push(`You have to physically force ${him} to ${slave.clothes !== "no clothing" ? `take off ${his} clothes and ` : ``} get on the floor, ass in the air and restraints around ${his} wrists and ankles, before calling in the ${animal.name}. The beast slowly saunters up to the slave, where it takes only a few short moments for its animal brain to realize that what it is standing behind is a warm hole that needs to be filled with seed. `);
			}
			switch (animal) {
				case V.active.canine:
					consummationResistantCanine(act);
					break;
				case V.active.hooved:
					consummationResistantHooved(act);
					break;
				case V.active.feline:
					consummationResistantFeline(act);
					break;
				default:
					throw new Error(`Unexpected animal type '${animal}' in consummationResistant()`);
			}
			if (act !== oral) {
				mainSpan.append(virginityCheck(act));
			}
			function consummationResistantCanine(type) {
				if (type === oral) {
					if (slaveApproves()) {
						r.push(`The slave glares daggers at you as ${he} takes the full length of the canine's cock in ${his} mouth, but ${slave.dick ?
							canAchieveErection(slave) ?
								`${his} fully-erect dick` :
								`the precum leaking from ${his} dick` :
							slave.vagina > -1 ?
								`a slight sheen on ${his} pussylips` :
								`a slight blush to ${his} cheeks`}
							tells you that ${he}'s enjoying this, at least a little. `);
					} else {
						r.push(`The slave visibly gags as the unfamiliar texture of ${anAnimal}'s cock fills it, and you get the feeling ${he} would have run away a long time ago if ${he} wasn't a little tied up at the moment. `);
					if (canWalk(slave)) {
						r.push(`The canine clambers up to mount ${slave.slaveName}, eliciting a squeal from the ${girl} as its claws dig into ${his} flesh. `);
					} else {
						r.push(`The canine takes a few curious sniffs, then lines up its large cock with ${slave.slaveName}'s ${act === vaginal ? `pussy` : `asshole`}. `);
					}
					r.push(`It takes a few tries, but the ${animal.name} finally manages to sink its cock into ${his} ${slaveApproves() && act === vaginal ? `wet ` : ``}${act === vaginal ? `cunt` : `asshole`} and begin to hammer away in the way that only canines can. `);
				}
			function consummationResistantHooved(type) {
				if (type === oral) {
					if (slaveApproves()) {
						r.push(`The slave glares daggers at you as ${he} takes the full length of the ${animal.name}'s cock in ${his} mouth, but ${slave.dick ?
							canAchieveErection(slave) ?
								`${his} fully-erect dick` :
								`the precum leaking from ${his} dick` :
							slave.vagina > -1 ?
								`a slight sheen on ${his} pussylips` :
								`a slight blush to ${his} cheeks`}
							tells you that ${he}'s enjoying this, at least a little. `);
					} else {
						r.push(`The slave visibly gags as the unfamiliar texture of ${anAnimal}'s cock fills it, and you get the feeling ${he} would have run away a long time ago if ${he} wasn't a little tied up at the moment. `);
					r.push(`${slave.slaveName} lets out a blood-curdling scream as the huge phallus fills ${his} ${act === vaginal ? `pussy` : `asshole`} nearly to its breaking point. `);
			function consummationResistantFeline(type) {
				if (type === oral) {
					if (slaveApproves()) {
						r.push(`The slave glares daggers at you as ${he} takes the full length of the feline's cock in ${his} mouth, but ${slave.dick ?
							canAchieveErection(slave) ?
								`${his} fully-erect dick` :
								`the precum leaking from ${his} dick` :
							slave.vagina > -1 ?
								`a slight sheen on ${his} pussylips` :
								`a slight blush to ${his} cheeks`}
							tells you that ${he}'s enjoying this, at least a little. `);
					} else {
						r.push(`The slave visibly gags as the unfamiliar texture of ${anAnimal}'s barbed dick fills it, and you get the feeling ${he} would have run away a long time ago if ${he} wasn't a little tied up at the moment .`);
					r.push(`${slave.slaveName} lets out a blood-curdling scream as the barbed cock makes its way into ${his} ${act === vaginal ? `pussy` : `asshole`}. `);
brickode's avatar
brickode committed

			mainSpan.append(r.join(' '));
brickode's avatar
brickode committed

	// MARK: Completion Function

	function completion() {
brickode's avatar
brickode committed
		const
			mainSpan = document.createElement("span"),
			r = [];

			case V.active.canine:
			case V.active.hooved:
				completionHooved();
				break;
			case V.active.feline:
				completionFeline();
				break;
				throw new Error(`Unexpected animal type '${animal}' in completion()`);
		if (act !== oral && canGetPregnant(slave) && canBreed(slave, animal)) {
			knockMeUp(slave, 5, hole, -8);
		}

		function completionCanine() {
			if (act === oral) {
brickode's avatar
brickode committed
				r.push(`The ${animal.species === "dog" ? `hound` : animal.name} wastes no time in beginning to hammer away at ${his} ${orifice[0]}, causing ${slave.slaveName} to moan uncontrollably as its thick, veiny member probes the depths of ${his} ${orifice[1]}. A few short minutes later, ${he} gives a loud groan ${slaveApproves() ? `and shakes in orgasm ` : ``}as the ${animal.name}'s knot begins to swell and its dick begins to erupt a thick stream of jizz down ${his} abused throat. Soon enough, the ${animal.name} finally finishes cumming and its knot is sufficiently small enough to slip out of ${slave.slaveName}'s mouth, causing ${him} to immediately begin coughing and retching uncontrollably. Having finished its business, the ${animal.name} runs off, presumably in search of food. `);
			} else {
				r.push(`The ${animal.species === "dog" ? `hound` : animal.name} wastes no time in beginning to hammer away at ${his} ${orifice[0]}, causing ${slave.slaveName} to moan uncontrollably as its thick, veiny member probes the depths of ${his} ${orifice[1]}. A few short minutes later, ${he} gives a loud groan ${slaveApproves() ? `and shakes in orgasm ` : ``}as the ${animal.name}'s knot begins to swell and its dick begins to erupt a thick stream of jizz into ${his} ${orifice[0]}. Soon enough, the ${animal.name} finally finishes cumming and its knot is sufficiently small enough to slip out of ${slave.slaveName}'s ${act === vaginal && slave.vagina < 3 || act === anal && slave.anus < 2 ?
					`now-gaping ${orifice[0]}` :
brickode's avatar
brickode committed
					orifice[0]}, causing a thick stream of cum to slide out of it. Having finished its business, the ${animal.name} runs off, presumably in search of food. `);
			}

			switch (act) {
				case oral:
					slave.counter.oral++;
brickode's avatar
brickode committed
					break;
				case vaginal:
					slave.counter.vaginal++;
					slave.vagina = slave.vagina < 3 ? 3 : slave.vagina;
brickode's avatar
brickode committed
					break;
					slave.counter.anal++;
					slave.anus = slave.anus < 2 ? 2 : slave.anus;
brickode's avatar
brickode committed
					break;
brickode's avatar
brickode committed
					throw new Error(`Unexpected act type '${act} in completionCanine().`);
			}
		}

		function completionHooved() {
			if (act === oral) {
brickode's avatar
brickode committed
				r.push(`The ${animal.species === "horse" ? `stallion` : animal.name} begins to thrust faster and faster, causing ${him} to moan and groan past the huge ${animal.species} cock stretching ${his} poor throat to its limits. Before too long, the ${animal.name}'s movements begin to slow, and you can see its large testicles contract as its begins to erupt and pour its thick semen down ${his} throat and into ${his} stomach, filling it to the brim. After what seems like an impossibly long time, the ${animal.name}'s dick finally begins to soften and pull out, causing ${slave.slaveName} to begin coughing and retching uncontrollably. You have another slave lead the ${animal.name} away, with a fresh apple as a treat for its good performance. `);
brickode's avatar
brickode committed
				r.push(`The ${animal.species === "horse" ? `stallion` : animal.name} begins to thrust faster and faster, causing ${him} to moan and groan as the huge ${animal.species} cock ${act === vaginal ? `batters ${his} cervix` : `fills ${him} completely`}. Before too long, the ${animal.name}'s movements begin to slow, and you can see its large testicles contract as its begins to erupt and fill ${his} ${orifice[1]} with its thick baby batter. After what seems like an impossibly long time, the ${animal.name}'s dick finally begins to soften and pull out, leaving ${slave.slaveName} panting and covered in sweat. You have another slave lead the ${animal.name} away, with a fresh apple as a treat for its good performance. `);
			}

			switch (act) {
				case oral:
					slave.counter.oral++;
brickode's avatar
brickode committed
					break;
				case vaginal:
					slave.counter.vaginal++;
					slave.vagina = slave.vagina < 4 ? 4 : slave.vagina;
brickode's avatar
brickode committed
					break;
				case anal:
					slave.counter.anal++;
					slave.anus = slave.anus < 3 ? 3 : slave.anus;
brickode's avatar
brickode committed
					break;
brickode's avatar
brickode committed
					throw new Error(`Unexpected act type '${act} in completionHooved().`);
			}
		}

		function completionFeline() {
			if (act === oral) {
brickode's avatar
brickode committed
				r.push(`The ${animal.name} begins to move, thrusting faster and faster. The ${girl} underneath it can't stop a groan of pain from escaping ${his} lips as the ${animal.species}'s barbed dick rubs the inside of ${his} mouth and throat raw. After a few minutes of painful coupling, the ${animal.species}'s thrusts finally slow, then stop completely as its ${animal.species !== "cat" ? `large` : ``} cock erupts down ${slave.slaveName}'s throat. With a ${animal.species !== "cat" ? `deep bellow` : `loud meow`}, he finally dismounts, gives you a long look, then stalks off. `);
brickode's avatar
brickode committed
				r.push(`The ${animal.name} begins to move, thrusting faster and faster. The ${girl} underneath it can't stop a groan of pain from escaping ${his} lips as the ${animal.species}'s barbed dick rubs the inside of ${his} ${orifice[0]} raw. After a few minutes of painful coupling, the ${animal.species}'s thrusts finally slow, then stop completely as its ${animal.species !== "cat" ? `large` : ``} cock erupts, filling ${slave.slaveName} with its sperm. With a ${animal.species !== "cat" ? `deep bellow` : `loud meow`}, he finally dismounts, gives you a long look, then stalks off. `);
			}

			healthDamage(slave, 1);

			switch (act) {
				case oral:
					slave.counter.oral++;
					return;
				case vaginal:
					slave.counter.vaginal++;
					slave.vagina = slave.vagina < 2 ? 2 : slave.vagina;
					return;
				case anal:
					slave.counter.anal++;
					slave.anus = slave.anus < 1 ? 1 : slave.anus;
brickode's avatar
brickode committed
					throw new Error(`Unexpected act type '${act} in completionFeline().`);
brickode's avatar
brickode committed

		mainSpan.append(r.join(' '));

		return mainSpan;
brickode's avatar
brickode committed
	// Post-sex Functions

	function sexEffects() {
brickode's avatar
brickode committed
		const mainSpan = App.UI.DOM.makeElement("span", '', ["flaw", "gain"]);

brickode's avatar
brickode committed
		if (jsRandom(1, 100) > 100 + slave.devotion) {
brickode's avatar
brickode committed
			switch (act) {
				case oral:
					if (slave.energy < 95 && slave.sexualFlaw !== "hates oral") {
						mainSpan.append(`Having ${anAnimal} fuck ${his} throat by force has given ${him} a hatred of oral sex. `);
brickode's avatar
brickode committed
					}
					slave.sexualFlaw = "hates oral";
brickode's avatar
brickode committed

					break;
brickode's avatar
brickode committed
				case vaginal:
					if (slave.energy < 95 && slave.sexualFlaw !== "hates penetration") {
						mainSpan.append(`Having ${anAnimal} fuck ${him} by force has given ${him} a hatred of penetration. `);
brickode's avatar
brickode committed
					}
					slave.sexualFlaw = "hates penetration";
brickode's avatar
brickode committed

					break;
brickode's avatar
brickode committed
				case anal:
					if (slave.energy < 95 && slave.sexualFlaw !== "hates anal") {
						mainSpan.append(`Having ${anAnimal} fuck ${his} asshole by force has given ${him} a hatred of anal penetration. `);
brickode's avatar
brickode committed
					}
					slave.sexualFlaw = "hates anal";
brickode's avatar
brickode committed

					break;
brickode's avatar
brickode committed
				default:
brickode's avatar
brickode committed
					throw new Error(`Unexpected act type '${act}' in sexEffects().`);
brickode's avatar
brickode committed
			}
		}
brickode's avatar
brickode committed

		return mainSpan;
brickode's avatar
brickode committed
	}

	function cleanUp() {
brickode's avatar
brickode committed
		const
			mainSpan = document.createElement("span"),
			r = [];

brickode's avatar
brickode committed
		if (act !== oral) {
			if (act === vaginal) {
				if (slave.vagina === 3) {
brickode's avatar
brickode committed
					r.push(`${capFirstChar(animal.name)} cum drips out out of ${his} fucked-out hole. `);
brickode's avatar
brickode committed
				} else if (slave.vagina === 2) {
brickode's avatar
brickode committed
					r.push(`${capFirstChar(animal.name)} cum drips out out of ${his} stretched vagina. `);
brickode's avatar
brickode committed
				} else if (slave.vagina === 1) {
brickode's avatar
brickode committed
					r.push(`${His} still-tight pussy keeps the ${animal.name}'s cum inside ${him}. `);
brickode's avatar
brickode committed
				} else {
brickode's avatar
brickode committed
					r.push(`${capFirstChar(animal.name)} cum slides right out of ${his} gaping hole. `);
brickode's avatar
brickode committed
				}
			} else {
				if (slave.anus === 1) {
brickode's avatar
brickode committed
					r.push(`${His} still-tight asshole keeps the ${animal.name}'s cum inside ${him}. `);
brickode's avatar
brickode committed
				} else if (slave.anus === 2) {
brickode's avatar
brickode committed
					r.push(`${capFirstChar(animal.name)} cum drips out of ${his} loosened anus. `);
brickode's avatar
brickode committed
				} else {
brickode's avatar
brickode committed
					r.push(`${capFirstChar(animal.name)} cum slides right out of ${his} fucked-out asshole. `);
brickode's avatar
brickode committed
			if (canWalk(slave)) {
				if (slave.vagina > 0) {
					r.push(`${He} uses a quick douche to clean ${his} ${slave.vagina < 2 ? `tight` : slave.vagina > 3 ? `loose` : ``} pussy,`);
				} else {
					r.push(`${He} uses an enema to clean ${his} ${slave.anus < 2 ? `tight` : slave.anus < 3 ? `used` : `gaping`} butthole,`);
				}
brickode's avatar
brickode committed

brickode's avatar
brickode committed
				switch (slave.assignment) {
					case Job.BROTHEL:
						r.push(`just like ${he} does between each customer. `);
						break;
					case Job.CLUB:
						r.push(`just like ${he} does in the club. `);
						break;
					case Job.DAIRY:
						r.push(`to avoid besmirching the nice clean dairy. `);
						break;
					case Job.FARMYARD:
						r.push(`to avoid tainting the food in ${V.farmyardName}. `);
						break;
					case Job.QUARTER:
						r.push(`mostly to keep everything ${he} has to clean from getting any dirtier. `);
						break;
					case Job.WHORE:
						r.push(`before returning to offering it for sale. `);
						break;
					case Job.PUBLIC:
						r.push(`before returning to offering it for free. `);
						break;
					case Job.REST:
						r.push(`before crawling back into bed. `);
						break;
					case Job.MILKED:
						r.push(`${slave.lactation > 0 ? `before going to get ${his} uncomfortably milk-filled tits drained` : `and then rests until ${his} balls are ready to be drained again`}. `);
						break;
					case Job.HOUSE:
						r.push(`since ${his} chores didn't perform themselves while you used ${his} fuckhole. `);
						break;
					case Job.FUCKTOY:
						r.push(`before returning to await your next use of ${his} fuckhole, as though nothing had happened. `);
						break;
					case Job.SUBORDINATE:
						r.push(`though it's only a matter of time before another slave decides to play with ${his} fuckhole. `);
						break;
					case Job.HEADGIRL:
						r.push(`worried that ${his} charges got up to trouble while ${he} enjoyed ${his} ${properMaster()}'s use. `);
brickode's avatar
brickode committed
						break;
					case Job.BODYGUARD:
						r.push(`so ${he} can be fresh and ready for more sexual use even as ${he} guards your person. `);
						break;
					case Job.TEACHER:
						r.push(`before ${he} returns to teaching ${his} classes. `);
						break;
					default:
						r.push(`before ${he} returns to ${slave.assignment}. `);
						break;
				}
brickode's avatar
brickode committed
			}
		}
brickode's avatar
brickode committed

		mainSpan.append(r.join(' '));

		return mainSpan;
	// MARK: Virginity Check Functions

	function virginityCheck(type) {
brickode's avatar
brickode committed
		const
			mainSpan = document.createElement("span"),
			virginityLossSpan = App.UI.DOM.makeElement("span", '', ["virginity", "loss"]);
brickode's avatar
brickode committed

		switch (type) {
			case vaginal:
				if (act === vaginal && slave.vagina === 0) {
brickode's avatar
brickode committed
					virginityLossSpan.append(`${his} virginity is taken from ${him}${slave.devotion < -20 ? ` by force` : ``}. `);
brickode's avatar
brickode committed

					mainSpan.append(`The slave gives a loud ${slave.devotion > 20 ? `moan` : `groan`} as `, virginityLossSpan, ` `);
brickode's avatar
brickode committed
					mainSpan.append(virginityEffects(type));
brickode's avatar
brickode committed

				return mainSpan;
			case anal:
				if (act === anal && slave.anus === 0) {
brickode's avatar
brickode committed
					mainSpan.append(`The slave gives a loud ${slave.devotion > 20 ? `moan` : `groan`} as ${his} anal virginity is taken from ${him}${slave.devotion < -20 ? ` by force` : ``}. `);
brickode's avatar
brickode committed
					mainSpan.append(virginityEffects(type));
brickode's avatar
brickode committed

				return mainSpan;
brickode's avatar
brickode committed
				throw new Error(`Unexpected type value '${type}' in virginityCheck().`);
brickode's avatar
brickode committed
		const
			mainSpan = document.createElement("span"),
			devotionSpan = document.createElement("span"),
			trustSpan = document.createElement("span"),
			healthSpan = App.UI.DOM.makeElement("span", '', ["health", "dec"]);
brickode's avatar
brickode committed

		switch (type) {
			case vaginal:
				if (slave.devotion >= -20) {
					if (slaveApproves()) {
brickode's avatar
brickode committed
						devotionSpan.classList.add("devotion", "inc");

						devotionSpan.append(`increased ${his} devotion to you. `);

						mainSpan.append(`Losing ${his} virginity in such a painful manner has `, devotionSpan);

						slave.devotion += 10;
					} else {
						if (slave.devotion > 50) {
brickode's avatar
brickode committed
							devotionSpan.classList.add("devotion", "inc");

							devotionSpan.append(`increased ${his} submission to you. `);

							mainSpan.append(`Since ${he} is well broken, losing ${his} virginity in such a manner has`, devotionSpan);

							slave.devotion += 5;
						} else if (slave.devotion >= -20) {
brickode's avatar
brickode committed
							devotionSpan.classList.add("devotion", "inc");
							trustSpan.classList.add("trust", "dec");

							devotionSpan.append(`increased ${his} submission to you,`);
							trustSpan.append(`fearful`);

							mainSpan.append(`Losing ${his} virginity in such a manner has`, devotionSpan, ` though ${he} is `, trustSpan, ` that you'll decide to only use ${him} to sate your animals' lust. `);
brickode's avatar
brickode committed
							devotionSpan.classList.add("devotion", "dec");
							trustSpan.classList.add("trust", "dec");

							devotionSpan.append(`unhappy`);
							trustSpan.append(`fears`);

							mainSpan.append(`${He} is clearly `, devotionSpan, ` in the manner in which ${his} virginity has been taken, and ${he} `, trustSpan, ` you'll decide to only use ${him} to sate your animals' lust. `);
brickode's avatar
brickode committed
					devotionSpan.classList.add("devotion", "dec");
					trustSpan.classList.add("trust", "dec");

					devotionSpan.append(`reinforced the hatred ${he} holds towards you,`);
					trustSpan.append(`terrified`);

					mainSpan.append(`Having ${his} pearl of great price taken by a mere beast has `, devotionSpan, ` and ${he} is `, trustSpan, ` you'll only use ${him} as a plaything for your animals. `);
brickode's avatar
brickode committed
				healthSpan.append(`slightly damaged ${his} health. `);

				mainSpan.append(`Having ${his} cherry popped in such a manner was extremely painful and `, healthSpan);
brickode's avatar
brickode committed
				return mainSpan;
					if (slaveApproves()) {
brickode's avatar
brickode committed
						devotionSpan.classList.add("devotion", "inc");

						devotionSpan.append(`increased ${his} devotion to you. `);

						mainSpan.append(`Losing ${his} anal virginity in such a painful manner has `, devotionSpan);

						slave.devotion += 10;
					} else {
						if (slave.devotion > 50) {
brickode's avatar
brickode committed
							devotionSpan.classList.add("devotion", "inc");

							devotionSpan.append(`increased ${his} submission to you. `);

							mainSpan.append(`Since ${he} is well broken, losing ${his} anal virginity in such a manner has `, devotionSpan);

							slave.devotion += 5;
						} else if (slave.devotion >= -20) {
brickode's avatar
brickode committed
							devotionSpan.classList.add("devotion", "inc");
							trustSpan.classList.add("trust", "dec");

							devotionSpan.append(`increased ${his} submission to you,`);
							trustSpan.append(`fearful`);

							mainSpan.append(`Losing ${his} anal virginity in such a manner has `, devotionSpan, ` though ${he} is `, trustSpan, ` that you'll decide to only use ${him} to sate your animals' lust. `);
brickode's avatar
brickode committed
							devotionSpan.classList.add("devotion", "dec");
							trustSpan.classList.add("trust", "dec");

							devotionSpan.append(`unhappy`);
							trustSpan.append(`fears`);

							mainSpan.append(`${He} is clearly `, devotionSpan, ` in the manner in which ${his} anal virginity has been taken, and ${he} `, trustSpan, ` you'll decide to only use ${him} to sate your animals' lust. `);
brickode's avatar
brickode committed
					devotionSpan.classList.add("devotion", "dec");
					trustSpan.classList.add("trust", "dec");

					devotionSpan.append(`reinforced the hatred ${he} holds towards you,`);
					trustSpan.append(`terrified`);

					mainSpan.append(`Having ${his} pearl of great price taken by a mere beast has `, devotionSpan, ` and ${he} is `, trustSpan, ` you'll only use ${him} as a plaything for your animals. `);
brickode's avatar
brickode committed
				healthSpan.append(`slightly damaged ${his} health. `);

				mainSpan.append(`Having ${his} rosebud broken in in such a manner was extremely painful and `, healthSpan);
brickode's avatar
brickode committed
				return mainSpan;
brickode's avatar
brickode committed
				throw new Error(`Unexpected type value '${type}' in virginityEffects().`);
brickode's avatar
brickode committed
};