code:
/**
 * @param {App.Entity.SlaveState} slave
 * @returns {string}
 */
App.Desc.drugs = function(slave) {
	const r = [];
	const {
		he, him, his, himself, He, His
	} = getPronouns(slave);
	let ignoredRule;
	if (slave.fuckdoll === 0) {
		r.push(drugs());
		r.push(aphrodisiacs());
	}

	return r.join(" ");

	function drugs() {
		const r = [];
		switch (slave.drugs) {
			case "priapism agents":
				if (slave.dick > 0 && slave.dick <= 10) {
					if (slave.chastityPenis === 1) {
						r.push(`${He} can do nothing but writhe in agony at the pain of ${his} priapismic erection trapped in ${his} chastity cage.`);
					} else {
						if (slave.dick > 8) {
							r.push(`${His} oversized dick is painfully engorged to a state of semi-hardness due to the priapism agents.`);
						} else if (slave.dick > 6) {
							r.push(`${He} sports a painful, oversized erection due to the priapism agents.`);
						} else {
							r.push(`${He} sports a throbbing, painful erection due to the priapism agents.`);
						}
					}
				}
				break;
			case "super fertility drugs":
				if (isFertile(slave) && slave.preg === 0) {
					r.push(`${He} is constantly dripping sexual fluids and ${his} breasts and belly are slightly swollen. The super fertility drugs have ${him} ready to be impregnated.`);
				}
				break;
			case "fertility drugs":
				if (isFertile(slave) && slave.preg === 0) {
					r.push(`${He} smells of sexual fluids and ${his} breasts are slightly swollen. The fertility drugs have ${him} ready to be impregnated.`);
				}
				break;
			case "intensive breast injections":
				if (hasAnyArms(slave)) {
					r.push(`${He} massages ${his} tits uncomfortably.`);
				} else {
					r.push(`${He} squirms under the unfamiliar weight on ${his} chest.`);
				}
				r.push(`The A-HGH must be having an effect, painfully stretching ${his} breasts as the mammary and adipose tissue underneath grows explosively.`);
				break;
			case "nipple enhancers":
				if (hasAnyArms(slave)) {
					r.push(`${He} massages ${his} nipples uncomfortably.`);
				} else {
					r.push(`${He} squirms in response to the discomfort in ${his} breasts.`);
				}
				r.push(`The A-HGH must be having an effect, painfully causing ${his} body to expand ${his} nipples.`);
				break;
			case "hyper breast injections":
				if (hasAnyArms(slave)) {
					r.push(`${He} massages ${his} tits uncomfortably.`);
				} else {
					r.push(`${He} squirms under the unfamiliar weight on ${his} chest.`);
				}
				r.push(`The HA-HGH must be having an effect, painfully stretching ${his} breasts as the mammary and adipose tissue underneath grows explosively.`);
				break;
			case "intensive butt injections":
				if (hasAnyArms(slave)) {
					r.push(`${He} massages ${his} butt uncomfortably.`);
				} else {
					r.push(`${He} squirms against the unfamiliar weight on ${his} backside.`);
				}
				r.push(`The A-HGH must be having an effect, painfully stretching ${his} buttocks as the muscular and adipose tissue underneath grows explosively.`);
				break;
			case "hyper butt injections":
				if (hasAnyArms(slave)) {
					r.push(`${He} massages ${his} butt uncomfortably.`);
				} else {
					r.push(`${He} squirms against the unfamiliar weight on ${his} backside.`);
				}
				r.push(`The HA-HGH must be having an effect, painfully stretching ${his} buttocks as the muscular and adipose tissue underneath grows explosively.`);
				break;
			case "intensive penis enhancement":
				if (hasAnyArms(slave)) {
					r.push(`${He} massages ${his}`);
					if (slave.dick > 0) {
						r.push(`dick`);
					} else {
						r.push(`clit`);
					}
					r.push(`uncomfortably.`);
				} else {
					r.push(`${He} squirms against the unfamiliar weight in ${his}`);
					if (slave.dick > 0) {
						r.push(`dick.`);
					} else {
						r.push(`clit.`);
					}
				}
				r.push(`The A-HGH must be having an effect, painfully lengthening and thickening ${his}`);
				if (slave.dick > 0) {
					r.push(`dick.`);
				} else {
					r.push(`clit.`);
				}
				break;
			case "intensive testicle enhancement":
				if (hasAnyArms(slave)) {
					r.push(`${He} massages ${his} balls uncomfortably`);
				} else {
					r.push(`${He} squirms in response to the pressure in ${his} balls`);
				}
				r.push(`as a bead of cum forms on tip of ${his} dick. The A-HGH must be having an effect, painfully expanding ${his} testicles.`);
				break;
			case "hyper penis enhancement":
				if (hasAnyArms(slave)) {
					r.push(`${He} massages ${his}`);
					if (slave.dick > 0) {
						r.push(`dick`);
					} else {
						r.push(`clit`);
					}
					r.push(`uncomfortably.`);
				} else {
					r.push(`${He} squirms against the unfamiliar weight in ${his}`);
					if (slave.dick > 0) {
						r.push(`dick.`);
					} else {
						r.push(`clit.`);
					}
				}
				r.push(`The HA-HGH must be having an effect, painfully lengthening and thickening ${his}`);
				if (slave.dick > 0) {
					r.push(`dick.`);
				} else {
					r.push(`clit.`);
				}
				break;
			case "hyper testicle enhancement":
				if (slave.balls < 20) {
					if (hasAnyArms(slave)) {
						r.push(`${He} massages ${his} balls uncomfortably`);
					} else {
						r.push(`${He} squirms in response to the pressure in ${his} balls`);
					}
					r.push(`as cum drools from the tip of ${his} dick. The HA-HGH must be having an effect, painfully expanding ${his} testicles.`);
				} else if (slave.balls >= 50) {
					if (hasAnyArms(slave)) {
						r.push(`${He} massages ${his} balls uncomfortably`);
					} else {
						r.push(`${He} squirms in response to the pressure in ${his} balls`);
					}
					r.push(`as a thick cascade of cum pours from the tip of ${his} cock. The HA-HGH must be having an effect, painfully expanding ${his} testicles.`);
				} else if (slave.balls >= 37) {
					if (hasAnyArms(slave)) {
						r.push(`${He} massages ${his} balls uncomfortably`);
					} else {
						r.push(`${He} squirms in response to the pressure in ${his} balls`);
					}
					r.push(`as cum freely flows from the tip of ${his} cock, pooling under ${him}. The HA-HGH must be having an effect, painfully expanding ${his} testicles.`);
				} else if (slave.balls >= 20) {
					if (hasAnyArms(slave)) {
						r.push(`${He} massages ${his} balls uncomfortably`);
					} else {
						r.push(`${He} squirms in response to the pressure in ${his} balls`);
					}
					r.push(`as precum pools under ${him}. The HA-HGH must be having an effect, painfully expanding ${his} testicles.`);
				}
				break;
			case "female hormone injections":
			case "male hormone injections":
				r.push(`${He} looks very ill, likely a side effect of the extreme hormone injections.`);
				break;
			case "appetite suppressors":
				r.push(`Despite how little ${he} has been eating lately, ${his} stomach barely growls at all.`);
				break;
			case "penis atrophiers":
				if (hasAnyArms(slave)) {
					r.push(`${He} massages ${his} dick uncomfortably.`);
				} else {
					r.push(`${He} squirms in response to the discomfort in ${his} dick.`);
				}
				r.push(`The A-TRPH must be having an effect, painfully causing ${his} body to atrophy ${his} dick.`);
				break;
			case "testicle atrophiers":
				if (hasAnyArms(slave)) {
					r.push(`${He} massages ${his} balls uncomfortably.`);
				} else {
					r.push(`${He} squirms in response to the discomfort in ${his} balls.`);
				}
				r.push(`The A-TRPH must be having an effect, painfully causing ${his} body to atrophy ${his} testicles.`);
				break;
			case "clitoris atrophiers":
				if (hasAnyArms(slave)) {
					r.push(`${He} massages ${his} clit uncomfortably.`);
				} else {
					r.push(`${He} squirms in response to the discomfort in ${his} clit.`);
				}
				r.push(`The A-TRPH must be having an effect, painfully causing ${his} body to atrophy ${his} clitoris.`);
				break;
			case "labia atrophiers":
				if (hasAnyArms(slave)) {
					r.push(`${He} massages ${his} pussy uncomfortably.`);
				} else {
					r.push(`${He} squirms in response to the discomfort in ${his} cunt.`);
				}
				r.push(`The A-TRPH must be having an effect, painfully causing ${his} body to atrophy ${his} labia.`);
				break;
			case "nipple atrophiers":
				if (hasAnyArms(slave)) {
					r.push(`${He} massages ${his} nipples uncomfortably.`);
				} else {
					r.push(`${He} squirms in response to the discomfort in ${his} breasts.`);
				}
				r.push(`The A-TRPH must be having an effect, painfully causing ${his} body to atrophy ${his} nipples.`);
				break;
			case "lip atrophiers":
				if (hasAnyArms(slave)) {
					r.push(`${He} massages ${his} lips uncomfortably.`);
				} else {
					r.push(`${He} licks ${his} lips uncomfortably.`);
				}
				r.push(`The A-TRPH must be having an effect, painfully causing ${his} body to atrophy ${his} lips.`);
				break;
			case "breast redistributors":
				if (hasAnyArms(slave)) {
					r.push(`${He} pinches at the fat building on ${his} belly and lets off a sigh.`);
				} else {
					r.push(`${He} squirms under the added weight building on ${his} belly.`);
				}
				r.push(`The RDST-D must be having an effect, encouraging ${his} body to redistribute ${his} breasts' adipose tissue to ${his} middle.`);
				break;
			case "butt redistributors":
				if (hasAnyArms(slave)) {
					r.push(`${He} pinches at the fat building on ${his} belly and lets off a sigh.`);
				} else {
					r.push(`${He} squirms under the added weight building on ${his} belly.`);
				}
				r.push(`The RDST-D must be having an effect, encouraging ${his} body to redistribute ${his} buttock's adipose tissue to ${his} middle.`);
				break;
			case "sag-B-gone":
				r.push(`${His} breasts are shiny from the layer of anti-sag cream rubbed onto them. They might be a little perkier, or not.`);
				break;
			default:
		}
		return r.join(" ");
	}

	function aphrodisiacs() {
		const r = [];
		if (slave.aphrodisiacs > 0 || slave.inflationType === "aphrodisiac") {
			if (slave.fetish === "mindbroken") {
				ignoredRule = 1;
			} else if (disobedience(slave) !== 0) {
				ignoredRule = (disobedience(slave) >= jsRandom(1, 100)) ? 1 : 0;
			} else {
				ignoredRule = 0;
			}
			if (slave.inflationType === "aphrodisiac" || slave.aphrodisiacs > 1) {
				if (slave.inflationType === "aphrodisiac") {
					r.push(`${He}'s literally full of`);
				} else {
					r.push(`${He}'s swimming in`);
				}
				if (!hasAnyArms(slave)) {
					r.push(`aphrodisiacs, but is an amputee, so ${he} cannot touch ${himself}. ${He} writhes with extreme sexual frustration, desperately trying to relieve`);
					if (slave.inflationType === "aphrodisiac") {
						r.push(`${himself}, but only managing to stir up the aphrodisiacs contained in ${his} gut, strengthening their effects even more.`);
					} else {
						r.push(`${himself}.`);
					}
				} else if (slave.rules.release.masturbation === 0 && slave.rules.release.master === 0 && ignoredRule === 0) {
					r.push(`aphrodisiacs, but is not permitted to touch ${him}self nor beg you for release. ${He} writhes with extreme sexual frustration, desperate to not break the rules in front of`);
					if (slave.inflationType === "aphrodisiac") {
						r.push(`you, but only manages to stir up the aphrodisiacs contained in ${his} gut, further strengthening their effects on ${him}.`);
					} else {
						r.push(`you.`);
					}
					if (canAchieveErection(slave)) {
						if (slave.chastityPenis) {
							r.push(`${His} cock agonizingly fills ${his} chastity cage, only adding to ${his} misery.`);
						} else {
							r.push(`${His} cock stands painfully erect, threatening to blow with the slightest contact.`);
						}
					}
				} else if (!canDoVaginal(slave) && !canDoAnal(slave) && (slave.dick === 0 || slave.chastityPenis) && slave.fetish === "boobs" && slave.boobs > 300) {
					if (slave.rules.release.masturbation === 1 || ignoredRule === 1) {
						r.push(`aphrodisiacs and`);
						if (ignoredRule === 1) {
							r.push(`has disregarded ${his} masturbation restriction,`);
						} else {
							r.push(`is allowed to masturbate,`);
						}
						r.push(`so as ${he}`);
						if (hasAnyLegs(slave)) {
							r.push(`stands`);
						} else {
							r.push(`sits`);
						}
						r.push(`before you, ${he}`);
						if (slave.nipples === "fuckable") {
							r.push(`uses`);
							if (hasBothArms(slave)) {
								r.push(`both hands`);
							} else {
								r.push(`${his} hand`);
							}
							r.push(`to vigorously fist ${his} nipples.`);
						} else {
							r.push(`viciously gropes, kneads and milks ${his} breasts, only stopping to occasionally focus on ${his} erect nipples.`);
						}
						if (slave.inflationType === "aphrodisiac") {
							r.push(`${His} frantic attempts force ${his} distended middle to jiggle obscenely, stirring up the aphrodisiacs contained in ${his} gut and strengthening their effects even more.`);
						}
					} else {
						r.push(`aphrodisiacs and is not allowed to masturbate so as ${he}`);
						if (hasAnyLegs(slave)) {
							r.push(`stands`);
						} else {
							r.push(`sits`);
						}
						r.push(`before you, ${he} desperately presents ${his} chest in the hopes you'll grab hold of ${his} favorite body parts.`);
					}
				} else if (canDoAnal(slave) && slave.fetish === "buttslut") {
					if (slave.rules.release.masturbation === 1 || ignoredRule === 1) {
						r.push(`aphrodisiacs and`);
						if (ignoredRule === 1) {
							r.push(`has disregarded ${his} masturbation restriction,`);
						} else {
							r.push(`is allowed to masturbate,`);
						}
						r.push(`so as ${he}`);
						if (hasAnyLegs(slave)) {
							r.push(`stands`);
						} else {
							r.push(`sits`);
						}
						r.push(`before you ${he}`);
						if (slave.anus === 0) {
							r.push(`furiously rubs ${his} virgin anus and the sensitive perineum beneath it, desperately trying to either get ${him}self off or entice you into giving ${him} what ${he} needs.`);
						} else {
							r.push(`uses`);
							if (slave.anus > 2) {
								if (hasBothArms(slave)) {
									r.push(`both hands,`);
								} else {
									r.push(`${his} entire fist,`);
								}
							} else {
								r.push(`several fingers`);
							}
							r.push(`to vigorously fuck ${his} favorite hole.`);
						}
						if (slave.inflationType === "aphrodisiac") {
							r.push(`${His} frantic attempts force ${his} distended middle to jiggle obscenely, stirring up the aphrodisiacs contained in ${his} gut and strengthening their effects even more.`);
						}
					} else {
						r.push(`aphrodisiacs and is not allowed to masturbate so as ${he}`);
						if (hasAnyLegs(slave)) {
							r.push(`stands`);
						} else {
							r.push(`sits`);
						}
						r.push(`before you, ${he} desperately presents ${his} anus hoping to entice you into giving ${him} relief.`);
					}
				} else if (slave.vagina >= 0 && slave.dick > 0) {
					if (slave.rules.release.masturbation === 1 || ignoredRule === 1) {
						if (!canDoVaginal(slave) && slave.chastityPenis) {
							if (canDoAnal(slave)) {
								r.push(`aphrodisiacs and`);
								if (ignoredRule === 1) {
									r.push(`has disregarded ${his} masturbation restriction,`);
								} else {
									r.push(`is allowed to masturbate,`);
								}
								r.push(`so as ${he}`);
								if (hasAnyLegs(slave)) {
									r.push(`stands`);
								} else {
									r.push(`sits`);
								}
								r.push(`before you ${he}`);
								if (slave.anus === 0) {
									if (hasBothArms(slave)) {
										r.push(`plays with a nipple with one hand while furiously rubbing ${his} virgin anus and the sensitive perineum beneath it with the other,`);
									} else {
										r.push(`furiously rubs ${his} virgin anus and the sensitive perineum beneath it,`);
									}
									r.push(`desperately trying to get ${him}self off.`);
								} else {
									r.push(`uses`);
									if (slave.anus > 2) {
										r.push(`${his} entire hand, formed into a beak shape,`);
									} else if (slave.anus > 1) {
										r.push(`two fingers`);
									} else {
										r.push(`a finger`);
									}
									r.push(`to fuck ${his} own ass.`);
								}
								if (slave.inflationType === "aphrodisiac") {
									r.push(`${His} frantic attempts force ${his} distended middle to jiggle obscenely, stirring up the aphrodisiacs contained in ${his} gut and strengthening their effects even more.`);
								}
							} else {
								r.push(`aphrodisiacs, but is wearing full chastity and cannot touch ${him}self. ${He} writhes with extreme sexual frustration, desperately trying to relieve`);
								if (slave.inflationType === "aphrodisiac") {
									r.push(`${himself}, but only managing to stir up the aphrodisiacs contained in ${his} gut, strengthening their effects even more`);
								} else {
									r.push(`${himself}.`);
								}
							}
						} else if (canDoVaginal(slave)) {
							r.push(`aphrodisiacs and`);
							if (ignoredRule === 1) {
								r.push(`has disregarded ${his} masturbation restriction,`);
							} else {
								r.push(`is allowed to masturbate,`);
							}
							r.push(`so as ${he}`);
							if (hasAnyLegs(slave)) {
								r.push(`stands`);
							} else {
								r.push(`sits`);
							}
							r.push(`before you ${he} fingers ${his} vagina with`);
							if (hasBothArms(slave)) {
								if (canDoAnal(slave) && slave.anus > 0) {
									r.push(`one hand while ${he} fingers ${his} anus with the other.`);
								} else {
									r.push(`one hand while ${he} plays with a nipple with the other.`);
								}
							} else {
								r.push(`${his} hand.`);
							}
						} else if (!slave.chastityPenis) {
							r.push(`aphrodisiacs and`);
							if (ignoredRule === 1) {
								r.push(`has disregarded ${his} masturbation restriction,`);
							} else {
								r.push(`is allowed to masturbate,`);
							}
							r.push(`so as ${he}`);
							if (hasAnyLegs(slave)) {
								r.push(`stands`);
							} else {
								r.push(`sits`);
							}
							r.push(`before you ${he} rubs ${his} shaft with`);
							if (hasBothArms(slave)) {
								if (canDoAnal(slave) && slave.anus > 0) {
									r.push(`one hand while ${he} fingers ${his} anus with the other.`);
								} else {
									r.push(`both hands.`);
								}
							} else {
								r.push(`${his} hand.`);
							}
							if (canPenetrate(slave)) {
								r.push(`${His} cock is painfully erect.`);
							}
						} else {
							r.push(`aphrodisiacs and`);
							if (ignoredRule === 1) {
								r.push(`has disregarded ${his} masturbation restriction,`);
							} else {
								r.push(`is allowed to masturbate,`);
							}
							r.push(`so as ${he}`);
							if (hasAnyLegs(slave)) {
								r.push(`stands`);
							} else {
								r.push(`sits`);
							}
							r.push(`before you ${he} rubs ${his} shaft`);
							if (hasBothArms(slave)) {
								if (canDoAnal(slave) && slave.anus > 0) {
									r.push(`and pussy with one hand while ${he} fingers ${his} anus with the other.`);
								} else {
									r.push(`one hand while ${he} fingers ${his} pussy with the other.`);
								}
							} else {
								r.push(`and pussy with ${his} hand.`);
							}
							if (canAchieveErection(slave)) {
								r.push(`${His} cock is painfully erect.`);
							} else {
								r.push(`${His} cock is painfully engorged.`);
							}
							if (slave.inflationType === "aphrodisiac") {
								r.push(`${His} frantic masturbation forces ${his} distended middle to jiggle obscenely, stirring up the aphrodisiacs contained in ${his} gut and strengthening their effects even more.`);
							}
						}
					} else {
						r.push(`aphrodisiacs and is not allowed to masturbate so as ${he}`);
						if (hasAnyLegs(slave)) {
							r.push(`stands`);
						} else {
							r.push(`sits`);
						}
						r.push(`before you ${he} desperately presents ${his} open mouth, ${his}`);
						if (slave.boobs >= 300) {
							r.push(`breasts,`);
						} else {
							r.push(`chest,`);
						}
						if (canDoVaginal(slave) || !slave.chastityPenis) {
							if (!canDoAnal(slave)) {
								r.push(`and`);
							}
							r.push(`${his} crotch,`);
						}
						if (canDoAnal(slave)) {
							if (canDoVaginal(slave) || !slave.chastityPenis) {
								r.push(`and`);
							}
							r.push(`${his} anus`);
						}
						if (!canDoVaginal(slave) && !slave.chastityPenis && !canDoAnal(slave)) {
							r.push(`and ${his} chastity`);
						}
						r.push(`in turn, hoping that something will entice you to give ${him} relief.`);
						if (slave.chastityPenis) {
							r.push(`${His} cock agonizingly fills ${his} chastity cage, only adding to ${his} misery.`);
						} else if (canAchieveErection(slave)) {
							r.push(`${His} cock stands painfully erect, threatening to blow with the slightest contact.`);
						} else {
							r.push(`${His} cock is painfully engorged and ready to burst at the slightest touch.`);
						}
					}
				} else if (slave.vagina >= 0) {
					if (slave.rules.release.masturbation === 1 || ignoredRule === 1) {
						if (!canDoVaginal(slave)) {
							if (canDoAnal(slave)) {
								r.push(`aphrodisiacs and`);
								if (ignoredRule === 1) {
									r.push(`has disregarded ${his} masturbation restriction,`);
								} else {
									r.push(`is allowed to masturbate,`);
								}
								r.push(`so as ${he}`);
								if (hasAnyLegs(slave)) {
									r.push(`stands`);
								} else {
									r.push(`sits`);
								}
								r.push(`before you ${he}`);
								if (slave.anus === 0) {
									if (hasBothArms(slave)) {
										r.push(`plays with a nipple with one hand while furiously rubbing ${his} virgin anus and the sensitive perineum beneath it with the other,`);
									} else {
										r.push(`furiously rubs ${his} virgin anus and the sensitive perineum beneath it,`);
									}
									r.push(`desperately trying to get ${him}self off.`);
								} else {
									r.push(`uses`);
									if (slave.anus > 2) {
										r.push(`${his} entire hand, formed into a beak shape,`);
									} else if (slave.anus > 1) {
										r.push(`two fingers`);
									} else {
										r.push(`a finger`);
									}
									r.push(`to fuck ${his} own ass.`);
								}
								if (slave.inflationType === "aphrodisiac") {
									r.push(`${His} frantic attempts force ${his} distended middle to jiggle obscenely, stirring up the aphrodisiacs contained in ${his} gut and strengthening their effects even more.`);
								}
							} else {
								r.push(`aphrodisiacs, but is wearing a chastity belt and cannot touch ${him}self. ${He} writhes with extreme sexual frustration, desperately trying to relieve`);
								if (slave.inflationType === "aphrodisiac") {
									r.push(`${himself}, but only managing to stir up the aphrodisiacs contained in ${his} gut, strengthening their effects even more.`);
								} else {
									r.push(`${himself}.`);
								}
							}
						} else {
							r.push(`aphrodisiacs and`);
							if (ignoredRule === 1) {
								r.push(`has disregarded ${his} masturbation restriction,`);
							} else {
								r.push(`is allowed to masturbate,`);
							}
							r.push(`so as ${he}`);
							if (hasAnyLegs(slave)) {
								r.push(`stands`);
							} else {
								r.push(`sits`);
							}
							r.push(`before you ${he} rubs ${his} clit with`);
							if (hasBothArms(slave)) {
								if (canDoAnal(slave) && slave.anus > 0) {
									r.push(`one hand while ${he} fingers ${his} anus with the other.`);
								} else {
									r.push(`one hand while ${he} plays with a nipple with the other.`);
								}
							} else {
								r.push(`${his} hand.`);
							}
						}
					} else {
						r.push(`aphrodisiacs and is not allowed to masturbate so as ${he}`);
						if (hasAnyLegs(slave)) {
							r.push(`stands`);
						} else {
							r.push(`sits`);
						}
						r.push(`before you ${he} desperately presents ${his} open mouth, ${his}`);
						if (slave.boobs >= 300) {
							r.push(`breasts,`);
						} else {
							r.push(`chest,`);
						}
						if (canDoVaginal(slave)) {
							if (!canDoAnal(slave)) {
								r.push(`and`);
							}
							r.push(`${his} crotch,`);
						}
						if (canDoAnal(slave)) {
							if (canDoVaginal(slave)) {
								r.push(`and`);
							}
							r.push(`${his} anus`);
						}
						if (!canDoVaginal(slave) && !slave.chastityAnus) {
							r.push(`and ${his} chastity belts`);
						}
						r.push(`in turn, hoping that something will entice you to give ${him} relief.`);
					}
				} else if (slave.dick > 0) {
					if (slave.rules.release.masturbation === 1 || ignoredRule === 1) {
						if (slave.chastityPenis) {
							if (canDoAnal(slave)) {
								r.push(`aphrodisiacs and`);
								if (ignoredRule === 1) {
									r.push(`has disregarded ${his} masturbation restriction,`);
								} else {
									r.push(`is allowed to masturbate,`);
								}
								r.push(`so as ${he}`);
								if (hasAnyLegs(slave)) {
									r.push(`stands`);
								} else {
									r.push(`sits`);
								}
								r.push(`before you ${he}`);
								if (slave.anus === 0) {
									if (hasBothArms(slave)) {
										r.push(`plays with a nipple with one hand while furiously rubbing ${his} virgin anus and the sensitive perineum beneath it with the other,`);
									} else {
										r.push(`furiously rubs ${his} virgin anus and the sensitive perineum beneath it,`);
									}
									r.push(`desperately trying to get ${him}self off.`);
								} else {
									r.push(`uses`);
									if (slave.anus > 2) {
										r.push(`${his} entire hand, formed into a beak shape,`);
									} else if (slave.anus > 1) {
										r.push(`two fingers`);
									} else {
										r.push(`a finger`);
									}
									r.push(`to fuck ${his} own ass.`);
								}
								if (slave.inflationType === "aphrodisiac") {
									r.push(`${His} frantic attempts force ${his} distended middle to jiggle obscenely, stirring up the aphrodisiacs contained in ${his} gut and strengthening their effects even more.`);
								}
							} else {
								r.push(`aphrodisiacs, but is wearing a chastity cage and cannot touch ${him}self. ${He} writhes with extreme sexual frustration, desperately trying to relieve`);
								if (slave.inflationType === "aphrodisiac") {
									r.push(`${himself}, but only managing to stir up the aphrodisiacs contained in ${his} gut, strengthening their effects even more`);
								} else {
									r.push(`${himself}.`);
								}
							}
						} else {
							r.push(`aphrodisiacs and`);
							if (ignoredRule === 1) {
								r.push(`has disregarded ${his} masturbation restriction,`);
							} else {
								r.push(`is allowed to masturbate,`);
							}
							r.push(`so as ${he}`);
							if (hasAnyLegs(slave)) {
								r.push(`stands`);
							} else {
								r.push(`sits`);
							}
							r.push(`before you ${he} rubs ${his} shaft with`);
							if (hasBothArms(slave)) {
								if (canDoAnal(slave) && slave.anus > 0) {
									r.push(`one hand while ${he} fingers ${his} anus with the other.`);
								} else {
									r.push(`both hands.`);
								}
							} else {
								r.push(`${his} hand.`);
							}
							if (canAchieveErection(slave)) {
								r.push(`${His} cock is painfully erect.`);
							} else {
								r.push(`${His} cock is painfully engorged.`);
							}
						}
					} else {
						r.push(`aphrodisiacs and is not allowed to masturbate so as ${he}`);
						if (hasAnyLegs(slave)) {
							r.push(`stands`);
						} else {
							r.push(`sits`);
						}
						r.push(`before you ${he} desperately presents ${his} open mouth, ${his}`);
						if (slave.boobs >= 300) {
							r.push(`breasts,`);
						} else {
							r.push(`chest,`);
						}
						if (!canDoAnal(slave)) {
							r.push(`and`);
						}
						r.push(`${his} crotch,`);
						if (canDoAnal(slave)) {
							r.push(`and ${his} anus`);
						}
						r.push(`in turn, hoping that something will entice you to give ${him} relief.`);
						if (slave.chastityPenis) {
							r.push(`${His} chastity cage painfully squeezes ${his} cock.`);
						} else if (canAchieveErection(slave)) {
							r.push(`${His} cock is painfully erect.`);
						} else {
							r.push(`${His} cock is painfully engorged.`);
						}
					}
				} else {
					// no tools
					r.push(`aphrodisiacs, has`);
					if (V.seeDicks > 0) {
						r.push(`no penis and`);
					}
					r.push(`no vagina, and`);
					if (slave.rules.release.masturbation === 1 || ignoredRule === 1) {
						if (ignoredRule === 1) {
							r.push(`has disregarded ${his} masturbation restriction,`);
						} else {
							r.push(`is allowed to masturbate,`);
						}
						r.push(`so as ${he}`);
						if (hasAnyLegs(slave)) {
							r.push(`stands`);
						} else {
							r.push(`sits`);
						}
						r.push(`before you ${he}`);
						if (canDoAnal(slave)) {
							if (slave.anus === 0) {
								r.push(`plays with a nipple with one hand while furiously rubbing ${his} virgin anus and the sensitive perineum beneath it with the other, desperately trying to get ${him}self off.`);
								if (slave.inflationType === "aphrodisiac") {
									r.push(`${His} frantic attempts force ${his} distended middle to jiggle obscenely, stirring up the aphrodisiacs contained in ${his} gut and strengthening their effects even more.`);
								}
							} else {
								r.push(`uses`);
								if (slave.anus > 2) {
									r.push(`${his} entire hand, formed into a beak shape,`);
								} else if (slave.anus > 1) {
									r.push(`two fingers`);
								} else {
									r.push(`a finger`);
								}
								r.push(`to fuck ${his} own ass.`);
								if (slave.inflationType === "aphrodisiac") {
									r.push(`${His} frantic attempts force ${his} distended middle to jiggle obscenely, stirring up the aphrodisiacs contained in ${his} gut and strengthening their effects even more.`);
								}
							}
						} else if (slave.fetish === "boobs") {
							r.push(`furiously works ${his} rock-hard nipples.`);
						} else {
							r.push(`writhes with extreme sexual frustration, desperately trying to relieve ${him}self despite ${his} anal chastity.`);
						}
						if (slave.inflationType === "aphrodisiac") {
							r.push(`${His} frantic attempts force ${his} distended middle to jiggle obscenely, stirring up the aphrodisiacs contained in ${his} gut and strengthening their effects even more.`);
						}
					} else {
						if (canDoAnal(slave)) {
							r.push(`and is not allowed to masturbate, so as ${he}`);
							if (hasAnyLegs(slave)) {
								r.push(`stands`);
							} else {
								r.push(`sits`);
							}
							r.push(`before you ${he} desperately presents ${his} asshole, hoping you'll fuck ${his} only real source of relief.`);
						} else {
							r.push(`and is locked in anal chastity, so as ${he}`);
							if (hasAnyLegs(slave)) {
								r.push(`stands`);
							} else {
								r.push(`sits`);
							}
							r.push(`before you ${he} desperately presents ${his} rear, hoping to entice you into removing ${his} belt and taking ${him} right there.`);
						}
					}
				}
			} else {
				r.push(`${He}'s on`);
				if (!hasAnyArms(slave)) {
					r.push(`aphrodisiacs, but is an amputee, so ${he} cannot touch ${him}self. ${He} writhes with sexual frustration.`);
				} else if (slave.rules.release.masturbation === 0 && slave.rules.release.master === 0 && ignoredRule === 0) {
					r.push(`aphrodisiacs, but is not permitted to touch ${him}self nor beg you for release, so as ${he} obeys your commands ${he} shifts ${his} weight uncomfortably.`);
					if (canAchieveErection(slave) && !slave.chastityPenis) {
						r.push(`${His} erect dick sways as ${he} does.`);
					}
				} else if (slave.vagina >= 0 && slave.dick > 0) {
					if (slave.rules.release.masturbation === 1 || ignoredRule === 1) {
						if (!canDoVaginal(slave) && slave.chastityPenis) {
							r.push(`aphrodisiacs, but is wearing chastity and cannot touch ${him}self. ${He} writhes with sexual frustration as ${he} runs ${his}`);
							if (hasBothArms(slave)) {
								r.push(`hands`);
							} else {
								r.push(`hand`);
							}
							r.push(`across ${his} body.`);
						} else if (canDoVaginal(slave)) {
							r.push(`aphrodisiacs and`);
							if (ignoredRule === 1) {
								r.push(`has disregarded ${his} masturbation restriction,`);
							} else {
								r.push(`is allowed to masturbate,`);
							}
							r.push(`so as ${he} obeys your commands ${he} idly rubs ${his} pussy with`);
							if (hasBothArms(slave)) {
								r.push(`one hand while the other pinches a nipple.`);
							} else {
								r.push(`${his} hand.`);
							}
						} else if (!slave.chastityPenis) {
							r.push(`aphrodisiacs and`);
							if (ignoredRule === 1) {
								r.push(`has disregarded ${his} masturbation restriction,`);
							} else {
								r.push(`is allowed to masturbate,`);
							}
							r.push(`so as ${he} obeys your commands ${he} idly rubs ${his} shaft with`);
							if (hasBothArms(slave)) {
								r.push(`one hand while the other pinches a nipple.`);
							} else {
								r.push(`${his} hand.`);
							}
						} else {
							r.push(`aphrodisiacs and`);
							if (ignoredRule === 1) {
								r.push(`has disregarded ${his} masturbation restriction,`);
							} else {
								r.push(`is allowed to masturbate,`);
							}
							r.push(`so as ${he} obeys your commands ${he} idly rubs ${his} shaft`);
							if (hasBothArms(slave)) {
								r.push(`with one hand while ${he} fingers ${his} pussy with the other.`);
							} else {
								r.push(`and pussy with ${his} hand.`);
							}
						}
					} else {
						r.push(`aphrodisiacs, but is not permitted to touch ${him}self, so as ${he} obeys your commands ${he} shifts ${his} weight uncomfortably.`);
						if (canAchieveErection(slave) && !slave.chastityPenis) {
							r.push(`${His} erect dick sways as ${he} does.`);
						}
					}
				} else if (slave.vagina >= 0) {
					if (slave.rules.release.masturbation === 1 || ignoredRule === 1) {
						if (!canDoVaginal(slave)) {
							r.push(`aphrodisiacs, but is wearing a chastity belt and cannot touch ${him}self. ${He} writhes with sexual frustration.`);
						} else {
							r.push(`aphrodisiacs and`);
							if (ignoredRule === 1) {
								r.push(`has disregarded ${his} masturbation restriction,`);
							} else {
								r.push(`is allowed to masturbate,`);
							}
							r.push(`so as ${he} obeys your commands ${he} idly rubs ${his} pussy with`);
							if (hasBothArms(slave)) {
								r.push(`one hand while the other pinches a nipple.`);
							} else {
								r.push(`${his} hand.`);
							}
						}
					} else {
						r.push(`aphrodisiacs, but is not permitted to touch ${him}self, so as ${he} obeys your commands ${he} shifts ${his} weight uncomfortably.`);
					}
				} else if (slave.dick > 0) {
					if (slave.rules.release.masturbation === 1 || ignoredRule === 1) {
						if (slave.chastityPenis) {
							r.push(`aphrodisiacs, but is wearing a chastity cage and cannot touch ${him}self. ${He} writhes with sexual frustration.`);
						} else {
							r.push(`aphrodisiacs and`);
							if (ignoredRule === 1) {
								r.push(`has disregarded ${his} masturbation restriction,`);
							} else {
								r.push(`is allowed to masturbate,`);
							}
							r.push(`so as ${he} obeys your commands ${he} idly rubs ${his} shaft with`);
							if (hasBothArms(slave)) {
								r.push(`one hand while the other pinches a nipple.`);
							} else {
								r.push(`${his} hand.`);
							}
						}
					} else {
						r.push(`aphrodisiacs, but is not permitted to touch ${him}self, so as ${he} obeys your commands ${he} shifts ${his} weight uncomfortably.`);
						if (canAchieveErection(slave) && !slave.chastityPenis) {
							r.push(`${His} erect dick sways as ${he} does.`);
						}
					}
				} else {
					r.push(`aphrodisiacs, but has`);
					if (V.seeDicks > 0) {
						r.push(`no penis and`);
					}
					r.push(`no vagina no touch, so as ${he} obeys your commands ${he} shifts ${his} weight uncomfortably.`);
				}
			}
		}
		if (slave.addict.isBetween(0, 3)) {
			r.push(`${He} is a new <span class="cyan">aphrodisiac addict.</span>`);
		} else if (slave.addict.isBetween(0, 10)) {
			r.push(`${He} is a confirmed <span class="cyan">aphrodisiac addict.</span>`);
		} else if (slave.addict > 0) {
			r.push(`${He} is completely <span class="cyan">dependent on aphrodisiacs,</span> and it is unlikely you will ever be able to wean ${him} off them.`);
		}
		return r.join(" ");
	}
};


code:
/**
 * @param {App.Entity.SlaveState} slave
 * @returns {string}
 */
App.Desc.ears = function(slave) {
	const r = [];
	const {
		he, him, his, He, His
	} = getPronouns(slave);
	// ear shape description here
	if (slave.earShape === "none") {
		if (slave.earImplant === 1) {
			if (slave.earT !== "none" && slave.race === "catgirl") {
				r.push(`${He} has smooth fur where a normal human's ears would be, as ${he} instead hears out of ${his} twitchy, sensitive cat ears.`);
			} else if (slave.earT !== "none" && slave.race !== "catgirl") {
				r.push(`${He} has smooth skin where ${his} ears should be as ${his} hearing has been cybernetically rerouted to ${his} secondary ears.`);
			} else {
				r.push(`${He} has nothing but small, perforated metal disks where ${his} ears should be.`);
			}
		} else if (slave.earwear === "none") {
			r.push(`${He} has small unsightly holes on the sides of ${his} head.`); // That can't be sanitary.
		} else {
			r.push(`The sides of ${his} head are smooth where ${his} ears should be, but upon closer inspection it is revealed that`);
			if (slave.earwear === "hearing aids") {
				r.push(`${his} ear canals are fitted with hearing aids capped with a skin-matching sheet to obscure the hole.`);
			} else {
				r.push(`${his} ear canals are filled with plugs with skin-matching caps.`);
			}
		}
	} else if (slave.earShape === "damaged") {
		r.push(`${His} outer ears have been severely damaged.`);
	} else if (slave.earShape === "normal" && slave.earT !== "none") {
		// Ears are expected, so lets only mention them if we have two sets
		r.push(`${He} has perfectly ordinary ears.`);
	} else if (slave.earShape === "robot") {
		r.push(`${He} has high tech cyber-ears that could be mistaken for headphones.`);// not yet implemented
	} else if (slave.earShape === "pointy") {
		r.push(`${His} small, ${either("elfin", "leaf-shaped", "pointed")} ears are quite cute and give ${him} an exotic appearance.`);
	} else if (slave.earShape === "elven") {
		r.push(`${He} has long, thin elven ears that ${either(`tend to droop when ${he} is relaxed or sad`, `tend to waggle up and down when ${he} is excited`, `twitch at the slightest touch`)}.`);
	} else if (slave.earShape === "ushi") {
		r.push(`${He} has long, floppy cow ears.`); // that ${either(`tend to droop when ${he} is relaxed or sad`, `tend waggle up and down when ${he} is excited`, `twitch at the slightest touch`)}. These don't make sense for the most part.
	}

	if (slave.earT === "neko") {
		r.push(`${He} has cute, ${slave.earTColor} cat ears on ${his} head; they`);
		if (slave.earImplant === 1) {
			r.push(`perk up at`);
			if (slave.devotion > 20) {
				r.push(`the sound of your voice and`);
			} else {
				r.push(`sudden noises and`);
			}
		}
		r.push(`${either(`tend to droop when ${he} is relaxed or sad`, `twitch at the slightest touch`)}.`);
	} else if (slave.earT === "inu") {
		r.push(`${He} has cute, ${slave.earTColor} dog ears on ${his} head; they`);
		if (slave.earImplant === 1) {
			r.push(`perk up at`);
			if (slave.devotion > 50) {
				r.push(`the sound of your voice and`);
			} else {
				r.push(`sudden noises and`);
			}
		}
		r.push(`${either(`tend to droop when ${he} is relaxed or sad`, `twitch at the slightest touch`)}.`);
	} else if (slave.earT === "kit") {
		r.push(`${He} has elegant, ${slave.earTColor} fox ears on ${his} head; they`);
		if (slave.earImplant === 1) {
			r.push(`perk up at`);
			if (slave.devotion > 50) {
				r.push(`the sound of your voice and`);
			} else {
				r.push(`sudden noises and`);
			}
		}
		r.push(`${either(`tend to droop when ${he} is relaxed or sad`, `twitch at the slightest touch`)}.`);
	} else if (slave.earT === "tanuki") {
		r.push(`${He} has adorable, ${slave.earTColor}, round tanuki ears on ${his} head; they`);
		if (slave.earImplant === 1) {
			r.push(`perk up at`);
			if (slave.devotion > 50) {
				r.push(`the sound of your voice and`);
			} else {
				r.push(`sudden noises and`);
			}
		}
		r.push(`${either(`tend to droop when ${he} is relaxed or sad`, `twitch at the slightest touch`)}.`);
	} else if (slave.earT === "usagi") {
		r.push(`${He} has long, ${slave.earTColor}, fluffy rabbit ears on ${his} head; they`);
		if (slave.earImplant === 1) {
			r.push(`perk up at`);
			if (slave.devotion > 50) {
				r.push(`the sound of your voice and`);
			} else {
				r.push(`sudden noises and`);
			}
		}
		r.push(`${either(`tend to droop when ${he} is relaxed or sad`, `twitch at the slightest touch`)}.`);
	} else if (slave.earT === "normal") {
		r.push(`${He} has`);
		if (slave.earShape !== "none") {
			r.push(`a second set`);
		} else {
			r.push(`a pair`);
		}
		r.push(`of non-functioning ears grafted to the top of ${his} head.`);
	}

	if (slave.hears < 0) {
		if (slave.hears === -1) {
			r.push(`${His} hearing is noticeably impaired,`);
		} else if (slave.hears < -1) {
			r.push(`${He} is completely deaf,`);
		}
		if (slave.hears < -1 && slave.earShape === "none") {
			r.push(`which is fitting due to ${his} lack of ears.`);
		} else {
			r.push(`but this isn't obvious just by looking at ${his} ears.`);
		}
	}
	return r.join(" ");
};

repo_name: Elohiem/fc

license: mit


code:
/**
 * returned string fits in a sentence like this:
 * She has {return}.
 *
 * @param {FC.HumanState} slave
 * @returns {string}
 */
App.Desc.eyesType = function(slave) {
	let r = "";
	if (hasBothEyes(slave)) {
		if (getLeftEyeType(slave) !== getRightEyeType(slave)) {
			r = `a ${App.Desc.eyeTypeToString(getRightEyeType(slave))} and a ${App.Desc.eyeTypeToString(getLeftEyeType(slave))} eye`;
		} else {
			r = `${App.Desc.eyeTypeToString(getRightEyeType(slave))} eyes`;
		}
	} else if (hasAnyEyes(slave)) {
		if (hasRightEye(slave)) {
			r = `a ${App.Desc.eyeTypeToString(getRightEyeType(slave))} eye`;
		} else if (hasLeftEye(slave)) {
			r = `a ${App.Desc.eyeTypeToString(getLeftEyeType(slave))} eye`;
		}
	} else {
		r = "no eyes";
	}

	return r;
};

/**
 * converts an eye type to a string
 * @param {number} type
 * @returns {string}
 */
App.Desc.eyeTypeToString = function(type) {
	switch (type) {
		case 1:
			return "natural";
		case 2:
			return "glass";
		case 3:
			return "artificial";
		default:
			return "unknown eye type: " + type;
	}
};

/**
 * Fits in a sentence like this:
 * She has {return}.
 *
 * Intentionally leaves out some information to make it flow nicer and have less grammatical restrictions.
 * Use App.Desc.eyesColorLong for a complete eye description.
 *
 * @param {FC.HumanState} slave
 * @param {string} [adj=""]
 * @param {string} [eye="eye"]
 * @param {string} [eyes="eyes"]
 * @param {boolean} [a=true]
 * @returns {string}
 */
App.Desc.eyesColor = function(slave, adj = "", eye = "eye", eyes = "eyes", a = true) {
	let r = "";
	if (hasBothEyes(slave)) {
		const leftEye = slave.eye.left;
		const rightEye = slave.eye.right;
		if (unusualPupil(leftEye) && leftEye.pupil === rightEye.pupil) {
			r += `${leftEye.pupil} `;
		}
		r += leftEye.iris;
		if (leftEye.iris !== rightEye.iris) {
			r += ` and ${rightEye.iris}`;
		}
		r += ` ${adj} ${eyes}`;
		if (unusualSclera(leftEye) && leftEye.sclera === rightEye.sclera) {
			r += ` with ${leftEye.sclera} sclerae`;
		}
	} else if (hasAnyEyes(slave)) {
		const slaveEye = hasLeftEye(slave) ? slave.eye.left : slave.eye.right;
		if (a) {
			r += "a ";
		}
		if (unusualPupil(slaveEye)) {
			r += `${slaveEye.pupil} `;
		}
		r += `${slaveEye.iris} ${adj ? `${adj} ` : ""}${eye}`;
		if (unusualSclera(slaveEye)) {
			r += ` with ${a ? "a " : ""}${slaveEye.sclera} sclera`;
		}
	} else {
		r = "no eyes";
	}

	return r;

	// TODO: deduplicate with eyesColorLong()
	function unusualPupil(eye) { return eye.pupil !== "circular"; }

	function unusualSclera(eye) { return eye.sclera !== "white"; }
};

/**
 * Returns a description of a given slave's eyes.
 * WARNING: Expects .,:;!? after the string, otherwise there might be grammatical errors!
 *
 * @param {FC.HumanState} slave
 * @returns {string}
 */
App.Desc.eyesColorLong = function(slave) {
	let r = "";
	if (hasBothEyes(slave)) {
		const leftEye = slave.eye.left;
		const rightEye = slave.eye.right;
		if (leftEye.iris === rightEye.iris) {
			if (leftEye.pupil === rightEye.pupil && unusualPupil(leftEye)) {
				r += `${leftEye.pupil} `;
			}
			// This line is the only guaranteed line, every other line has a space on the side TOWARDS this line.
			r += `${leftEye.iris} eyes`;
			let comma = false;
			let left = "";
			let right = "";
			if (leftEye.pupil !== rightEye.pupil) {
				if (unusualPupil(leftEye)) {
					left = ` ${leftEye.pupil}`;
				}
				if (unusualPupil(rightEye)) {
					right = ` ${rightEye.pupil}`;
				}
			}
			if (leftEye.sclera !== rightEye.sclera) {
				if (unusualSclera(leftEye)) {
					left += ` with a ${leftEye.sclera} sclera`;
				}
				if (unusualSclera(rightEye)) {
					right += ` with a ${rightEye.sclera} sclera`;
				}
			}
			if (left !== "") {
				r += `; one${left}`;
				if (right !== "") {
					r += ` and the other${right}`;
				}
				comma = true;
			} else if (right !== "") {
				r += `; one${right}`;
				comma = true;
			}
			if (leftEye.sclera === rightEye.sclera && unusualSclera(leftEye)) {
				r += `${comma ? "," : ""} with ${leftEye.sclera} sclerae`;
			}
		} else {
			const splitPupil = leftEye.pupil !== rightEye.pupil;
			const splitSclerae = leftEye.sclera !== rightEye.sclera;
			if (splitPupil || splitSclerae) {
				r += "a";
				if (splitPupil && unusualPupil(leftEye)) {
					r += ` ${leftEye.pupil}`;
				}
				r += ` ${leftEye.iris} eye`;
				if (splitSclerae && unusualSclera(leftEye)) {
					r += ` with a ${leftEye.sclera} sclera`;
				}
				r += " and a";
				if (splitPupil && unusualPupil(rightEye)) {
					r += ` ${rightEye.pupil}`;
				}
				r += ` ${rightEye.iris} eye`;
				if (splitSclerae && unusualSclera(rightEye)) {
					r += ` with a ${rightEye.sclera} sclera`;
				}
				if (!splitPupil && unusualPupil(leftEye)) {
					r += `; both ${leftEye.pupil}`;
				} else if (!splitSclerae && unusualSclera(leftEye)) {
					r += `; both with ${leftEye.sclera} sclerae`;
				}
			} else {
				if (unusualPupil(leftEye)) {
					r += `${leftEye.pupil} `;
				}
				r += `${leftEye.iris} and ${rightEye.iris} eyes`;
				if (unusualSclera(leftEye)) {
					r += ` with ${leftEye.sclera} sclerae`;
				}
			}
		}
	} else if (hasAnyEyes(slave)) {
		const eye = hasLeftEye(slave) ? slave.eye.left : slave.eye.right;
		r += "a";
		if (unusualPupil(eye)) {
			r += ` ${eye.pupil}`;
		}
		r += ` ${eye.iris} eye`;
		if (unusualSclera(eye)) {
			r += ` with a ${eye.sclera} sclera`;
		}
	} else {
		r = "no eyes";
	}
	return r;

	function unusualPupil(eye) { return eye.pupil !== "circular"; }

	function unusualSclera(eye) { return eye.sclera !== "white"; }
};

/**
 * Fits in a sentence like this:
 * She has {return} eyes.
 * Prefer App.Desc.eyesColor if possible as it works reliably with only one eye.
 * Example where this is better: {return}-eyed gaze
 *
 * @param {FC.HumanState} slave
 * @returns {string} Slave's eye color
 */
App.Desc.eyeColor = function(slave) {
	"use strict";
	let r;

	if (!hasAnyEyes(slave)) {
		r = "empty";
	} else if (hasBothEyes(slave)) {
		if (hasVisibleHeterochromia(slave)) {
			r = `heterochromatic ${getRightEyeColor(slave)} and ${getLeftEyeColor(slave)}`;
		} else {
			r = getLeftEyeColor(slave);
		}
	} else if (hasLeftEye(slave)) {
		r = getLeftEyeColor(slave);
	} else {
		r = getRightEyeColor(slave);
	}
	return r;
};

/**
 * returned string fits in a sentence like this:
 * She has {return}.
 *
 * @param {FC.HumanState} slave
 * @returns {string}
 */
App.Desc.eyesVision = function(slave) {
	let r = "";
	if (hasBothEyes(slave)) {
		if (getLeftEyeVision(slave) !== getRightEyeVision(slave)) {
			r = `a ${App.Desc.eyeVisionToString(getRightEyeVision(slave))} and a ${App.Desc.eyeVisionToString(getLeftEyeVision(slave))} eye`;
		} else {
			r = `${App.Desc.eyeVisionToString(getRightEyeVision(slave))} eyes`;
		}
	} else if (hasAnyEyes(slave)) {
		if (hasRightEye(slave)) {
			r = `a ${App.Desc.eyeVisionToString(getRightEyeVision(slave))} eye`;
		} else if (hasLeftEye(slave)) {
			r = `a ${App.Desc.eyeVisionToString(getLeftEyeVision(slave))} eye`;
		}
	} else {
		r = "no eyes";
	}

	return r;
};

/**
 * converts an eye vision to a string
 * @param {number} type
 * @returns {string}
 */
App.Desc.eyeVisionToString = function(type) {
	switch (type) {
		case 0:
			return "blind";
		case 1:
			return "nearsighted";
		case 2:
			return "normal";
		default:
			return "unknown eye vision: " + type;
	}
};


code:
/**
 * @param {App.Entity.SlaveState} slave
 * @returns {string}
 */
App.Desc.face = function(slave) {
	const r = [];
	const {
		he, him, his, He, His
	} = getPronouns(slave);

	r.push(`${His} <span class="pink">face is`);

	switch (slave.faceShape) {
		case "masculine":
			if (slave.face < -95) {
				r.push(`so ugly and masculine that ${his} designation as a slave girl is a mockery.`);
			} else if (slave.face < -40) {
				r.push(`ugly and masculine, making ${him} a poor slave girl by appearance.`);
			} else if (slave.face < -10) {
				r.push(`unattractively masculine.`);
			} else if (slave.face <= 10) {
				r.push(`masculine, but not entirely unappealing.`);
			} else if (slave.face <= 40) {
				r.push(`attractively masculine.`);
			} else if (slave.face <= 95) {
				r.push(`quite handsome in a masculine way.`);
			} else {
				r.push(`the height of masculine handsomeness.`);
			}
			break;
		case "androgynous":
			if (slave.face < -95) {
				r.push(`disturbingly androgynous and terribly ugly.`);
			} else if (slave.face < -40) {
				r.push(`ugly and androgynous; ${he} has neither masculine nor feminine appeal.`);
			} else if (slave.face < -10) {
				r.push(`strangely androgynous, and rather unattractive.`);
			} else if (slave.face <= 10) {
				r.push(`strangely androgynous.`);
			} else if (slave.face <= 40) {
				r.push(`androgynous, and attractive enough that this ambiguity is interesting.`);
			} else if (slave.face <= 95) {
				r.push(`gorgeously androgynous in a complex way that captures the eye.`);
			} else {
				r.push(`so gorgeously androgynous that ${he} tends to induce sexual confusion.`);
			}
			break;
		case "cute":
			if (slave.face < -95) {
				r.push(`very ugly, yet somehow cute; ${he}'s so unattractive that ${he} inspires pity.`);
			} else if (slave.face < -40) {
				r.push(`ugly, but cute, with a pitiable appeal.`);
			} else if (slave.face < -10) {
				r.push(`not attractive, but is appealingly cute.`);
			} else if (slave.face <= 10) {
				r.push(`merely average, but is appealingly cute.`);
			} else if (slave.face <= 40) {
				r.push(`both attractive and appealingly cute.`);
			} else if (slave.face <= 95) {
				r.push(`beautiful, yet somehow also approachably cute.`);
			} else {
				r.push(`an impossibly perfect combination of beauty and girl-next-door cuteness.`);
			}
			break;
		case "sensual":
			if (slave.face < -95) {
				r.push(`very ugly, yet naturally slutty, promising a decent fuck despite its appearance.`);
			} else if (slave.face < -40) {
				r.push(`ugly, but also slutty, promising a good fuck despite its appearance.`);
			} else if (slave.face < -10) {
				r.push(`not attractive, but it has a certain sensual appeal.`);
			} else if (slave.face <= 10) {
				r.push(`merely average, but undeniably sensual.`);
			} else if (slave.face <= 40) {
				r.push(`both attractive and naturally sultry.`);
			} else if (slave.face <= 95) {
				r.push(`both beautiful and sultry, bringing sex to mind naturally.`);
			} else {
				r.push(`very beautiful in a consummately sexual way.`);
			}
			break;
		case "exotic":
			if (slave.face < -95) {
				r.push(`very ugly and unusual, a real tragedy in flesh.`);
			} else if (slave.face < -40) {
				r.push(`ugly and unusual, a real misfortune.`);
			} else if (slave.face < -10) {
				r.push(`unattractive, and distinctive in its unattractiveness.`);
			} else if (slave.face <= 10) {
				r.push(`quite average, but not uninteresting.`);
			} else if (slave.face <= 40) {
				r.push(`attractive in an exotic and interesting way.`);
			} else if (slave.face <= 95) {
				r.push(`exotic and beautiful, capable of catching the eye and keeping its gaze.`);
			} else {
				r.push(`very beautiful and exotic, almost to the point of alien fascination.`);
			}
			break;
		case "feline":
			if (slave.face < -95) {
				r.push(`a hideous, furred feline face with pronounced fangs and whiskers that's nothing short of terrifying.`);
			} else if (slave.face < -40) {
				r.push(`an ugly, furred feline face, featuring idly-twitching whiskers and a misshapen button nose.`);
			} else if (slave.face < -10) {
				r.push(`an comely, furred feline face, somewhat unappealing in its strange catlike whiskers and nose.`);
			} else if (slave.face <= 10) {
				r.push(`a plain, feline face, remarkable only for the whiskers and button nose that decorate it.`);
			} else if (slave.face <= 40) {
				r.push(`an attractive feline face, silky fur framing well-manicured whiskers in an eye-catching fashion.`);
			} else if (slave.face <= 95) {
				r.push(`a beautiful feline face, combining catlike grace and human structure into a gorgeous whiskered visage.`);
			} else {
				r.push(`an absolutely stunningly beautiful feline face, perfectly inviting silky fur framing a whiskered, catlike appearance that's as alien as it is perfect.`);
			}
			break;
		default:
			if (slave.face < -95) {
				r.push(`very ugly.`);
			} else if (slave.face < -40) {
				r.push(`quite ugly.`);
			} else if (slave.face < -10) {
				r.push(`unattractive.`);
			} else if (slave.face <= 10) {
				r.push(`average and conventionally feminine.`);
			} else if (slave.face <= 40) {
				r.push(`conventionally attractive.`);
			} else if (slave.face <= 95) {
				r.push(`conventionally beautiful.`);
			} else {
				r.push(`the height of conventional feminine beauty.`);
			}
	}
	r.push(`</span>`);
	if (slave.weight > 190) {
		r.push(`${His} face is quite fat with ample excess chins.`);
	} else if (slave.weight > 160) {
		r.push(`${His} face is round and plump with a trio of extra chins.`);
	} else if (slave.weight > 130) {
		r.push(`${His} face is chubby with an obvious second chin.`);
	} else if (slave.weight > 97) {
		r.push(`${His} face is soft with barely a second chin.`);
	}
	if (slave.fuckdoll > 0) {
		r.push(`However,`);
		if (slave.face < -1) {
			r.push(`it's hard to see this past the suit, since its face is padded to make ${him} seem less ugly.`);
		} else if (slave.face < 1) {
			r.push(`it's hard to see this past the suit, since its face is shaped to make ${him} seem prettier.`);
		} else {
			r.push(`the suit obscures all but the shape of ${his} pretty face.`);
		}
	} else {
		if (slave.markings === "beauty mark") {
			if (slave.face < -95) {
				r.push(`It bears a severely disfiguring, discolored mark.`);
			} else if (slave.face < -40) {
				r.push(`It bears a couple of unsightly moles.`);
			} else if (slave.face < -10) {
				r.push(`It bears an ugly mole.`);
			} else if (slave.face <= 10) {
				r.push(`${He} has a distinctive beauty mark.`);
			} else if (slave.face <= 40) {
				r.push(`${He} has a nice beauty mark.`);
			} else if (slave.face <= 95) {
				r.push(`${He} has a beauty mark that adds to ${his} distinctiveness.`);
			} else {
				r.push(`${He} has a beauty mark that makes ${him} really memorable.`);
			}
		}
	}
	if (slave.faceImplant > 5) {
		r.push(`${He}'s`);
		if (slave.faceImplant > 95) {
			r.push(`had so much cosmetic surgery that ${his} face is located at the bottom of the uncanny`);
			if (slave.face < -10) {
				r.push(`valley in addition to its ugliness.`);
			} else if (slave.face <= 10) {
				r.push(`valley; the only thing really distinctive about it.`);
			} else {
				r.push(`valley, its attractiveness notwithstanding.`);
			}
		} else if (slave.faceImplant > 60) {
			r.push(`obviously gotten a lot of facial cosmetic surgery.`);
		} else if (slave.faceImplant > 30) {
			r.push(`noticeably received facial cosmetic surgery.`);
		} else {
			r.push(`had some facial cosmetic surgery, though it's subtle.`);
			if (V.PC.skill.medicine >= 100) {
				r.push(`Someone without your knowledge might miss it entirely.`);
			}
		}
		if (V.arcologies[0].FSBodyPurist !== "unset") {
			if (slave.faceImplant > 30) {
				r.push(`This is considered extremely tragic by a society that values bodily purity.`);
			} else {
				r.push(`Since society values bodily purity, even this subtlety affects ${his} attractiveness when it's noticed.`);
			}
		} else if (V.arcologies[0].FSTransformationFetishist !== "unset") {
			if (slave.faceImplant > 30) {
				r.push(`Your transformationist society doesn't think this`);
				if (slave.face >= -10) {
					r.push(`reduces ${his} attractiveness.`);
				} else {
					r.push(`makes ${him} uglier.`);
				}
			}
		} else {
			if (slave.faceImplant > 30) {
				r.push(`The effect is enough to reduce ${his} attractiveness.`);
			}
		}
	}
	if (slave.smells === -1) {
		r.push(`${He} has no sense of smell, but this isn't immediately obvious just by looking at ${his} nose.`);
	}

	if (V.showBodyMods === 1) {
		if (slave.fuckdoll === 0) {
			r.push(App.Desc.makeup(slave));
		}
	}
	return r.join(" ");
};


code:
/**
 * @example const beautiful = beautiful(slave); `The slave's ${beautiful} face.`
 * @param {App.Entity.SlaveState} slave
 * @returns {string}
 */
globalThis.beautiful = function(slave) {
	return slave.genes === "XX" ? `beautiful` : `handsome`;
};

/**
 * @example const pretty = pretty(slave); `The slave's ${pretty} face.`
 * @param {App.Entity.SlaveState} slave
 * @returns {string}
 */
globalThis.pretty = function(slave) {
	return slave.genes === "XX" ? `pretty` : `good-looking`;
};


code:
/**
 * @param {App.Entity.SlaveState} slave
 * @param {object} params
 * @param {FC.Zeroable<FC.SlaveMarketName>} [params.market]
 * @param {boolean} [params.eventDescription]
 * @returns {string}
 */
App.Desc.heels = function(slave, {market, eventDescription} = {}) {
	const r = [];
	const {
		he, He, His
	} = getPronouns(slave);
	if (slave.heels === 1 && hasAnyLegs(slave)) {
		r.push(`${His}`);
		if (hasBothLegs(slave)) {
			r.push(`<span class="pink">legs have been altered</span>`);
		} else {
			r.push(`<span class="pink">leg has been altered</span>`);
		}
		r.push(`so that ${he} must wear heels in order to walk.`);
		if (V.showClothing === 1 && !market) {
			if (shoeHeelCategory(slave) > 0) {
				r.push(`${He} is, so ${he} can walk reasonably well.`);
			} else {
				r.push(`Since ${he} is without them, ${he}'s crawling on`);
				if (!hasAllLimbs(slave)) {
					r.push(`the ground.`);
				} else {
					r.push(`all fours.`);
				}
			}
		}
	}
	return r.join(" ");
};


code:
/**
 * @param {App.Entity.SlaveState} slave
 * @returns {string}
 */
App.Desc.heightImplant = function(slave) {
	let r = [];
	const {his} = getPronouns(slave);
	if (slave.heightImplant > 1) {
		r = limbs();
		r.push(`are wrong; it's obvious that they have been artificially lengthened.`);
	} else if (slave.heightImplant > 0) {
		r = limbs();
		r.push(`are odd, as though they have been artificially lengthened.`);
	} else if (slave.heightImplant < -1) {
		r = limbs();
		r.push(`are wrong; it's obvious that they have been artificially shortened.`);
	} else if (slave.heightImplant < 0) {
		r = limbs();
		r.push(`are odd, as though they have been artificially shortened.`);
	}

	return r.join(" ");

	function limbs() {
		const r = [];
		r.push(`The proportions of ${his}`);
		if (hasAnyArms(slave)) {
			if (hasBothArms(slave)) {
				r.push(`arms`);
			} else {
				r.push(`arm`);
			}
			if (hasAnyLegs(slave)) {
				r.push(`and`);
			}
		}
		if (hasAnyLegs(slave)) {
			if (hasBothLegs(slave)) {
				r.push(`legs`);
			} else {
				r.push(`leg`);
			}
		}
		return r;
	}
};


code:
/**
 * @param {App.Entity.SlaveState} slave
 * @returns {string}
 */
App.Desc.hips = function(slave) {
	const r = [];
	const {his} = getPronouns(slave);
	if (slave.hips < -1) {
		if (slave.butt > 2) {
			if (V.arcologies[0].FSHedonisticDecadence !== "unset") {
				r.push(`disproportionately large for ${his} narrow hips, but your hedonistic arcology finds this attractive.`);
			} else if (V.arcologies[0].FSTransformationFetishist !== "unset") {
				r.push(`disproportionately large for ${his} narrow hips, but your transformation fetishist arcology considers this attractive.`);
			} else if (V.arcologies[0].FSAssetExpansionist !== "unset") {
				r.push(`disproportionately large for ${his} narrow hips, but that's just fine to your asset expansionist society.`);
			} else {
				r.push(`<span class="red">disproportionately large</span> for ${his} narrow hips.`);
			}
		} else {
			r.push(`and ${his} hips are very narrow.`);
		}
	} else if (slave.hips < 0) {
		if (slave.butt > 4) {
			if (V.arcologies[0].FSHedonisticDecadence !== "unset") {
				r.push(`disproportionately large for ${his} trim hips, but your hedonistic arcology finds this attractive.`);
			} else if (V.arcologies[0].FSTransformationFetishist !== "unset") {
				r.push(`disproportionately large for ${his} trim hips, but your transformation fetishist arcology considers this attractive.`);
			} else if (V.arcologies[0].FSAssetExpansionist !== "unset") {
				r.push(`disproportionately large for ${his} trim hips, but that's just fine to your asset expansionist society.`);
			} else {
				r.push(`<span class="red">disproportionately large</span> for ${his} trim hips.`);
			}
		} else {
			r.push(`complemented by ${his} trim hips.`);
		}
	} else if (slave.hips > 2) {
		if (slave.butt <= 8) {
			r.push(`<span class="red">disproportionately small</span> for ${his} monstrous hips.`);
		} else {
			r.push(`fitting for ${his} monstrous hips.`);
		}
	} else if (slave.hips > 1) {
		if (slave.butt <= 3 && (V.arcologies[0].FSSlimnessEnthusiast === "unset" || (slave.boobs >= 500))) {
			r.push(`<span class="red">disproportionately small</span> for ${his} very wide`);
			if (V.arcologies[0].FSSlimnessEnthusiast !== "unset") {
				r.push(`hips, which your arcology finds unattractive on busty slaves.`);
			} else {
				r.push(`hips.`);
			}
		} else {
			r.push(`flattered by ${his} very wide hips.`);
		}
	} else if (slave.hips > 0) {
		if (slave.butt > 8) {
			if (V.arcologies[0].FSHedonisticDecadence !== "unset") {
				r.push(`disproportionately large for ${his} broad hips, but your hedonistic arcology finds this attractive.`);
			} else if (V.arcologies[0].FSTransformationFetishist !== "unset") {
				r.push(`disproportionately large for ${his} broad hips, but your transformation fetishist arcology considers this attractive.`);
			} else if (V.arcologies[0].FSAssetExpansionist !== "unset") {
				r.push(`disproportionately large for ${his} broad hips, but that's just fine to your asset expansionist society.`);
			} else {
				r.push(`<span class="red">disproportionately large</span> for ${his} broad hips.`);
			}
		} else if (slave.butt <= 2 && (V.arcologies[0].FSSlimnessEnthusiast === "unset" || (slave.boobs >= 500))) {
			r.push(`<span class="red">disproportionately small</span> for ${his} broad`);
			if (V.arcologies[0].FSSlimnessEnthusiast !== "unset") {
				r.push(`hips, which your arcology finds unattractive on busty slaves.`);
			} else {
				r.push(`hips.`);
			}
		} else {
			r.push(`complemented by ${his} broad hips.`);
		}
	} else {
		if (slave.butt > 6) {
			if (V.arcologies[0].FSHedonisticDecadence !== "unset") {
				r.push(`disproportionately large for ${his} womanly hips, but your hedonistic arcology finds this attractive.`);
			} else if (V.arcologies[0].FSTransformationFetishist !== "unset") {
				r.push(`disproportionately large for ${his} womanly hips, but your transformation fetishist arcology considers this attractive.`);
			} else if (V.arcologies[0].FSAssetExpansionist !== "unset") {
				r.push(`disproportionately large for ${his} womanly hips, but that's just fine to your asset expansionist society.`);
			} else {
				r.push(`<span class="red">disproportionately large</span> for ${his} womanly hips.`);
			}
		} else if (slave.butt <= 1 && (V.arcologies[0].FSSlimnessEnthusiast === "unset" || (slave.boobs >= 500))) {
			r.push(`<span class="red">disproportionately small</span> for ${his} ample`);
			if (V.arcologies[0].FSSlimnessEnthusiast !== "unset") {
				r.push(`hips, which your arcology finds unattractive on busty slaves.`);
			} else {
				r.push(`hips.`);
			}
		} else {
			r.push(`complemented by ${his} ample hips.`);
		}
	}
	return r.join(" ");
};


code:
/**
 * @param {App.Entity.SlaveState} slave
 * @returns {string}
 */
App.Desc.horns = function(slave) {
	const r = [];
	const {
		he, his, He
	} = getPronouns(slave);
	if (slave.horn === "curved succubus horns") {
		r.push(`${He} has`);
		if (slave.face > 40) {
			r.push(`majestic ${slave.hornColor} horns that jut out from the back of ${his} head and curve forward, looking almost like a crown.`);
		} else if (slave.face > 0) {
			r.push(`imposing ${slave.hornColor} horns that jut out from the back of ${his} head and curve forward nicely.`);
		} else {
			r.push(`terrifying ${slave.hornColor} horns that jut out from the back of ${his} head and curve forward menacingly.`);
		}
	} else if (slave.horn === "backswept horns") {
		if (slave.face > 40) {
			r.push(`majestic ${slave.hornColor} horns that jut out the front of ${his} head and curve backwards, like some royal headdress.`);
		} else if (slave.face > 0) {
			r.push(`imposing ${slave.hornColor} horns that jut out the front of ${his} head and curve backwards nicely.`);
		} else {
			r.push(`terrifying ${slave.hornColor} horns that jut out the front of ${his} head and curve backwards, looking like some twisted helmet.`);
		}
	} else if (slave.horn === "cow horns") {
		r.push(`${He} has two ${slave.hornColor} cow horns on the sides of ${his} head; they curve sharply upward.`);
	} else if (slave.horn === "two long oni horns") {
		r.push(`${He} has two long ${slave.hornColor} horns sticking straight up out of ${his}`);
		if (slave.devotion > 20) {
			r.push(`forehead; ${he} holds them up proudly.`);
		} else {
			r.push(`forehead.`);
		}
	} else if (slave.horn === "one long oni horn") {
		r.push(`${He} has a long ${slave.hornColor} horn sticking straight up out of ${his}`);
		if (slave.devotion > 20) {
			r.push(`forehead; ${he} holds it up proudly`);
		} else {
			r.push(`forehead.`);
		}
	} else if (slave.horn === "small horns") {
		r.push(`${He} has cute, little ${slave.hornColor} horns sticking out of ${his} head.`);
	}
	return r.join(" ");
};


code:
/**
 * @param {App.Entity.SlaveState} slave
 * @returns {string}
 */
App.Desc.legs = function(slave) {
	const {
		his, He
	} = getPronouns(slave);

	if (hasAnyNaturalLegs(slave) && (slave.weight > 95 || slave.muscles > 5)) {
		const thighs = hasBothNaturalLegs(slave) ? "thighs" : "thigh";
		const thighMuscles = slave.muscles > 5 ? `${thighs} and ${muscleDesc()}` : thighs;
		if (slave.weight > 190) {
			if (hasBothNaturalLegs(slave)) {
				return `${He} has extremely fat legs with immense soft, rather uneven ${thighMuscles}.`;
			} else {
				return `${He} has an extremely fat leg with an immense soft, rather uneven ${thighMuscles}.`;
			}
		} else if (slave.weight > 160) {
			if (hasBothNaturalLegs(slave)) {
				return `${He} has very fat legs with massively thick, soft, somewhat uneven ${thighMuscles}.`;
			} else {
				return `${He} has a very fat leg with a massively thick, soft, somewhat uneven ${thighMuscles}.`;
			}
		} else if (slave.weight > 130) {
			if (hasBothNaturalLegs(slave)) {
				return `${He} has fat legs with hugely thick, soft ${thighMuscles}.`;
			} else {
				return `${He} has a fat leg with a hugely thick, soft ${thighMuscles}.`;
			}
		} else if (slave.weight > 97) {
			if (hasBothNaturalLegs(slave)) {
				return `${He} has fat legs with thick, soft ${thighMuscles}.`;
			} else {
				return `${He} has a fat leg with a thick, soft ${thighMuscles}.`;
			}
		} else if (slave.weight > 95) {
			if (hasBothNaturalLegs(slave)) {
				return `${He} has normal legs with thick, soft ${thighMuscles}.`;
			} else {
				return `${He} has a normal leg with a thick, soft ${thighMuscles}.`;
			}
		} else if (slave.muscles > 5) {
			if (hasBothNaturalLegs(slave)) {
				return `${He} has relatively normal legs and thighs with ${muscleDesc()}.`;
			} else {
				return `${He} has a relatively normal leg and thigh with ${muscleDesc()}.`;
			}
		}
	}

	function muscleDesc(){
		if (slave.muscles > 95) {
			if (slave.weight > 95) {
				return `huge muscles hidden beneath ${his} soft flab`;
			} else {
				return `huge muscles`;
			}
		} else if (slave.muscles > 30) {
			if (slave.weight > 95) {
				return `obvious muscles hidden beneath ${his} soft flab`;
			} else {
				return `obvious muscles`;
			}
		} else if (slave.muscles > 5) {
			if (slave.weight > 30) {
				return `toned muscles hidden beneath ${his} soft flab`;
			} else {
				return `toned muscles`;
			}
		}
	}
};


code:
App.Medicine.Limbs = {};

/**
 * Generates an object usable with the standard limb check functions.
 * @param {App.Entity.SlaveState} slave
 * @returns {FC.LimbsState}
 */
App.Medicine.Limbs.currentLimbs = function(slave) {
	let s = {arm: {left: {type: 1}, right: {type: 1}}, leg: {left: {type: 1}, right: {type: 1}}, PLimb: 0};
	if (hasLeftArm(slave)) {
		s.arm.left.type = getLeftArmID(slave);
	} else {
		s.arm.left = null;
	}
	if (hasRightArm(slave)) {
		s.arm.right.type = getRightArmID(slave);
	} else {
		s.arm.right = null;
	}
	if (hasLeftLeg(slave)) {
		s.leg.left.type = getLeftLegID(slave);
	} else {
		s.leg.left = null;
	}
	if (hasRightLeg(slave)) {
		s.leg.right.type = getRightLegID(slave);
	} else {
		s.leg.right = null;
	}
	s.PLimb = slave.PLimb;
	return s;
};

/**
 * @param {App.Entity.SlaveState} slave
 * @param {FC.LimbsState} oldLimbs
 * @param {string} returnTo
 * @returns {HTMLElement|DocumentFragment}
 */
App.Medicine.Limbs.amputate = function(slave, oldLimbs, returnTo) {
	const {his} = getPronouns(slave);

	const r = [];

	let implant = false;
	if (slave.PLimb < 1 && isProstheticAvailable(slave, "interfaceP1")) {
		implant = true;
		r.push(App.UI.DOM.makeElement("div", App.UI.DOM.link("Install basic interface", () => install(1))));
	}
	if (slave.PLimb < 2 && isProstheticAvailable(slave, "interfaceP2")) {
		implant = true;
		r.push(App.UI.DOM.makeElement("div", App.UI.DOM.link("Install advanced interface", () => install(2))));
	}

	// check if we can install a limb interface and if yes, give player the option to do so.
	if (implant) {
		const outerDiv = document.createElement("div");
		outerDiv.id = "amputate";
		outerDiv.append(
			App.UI.DOM.makeElement("div", `Since you already have a prosthetic interface prepared for this slave, you can install it during the operation. The procedure will put additional strain on ${his} health but less so than if you were to perform the procedures separately.`),
			...r,
			App.UI.DOM.makeElement("div", App.UI.DOM.link("Do not install", noInstall)));
		return outerDiv;
	}

	/**
	 * @param {number} id
	 */
	function install(id) {
		slave.PLimb = id;
		surgeryDamage(slave, 10);
		App.UI.DOM.replace("#amputate", App.Medicine.Limbs.prosthetic(slave, oldLimbs, returnTo));
	}

	function noInstall() {
		App.UI.DOM.replace("#amputate", App.Medicine.Limbs.reaction(slave, oldLimbs, returnTo));
	}

	// check if there is a limb interface installed already, if there is show limb selection screen
	if (slave.PLimb > 0) {
		return App.Medicine.Limbs.prosthetic(slave, oldLimbs, returnTo);
	}
	return App.Medicine.Limbs.reaction(slave, oldLimbs, returnTo);
};

/**
 * @param {App.Entity.SlaveState} slave
 * @param {FC.LimbsState} oldLimbs
 * @param {string} returnTo
 * @returns {DocumentFragment|HTMLDivElement}
 */
App.Medicine.Limbs.prosthetic = function(slave, oldLimbs, returnTo) {
	if (!(isProstheticAvailable(slave, "basicL") || isProstheticAvailable(slave, "sexL")
		|| isProstheticAvailable(slave, "beautyL") || isProstheticAvailable(slave, "combatL")
		|| (isProstheticAvailable(slave, "cyberneticL") && slave.PLimb > 1))) {
		return App.Medicine.Limbs.reaction(slave, oldLimbs, returnTo);
	}
	const {him} = getPronouns(slave);

	const div = document.createElement("div");
	div.id = "selector";

	App.UI.DOM.appendNewElement("div", div, `Since you already have limbs prepared for ${him} you might as well attach them while you are working on ${him}:`);
	div.append(App.Medicine.Limbs.selector(slave, oldLimbs, returnTo));

	return div;
};

/**
 * Displays a selector for prosthetic limbs of getSlave(V.AS)
 * @param {App.Entity.SlaveState} slave
 * @param {FC.LimbsState} oldLimbs
 * @param {string} [returnTo=""]
 * @returns {HTMLSpanElement|DocumentFragment}
 */
App.Medicine.Limbs.selector = function(slave, oldLimbs, returnTo = "") {
	const {her} = getPronouns(slave);
	if (hasAllNaturalLimbs(slave)) {
		return App.UI.DOM.makeElement("span", `You must amputate ${her} limbs before you can attach prosthetics.`, "detail");
	}
	if (slave.PLimb < 1) {
		return App.UI.DOM.makeElement("span", `You must surgically install a prosthetic interface before you can attach prosthetics.`, "detail");
	}

	const {his} = getPronouns(slave);
	const newState = currentState(slave);

	const f = document.createDocumentFragment();

	const limbSelector = document.createElement("div");
	limbSelector.classList.add("limb-selector");

	App.UI.DOM.appendNewElement("div", limbSelector, "");
	App.UI.DOM.appendNewElement("div", limbSelector, "Left Arm");
	App.UI.DOM.appendNewElement("div", limbSelector, "Right Arm");
	App.UI.DOM.appendNewElement("div", limbSelector, "Left Leg");
	App.UI.DOM.appendNewElement("div", limbSelector, "Right Leg");

	limbSelector.append(row("None", 0));
	App.Data.prostheticLimbs.forEach((limb, key) => {
		if (isProstheticAvailable(slave, limb.prostheticKey)) {
			if (limb.minimumInterface <= slave.PLimb) {
				limbSelector.append(row(capFirstChar(limb.short), key));
			} else {
				App.UI.DOM.appendNewElement("div", limbSelector,
					`You need to upgrade ${his} prosthetic interface to attach ${limb.short} limbs.`, ["full", "detail"]);
			}
		}
	});

	f.append(limbSelector);
	f.append(apply());

	return f;

	function apply() {
		V.AS = slave.ID;

		return App.UI.DOM.link("Apply", () => {
			applySelector(slave, newState);
			if (returnTo) {
				App.UI.DOM.replace("#selector", App.Medicine.Limbs.reaction(slave, oldLimbs, returnTo));
			} else {
				V.prostheticsConfig = "limbs";
				V.oldLimbs = oldLimbs;
				Engine.play("Prosthetics Configuration");
			}
		});
	}

	/**
	 * Generates an array with the current limbs of a slave.
	 * @param {App.Entity.SlaveState} slave
	 * @returns {number[]}
	 */
	function currentState(slave) {
		return [getLeftArmID(slave), getRightArmID(slave), getLeftLegID(slave), getRightLegID(slave)];
	}

	/**
	 * @param {number} limb
	 * @param {number} id
	 * @returns {HTMLDivElement}
	 */
	function radio(limb, id) {
		const div = document.createElement("div");

		if (newState[limb] !== 1) {
			const radio = document.createElement("input");
			radio.type = "radio";
			radio.name = "limb" + limb;
			if (newState[limb] === id) {
				radio.checked = true;
			}
			radio.onclick = () => {
				newState[limb] = id;
			};
			div.append(radio);
		}

		return div;
	}

	/**
	 * @param {string} title
	 * @param {number} id
	 * @returns {DocumentFragment}
	 */
	function row(title, id) {
		const f = document.createDocumentFragment();

		App.UI.DOM.appendNewElement("div", f, title);

		for (let i = 0; i < newState.length; i++) {
			f.append(radio(i, id));
		}

		return f;
	}

	/**
	 *
	 * @param {App.Entity.SlaveState} slave
	 * @param {number[]} newState
	 */
	function applySelector(slave, newState) {
		if (getLeftArmID(slave) !== newState[0]) {
			if (getLeftArmID(slave) > 1) {
				removeLimbs(slave, "left arm");
			}
			if (newState[0] > 1) {
				attachLimbs(slave, "left arm", newState[0]);
			}
		}
		if (getRightArmID(slave) !== newState[1]) {
			if (getRightArmID(slave) > 1) {
				removeLimbs(slave, "right arm");
			}
			if (newState[1] > 1) {
				attachLimbs(slave, "right arm", newState[1]);
			}
		}
		if (getLeftLegID(slave) !== newState[2]) {
			if (getLeftLegID(slave) > 1) {
				removeLimbs(slave, "left leg");
			}
			if (newState[2] > 1) {
				attachLimbs(slave, "left leg", newState[2]);
			}
		}
		if (getRightLegID(slave) !== newState[3]) {
			if (getRightLegID(slave) > 1) {
				removeLimbs(slave, "right leg");
			}
			if (newState[3] > 1) {
				attachLimbs(slave, "right leg", newState[3]);
			}
		}
	}
};

/**
 * @param {App.Entity.SlaveState} slave
 * @param {FC.LimbsState} oldLimbs
 * @param {string} returnTo
 * @returns {DocumentFragment}
 */
App.Medicine.Limbs.reaction = function(slave, oldLimbs, returnTo = "") {
	let r = "";
	if (oldLimbs.PLimb !== slave.PLimb) {
		r += `Prosthetic interface was ${oldLimbs.PLimb === 0 ? "none" : "basic"} and is now ${slave.PLimb === 1 ? "basic" : "advanced"}. `;
	}
	if (getLeftArmID(oldLimbs) !== getLeftArmID(slave)) {
		r += `Left arm was ${idToDescription(getLeftArmID(oldLimbs))} and is now ${idToDescription(getLeftArmID(slave))}. `;
	}
	if (getRightArmID(oldLimbs) !== getRightArmID(slave)) {
		r += `Right arm was ${idToDescription(getRightArmID(oldLimbs))} and is now ${idToDescription(getRightArmID(slave))}. `;
	}
	if (getLeftLegID(oldLimbs) !== getLeftLegID(slave)) {
		r += `Left leg was ${idToDescription(getLeftLegID(oldLimbs))} and is now ${idToDescription(getLeftLegID(slave))}. `;
	}
	if (getRightLegID(oldLimbs) !== getRightLegID(slave)) {
		r += `Right leg was ${idToDescription(getRightLegID(oldLimbs))} and is now ${idToDescription(getRightLegID(slave))}. `;
	}

	const f = document.createDocumentFragment();

	App.UI.DOM.appendNewElement("p", f, r,);
	App.UI.DOM.appendNewElement("p", f, "Slave's reaction", "note");

	if (returnTo) {
		f.append(App.UI.DOM.passageLink("Continue", returnTo));
	}

	return f;
};