code:
package com.lilithsthrone.game.character.body;

import com.lilithsthrone.game.character.GameCharacter;
import com.lilithsthrone.game.character.body.types.BodyCoveringType;
import com.lilithsthrone.game.character.body.types.EyeType;
import com.lilithsthrone.game.character.body.valueEnums.CoveringPattern;
import com.lilithsthrone.game.character.body.valueEnums.EyeShape;
import com.lilithsthrone.game.dialogue.utils.UtilText;
import com.lilithsthrone.main.Main;
import com.lilithsthrone.utils.Util;

/**
 * @since 0.1.0
 * @version 0.3.1
 * @author Innoxia
 */
public class Eye implements BodyPartInterface {

	public static final int MAXIMUM_PAIRS = 4;

	protected EyeType type;
	protected int eyePairs;
	protected EyeShape irisShape, pupilShape;

	public Eye(EyeType type) {
		this.type = type;
		eyePairs = type.getEyePairs();
		irisShape = type.getIrisShape();
		pupilShape = type.getPupilShape();
	}

	@Override
	public EyeType getType() {
		return type;
	}

	@Override
	public String getDeterminer(GameCharacter gc) {
		if(gc.getEyePairs()==1) {
			return "a pair of";
		} else {
			return Util.intToString(gc.getEyePairs())+" pairs of";
		}
	}

	@Override
	public String getName(GameCharacter gc) {
		return type.getName(gc);
	}

	@Override
	public String getNameSingular(GameCharacter gc) {
		return type.getNameSingular(gc);
	}

	@Override
	public String getNamePlural(GameCharacter gc) {
		return type.getNamePlural(gc);
	}

	@Override
	public String getDescriptor(GameCharacter gc) {
		return type.getDescriptor(gc);
	}

	public String setType(GameCharacter owner, EyeType type) {
		if(!Main.game.isStarted() || owner==null) {
			this.type = type;
			irisShape = type.getIrisShape();
			pupilShape = type.getPupilShape();
			if(owner!=null) {
				owner.postTransformationCalculation();
			}
			return "";
		}

		if (type == getType()) {
			return UtilText.parse(owner, "
[style.colourDisabled([npc.Name] already [npc.has] the [npc.eyes] of [npc.a_eyeRace], so nothing happens...)]
");
		}

		UtilText.transformationContentSB.setLength(0);

		if (owner.isPlayer()) {
			UtilText.transformationContentSB.append(
					"
"
						+ "Your [pc.eyes] suddenly grow hot and itchy, and you instinctively scrunch them up tight as you reach up to rub at them.");
		} else {
			UtilText.transformationContentSB.append(
					"
"
						+ "[npc.NamePos] [npc.eyes] suddenly grow hot and itchy, and [npc.she] instinctively scrunches them up tight as [npc.she] reaches up to rub at them.");
		}

		// Parse existing content before transformation:
		String s = UtilText.parse(owner, UtilText.transformationContentSB.toString());
		UtilText.transformationContentSB.setLength(0);
		UtilText.transformationContentSB.append(s);

		this.type = type;
		irisShape = type.getIrisShape();
		pupilShape = type.getPupilShape();

		switch (type) {
			case HUMAN:
				UtilText.transformationContentSB.append(
							" By the time [npc.she] hesitantly [npc.verb(open)] them again, they've changed into human eyes, with normally-proportioned irises and pupils."
							+ "
"
							+ "[npc.Name] now [npc.has] [style.boldHuman(human eyes)]");
				break;
			case DEMON_COMMON:
				if (owner.isShortStature()) {
					UtilText.transformationContentSB.append(
							" By the time [npc.she] hesitantly [npc.verb(open)] them again, they've changed into impish eyes, with vertical pupils and large irises."
							+ "
"
							+ "[npc.Name] now [npc.has] [style.boldImp(impish eyes)]");
				} else {
					UtilText.transformationContentSB.append(
							" By the time [npc.she] hesitantly [npc.verb(open)] them again, they've changed into demonic eyes, with vertical pupils and large irises."
							+ "
"
							+ "[npc.Name] now [npc.has] [style.boldDemon(demonic eyes)]");
				}
				break;
			case COW_MORPH:
				UtilText.transformationContentSB.append(
							" By the time [npc.she] hesitantly [npc.verb(open)] them again, they've changed into cow-like eyes, with larger-than-average pupils and irises."
							+ "
"
							+ "[npc.Name] now [npc.has] [style.boldCowMorph(cow-like eyes)]");
				break;
			case DOG_MORPH:
				UtilText.transformationContentSB.append(
							" By the time [npc.she] hesitantly [npc.verb(open)] them again, they've changed into dog-like eyes, with larger-than-average pupils and irises."
							+ "
"
							+ "[npc.Name] now [npc.has] [style.boldDogMorph(dog-like eyes)]");
				break;
			case FOX_MORPH:
				UtilText.transformationContentSB.append(
							" By the time [npc.she] hesitantly [npc.verb(open)] them again, they've changed into fox-like eyes, with larger-than-average pupils and irises."
							+ "
"
							+ "[npc.Name] now [npc.has] [style.boldFoxMorph(fox-like eyes)]");
				break;
			case LYCAN:
				UtilText.transformationContentSB.append(
							" By the time [npc.she] hesitantly [npc.verb(open)] them again, they've changed into wolf-like eyes, with larger-than-average pupils and irises."
							+ "
"
							+ "[npc.Name] now [npc.has] [style.boldWolfMorph(wolf-like eyes)]");
				break;
			case CAT_MORPH:
				UtilText.transformationContentSB.append(
							" By the time [npc.she] hesitantly [npc.verb(open)] them again, they've changed into cat-like eyes, with smaller-than-average pupils and large irises."
							+ "
"
							+ "[npc.Name] now [npc.has] [style.boldCatMorph(cat-like eyes)]");
				break;
			case SQUIRREL_MORPH:
				UtilText.transformationContentSB.append(
							" By the time [npc.she] hesitantly [npc.verb(open)] them again, they've changed into squirrel-like eyes, with larger-than-average pupils and small irises."
							+ "
"
							+ "[npc.Name] now [npc.has] [style.boldSquirrelMorph(squirrel-like eyes)]");
				break;
			case RAT_MORPH:
				UtilText.transformationContentSB.append(
							" By the time [npc.she] hesitantly [npc.verb(open)] them again, they've changed into rat-like eyes, with larger-than-average pupils and small irises."
							+ "
"
							+ "[npc.Name] now [npc.has] [style.boldRatMorph(rat-like eyes)]");
				break;
			case RABBIT_MORPH:
				UtilText.transformationContentSB.append(
							" By the time [npc.she] hesitantly [npc.verb(open)] them again, they've changed into rabbit-like eyes, with larger-than-average pupils and small irises."
							+ "
"
							+ "[npc.Name] now [npc.has] [style.boldRabbitMorph(rabbit-like eyes)]");
				break;
			case BAT_MORPH:
				UtilText.transformationContentSB.append(
							" By the time [npc.she] hesitantly [npc.verb(open)] them again, they've changed into bat-like eyes, with larger-than-average pupils and small irises."
							+ "
"
							+ "[npc.Name] now [npc.has] [style.boldBatMorph(bat-like eyes)]");
				break;
			case ALLIGATOR_MORPH:
				UtilText.transformationContentSB.append(
							" By the time [npc.she] hesitantly [npc.verb(open)] them again, they've changed into alligator-like eyes, with larger-than-average pupils and small irises."
							+ "
"
							+ "[npc.Name] now [npc.has] [style.boldGatorMorph(alligator-like eyes)]");
				break;
			case HORSE_MORPH:
				UtilText.transformationContentSB.append(
							" By the time [npc.she] hesitantly [npc.verb(open)] them again, they've changed into horse-like eyes, with larger-than-average pupils and irises."
							+ "
"
							+ "[npc.Name] now [npc.has] [style.boldHorseMorph(horse-like eyes)]");
				break;
			case REINDEER_MORPH:
				UtilText.transformationContentSB.append(
							" By the time [npc.she] hesitantly [npc.verb(open)] them again, they've changed into reindeer-like eyes, with larger-than-average pupils and irises."
							+ "
"
							+ "[npc.Name] now [npc.has] [style.boldReindeerMorph(reindeer-like eyes)]");
				break;
			case HARPY:
				UtilText.transformationContentSB.append(
							" By the time [npc.she] hesitantly [npc.verb(open)] them again, they've changed into bird-like eyes, with larger-than-average pupils and small irises."
							+ "
"
							+ "[npc.Name] now [npc.has] [style.boldHarpy(harpy eyes)]");
				break;
			case ANGEL://TODO
				break;
		}

		UtilText.transformationContentSB.append(", with [style.boldGenericTF([npc.irisShape])], [npc.irisFullDescription(true)] and [style.boldGenericTF([npc.pupilShape])], [npc.pupilFullDescription(true)]."
			+ "
");

		return UtilText.parse(owner, UtilText.transformationContentSB.toString())
				+ "
"
					+ owner.postTransformationCalculation()
				+ "
";
	}

	public int getEyePairs() {
		return eyePairs;
	}

	public String setEyePairs(GameCharacter owner, int eyePairs) {
		eyePairs = Math.max(1, Math.min(eyePairs, MAXIMUM_PAIRS));

		if(owner.getEyePairs() == eyePairs) {
			return "
[style.colourDisabled(Nothing happens...)]
";
		}

		boolean removingExtraEyes = owner.getEyePairs() > eyePairs;
		this.eyePairs = eyePairs;

		if(removingExtraEyes) {
			if(owner.isPlayer()) {
				return "
"
							+ "A tingling feeling spreads over your [pc.face], before moving up and concentrating into your [pc.eyes]."
							+ " You scrunch them shut and let out a little cry as you feel some of them [style.boldShrink(disappearing)] back into the [pc.faceSkin] above your main pair.
"
							+ "After a few moments, you're left with [style.boldTfGeneric([pc.a_eyes])]."
						+ "
";
			} else {
				return UtilText.parse(owner,
						"
"
							+ "A tingling feeling spreads over [npc.namePos] [npc.face], before moving up and concentrating into [npc.her] [npc.eyes]."
							+ " [npc.She] scrunches them shut and lets out a little cry as [npc.she] feels some of them [style.boldShrink(disappearing)] into the [npc.faceSkin] above [npc.her] main pair.
"
							+ "After a few moments, [npc.sheIs] left with [style.boldTfGeneric([npc.a_eyes])]."
						+ "
");
			}

		} else {
			if(owner.isPlayer()) {
				return "
"
							+ "A tingling feeling spreads over your [pc.face], before moving up and concentrating into your [pc.eyes]."
							+ " You scrunch them shut and let out a little cry as you feel the strange sensation of new [pc.eyes] [style.boldGrow(growing)] out of the [pc.faceSkin] above your main pair.
"
							+ "After a few moments, you're left with [style.boldTfGeneric([pc.a_eyes])]."
						+ "
";
			} else {
				return UtilText.parse(owner,
						"
"
							+ "A tingling feeling spreads over [npc.namePos] [npc.face], before moving up and concentrating into [npc.her] [npc.eyes]."
							+ " [npc.She] scrunches them shut and lets out a little cry as [npc.she] feels the strange sensation of new [npc.eyes] [style.boldGrow(growing)] out of the [npc.faceSkin] above [npc.her] main pair.
"
							+ "After a few moments, [npc.sheIs] left with [style.boldTfGeneric([npc.a_eyes])]."
						+ "
");
			}
		}
	}

	public EyeShape getIrisShape() {
		return irisShape;
	}

	public String setIrisShape(GameCharacter owner, EyeShape irisShape) {
		if(owner.getIrisShape() == irisShape) {
			return "
[style.colourDisabled(Nothing happens...)]
";
		}

		this.irisShape = irisShape;

		return UtilText.parse(owner,
				"
"
					+ "An irritable itchy feeling rises up into [npc.namePos] [npc.eyes], but, much to [npc.her] relief, it passes even before [npc.sheIs] able to reach up and rub at them.
"
					+ "[npc.Name] now [npc.has] [style.boldTfGeneric([npc.irisShape] irises)]!"
				+ "
");
	}

	public EyeShape getPupilShape() {
		return pupilShape;
	}

	public String setPupilShape(GameCharacter owner, EyeShape pupilShape) {
		if(owner.getPupilShape() == pupilShape) {
			return "
[style.colourDisabled(Nothing happens...)]
";
		}

		this.pupilShape = pupilShape;

		return UtilText.parse(owner,
				"
"
					+ "An irritable itchy feeling rises up into [npc.namePos] [npc.eyes], but, much to [npc.her] relief, it passes even before [npc.sheIs] able to reach up and rub at them.
"
					+ "[npc.Name] now [npc.has] [style.boldTfGeneric([npc.pupilShape] pupils)]!"
				+ "
");
	}

	public String setEyeCovering(GameCharacter owner, Covering covering) {
		if(owner.getCovering(owner.getEyeCovering()).equals(covering)
				|| owner.getCovering(BodyCoveringType.EYE_PUPILS).equals(covering)
				|| owner.getCovering(BodyCoveringType.EYE_SCLERA).equals(covering)) {
			return "
[style.colourDisabled(Nothing happens...)]
";
		}

		UtilText.transformationContentSB.setLength(0);

		owner.getBody().getCoverings().put(covering.getType(), covering);

		if (owner.isPlayer()) {
			UtilText.transformationContentSB.append(
					"
"
						+ "Your vision goes blurry for a moment as your [pc.eyes] shift and change colour.
"
						+ "You now have ");
		} else {
			UtilText.transformationContentSB.append(
					"
"
						+ "[npc.Name] blinks a few times as [npc.her] [npc.eyes] shift and change colour.
"
						+ "[npc.She] now has ");
		}

		if(covering.getPattern() == CoveringPattern.EYE_IRISES_HETEROCHROMATIC) {
			UtilText.transformationContentSB.append("heterochromatic [npc.irisPrimaryColour(true)]-and-[npc.irisSecondaryColour(true)] [npc.irisShape] irises, ");
		} else {
			UtilText.transformationContentSB.append("[npc.irisPrimaryColour(true)] [npc.irisShape] irises ");
		}
		if(covering.getPattern() == CoveringPattern.EYE_PUPILS_HETEROCHROMATIC) {
			UtilText.transformationContentSB.append("with heterochromatic [npc.pupilPrimaryColour(true)]-and-[npc.pupilSecondaryColour(true)] [npc.pupilShape] pupils ");
		} else {
			UtilText.transformationContentSB.append("with [npc.pupilPrimaryColour(true)] [npc.pupilShape] pupils ");
		}
		if(covering.getPattern() == CoveringPattern.EYE_SCLERA_HETEROCHROMATIC) {
			UtilText.transformationContentSB.append("and heterochromatic [npc.scleraPrimaryColour(true)]-and-[npc.scleraSecondaryColour(true)] sclerae.
");
		} else {
			UtilText.transformationContentSB.append("and [npc.scleraPrimaryColour(true)] sclerae.
");
		}

		return UtilText.parse(owner, UtilText.transformationContentSB.toString());
	}

	@Override
	public boolean isBestial(GameCharacter owner) {
		if(owner==null) {
			return false;
		}
		return owner.getLegConfiguration().getBestialParts().contains(Eye.class) && getType().getRace().isBestialPartsAvailable();
	}
}


code:
package com.lilithsthrone.game.character.body;

import com.lilithsthrone.game.PropertyValue;
import com.lilithsthrone.game.character.GameCharacter;
import com.lilithsthrone.game.character.body.types.FaceType;
import com.lilithsthrone.game.character.body.valueEnums.BodyHair;
import com.lilithsthrone.game.character.body.valueEnums.Capacity;
import com.lilithsthrone.game.character.body.valueEnums.Femininity;
import com.lilithsthrone.game.character.body.valueEnums.OrificeElasticity;
import com.lilithsthrone.game.character.body.valueEnums.OrificePlasticity;
import com.lilithsthrone.game.character.body.valueEnums.Wetness;
import com.lilithsthrone.game.dialogue.utils.UtilText;
import com.lilithsthrone.game.inventory.InventorySlot;
import com.lilithsthrone.game.inventory.clothing.AbstractClothing;
import com.lilithsthrone.main.Main;

/**
 * @since 0.1.0
 * @version 0.3.1
 * @author Innoxia
 */
public class Face implements BodyPartInterface {

	protected FaceType type;
	protected boolean piercedNose;
	protected BodyHair facialHair;

	protected Mouth mouth;
	protected Tongue tongue;

	public Face(FaceType type, int lipSize) {
		this.type = type;
		piercedNose = false;
		facialHair = BodyHair.ZERO_NONE;

		mouth = new Mouth(type.getMouthType(), lipSize, Wetness.THREE_WET.getValue(), Capacity.THREE_SLIGHTLY_LOOSE.getMedianValue(), OrificeElasticity.FOUR_LIMBER.getValue(), OrificePlasticity.THREE_RESILIENT.getValue(), true);
		tongue = new Tongue(type.getTongueType());
	}

	public Mouth getMouth() {
		return mouth;
	}

	public Tongue getTongue() {
		return tongue;
	}

	@Override
	public FaceType getType() {
		return type;
	}

	@Override
	public String getDeterminer(GameCharacter gc) {
		return type.getDeterminer(gc);
	}

	@Override
	public String getName(GameCharacter gc) {
		return type.getName(gc);
	}

	@Override
	public String getNameSingular(GameCharacter gc) {
		return type.getNameSingular(gc);
	}

	@Override
	public String getNamePlural(GameCharacter gc) {
		return type.getNamePlural(gc);
	}

	public String getDescriptor(GameCharacter owner) {
		return type.getDescriptor(owner);
	}

	public String getNoseNameSingular(GameCharacter gc) {
		switch(type) {
			case HARPY:
				return "beak";
			default:
				return "nose";
		}
	}

	public String getNoseNamePlural(GameCharacter gc) {
		switch(type) {
			case HARPY:
				return "beaks";
			default:
				return "noses";
		}
	}

	public String getNoseDescriptor(GameCharacter gc) {
		return UtilText.returnStringAtRandom("");
	}

	public String setType(GameCharacter owner, FaceType type) {
		if(!Main.game.isStarted() || owner==null) {
			this.type = type;
			mouth.setType(type.getMouthType());
			tongue.setType(type.getTongueType());
			if(owner!=null) {
				owner.postTransformationCalculation();
			}
			return "";
		}

		if (type == getType()) {
			if (owner.isPlayer()) {
				return "
[style.colourDisabled(You already have the [pc.face] of [pc.a_faceRace], so nothing happens...)]
";
			} else {
				return UtilText.parse(owner, "
[style.colourDisabled([npc.Name] already has the [npc.face] of [npc.a_faceRace], so nothing happens...)]
");
			}

		} else {
			UtilText.transformationContentSB.setLength(0);

			if (owner.isPlayer()) {
				UtilText.transformationContentSB.append(
						"
"
							+ "An intense tingling sensation suddenly sweeps across your [pc.face], and you scrunch up your [pc.eyes] as you feel it start to transform."
							+ " With an audible crunch, your facial bones start to restructure themselves, and although the feeling isn't painful, it's enough of a shock to cause you to let out an involuntary cry.");
			} else {
				UtilText.transformationContentSB.append(
						"
"
							+ "An intense tingling sensation suddenly sweeps across [npc.namePos] [npc.face], and [npc.she] scrunches up [npc.her] [npc.eyes] as [npc.she] feels it start to transform."
							+ " With an audible crunch, [npc.her] facial bones start to restructure themselves, and although the feeling isn't painful, it's enough of a shock to cause [npc.herHim] to let out an involuntary cry.");
			}
		}

		// Parse existing content before transformation:
		String s = UtilText.parse(owner, UtilText.transformationContentSB.toString());
		UtilText.transformationContentSB.setLength(0);
		UtilText.transformationContentSB.append(s);
		this.type = type;

		mouth.setType(type.getMouthType());
		tongue.setType(type.getTongueType());

		switch (type) {
			case HUMAN:
				if (owner.isPlayer()) {
					UtilText.transformationContentSB.append(
								" Thankfully, the alarming feeling is over within a few moments, and you discover that you've been left with a normal human face, covered in [pc.faceSkin+].
"
								+ "You now have a [style.boldHuman(human face)], covered in [pc.faceFullDescription], and within your mouth, you have a [style.boldHuman(human tongue)]."
							+ "
");
				} else {
					UtilText.transformationContentSB.append(UtilText.parse(owner,
								" Thankfully for [npc.herHim], the transformation only lasts a matter of moments, leaving [npc.herHim] with a normal human face, covered in [npc.faceSkin+].
"
								+ "[npc.Name] now has a [style.boldHuman(human face)], covered in [npc.faceFullDescription], and within [npc.her] [npc.mouth], [npc.she] has a [style.boldHuman(human tongue)]."
							+ "
"));
				}
				break;
			case ANGEL:
				if (owner.isPlayer()) {
					UtilText.transformationContentSB.append(
								" Thankfully, the alarming feeling is over within a few moments, and you discover that you've been left with an angelic, human-looking face, covered in [pc.faceSkin+].
"
								+ "You now have an [style.boldAngel(angelic face)], covered in [pc.faceFullDescription], and within your [npc.mouth], you have an [style.boldAngel(angelic tongue)]."
							+ "
");
				} else {
					UtilText.transformationContentSB.append(UtilText.parse(owner,
								" Thankfully for [npc.herHim], the transformation only lasts a matter of moments, leaving [npc.herHim] with an angelic, human-looking face, covered in [npc.faceSkin+].
"
								+ "[npc.Name] now has an [style.boldAngel(angelic face)], covered in [npc.faceFullDescription], and within [npc.her] [npc.mouth], [npc.she] has an [style.boldAngel(angelic tongue)]."
							+ "
"));
				}
				break;
			case DEMON_COMMON:
				if (!owner.isShortStature()) {
					UtilText.transformationContentSB.append(UtilText.parse(owner,
							" Thankfully, the alarming transformation only lasts a matter of moments, leaving [npc.herHim] with a demonic, human-looking face, covered in [npc.faceSkin+].
"
							+ "[npc.Name] now [npc.has] a [style.boldDemon(demonic face)], covered in [npc.faceFullDescription], and within [npc.her] [npc.mouth], [npc.she] [npc.has] a [style.boldDemon(demonic tongue)]."
						+ "
"));
				} else {
					UtilText.transformationContentSB.append(UtilText.parse(owner,
							" Thankfully, the alarming transformation only lasts a matter of moments, leaving [npc.herHim] with an impish, human-looking face, covered in [npc.faceSkin+].
"
							+ "[npc.Name] now [npc.has] an [style.boldImp(impish face)], covered in [npc.faceFullDescription], and within [npc.her] [npc.mouth], [npc.she] [npc.has] an [style.boldImp(impish tongue)]."
						+ "
"));
				}
				break;
			case DOG_MORPH:
				if (owner.isPlayer()) {
					UtilText.transformationContentSB.append(
								" You feel your nose and mouth twitching and transforming as they push out into an anthropomorphic canine muzzle, and your tongue flattens and grows wider, turning into a dog-like tongue."
								+ " A layer of [pc.faceSkin+] quickly grows to cover your new face, and as the transformation finally comes to an end, you're left panting as you try to recover and catch your breath.
"
								+ "You now have an anthropomorphic [style.boldDogMorph(dog-like face)], covered in [pc.faceFullDescription], and within your [npc.mouth], you have a [style.boldDogMorph(flat, dog-like tongue)]."
							+ "
");
				} else {
					UtilText.transformationContentSB.append(UtilText.parse(owner,
								" [npc.Her] nose and mouth twitch and transform as they push out into an anthropomorphic canine muzzle, and [npc.her] tongue flattens and grows wider, turning into a dog-like tongue."
								+ " A layer of [npc.faceSkin+] quickly grows to cover [npc.her] new face, and as the transformation finally comes to an end, [npc.sheIs] left panting as [npc.she] tries to recover and catch [npc.her] breath.
"
								+ "[npc.Name] now has an anthropomorphic [style.boldDogMorph(dog-like face)], covered in [npc.faceFullDescription], and within [npc.her] [npc.mouth], [npc.she] has a [style.boldDogMorph(flat, dog-like tongue)]."
							+ "
"));
				}
				break;
			case FOX_MORPH:
				if (owner.isPlayer()) {
					UtilText.transformationContentSB.append(
								" You feel your nose and mouth twitching and transforming as they push out into an anthropomorphic vulpine muzzle, and your tongue flattens and shifts into a pink fox-like tongue."
								+ " A layer of [pc.faceSkin+] quickly grows to cover your new face, and as the transformation finally comes to an end, you're left panting as you try to recover and catch your breath.
"
								+ "You now have an anthropomorphic [style.boldFoxMorph(fox-like face)], covered in [pc.faceFullDescription], and within your [npc.mouth], you have a [style.boldFoxMorph(flat, fox-like tongue)]."
							+ "
");
				} else {
					UtilText.transformationContentSB.append(UtilText.parse(owner,
								" [npc.Her] nose and mouth twitch and transform as they push out into an anthropomorphic vulpine muzzle, and [npc.her] tongue flattens and shifts into a pink fox-like tongue."
								+ " A layer of [npc.faceSkin+] quickly grows to cover [npc.her] new face, and as the transformation finally comes to an end, [npc.sheIs] left panting as [npc.she] tries to recover and catch [npc.her] breath.
"
								+ "[npc.Name] now has an anthropomorphic [style.boldFoxMorph(fox-like face)], covered in [npc.faceFullDescription], and within [npc.her] [npc.mouth], [npc.she] has a [style.boldFoxMorph(flat, fox-like tongue)]."
							+ "
"));
				}
				break;
			case LYCAN:
				if (owner.isPlayer()) {
					UtilText.transformationContentSB.append(
								" You feel your nose and mouth twitching and transforming as they push out into an anthropomorphic lupine muzzle, and your tongue flattens and grows wider, turning into a wolf-like tongue."
								+ " A layer of [pc.faceSkin+] quickly grows to cover your new face, and as the transformation finally comes to an end, you're left panting as you try to recover and catch your breath.
"
								+ "You now have an anthropomorphic [style.boldWolfMorph(wolf-like face)], covered in [pc.faceFullDescription], and within your [npc.mouth], you have a [style.boldWolfMorph(flat, wolf-like tongue)]."
							+ "
");
				} else {
					UtilText.transformationContentSB.append(UtilText.parse(owner,
								" [npc.Her] nose and mouth twitch and transform as they push out into an anthropomorphic lupine muzzle, and [npc.her] tongue flattens and grows wider, turning into a wolf-like tongue."
								+ " A layer of [npc.faceSkin+] quickly grows to cover [npc.her] new face, and as the transformation finally comes to an end, [npc.sheIs] left panting as [npc.she] tries to recover and catch [npc.her] breath.
"
								+ "[npc.Name] now has an anthropomorphic [style.boldWolfMorph(wolf-like face)], covered in [npc.faceFullDescription], and within [npc.her] [npc.mouth], [npc.she] has a [style.boldWolfMorph(flat, wolf-like tongue)]."
							+ "
"));
				}
				break;
			case CAT_MORPH: case CAT_MORPH_PANTHER:
				if (owner.isPlayer()) {
					UtilText.transformationContentSB.append(
								" You feel your nose and mouth twitching and transforming as they push out into an anthropomorphic feline muzzle, and your tongue flattens and shifts into a little pink cat-like tongue."
								+ " A layer of [pc.faceSkin+] quickly grows to cover your new face, and as the transformation finally comes to an end, you're left panting as you try to recover and catch your breath.
"
								+ "You now have an anthropomorphic [style.boldCatMorph(cat-like face)], covered in [pc.faceFullDescription], and within your [npc.mouth], you have a [style.boldCatMorph(flat, cat-like tongue)]."
							+ "
");
				} else {
					UtilText.transformationContentSB.append(UtilText.parse(owner,
								" [npc.Her] nose and mouth twitch and transform as they push out into an anthropomorphic feline muzzle, and [npc.her] tongue flattens and shifts into a little pink cat-like tongue."
								+ " A layer of [npc.faceSkin+] quickly grows to cover [npc.her] new face, and as the transformation finally comes to an end, [npc.sheIs] left panting as [npc.she] tries to recover and catch [npc.her] breath.
"
								+ "[npc.Name] now has an anthropomorphic [style.boldCatMorph(cat-like face)], covered in [npc.faceFullDescription], and within [npc.her] [npc.mouth], [npc.she] has a [style.boldCatMorph(flat, cat-like tongue)]."
							+ "
"));
				}
				break;
			case COW_MORPH:
				if (owner.isPlayer()) {
					UtilText.transformationContentSB.append(
								" You feel your nose and mouth twitching and transforming as they push out into an anthropomorphic bovine muzzle, and your tongue flattens and shifts into a cow-like tongue."
								+ " A layer of [pc.faceSkin+] quickly grows to cover your new face, and as the transformation finally comes to an end, you're left panting as you try to recover and catch your breath.
"
								+ "You now have an anthropomorphic [style.boldCowMorph(cow-like face)], covered in [pc.faceFullDescription], and within your [npc.mouth], you have a [style.boldCowMorph(flat, cow-like tongue)]."
							+ "
");
				} else {
					UtilText.transformationContentSB.append(UtilText.parse(owner,
								" [npc.Her] nose and mouth twitch and transform as they push out into an anthropomorphic bovine muzzle, and [npc.her] tongue flattens and shifts into a cow-like tongue."
								+ " A layer of [npc.faceSkin+] quickly grows to cover [npc.her] new face, and as the transformation finally comes to an end, [npc.sheIs] left panting as [npc.she] tries to recover and catch [npc.her] breath.
"
								+ "[npc.Name] now has an anthropomorphic [style.boldCowMorph(cow-like face)], covered in [npc.faceFullDescription], and within [npc.her] [npc.mouth], [npc.she] has a [style.boldCowMorph(flat, cow-like tongue)]."
							+ "
"));
				}
				break;
			case ALLIGATOR_MORPH:
				if (owner.isPlayer()) {
					UtilText.transformationContentSB.append(
								" You feel your nose and mouth twitching and transforming as they push out into an anthropomorphic reptile muzzle, and your tongue flattens out, turning into an alligator-like tongue."
								+ " A layer of [pc.faceSkin+] quickly grows to cover your new face, and as the transformation finally comes to an end, you're left panting as you try to recover and catch your breath.
"
								+ "You now have an anthropomorphic [style.boldGatorMorph(alligator-like face)], covered in [pc.faceFullDescription], and within your [npc.mouth], you have a [style.boldGatorMorph(flat, alligator-like tongue)]."
							+ "
");
				} else {
					UtilText.transformationContentSB.append(UtilText.parse(owner,
								" [npc.Her] nose and mouth twitch and transform as they push out into an anthropomorphic reptile muzzle, and [npc.her] tongue flattens out, turning into an alligator-like tongue."
								+ " A layer of [npc.faceSkin+] quickly grows to cover [npc.her] new face, and as the transformation finally comes to an end, [npc.sheIs] left panting as [npc.she] tries to recover and catch [npc.her] breath.
"
								+ "[npc.Name] now has an anthropomorphic [style.boldGatorMorph(alligator-like face)], covered in [npc.faceFullDescription], and within [npc.her] [npc.mouth], [npc.she] has a [style.boldGatorMorph(flat, alligator-like tongue)]."
							+ "
"));
				}
				break;
			case HORSE_MORPH:
				if (owner.isPlayer()) {
					UtilText.transformationContentSB.append(
								" You feel your nose and mouth twitching and transforming as they push out into an anthropomorphic equine muzzle, and your tongue grows thicker and stronger, turning into a horse-like tongue."
								+ " A layer of [pc.faceSkin+] quickly grows to cover your new face, and as the transformation finally comes to an end, you're left panting as you try to recover and catch your breath.
"
								+ "You now have an anthropomorphic [style.boldHorseMorph(horse-like face)], covered in [pc.faceFullDescription], and within your [npc.mouth], you have a [style.boldHorseMorph(strong, horse-like tongue)]."
							+ "
");
				} else {
					UtilText.transformationContentSB.append(UtilText.parse(owner,
								" [npc.Her] nose and mouth twitch and transform as they push out into an anthropomorphic equine muzzle, and [npc.her] tongue grows thicker and stronger, turning into a horse-like tongue."
								+ " A layer of [npc.faceSkin+] quickly grows to cover [npc.her] new face, and as the transformation finally comes to an end, [npc.sheIs] left panting as [npc.she] tries to recover and catch [npc.her] breath.
"
								+ "[npc.Name] now has an anthropomorphic [style.boldHorseMorph(horse-like face)], covered in [npc.faceFullDescription], and within [npc.her] [npc.mouth], [npc.she] has a [style.boldHorseMorph(strong, horse-like tongue)]."
							+ "
"));
				}
				break;
			case REINDEER_MORPH:
				if (owner.isPlayer()) {
					UtilText.transformationContentSB.append(
								" You feel your nose and mouth twitching and transforming as they push out into an anthropomorphic reindeer-like muzzle, and your tongue grows thicker and stronger, turning into a rangiferine tongue."
								+ " A layer of [pc.faceSkin+] quickly grows to cover your new face, and as the transformation finally comes to an end, you're left panting as you try to recover and catch your breath.
"
								+ "You now have an anthropomorphic [style.boldReindeerMorph(reindeer-like face)], covered in [pc.faceFullDescription], and within your [npc.mouth], you have a [style.boldReindeerMorph(strong, reindeer-like tongue)]."
							+ "
");
				} else {
					UtilText.transformationContentSB.append(UtilText.parse(owner,
								" [npc.Her] nose and mouth twitch and transform as they push out into an anthropomorphic reindeer-like muzzle, and [npc.her] tongue grows thicker and stronger, turning into a rangiferine tongue."
								+ " A layer of [npc.faceSkin+] quickly grows to cover [npc.her] new face, and as the transformation finally comes to an end, [npc.sheIs] left panting as [npc.she] tries to recover and catch [npc.her] breath.
"
								+ "[npc.Name] now has an anthropomorphic [style.boldReindeerMorph(reindeer-like face)], covered in [npc.faceFullDescription],"
									+ " and within [npc.her] [npc.mouth], [npc.she] has a [style.boldReindeerMorph(strong, reindeer-like tongue)]."
							+ "
"));
				}
				break;
			case SQUIRREL_MORPH:
				if (owner.isPlayer()) {
					UtilText.transformationContentSB.append(
								" You feel your nose and mouth twitching and transforming as they push out into an anthropomorphic squirrel-like muzzle, and your tongue flattens and shifts into a little pink squirrel-like tongue."
								+ " A layer of [pc.faceSkin+] quickly grows to cover your new face, and as the transformation finally comes to an end, you're left panting as you try to recover and catch your breath.
"
								+ "You now have an anthropomorphic [style.boldSquirrelMorph(squirrel-like face)], covered in [pc.faceFullDescription], and within your [npc.mouth], you have a [style.boldSquirrelMorph(little squirrel-like tongue)]."
							+ "
");
				} else {
					UtilText.transformationContentSB.append(UtilText.parse(owner,
								" [npc.Her] nose and mouth twitch and transform as they push out into an anthropomorphic squirrel-like muzzle, and [npc.her] tongue flattens and shifts into a little pink squirrel-like tongue."
								+ " A layer of [npc.faceSkin+] quickly grows to cover [npc.her] new face, and as the transformation finally comes to an end, [npc.sheIs] left panting as [npc.she] tries to recover and catch [npc.her] breath.
"
								+ "[npc.Name] now has an anthropomorphic [style.boldSquirrelMorph(squirrel-like face)], covered in [npc.faceFullDescription], and within [npc.her] [npc.mouth], [npc.she] has a [style.boldSquirrelMorph(little squirrel-like tongue)]."
							+ "
"));
				}
				break;
			case RAT_MORPH:
				if (owner.isPlayer()) {
					UtilText.transformationContentSB.append(
								" You feel your nose and mouth twitching and transforming as they push out into an anthropomorphic rat-like muzzle, and your tongue flattens and shifts into a little pink rat-like tongue."
								+ " A layer of [pc.faceSkin+] quickly grows to cover your new face, and as the transformation finally comes to an end, you're left panting as you try to recover and catch your breath.
"
								+ "You now have an anthropomorphic [style.boldRatMorph(rat-like face)], covered in [pc.faceFullDescription], and within your [npc.mouth], you have a [style.boldRatMorph(little rat-like tongue)]."
							+ "
");
				} else {
					UtilText.transformationContentSB.append(UtilText.parse(owner,
								" [npc.Her] nose and mouth twitch and transform as they push out into an anthropomorphic rat-like muzzle, and [npc.her] tongue flattens and shifts into a little pink rat-like tongue."
								+ " A layer of [npc.faceSkin+] quickly grows to cover [npc.her] new face, and as the transformation finally comes to an end, [npc.sheIs] left panting as [npc.she] tries to recover and catch [npc.her] breath.
"
								+ "[npc.Name] now has an anthropomorphic [style.boldRatMorph(rat-like face)], covered in [npc.faceFullDescription], and within [npc.her] [npc.mouth], [npc.she] has a [style.boldRatMorph(little rat-like tongue)]."
							+ "
"));
				}
				break;
			case RABBIT_MORPH:
				if (owner.isPlayer()) {
					UtilText.transformationContentSB.append(
								" You feel your nose and mouth twitching and transforming as they push out into an anthropomorphic rabbit-like muzzle, and your tongue flattens and shifts into a little pink rabbit-like tongue."
								+ " A layer of [pc.faceSkin+] quickly grows to cover your new face, and as the transformation finally comes to an end, you're left panting as you try to recover and catch your breath.
"
								+ "You now have an anthropomorphic [style.boldRabbitMorph(rabbit-like face)], covered in [pc.faceFullDescription], and within your [npc.mouth], you have a [style.boldRabbitMorph(little rabbit-like tongue)]."
							+ "
");
				} else {
					UtilText.transformationContentSB.append(UtilText.parse(owner,
								" [npc.Her] nose and mouth twitch and transform as they push out into an anthropomorphic rabbit-like muzzle, and [npc.her] tongue flattens and shifts into a little pink rabbit-like tongue."
								+ " A layer of [npc.faceSkin+] quickly grows to cover [npc.her] new face, and as the transformation finally comes to an end, [npc.sheIs] left panting as [npc.she] tries to recover and catch [npc.her] breath.
"
								+ "[npc.Name] now has an anthropomorphic [style.boldRabbitMorph(rabbit-like face)], covered in [npc.faceFullDescription], and within [npc.her] [npc.mouth], [npc.she] has a [style.boldRabbitMorph(little rabbit-like tongue)]."
							+ "
"));
				}
				break;
			case BAT_MORPH:
				if (owner.isPlayer()) {
					UtilText.transformationContentSB.append(
								" You feel your nose and mouth twitching and transforming as they push out into an anthropomorphic bat-like muzzle, and your tongue flattens and shifts into a little pink bat-like tongue."
								+ " A layer of [pc.faceSkin+] quickly grows to cover your new face, and as the transformation finally comes to an end, you're left panting as you try to recover and catch your breath.
"
								+ "You now have an anthropomorphic [style.boldBatMorph(bat-like face)], covered in [pc.faceFullDescription], and within your [npc.mouth], you have a [style.boldBatMorph(little bat-like tongue)]."
							+ "
");
				} else {
					UtilText.transformationContentSB.append(UtilText.parse(owner,
								" [npc.Her] nose and mouth twitch and transform as they push out into an anthropomorphic bat-like muzzle, and [npc.her] tongue flattens and shifts into a little pink bat-like tongue."
								+ " A layer of [npc.faceSkin+] quickly grows to cover [npc.her] new face, and as the transformation finally comes to an end, [npc.sheIs] left panting as [npc.she] tries to recover and catch [npc.her] breath.
"
								+ "[npc.Name] now has an anthropomorphic [style.boldBatMorph(bat-like face)], covered in [npc.faceFullDescription], and within [npc.her] [npc.mouth], [npc.she] has a [style.boldBatMorph(little bat-like tongue)]."
							+ "
"));
				}
				break;
			case HARPY:
				if (owner.isPlayer()) {
					UtilText.transformationContentSB.append(
								" You feel your nose and mouth twitching and transforming as they fuse together and push out into a short beak, and your tongue grows longer and thinner, turning into a bird-like tongue."
								+ " A layer of [pc.faceSkin+] quickly grows to cover your new face, and as the transformation finally comes to an end, you're left panting as you try to recover and catch your breath."
								+ " You find, much to your relief, that you're able to harden or soften the edges of your beak, allowing you to portray facial emotions as well as wrap your beak's edges around anything you might want to put in your mouth
"
								+ "You now have an anthropomorphic [style.boldHarpy(bird-like face)], covered in [pc.faceFullDescription], and within your [npc.mouth], you have a [style.boldHarpy(thin, bird-like tongue)]."
							+ "
");
				} else {
					UtilText.transformationContentSB.append(UtilText.parse(owner,
								" [npc.Her] nose and mouth twitch and transform as they fuse together and push out into a short beak, and [npc.her] tongue grows longer and thinner, turning into a bird-like tongue."
								+ " A layer of [npc.faceSkin+] quickly grows to cover [npc.her] new face, and as the transformation finally comes to an end, [npc.sheIs] left panting as [npc.she] tries to recover and catch [npc.her] breath."
								+ " [npc.She] finds, much to [npc.her] relief, that [npc.sheIs] able to harden or soften the edges of [npc.her] beak,"
									+ " allowing [npc.herHim] to portray facial emotions as well as wrap [npc.her] beak's edges around anything [npc.she] might want to put in [npc.her] mouth
"
								+ "[npc.Name] now has an anthropomorphic [style.boldHarpy(bird-like face)], covered in [npc.faceFullDescription], and within [npc.her] [npc.mouth], [npc.she] has a [style.boldHarpy(thin, bird-like tongue)]."
							+ "
"));
				}
				break;
//			default:
//				if (owner.isPlayer()) {
//					UtilText.transformationContentSB.append(
//								" Within a matter of moments, a layer of [pc.faceFullDescription] has quickly grown over your new face.
"
//								+ "As the transformation comes to an end, you're left with [style.boldTfLesser([pc.face+])], which is covered in [pc.faceFullDescription]."
//							+ "
");
//				} else {
//					UtilText.transformationContentSB.append(UtilText.parse(owner,
//								" Within a matter of moments, a layer of [npc.faceFullDescription] has quickly grown over [npc.her] new face.
"
//								+ "As the transformation comes to an end, [npc.name] is left with [style.boldTfLesser([npc.face+])], which is covered in [npc.faceFullDescription]."
//							+ "
"));
//				}
		}
		return UtilText.parse(owner, UtilText.transformationContentSB.toString())
				+ "

"
				+ owner.postTransformationCalculation()
				+ "
";
	}

	public boolean isPiercedNose() {
		return piercedNose;
	}

	public String setPiercedNose(GameCharacter owner, boolean piercedNose) {
		if(owner.isPiercedNose() == piercedNose) {
			return "
[style.colourDisabled(Nothing happens...)]
";
		}

		this.piercedNose = piercedNose;

		if(piercedNose) {
			if(owner.isPlayer()) {
				return "
Your [pc.nose] is now [style.boldGrow(pierced)]!
";
			} else {
				return UtilText.parse(owner,
						"
[npc.NamePos] [npc.nose] is now [style.boldGrow(pierced)]!
");
			}

		} else {
			AbstractClothing c = owner.getClothingInSlot(InventorySlot.PIERCING_NOSE);
			String piercingUnequip = "";
			if(c!=null) {
				owner.forceUnequipClothingIntoVoid(owner, c);
				piercingUnequip = owner.addClothing(c, false);
			}

			if(owner.isPlayer()) {
				return "
"
							+ "Your [pc.nose] is [style.boldShrink(no longer pierced)]!"
						+ "
"
						+piercingUnequip;
			} else {
				return UtilText.parse(owner,
						"
"
								+ "[npc.NamePos] [npc.nose] is [style.boldShrink(no longer pierced)]!"
						+ "
"
						+piercingUnequip);
			}
		}
	}

	public BodyHair getFacialHair() {
		return facialHair;
	}

	public Covering getFacialHairType(GameCharacter owner) {
		return owner.getCovering(owner.getBodyHairCoveringType(owner.getFaceType().getRace()));
	}

	public String setFacialHair(GameCharacter owner, BodyHair facialHair) {
		if(owner==null) {
			this.facialHair = facialHair;
			return "";
		}

		if(owner.getFemininityValue()>=Femininity.ANDROGYNOUS.getMinimumFemininity() && facialHair!=BodyHair.ZERO_NONE && !Main.getProperties().hasValue(PropertyValue.feminineBeardsContent)) {
			if(owner.isPlayer()) {
				return "
[style.colourDisabled(You're too feminine to be able to grow a beard...)]
";
			} else {
				return UtilText.parse(owner, "
[style.colourDisabled([npc.sheIs] too feminine to be able to grow a beard...)]
");
			}
		}

		if(getFacialHair() == facialHair) {
			return "
[style.colourDisabled(Nothing happens...)]
";

		} else {
			UtilText.transformationContentSB.setLength(0);

			switch(facialHair) {
				case ZERO_NONE:
					if(owner.isPlayer()) {
						UtilText.transformationContentSB.append("
There is no longer any trace of "+getFacialHairType(owner).getFullDescription(owner, true)+" on your face.
");
					} else {
						UtilText.transformationContentSB.append(UtilText.parse(owner, "
There is no longer any trace of "+getFacialHairType(owner).getFullDescription(owner, true)+" on [npc.her] face.
"));
					}
					break;
				case ONE_STUBBLE:
					if(owner.isPlayer()) {
						UtilText.transformationContentSB.append("
You now have a stubbly layer of "+getFacialHairType(owner).getFullDescription(owner, true)+" on your face.
");
					} else {
						UtilText.transformationContentSB.append(UtilText.parse(owner, "
[npc.Name] now has a stubbly layer of "+getFacialHairType(owner).getFullDescription(owner, true)+" on [npc.her] face.
"));
					}
					break;
				case TWO_MANICURED:
					if(owner.isPlayer()) {
						UtilText.transformationContentSB.append("
You now have a small amount of "+getFacialHairType(owner).getFullDescription(owner, true)+" on your face.
");
					} else {
						UtilText.transformationContentSB.append(UtilText.parse(owner, "
[npc.Name] now has a small amount of "+getFacialHairType(owner).getFullDescription(owner, true)+" on [npc.her] face.
"));
					}
					break;
				case THREE_TRIMMED:
					if(owner.isPlayer()) {
						UtilText.transformationContentSB.append("
You now have a well-trimmed beard of "+getFacialHairType(owner).getFullDescription(owner, true)+" on your face.
");
					} else {
						UtilText.transformationContentSB.append(UtilText.parse(owner, "
[npc.Name] now has a well-trimmed beard of "+getFacialHairType(owner).getFullDescription(owner, true)+" on [npc.her] face.
"));
					}
					break;
				case FOUR_NATURAL:
					if(owner.isPlayer()) {
						UtilText.transformationContentSB.append("
You now have a beard, made of "+getFacialHairType(owner).getFullDescription(owner, true)+".
");
					} else {
						UtilText.transformationContentSB.append(UtilText.parse(owner, "
[npc.Name] now has a beard, made of "+getFacialHairType(owner).getFullDescription(owner, true)+".
"));
					}
					break;
				case FIVE_UNKEMPT:
					if(owner.isPlayer()) {
						UtilText.transformationContentSB.append("
You now have an unkempt, bushy beard, made of "+getFacialHairType(owner).getFullDescription(owner, true)+".
");
					} else {
						UtilText.transformationContentSB.append(UtilText.parse(owner, "
[npc.Name] now has an unkempt, bushy beard, made of "+getFacialHairType(owner).getFullDescription(owner, true)+".
"));
					}
					break;
				case SIX_BUSHY:
					if(owner.isPlayer()) {
						UtilText.transformationContentSB.append("
You now have a large, bushy beard, made of "+getFacialHairType(owner).getFullDescription(owner, true)+".
");
					} else {
						UtilText.transformationContentSB.append(UtilText.parse(owner, "
[npc.Name] now has a large, bushy beard, made of "+getFacialHairType(owner).getFullDescription(owner, true)+".
"));
					}
					break;
				case SEVEN_WILD:
					if(owner.isPlayer()) {
						UtilText.transformationContentSB.append("
You now have a wild, thick beard, made of "+getFacialHairType(owner).getFullDescription(owner, true)+".
");
					} else {
						UtilText.transformationContentSB.append(UtilText.parse(owner, "
[npc.Name] now has a wild, thick beard, made of "+getFacialHairType(owner).getFullDescription(owner, true)+".
"));
					}
					break;
			}
		}

		this.facialHair = facialHair;

		return UtilText.transformationContentSB.toString();
	}

	@Override
	public boolean isBestial(GameCharacter owner) {
		if(owner==null) {
			return false;
		}
		return owner.getLegConfiguration().getBestialParts().contains(Face.class) && getType().getRace().isBestialPartsAvailable();
	}
}

repo_name: klorpa/Pedo

license: unknown


code:
package com.lilithsthrone.game.character.body;

import java.util.ArrayList;
import java.util.List;

import org.w3c.dom.Document;
import org.w3c.dom.Element;

import com.lilithsthrone.game.character.CharacterUtils;
import com.lilithsthrone.game.character.GameCharacter;
import com.lilithsthrone.game.character.attributes.Attribute;
import com.lilithsthrone.game.character.body.types.FluidType;
import com.lilithsthrone.game.character.body.valueEnums.FluidFlavour;
import com.lilithsthrone.game.character.body.valueEnums.FluidModifier;
import com.lilithsthrone.game.dialogue.utils.UtilText;
import com.lilithsthrone.game.inventory.enchanting.ItemEffect;
import com.lilithsthrone.utils.Util;
import com.lilithsthrone.utils.XMLSaving;

/**
 * @since 0.1.83
 * @version 0.3.1
 * @author Innoxia
 */
public class FluidCum implements FluidInterface, XMLSaving {

	protected FluidType type;
	protected FluidFlavour flavour;
	protected List<FluidModifier> fluidModifiers;
	protected List<ItemEffect> transformativeEffects;

	public FluidCum(FluidType type) {
		this.type = type;
		this.flavour = type.getFlavour();
		transformativeEffects = new ArrayList<>();

		fluidModifiers = new ArrayList<>();
		fluidModifiers.addAll(type.getFluidModifiers());
	}

	public Element saveAsXML(Element parentElement, Document doc) {
		Element element = doc.createElement("cum");
		parentElement.appendChild(element);

		CharacterUtils.addAttribute(doc, element, "type", this.type.toString());
		CharacterUtils.addAttribute(doc, element, "flavour", this.flavour.toString());

		Element cumModifiers = doc.createElement("cumModifiers");
		element.appendChild(cumModifiers);
		for(FluidModifier fm : this.getFluidModifiers()) {
			CharacterUtils.addAttribute(doc, cumModifiers, fm.toString(), "true");
		}

		return element;
	}

	public static FluidCum loadFromXML(Element parentElement, Document doc) {
		return loadFromXML(parentElement, doc, null);
	}

	/**
	 *
	 * @param parentElement
	 * @param doc
	 * @param baseType If you pass in a baseType, this method will ignore the saved type in parentElement.
	 */
	public static FluidCum loadFromXML(Element parentElement, Document doc, FluidType baseType) {

		Element cum = (Element)parentElement.getElementsByTagName("cum").item(0);

		FluidType fluidType = FluidType.CUM_HUMAN;

		if(baseType!=null) {
			fluidType = baseType;

		} else {
			try {
				fluidType = FluidType.getTypeFromString(cum.getAttribute("type"));
			} catch(Exception ex) {
			}
		}

		FluidCum fluidCum = new FluidCum(fluidType);

		String flavourId = cum.getAttribute("flavour");
		if(flavourId.equalsIgnoreCase("SLIME")) {
			fluidCum.flavour = FluidFlavour.BUBBLEGUM;
		} else {
			fluidCum.flavour = FluidFlavour.valueOf(flavourId);
		}

		Element cumModifiers = (Element)cum.getElementsByTagName("cumModifiers").item(0);
		fluidCum.fluidModifiers.clear();
		if(cumModifiers!=null) {
			List<FluidModifier> fluidModifiers = fluidCum.fluidModifiers;
			Body.handleLoadingOfModifiers(FluidModifier.values(), null, cumModifiers, fluidModifiers);
		}

		return fluidCum;
	}

	@Override
	public boolean equals(Object o) {
		if(o instanceof FluidCum){
			if(((FluidCum)o).getType().equals(this.getType())
				&& ((FluidCum)o).getFlavour() == this.getFlavour()
				&& ((FluidCum)o).getFluidModifiers().equals(this.getFluidModifiers())
				&& ((FluidCum)o).getTransformativeEffects().equals(this.getTransformativeEffects())){
					return true;
			}
		}
		return false;
	}

	@Override
	public int hashCode() {
		int result = 17;
		result = 31 * result + this.getType().hashCode();
		result = 31 * result + this.getFlavour().hashCode();
		result = 31 * result + this.getFluidModifiers().hashCode();
		result = 31 * result + this.getTransformativeEffects().hashCode();
		return result;
	}

	@Override
	public String getDeterminer(GameCharacter gc) {
		return type.getDeterminer(gc);
	}

	@Override
	public String getName(GameCharacter gc) {
		switch(type){
			case CUM_WOLF_MORPH:
				return UtilText.returnStringAtRandom("wolf-cum", "wolf-cream", "wolf-jism", "wolf-jizz", "wolf-seed");
			case CUM_DOG_MORPH:
				return UtilText.returnStringAtRandom("dog-cum", "dog-cream", "dog-jism", "dog-jizz", "dog-seed");
			case CUM_HORSE_MORPH:
				return UtilText.returnStringAtRandom("horse-cum", "horse-cream", "horse-jism", "horse-jizz", "horse-seed");
			case CUM_CAT_MORPH:
				return UtilText.returnStringAtRandom("cat-cum", "cat-cream", "cat-jism", "cat-jizz", "cat-seed");
			default:
				return UtilText.returnStringAtRandom("cum", "cream", "jism", "jizz", "load", "seed", "spooge");
		}
	}

	@Override
	public String getNameSingular(GameCharacter gc) {
		return type.getNameSingular(gc);
	}

	@Override
	public String getNamePlural(GameCharacter gc) {
		return type.getNamePlural(gc);
	}

	@Override
	public String getDescriptor(GameCharacter gc) {
		String modifierDescriptor = "";
		if(!fluidModifiers.isEmpty()) {
			modifierDescriptor = fluidModifiers.get(Util.random.nextInt(fluidModifiers.size())).getName();
		}

		return UtilText.returnStringAtRandom(
				(gc.getAttributeValue(Attribute.VIRILITY)>=20?"potent":""),
				"hot",
				modifierDescriptor,
				flavour.getRandomFlavourDescriptor(),
				(type.getDescriptor(gc).equals("human")?null:type.getDescriptor(gc)));
	}

	@Override
	public FluidType getType() {
		return type;
	}

	public void setType(FluidType type) {
		this.type = type;
	}

	public FluidFlavour getFlavour() {
		return flavour;
	}

	public String setFlavour(GameCharacter owner, FluidFlavour flavour) {
		if(owner==null) {
			this.flavour = flavour;
			return "";
		}

		if(this.flavour == flavour || !owner.hasPenis()) {
			return "
[style.colourDisabled(Nothing happens...)]
";
		}

		this.flavour = flavour;

		if(owner.isPlayer()) {
			return "
"
						+ "A soothing warmth spreads down into your [pc.balls], causing you to let out a contented little sigh.
"
						+ "Your [pc.cum] now tastes of "+flavour.getName()+"."
					+ "
";
		} else {
			return UtilText.parse(owner,
					"
"
						+ "A soothing warmth spreads down into [npc.namePos] [npc.balls], causing [npc.herHim] to let out a contented little sigh.
"
						+ "[npc.NamePos] [pc.cum] now tastes of "+flavour.getName()+"."
					+ "
");
		}
	}

	public boolean hasFluidModifier(FluidModifier fluidModifier) {
		return fluidModifiers.contains(fluidModifier);
	}

	public String addFluidModifier(GameCharacter owner, FluidModifier fluidModifier) {
		if(owner==null && !fluidModifiers.contains(fluidModifier)) {
			fluidModifiers.add(fluidModifier);
			return "";
		}

		if(fluidModifiers.contains(fluidModifier) || !owner.hasPenis()) {
			return "
[style.colourDisabled(Nothing happens...)]
";
		}

		fluidModifiers.add(fluidModifier);

		switch(fluidModifier) {
			case ADDICTIVE:
				if(owner.isPlayer()) {
					return "
"
								+ "You feel a strange, pulsating heat deep within your [pc.balls], causing you to let out [pc.a_moan+].
"
								+ "Your [pc.cum] is now [style.boldGrow(addictive)]!"
							+ "
";
				} else {
					return UtilText.parse(owner,
							"
"
								+ "A strange, pulsating heat takes root deep within [npc.namePos] [npc.balls], causing [npc.herHim] to let out [npc.a_moan+].
"
								+ "[npc.NamePos] [npc.cum] is now [style.boldGrow(addictive)]!"
							+ "
");
				}
			case ALCOHOLIC:
				if(owner.isPlayer()) {
					return "
"
								+ "You feel a strange, soothing warmth deep within your [pc.balls], causing you to let out [pc.a_moan+].
"
								+ "Your [pc.cum] is now [style.boldGrow(alcoholic)]!"
							+ "
";
				} else {
					return UtilText.parse(owner,
							"
"
								+ "A strange, soothing warmth takes root deep within [npc.namePos] [npc.balls], causing [npc.herHim] to let out [npc.a_moan+].
"
								+ "[npc.NamePos] [npc.cum] is now [style.boldGrow(alcoholic)]!"
							+ "
");
				}
			case BUBBLING:
				if(owner.isPlayer()) {
					return "
"
								+ "You feel a light, bubbly feeling rising up into your [pc.balls], causing you to let out [pc.a_moan+].
"
								+ "Your [pc.cum] is now [style.boldGrow(bubbly)]!"
							+ "
";
				} else {
					return UtilText.parse(owner,
							"
"
								+ "A light, bubbly feeling rises up into [npc.namePos] [npc.balls], causing [npc.herHim] to let out [npc.a_moan+].
"
								+ "[npc.NamePos] [npc.cum] is now [style.boldGrow(bubbly)]!"
							+ "
");
				}
			case HALLUCINOGENIC:
				if(owner.isPlayer()) {
					return "
"
								+ "You feel a series of strange pulses shoot down into your [pc.balls], causing you to let out [pc.a_moan+].
"
								+ "Your [pc.cum] is now [style.boldGrow(psychoactive)]!"
							+ "
";
				} else {
					return UtilText.parse(owner,
							"
"
								+ "A series of strange pulses shoot down into [npc.namePos] [npc.balls], causing [npc.herHim] to let out [npc.a_moan+].
"
								+ "[npc.NamePos] [npc.cum] is now [style.boldGrow(psychoactive)]!"
							+ "
");
				}
			case MINERAL_OIL:
				if(owner.isPlayer()) {
					return "
"
								+ "You feel a soothing warmth flow into your [pc.balls], causing you to let out [pc.a_moan+].
"
								+ "Your [pc.cum] is now imbued with [style.boldGrow(mineral oil)], and can melt condoms!"
							+ "
";
				} else {
					return UtilText.parse(owner,
							"
"
								+ "A soothing warmth flows into [npc.namePos] [npc.balls], causing [npc.herHim] to let out [npc.a_moan+].
"
								+ "[npc.NamePos] [npc.cum] is now imbued with [style.boldGrow(mineral oil)], and can melt condoms!"
							+ "
");
				}
			case MUSKY:
				if(owner.isPlayer()) {
					return "
"
								+ "You feel a slow, creeping warmth rise up into your [pc.balls], causing you to let out [pc.a_moan+].
"
								+ "Your [pc.cum] is now [style.boldGrow(musky)]!"
							+ "
";
				} else {
					return UtilText.parse(owner,
							"
"
								+ "A slow, creeping warmth rises up into [npc.namePos] [npc.balls], causing [npc.herHim] to let out [npc.a_moan+].
"
								+ "[npc.NamePos] [npc.cum] is now [style.boldGrow(musky)]!"
							+ "
");
				}
			case SLIMY:
				if(owner.isPlayer()) {
					return "
"
								+ "You feel a strange, soothing warmth flow up into your [pc.balls], causing you to let out [pc.a_moan+].
"
								+ "Your [pc.cum] is now [style.boldGrow(slimy)]!"
							+ "
";
				} else {
					return UtilText.parse(owner,
							"
"
								+ "A strange, soothing warmth flows up into [npc.namePos] [npc.balls], causing [npc.herHim] to let out [npc.a_moan+].
"
								+ "[npc.NamePos] [npc.cum] is now [style.boldGrow(slimy)]!"
							+ "
");
				}
			case STICKY:
				if(owner.isPlayer()) {
					return "
"
								+ "You feel a thick, sickly warmth flow up into your [pc.balls], causing you to let out [pc.a_moan+].
"
								+ "Your [pc.cum] is now [style.boldGrow(sticky)]!"
							+ "
";
				} else {
					return UtilText.parse(owner,
							"
"
								+ "A thick, sickly warmth flows up into [npc.namePos] [npc.balls], causing [npc.herHim] to let out [npc.a_moan+].
"
								+ "[npc.NamePos] [npc.cum] is now [style.boldGrow(sticky)]!"
							+ "
");
				}
			case VISCOUS:
				if(owner.isPlayer()) {
					return "
"
								+ "You feel a heavy heat slowly rising up into your [pc.balls], causing you to let out [pc.a_moan+].
"
								+ "Your [pc.cum] is now [style.boldGrow(viscous)]!"
							+ "
";
				} else {
					return UtilText.parse(owner,
							"
"
								+ "A heavy heat slowly rises up into [npc.namePos] [npc.balls], causing [npc.herHim] to let out [npc.a_moan+].
"
								+ "[npc.NamePos] [npc.cum] is now [style.boldGrow(viscous)]!"
							+ "
");
				}
			case MINERAL_OIL:
				if(owner.isPlayer()) {
					return "
"
								+ "You feel a prolonged heat flow up into your [pc.balls], causing you to let out [pc.a_moan+].
"
								+ "Your [pc.cum] is now [style.boldGrow(mineral oil)]!"
							+ "
";
				} else {
					return UtilText.parse(owner,
							"
"
								+ "A prolonged heat flows up into [npc.namePos] [npc.balls], causing [npc.herHim] to let out [npc.a_moan+].
"
								+ "[npc.NamePos] [npc.cum] is now [style.boldGrow(mineral oil)]!"
							+ "
");
				}
		}

		return "
[style.colourDisabled(Nothing happens...)]
";
	}

	public String removeFluidModifier(GameCharacter owner, FluidModifier fluidModifier) {
		if(owner==null) {
			fluidModifiers.remove(fluidModifier);
			return "";
		}

		if(!fluidModifiers.contains(fluidModifier) || !owner.hasPenis()) {
			return "
[style.colourDisabled(Nothing happens...)]
";
		}

		fluidModifiers.remove(fluidModifier);

		switch(fluidModifier) {
			case ADDICTIVE:
				if(owner.isPlayer()) {
					return "
"
								+ "You feel a soft coolness spreading up into your [pc.balls], causing you to let out a gentle sigh.
"
								+ "Your [pc.cum] is [style.boldShrink(no longer addictive)]!"
							+ "
";
				} else {
					return UtilText.parse(owner,
							"
"
								+ "A soft coolness spreads up into [npc.namePos] [npc.balls], causing [npc.herHim] to let out a gentle sigh.
"
								+ "[npc.NamePos] [npc.cum] is [style.boldShrink(no longer addictive)]!"
							+ "
");
				}
			case ALCOHOLIC:
				if(owner.isPlayer()) {
					return "
"
								+ "You feel a soft coolness spreading up into your [pc.balls], causing you to let out a gentle sigh.
"
								+ "Your [pc.cum] is [style.boldShrink(no longer alcoholic)]!"
							+ "
";
				} else {
					return UtilText.parse(owner,
							"
"
								+ "A soft coolness spreads up into [npc.namePos] [npc.balls], causing [npc.herHim] to let out a gentle sigh.
"
								+ "[npc.NamePos] [npc.cum] is [style.boldShrink(no longer alcoholic)]!"
							+ "
");
				}
			case BUBBLING:
				if(owner.isPlayer()) {
					return "
"
								+ "You feel a calm, settling feeling rising up into your [pc.balls], causing you to let out a gentle sigh.
"
								+ "Your [pc.cum] is [style.boldShrink(no longer bubbly)]!"
							+ "
";
				} else {
					return UtilText.parse(owner,
							"
"
								+ "A calm, settling feeling spreads up into [npc.namePos] [npc.balls], causing [npc.herHim] to let out a gentle sigh.
"
								+ "[npc.NamePos] [npc.cum] is [style.boldShrink(no longer bubbly)]!"
							+ "
");
				}
			case HALLUCINOGENIC:
				if(owner.isPlayer()) {
					return "
"
								+ "You feel a series of soothing waves wash up into your [pc.balls], causing you to let out a gentle sigh.
"
								+ "Your [pc.cum] is [style.boldShrink(no longer psychoactive)]!"
							+ "
";
				} else {
					return UtilText.parse(owner,
							"
"
								+ "A series of soothing waves wash up into [npc.namePos] [npc.balls], causing [npc.herHim] to let out a gentle sigh.
"
								+ "[npc.NamePos] [npc.cum] is [style.boldShrink(no longer psychoactive)]!"
							+ "
");
				}
			case MUSKY:
				if(owner.isPlayer()) {
					return "
"
								+ "You feel a gentle coolness rise up into your [pc.balls], causing you to let out soft sigh.
"
								+ "Your [pc.cum] is [style.boldShrink(no longer musky)]!"
							+ "
";
				} else {
					return UtilText.parse(owner,
							"
"
								+ "A gentle coolness rises up into [npc.namePos] [npc.balls], causing [npc.herHim] to let out a soft sigh.
"
								+ "[npc.NamePos] [npc.cum] is [style.boldShrink(no longer musky)]!"
							+ "
");
				}
			case SLIMY:
				if(owner.isPlayer()) {
					return "
"
								+ "You feel a calming coolness flow up into your [pc.balls], causing you to let out a gentle sigh.
"
								+ "Your [pc.cum] is [style.boldShrink(no longer slimy)]!"
							+ "
";
				} else {
					return UtilText.parse(owner,
							"
"
								+ "A calming coolness flows up into [npc.namePos] [npc.balls], causing [npc.herHim] to let out a gentle sigh.
"
								+ "[npc.NamePos] [npc.cum] is [style.boldShrink(no longer slimy)]!"
							+ "
");
				}
			case STICKY:
				if(owner.isPlayer()) {
					return "
"
								+ "You feel a soft warmth flow up into your [pc.balls], causing you to let out a gentle sigh.
"
								+ "Your [pc.cum] is [style.boldShrink(no longer sticky)]!"
							+ "
";
				} else {
					return UtilText.parse(owner,
							"
"
								+ "A soft warmth flows up into [npc.namePos] [npc.balls], causing [npc.herHim] to let out a gentle sigh.
"
								+ "[npc.NamePos] [npc.cum] is [style.boldShrink(no longer sticky)]!"
							+ "
");
				}
			case VISCOUS:
				if(owner.isPlayer()) {
					return "
"
								+ "You feel a soft coolness slowly rising up into your [pc.balls], causing you to let out a gentle sigh.
"
								+ "Your [pc.cum] is [style.boldShrink(no longer viscous)]!"
							+ "
";
				} else {
					return UtilText.parse(owner,
							"
"
								+ "A soft coolness rises up into [npc.namePos] [npc.balls], causing [npc.herHim] to let out a gentle sigh.
"
								+ "[npc.NamePos] [npc.cum] is [style.boldShrink(no longer viscous)]!"
							+ "
");
				}
			case MINERAL_OIL:
				if(owner.isPlayer()) {
					return "
"
								+ "You feel a short relief flow up into your [pc.balls], causing you to let out a gentle sigh.
"
								+ "Your [pc.cum] is [style.boldShrink(no longer mineral oil)]!"
							+ "
";
				} else {
					return UtilText.parse(owner,
							"
"
								+ "A short relief flows up into [npc.namePos] [npc.balls], causing [npc.herHim] to let out a gentle sigh.
"
								+ "[npc.NamePos] [npc.cum] is [style.boldShrink(no longer mineral oil)]!"
							+ "
");
				}
		}

		return "
[style.colourDisabled(Nothing happens...)]
";
	}

	public List<ItemEffect> getTransformativeEffects() {
		return transformativeEffects;
	}

	public void addTransformativeEffect(ItemEffect ie) {
		transformativeEffects.add(ie);
	}

	/**
	 * DO NOT MODIFY!
	 */
	public List<FluidModifier> getFluidModifiers() {
		return fluidModifiers;
	}

	public void clearFluidModifiers() {
		fluidModifiers.clear();
	}

	public float getValuePerMl() {
		return (0.1f + (this.getFluidModifiers().size()*0.1f)) * (this.getFlavour()!=FluidFlavour.CUM?1.5f:1);
	}

	@Override
	public boolean isBestial(GameCharacter owner) {
		if(owner==null) {
			return false;
		}
		return owner.getLegConfiguration().getBestialParts().contains(FluidCum.class) && getType().getRace().isBestialPartsAvailable();
	}
}


code:
package com.lilithsthrone.game.character.body;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.w3c.dom.Document;
import org.w3c.dom.Element;

import com.lilithsthrone.game.character.CharacterUtils;
import com.lilithsthrone.game.character.GameCharacter;
import com.lilithsthrone.game.character.body.types.FluidType;
import com.lilithsthrone.game.character.body.valueEnums.FluidFlavour;
import com.lilithsthrone.game.character.body.valueEnums.FluidModifier;
import com.lilithsthrone.game.dialogue.utils.UtilText;
import com.lilithsthrone.game.inventory.enchanting.ItemEffect;
import com.lilithsthrone.utils.Util;
import com.lilithsthrone.utils.XMLSaving;

/**
 * @since 0.1.83
 * @version 0.3.1
 * @author Innoxia
 */
public class FluidGirlCum implements FluidInterface, XMLSaving {

	protected FluidType type;
	protected FluidFlavour flavour;
	protected List<FluidModifier> fluidModifiers;
	protected List<ItemEffect> transformativeEffects;

	public FluidGirlCum(FluidType type) {
		this.type = type;
		this.flavour = type.getFlavour();
		transformativeEffects = new ArrayList<>();

		fluidModifiers = new ArrayList<>();
		fluidModifiers.addAll(type.getFluidModifiers());
	}

	public Element saveAsXML(Element parentElement, Document doc) {
		Element element = doc.createElement("girlcum");
		parentElement.appendChild(element);

		CharacterUtils.addAttribute(doc, element, "type", this.type.toString());
		CharacterUtils.addAttribute(doc, element, "flavour", this.flavour.toString());

		Element cumModifiers = doc.createElement("girlcumModifiers");
		element.appendChild(cumModifiers);
		for(FluidModifier fm : this.getFluidModifiers()) {
			CharacterUtils.addAttribute(doc, cumModifiers, fm.toString(), "true");
		}

		return element;
	}

	public static FluidGirlCum loadFromXML(Element parentElement, Document doc) {
		return loadFromXML(parentElement, doc, null);
	}

	/**
	 *
	 * @param parentElement
	 * @param doc
	 * @param baseType If you pass in a baseType, this method will ignore the saved type in parentElement.
	 */
	public static FluidGirlCum loadFromXML(Element parentElement, Document doc, FluidType baseType) {

		Element girlcum = (Element)parentElement.getElementsByTagName("girlcum").item(0);

		FluidType fluidType = FluidType.GIRL_CUM_HUMAN;

		if(baseType!=null) {
			fluidType = baseType;

		} else {
			try {
				fluidType = FluidType.getTypeFromString(girlcum.getAttribute("type"));
			} catch(Exception ex) {
			}
		}

		FluidGirlCum fluidGirlcum = new FluidGirlCum(fluidType);

		String flavourId = girlcum.getAttribute("flavour");
		if(flavourId.equalsIgnoreCase("SLIME")) {
			fluidGirlcum.flavour = FluidFlavour.BUBBLEGUM;
		} else {
			fluidGirlcum.flavour = FluidFlavour.valueOf(flavourId);
		}

		Element girlcumModifiersElement = (Element)girlcum.getElementsByTagName("girlcumModifiers").item(0);
		fluidGirlcum.fluidModifiers.clear();
		if(girlcumModifiersElement!=null) {
			Collection<FluidModifier> girlcumFluidModifiers = fluidGirlcum.fluidModifiers;
			Body.handleLoadingOfModifiers(FluidModifier.values(), null, girlcumModifiersElement, girlcumFluidModifiers);
		}

		return fluidGirlcum;
	}

	@Override
	public boolean equals(Object o) {
		if(o instanceof FluidGirlCum){
			if(((FluidGirlCum)o).getType().equals(this.getType())
				&& ((FluidGirlCum)o).getFlavour() == this.getFlavour()
				&& ((FluidGirlCum)o).getFluidModifiers().equals(this.getFluidModifiers())
				&& ((FluidGirlCum)o).getTransformativeEffects().equals(this.getTransformativeEffects())){
					return true;
			}
		}
		return false;
	}

	@Override
	public int hashCode() {
		int result = 17;
		result = 31 * result + this.getType().hashCode();
		result = 31 * result + this.getFlavour().hashCode();
		result = 31 * result + this.getFluidModifiers().hashCode();
		result = 31 * result + this.getTransformativeEffects().hashCode();
		return result;
	}

	@Override
	public String getDeterminer(GameCharacter gc) {
		return type.getDeterminer(gc);
	}

	@Override
	public String getName(GameCharacter gc) {
		return type.getName(gc);
	}

	@Override
	public String getNameSingular(GameCharacter gc) {
		return type.getNameSingular(gc);
	}

	@Override
	public String getNamePlural(GameCharacter gc) {
		return type.getNamePlural(gc);
	}

	@Override
	public String getDescriptor(GameCharacter gc) {
		String modifierDescriptor = "";
		if(!fluidModifiers.isEmpty()) {
			modifierDescriptor = fluidModifiers.get(Util.random.nextInt(fluidModifiers.size())).getName();
		}

		return UtilText.returnStringAtRandom(
				modifierDescriptor,
				flavour.getRandomFlavourDescriptor(),
				(type.getDescriptor(gc).equals("human")?null:type.getDescriptor(gc)));
	}

	@Override
	public FluidType getType() {
		return type;
	}

	public void setType(FluidType type) {
		this.type = type;
	}

	public FluidFlavour getFlavour() {
		return flavour;
	}

	public String setFlavour(GameCharacter owner, FluidFlavour flavour) {
		if (owner == null) {
			this.flavour = flavour;
			return "";
		}
		if(this.flavour == flavour || !owner.hasVagina()) {
			return "
[style.colourDisabled(Nothing happens...)]
";
		}

		this.flavour = flavour;

		if(owner.isPlayer()) {
			return "
"
						+ "A soothing warmth spreads down into your [pc.pussy], causing you to let out a contented little sigh.
"
						+ "Your [pc.girlcum] now tastes of "+flavour.getName()+"."
					+ "
";
		} else {
			return UtilText.parse(owner,
					"
"
						+ "A soothing warmth spreads down into [npc.namePos] [npc.pussy], causing [npc.herHim] to let out a contented little sigh.
"
						+ "[npc.NamePos] [pc.girlcum] now tastes of "+flavour.getName()+"."
					+ "
");
		}
	}

	public boolean hasFluidModifier(FluidModifier fluidModifier) {
		return fluidModifiers.contains(fluidModifier);
	}

	public String addFluidModifier(GameCharacter owner, FluidModifier fluidModifier) {
		if(owner==null && !fluidModifiers.contains(fluidModifier)) {
			fluidModifiers.add(fluidModifier);
			return "";
		}
		if(fluidModifiers.contains(fluidModifier) || !owner.hasVagina()) {
			return "
[style.colourDisabled(Nothing happens...)]
";
		}

		fluidModifiers.add(fluidModifier);

		switch(fluidModifier) {
			case ADDICTIVE:
				if(owner.isPlayer()) {
					return "
"
								+ "You feel a strange, pulsating heat deep within your [pc.pussy], causing you to let out [pc.a_moan+].
"
								+ "Your [pc.girlcum] is now [style.boldGrow(addictive)]!"
							+ "
";
				} else {
					return UtilText.parse(owner,
							"
"
								+ "A strange, pulsating heat takes root deep within [npc.namePos] [npc.pussy], causing [npc.herHim] to let out [npc.a_moan+].
"
								+ "[npc.NamePos] [npc.girlcum] is now [style.boldGrow(addictive)]!"
							+ "
");
				}
			case ALCOHOLIC:
				if(owner.isPlayer()) {
					return "
"
								+ "You feel a strange, soothing warmth deep within your [pc.pussy], causing you to let out [pc.a_moan+].
"
								+ "Your [pc.girlcum] is now [style.boldGrow(alcoholic)]!"
							+ "
";
				} else {
					return UtilText.parse(owner,
							"
"
								+ "A strange, soothing warmth takes root deep within [npc.namePos] [npc.pussy], causing [npc.herHim] to let out [npc.a_moan+].
"
								+ "[npc.NamePos] [npc.girlcum] is now [style.boldGrow(alcoholic)]!"
							+ "
");
				}
			case BUBBLING:
				if(owner.isPlayer()) {
					return "
"
								+ "You feel a light, bubbly feeling rising up into your [pc.pussy], causing you to let out [pc.a_moan+].
"
								+ "Your [pc.girlcum] is now [style.boldGrow(bubbly)]!"
							+ "
";
				} else {
					return UtilText.parse(owner,
							"
"
								+ "A light, bubbly feeling rises up into [npc.namePos] [npc.pussy], causing [npc.herHim] to let out [npc.a_moan+].
"
								+ "[npc.NamePos] [npc.girlcum] is now [style.boldGrow(bubbly)]!"
							+ "
");
				}
			case HALLUCINOGENIC:
				if(owner.isPlayer()) {
					return "
"
								+ "You feel a series of strange pulses shoot up into your [pc.pussy], causing you to let out [pc.a_moan+].
"
								+ "Your [pc.girlcum] is now [style.boldGrow(psychoactive)]!"
							+ "
";
				} else {
					return UtilText.parse(owner,
							"
"
								+ "A series of strange pulses shoot up into [npc.namePos] [npc.pussy], causing [npc.herHim] to let out [npc.a_moan+].
"
								+ "[npc.NamePos] [npc.girlcum] is now [style.boldGrow(psychoactive)]!"
							+ "
");
				}
			case MINERAL_OIL:
				if(owner.isPlayer()) {
					return "
"
								+ "You feel a soothing warmth flow into your [pc.pussy], causing you to let out [pc.a_moan+].
"
								+ "Your [pc.girlcum] is now imbued with [style.boldGrow(mineral oil)], and can melt condoms!"
							+ "
";
				} else {
					return UtilText.parse(owner,
							"
"
								+ "A soothing warmth flows into [npc.namePos] [npc.pussy], causing [npc.herHim] to let out [npc.a_moan+].
"
								+ "[npc.NamePos] [npc.girlcum] is now imbued with [style.boldGrow(mineral oil)], and can melt condoms!"
							+ "
");
				}
			case MUSKY:
				if(owner.isPlayer()) {
					return "
"
								+ "You feel a slow, creeping warmth rise up into your [pc.pussy], causing you to let out [pc.a_moan+].
"
								+ "Your [pc.girlcum] is now [style.boldGrow(musky)]!"
							+ "
";
				} else {
					return UtilText.parse(owner,
							"
"
								+ "A slow, creeping warmth rises up into [npc.namePos] [npc.pussy], causing [npc.herHim] to let out [npc.a_moan+].
"
								+ "[npc.NamePos] [npc.girlcum] is now [style.boldGrow(musky)]!"
							+ "
");
				}
			case SLIMY:
				if(owner.isPlayer()) {
					return "
"
								+ "You feel a strange, soothing warmth flow up into your [pc.pussy], causing you to let out [pc.a_moan+].
"
								+ "Your [pc.girlcum] is now [style.boldGrow(slimy)]!"
							+ "
";
				} else {
					return UtilText.parse(owner,
							"
"
								+ "A strange, soothing warmth flows up into [npc.namePos] [npc.pussy], causing [npc.herHim] to let out [npc.a_moan+].
"
								+ "[npc.NamePos] [npc.girlcum] is now [style.boldGrow(slimy)]!"
							+ "
");
				}
			case STICKY:
				if(owner.isPlayer()) {
					return "
"
								+ "You feel a thick, sickly warmth flow up into your [pc.pussy], causing you to let out [pc.a_moan+].
"
								+ "Your [pc.girlcum] is now [style.boldGrow(sticky)]!"
							+ "
";
				} else {
					return UtilText.parse(owner,
							"
"
								+ "A thick, sickly warmth flows up into [npc.namePos] [npc.pussy], causing [npc.herHim] to let out [npc.a_moan+].
"
								+ "[npc.NamePos] [npc.girlcum] is now [style.boldGrow(sticky)]!"
							+ "
");
				}
			case VISCOUS:
				if(owner.isPlayer()) {
					return "
"
								+ "You feel a heavy heat slowly rising up into your [pc.pussy], causing you to let out [pc.a_moan+].
"
								+ "Your [pc.girlcum] is now [style.boldGrow(viscous)]!"
							+ "
";
				} else {
					return UtilText.parse(owner,
							"
"
								+ "A heavy heat slowly rises up into [npc.namePos] [npc.pussy], causing [npc.herHim] to let out [npc.a_moan+].
"
								+ "[npc.NamePos] [npc.girlcum] is now [style.boldGrow(viscous)]!"
							+ "
");
				}
			case MINERAL_OIL:
				if(owner.isPlayer()) {
					return "
"
								+ "You feel a prolonged heat flow up into your [pc.pussy], causing you to let out [pc.a_moan+].
"
								+ "Your [pc.girlcum] is now [style.boldGrow(mineral oil)]!"
							+ "
";
				} else {
					return UtilText.parse(owner,
							"
"
								+ "A prolonged heat flows up into [npc.namePos] [npc.pussy], causing [npc.herHim] to let out [npc.a_moan+].
"
								+ "[npc.NamePos] [npc.girlcum] is now [style.boldGrow(mineral oil)]!"
							+ "
");
				}
		}

		return "
[style.colourDisabled(Nothing happens...)]
";
	}

	public String removeFluidModifier(GameCharacter owner, FluidModifier fluidModifier) {
		if(!fluidModifiers.contains(fluidModifier) || !owner.hasVagina()) {
			return "
[style.colourDisabled(Nothing happens...)]
";
		}

		fluidModifiers.remove(fluidModifier);

		switch(fluidModifier) {
			case ADDICTIVE:
				if(owner.isPlayer()) {
					return "
"
								+ "You feel a soft coolness spreading up into your [pc.pussy], causing you to let out a gentle sigh.
"
								+ "Your [pc.girlcum] is [style.boldShrink(no longer addictive)]!"
							+ "
";
				} else {
					return UtilText.parse(owner,
							"
"
								+ "A soft coolness spreads up into [npc.namePos] [npc.pussy], causing [npc.herHim] to let out a gentle sigh.
"
								+ "[npc.NamePos] [npc.girlcum] is [style.boldShrink(no longer addictive)]!"
							+ "
");
				}
			case ALCOHOLIC:
				if(owner.isPlayer()) {
					return "
"
								+ "You feel a soft coolness spreading up into your [pc.pussy], causing you to let out a gentle sigh.
"
								+ "Your [pc.girlcum] is [style.boldShrink(no longer alcoholic)]!"
							+ "
";
				} else {
					return UtilText.parse(owner,
							"
"
								+ "A soft coolness spreads up into [npc.namePos] [npc.pussy], causing [npc.herHim] to let out a gentle sigh.
"
								+ "[npc.NamePos] [npc.girlcum] is [style.boldShrink(no longer alcoholic)]!"
							+ "
");
				}
			case BUBBLING:
				if(owner.isPlayer()) {
					return "
"
								+ "You feel a calm, settling feeling rising up into your [pc.pussy], causing you to let out a gentle sigh.
"
								+ "Your [pc.girlcum] is [style.boldShrink(no longer bubbly)]!"
							+ "
";
				} else {
					return UtilText.parse(owner,
							"
"
								+ "A calm, settling feeling spreads up into [npc.namePos] [npc.pussy], causing [npc.herHim] to let out a gentle sigh.
"
								+ "[npc.NamePos] [npc.girlcum] is [style.boldShrink(no longer bubbly)]!"
							+ "
");
				}
			case HALLUCINOGENIC:
				if(owner.isPlayer()) {
					return "
"
								+ "You feel a series of soothing waves wash up into your [pc.pussy], causing you to let out a gentle sigh.
"
								+ "Your [pc.girlcum] is [style.boldShrink(no longer psychoactive)]!"
							+ "
";
				} else {
					return UtilText.parse(owner,
							"
"
								+ "A series of soothing waves wash up into [npc.namePos] [npc.pussy], causing [npc.herHim] to let out a gentle sigh.
"
								+ "[npc.NamePos] [npc.girlcum] is [style.boldShrink(no longer psychoactive)]!"
							+ "
");
				}
			case MUSKY:
				if(owner.isPlayer()) {
					return "
"
								+ "You feel a gentle coolness rise up into your [pc.pussy], causing you to let out soft sigh.
"
								+ "Your [pc.girlcum] is [style.boldShrink(no longer musky)]!"
							+ "
";
				} else {
					return UtilText.parse(owner,
							"
"
								+ "A gentle coolness rises up into [npc.namePos] [npc.pussy], causing [npc.herHim] to let out a soft sigh.
"
								+ "[npc.NamePos] [npc.girlcum] is [style.boldShrink(no longer musky)]!"
							+ "
");
				}
			case SLIMY:
				if(owner.isPlayer()) {
					return "
"
								+ "You feel a calming coolness flow up into your [pc.pussy], causing you to let out a gentle sigh.
"
								+ "Your [pc.girlcum] is [style.boldShrink(no longer slimy)]!"
							+ "
";
				} else {
					return UtilText.parse(owner,
							"
"
								+ "A calming coolness flows up into [npc.namePos] [npc.pussy], causing [npc.herHim] to let out a gentle sigh.
"
								+ "[npc.NamePos] [npc.girlcum] is [style.boldShrink(no longer slimy)]!"
							+ "
");
				}
			case STICKY:
				if(owner.isPlayer()) {
					return "
"
								+ "You feel a soft warmth flow up into your [pc.pussy], causing you to let out a gentle sigh.
"
								+ "Your [pc.girlcum] is [style.boldShrink(no longer sticky)]!"
							+ "
";
				} else {
					return UtilText.parse(owner,
							"
"
								+ "A soft warmth flows up into [npc.namePos] [npc.pussy], causing [npc.herHim] to let out a gentle sigh.
"
								+ "[npc.NamePos] [npc.girlcum] is [style.boldShrink(no longer sticky)]!"
							+ "
");
				}
			case VISCOUS:
				if(owner.isPlayer()) {
					return "
"
								+ "You feel a soft coolness slowly rising up into your [pc.pussy], causing you to let out a gentle sigh.
"
								+ "Your [pc.girlcum] is [style.boldShrink(no longer viscous)]!"
							+ "
";
				} else {
					return UtilText.parse(owner,
							"
"
								+ "A soft coolness rises up into [npc.namePos] [npc.pussy], causing [npc.herHim] to let out a gentle sigh.
"
								+ "[npc.NamePos] [npc.girlcum] is [style.boldShrink(no longer viscous)]!"
							+ "
");
				}
			case MINERAL_OIL:
				if(owner.isPlayer()) {
					return "
"
								+ "You feel a short relief flow up into your [pc.pussy], causing you to let out a gentle sigh.
"
								+ "Your [pc.girlcum] is [style.boldShrink(no longer mineral oil)]!"
							+ "
";
				} else {
					return UtilText.parse(owner,
							"
"
								+ "A short relief flows up into [npc.namePos] [npc.pussy], causing [npc.herHim] to let out a gentle sigh.
"
								+ "[npc.NamePos] [npc.girlcum] is [style.boldShrink(no longer mineral oil)]!"
							+ "
");
				}
		}

		return "
[style.colourDisabled(Nothing happens...)]
";
	}

	public List<ItemEffect> getTransformativeEffects() {
		return transformativeEffects;
	}

	public void addTransformativeEffect(ItemEffect ie) {
		transformativeEffects.add(ie);
	}

	/**
	 * DO NOT MODIFY!
	 */
	public List<FluidModifier> getFluidModifiers() {
		return fluidModifiers;
	}

	public void clearFluidModifiers() {
		fluidModifiers.clear();
	}

	public float getValuePerMl() {
		return (4f + (this.getFluidModifiers().size()*0.5f)) * (this.getFlavour()!=FluidFlavour.GIRL_CUM?1.5f:1);
	}

	@Override
	public boolean isBestial(GameCharacter owner) {
		if(owner==null) {
			return false;
		}
		return owner.getLegConfiguration().getBestialParts().contains(FluidGirlCum.class) && getType().getRace().isBestialPartsAvailable();
	}
}


code:
package com.lilithsthrone.game.character.body;

import java.util.List;

import com.lilithsthrone.game.character.GameCharacter;
import com.lilithsthrone.game.character.body.types.FluidType;
import com.lilithsthrone.game.character.body.valueEnums.FluidFlavour;
import com.lilithsthrone.game.character.body.valueEnums.FluidModifier;
import com.lilithsthrone.game.inventory.enchanting.ItemEffect;

/**
 * @since 0.2.6
 * @version 0.2.6
 * @author Innoxia
 */
public interface FluidInterface extends BodyPartInterface {

	@Override
	public FluidType getType();

	public FluidFlavour getFlavour();
	public String setFlavour(GameCharacter owner, FluidFlavour flavour);

	public List<FluidModifier> getFluidModifiers();

	public boolean hasFluidModifier(FluidModifier fluidModifier);

	public String addFluidModifier(GameCharacter owner, FluidModifier fluidModifier);
	public String removeFluidModifier(GameCharacter owner, FluidModifier fluidModifier);

	public List<ItemEffect> getTransformativeEffects();
	public void addTransformativeEffect(ItemEffect ie);

	public float getValuePerMl();

}