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

import java.util.List;

import com.lilithsthrone.game.character.GameCharacter;
import com.lilithsthrone.game.character.body.Body;
import com.lilithsthrone.game.character.body.valueEnums.FluidFlavour;
import com.lilithsthrone.game.character.body.valueEnums.FluidModifier;
import com.lilithsthrone.game.character.body.valueEnums.FluidTypeBase;
import com.lilithsthrone.game.character.race.Race;
import com.lilithsthrone.utils.Util;

/**
 * @since 0.1.83
 * @version 0.2.11
 * @author Innoxia
 */
public enum FluidType implements BodyPartTypeInterface {

	// Cum:

	CUM_HUMAN(FluidTypeBase.CUM,
			BodyCoveringType.CUM,
			FluidFlavour.CUM,
			Util.newArrayListOfValues("human"),
			Util.newArrayListOfValues(
					FluidModifier.STICKY,
					FluidModifier.SLIMY),
			Race.HUMAN),

	CUM_ANGEL(FluidTypeBase.CUM,
			BodyCoveringType.CUM,
			FluidFlavour.CUM,
			Util.newArrayListOfValues("angelic"),
			Util.newArrayListOfValues(
					FluidModifier.STICKY,
					FluidModifier.SLIMY),
			Race.ANGEL),

	CUM_DEMON(FluidTypeBase.CUM,
			BodyCoveringType.CUM,
			FluidFlavour.CUM,
			Util.newArrayListOfValues("demonic"),
			Util.newArrayListOfValues(
					FluidModifier.STICKY,
					FluidModifier.SLIMY),
			Race.DEMON),

	CUM_DOG_MORPH(FluidTypeBase.CUM,
			BodyCoveringType.CUM,
			FluidFlavour.CUM,
			Util.newArrayListOfValues("canine"),
			Util.newArrayListOfValues(
					FluidModifier.STICKY,
					FluidModifier.SLIMY),
			Race.DOG_MORPH),

	CUM_WOLF_MORPH(FluidTypeBase.CUM,
			BodyCoveringType.CUM,
			FluidFlavour.CUM,
			Util.newArrayListOfValues("lupine"),
			Util.newArrayListOfValues(
					FluidModifier.MUSKY,
					FluidModifier.STICKY,
					FluidModifier.SLIMY),
			Race.WOLF_MORPH),

	CUM_FOX_MORPH(FluidTypeBase.CUM,
			BodyCoveringType.CUM,
			FluidFlavour.CUM,
			Util.newArrayListOfValues("vulpine"),
			Util.newArrayListOfValues(
					FluidModifier.STICKY,
					FluidModifier.SLIMY),
			Race.FOX_MORPH),

	CUM_CAT_MORPH(FluidTypeBase.CUM,
			BodyCoveringType.CUM,
			FluidFlavour.CUM,
			Util.newArrayListOfValues("feline"),
			Util.newArrayListOfValues(
					FluidModifier.STICKY,
					FluidModifier.SLIMY),
			Race.CAT_MORPH),

	CUM_SQUIRREL_MORPH(FluidTypeBase.CUM,
			BodyCoveringType.CUM,
			FluidFlavour.CUM,
			Util.newArrayListOfValues("squirrel"),
			Util.newArrayListOfValues(
					FluidModifier.STICKY,
					FluidModifier.SLIMY),
			Race.SQUIRREL_MORPH),

	CUM_RAT_MORPH(FluidTypeBase.CUM,
			BodyCoveringType.CUM,
			FluidFlavour.CUM,
			Util.newArrayListOfValues("rat"),
			Util.newArrayListOfValues(
					FluidModifier.STICKY,
					FluidModifier.SLIMY),
			Race.RAT_MORPH),

	CUM_RABBIT_MORPH(FluidTypeBase.CUM,
			BodyCoveringType.CUM,
			FluidFlavour.CUM,
			Util.newArrayListOfValues("rabbit"),
			Util.newArrayListOfValues(
					FluidModifier.STICKY,
					FluidModifier.SLIMY),
			Race.RABBIT_MORPH),

	CUM_BAT_MORPH(FluidTypeBase.CUM,
			BodyCoveringType.CUM,
			FluidFlavour.CUM,
			Util.newArrayListOfValues("bat"),
			Util.newArrayListOfValues(
					FluidModifier.STICKY,
					FluidModifier.SLIMY),
			Race.BAT_MORPH),

	CUM_ALLIGATOR_MORPH(FluidTypeBase.CUM,
			BodyCoveringType.CUM,
			FluidFlavour.CUM,
			Util.newArrayListOfValues("alligator"),
			Util.newArrayListOfValues(
					FluidModifier.STICKY,
					FluidModifier.SLIMY),
			Race.ALLIGATOR_MORPH),

	CUM_HORSE_MORPH(FluidTypeBase.CUM,
			BodyCoveringType.CUM,
			FluidFlavour.CUM,
			Util.newArrayListOfValues("equine"),
			Util.newArrayListOfValues(
					FluidModifier.MUSKY,
					FluidModifier.STICKY,
					FluidModifier.SLIMY),
			Race.HORSE_MORPH),

	CUM_REINDEER_MORPH(FluidTypeBase.CUM,
			BodyCoveringType.CUM,
			FluidFlavour.CUM,
			Util.newArrayListOfValues("rangiferine"),
			Util.newArrayListOfValues(
					FluidModifier.MUSKY,
					FluidModifier.STICKY,
					FluidModifier.SLIMY),
			Race.REINDEER_MORPH),

	CUM_COW_MORPH(FluidTypeBase.CUM,
			BodyCoveringType.CUM,
			FluidFlavour.CUM,
			Util.newArrayListOfValues("bovine"),
			Util.newArrayListOfValues(
					FluidModifier.MUSKY,
					FluidModifier.STICKY,
					FluidModifier.SLIMY),
			Race.COW_MORPH),

	CUM_HARPY(FluidTypeBase.CUM,
			BodyCoveringType.CUM,
			FluidFlavour.CUM,
			Util.newArrayListOfValues("avian"),
			Util.newArrayListOfValues(
					FluidModifier.STICKY,
					FluidModifier.SLIMY),
			Race.HARPY),

	// Girl cum:

	GIRL_CUM_HUMAN(FluidTypeBase.GIRLCUM,
			BodyCoveringType.GIRL_CUM,
			FluidFlavour.GIRL_CUM,
			Util.newArrayListOfValues("human"),
			Util.newArrayListOfValues(
					FluidModifier.SLIMY),
			Race.HUMAN),

	GIRL_CUM_ANGEL(FluidTypeBase.GIRLCUM,
			BodyCoveringType.GIRL_CUM,
			FluidFlavour.GIRL_CUM,
			Util.newArrayListOfValues("angelic"),
			Util.newArrayListOfValues(
					FluidModifier.SLIMY),
			Race.ANGEL),

	GIRL_CUM_DEMON(FluidTypeBase.GIRLCUM,
			BodyCoveringType.GIRL_CUM,
			FluidFlavour.GIRL_CUM,
			Util.newArrayListOfValues("demonic"),
			Util.newArrayListOfValues(
					FluidModifier.SLIMY),
			Race.DEMON),

	GIRL_CUM_DOG_MORPH(FluidTypeBase.GIRLCUM,
			BodyCoveringType.GIRL_CUM,
			FluidFlavour.GIRL_CUM,
			Util.newArrayListOfValues("canine"),
			Util.newArrayListOfValues(
					FluidModifier.SLIMY),
			Race.DOG_MORPH),

	GIRL_CUM_WOLF_MORPH(FluidTypeBase.GIRLCUM,
			BodyCoveringType.GIRL_CUM,
			FluidFlavour.GIRL_CUM,
			Util.newArrayListOfValues("lupine"),
			Util.newArrayListOfValues(
					FluidModifier.SLIMY),
			Race.WOLF_MORPH),

	GIRL_CUM_FOX_MORPH(FluidTypeBase.GIRLCUM,
			BodyCoveringType.GIRL_CUM,
			FluidFlavour.GIRL_CUM,
			Util.newArrayListOfValues("vulpine"),
			Util.newArrayListOfValues(
					FluidModifier.SLIMY),
			Race.FOX_MORPH),

	GIRL_CUM_CAT_MORPH(FluidTypeBase.GIRLCUM,
			BodyCoveringType.GIRL_CUM,
			FluidFlavour.GIRL_CUM,
			Util.newArrayListOfValues("feline"),
			Util.newArrayListOfValues(
					FluidModifier.SLIMY),
			Race.CAT_MORPH),

	GIRL_CUM_SQUIRREL_MORPH(FluidTypeBase.GIRLCUM,
			BodyCoveringType.GIRL_CUM,
			FluidFlavour.GIRL_CUM,
			Util.newArrayListOfValues("squirrel"),
			Util.newArrayListOfValues(
					FluidModifier.SLIMY),
			Race.SQUIRREL_MORPH),

	GIRL_CUM_RAT_MORPH(FluidTypeBase.GIRLCUM,
			BodyCoveringType.GIRL_CUM,
			FluidFlavour.GIRL_CUM,
			Util.newArrayListOfValues("rat"),
			Util.newArrayListOfValues(
					FluidModifier.SLIMY),
			Race.RAT_MORPH),

	GIRL_CUM_RABBIT_MORPH(FluidTypeBase.GIRLCUM,
			BodyCoveringType.GIRL_CUM,
			FluidFlavour.GIRL_CUM,
			Util.newArrayListOfValues("rabbit"),
			Util.newArrayListOfValues(
					FluidModifier.SLIMY),
			Race.RABBIT_MORPH),

	GIRL_CUM_BAT_MORPH(FluidTypeBase.GIRLCUM,
			BodyCoveringType.GIRL_CUM,
			FluidFlavour.GIRL_CUM,
			Util.newArrayListOfValues("bat"),
			Util.newArrayListOfValues(
					FluidModifier.SLIMY),
			Race.BAT_MORPH),

	GIRL_CUM_ALLIGATOR_MORPH(FluidTypeBase.GIRLCUM,
			BodyCoveringType.GIRL_CUM,
			FluidFlavour.GIRL_CUM,
			Util.newArrayListOfValues("alligator"),
			Util.newArrayListOfValues(
					FluidModifier.SLIMY),
			Race.ALLIGATOR_MORPH),

	GIRL_CUM_HORSE_MORPH(FluidTypeBase.GIRLCUM,
			BodyCoveringType.GIRL_CUM,
			FluidFlavour.GIRL_CUM,
			Util.newArrayListOfValues("equine"),
			Util.newArrayListOfValues(
					FluidModifier.SLIMY),
			Race.HORSE_MORPH),

	GIRL_CUM_REINDEER_MORPH(FluidTypeBase.GIRLCUM,
			BodyCoveringType.GIRL_CUM,
			FluidFlavour.GIRL_CUM,
			Util.newArrayListOfValues("rangiferine"),
			Util.newArrayListOfValues(
					FluidModifier.SLIMY),
			Race.REINDEER_MORPH),

	GIRL_CUM_COW_MORPH(FluidTypeBase.GIRLCUM,
			BodyCoveringType.GIRL_CUM,
			FluidFlavour.GIRL_CUM,
			Util.newArrayListOfValues("bovine"),
			Util.newArrayListOfValues(
					FluidModifier.SLIMY),
			Race.COW_MORPH),

	GIRL_CUM_HARPY(FluidTypeBase.GIRLCUM,
			BodyCoveringType.GIRL_CUM,
			FluidFlavour.GIRL_CUM,
			Util.newArrayListOfValues("avian"),
			Util.newArrayListOfValues(
					FluidModifier.SLIMY),
			Race.HARPY),

	// Milks:

	MILK_HUMAN(FluidTypeBase.MILK,
			BodyCoveringType.MILK,
			FluidFlavour.MILK,
			Util.newArrayListOfValues("human"),
			Util.newArrayListOfValues(),
			Race.HUMAN),

	MILK_ANGEL(FluidTypeBase.MILK,
			BodyCoveringType.MILK,
			FluidFlavour.MILK,
			Util.newArrayListOfValues("angelic"),
			Util.newArrayListOfValues(),
			Race.ANGEL),

	MILK_COW_MORPH(FluidTypeBase.MILK,
			BodyCoveringType.MILK,
			FluidFlavour.MILK,
			Util.newArrayListOfValues("bovine"),
			Util.newArrayListOfValues(),
			Race.COW_MORPH),

	MILK_DEMON_COMMON(FluidTypeBase.MILK,
			BodyCoveringType.MILK,
			FluidFlavour.MILK,
			Util.newArrayListOfValues("demonic"),
			Util.newArrayListOfValues(),
			Race.DEMON),

	MILK_DOG_MORPH(FluidTypeBase.MILK,
			BodyCoveringType.MILK,
			FluidFlavour.MILK,
			Util.newArrayListOfValues("canine"),
			Util.newArrayListOfValues(),
			Race.DOG_MORPH),

	MILK_WOLF_MORPH(FluidTypeBase.MILK,
			BodyCoveringType.MILK,
			FluidFlavour.MILK,
			Util.newArrayListOfValues("lupine"),
			Util.newArrayListOfValues(),
			Race.WOLF_MORPH),

	MILK_FOX_MORPH(FluidTypeBase.MILK,
			BodyCoveringType.MILK,
			FluidFlavour.MILK,
			Util.newArrayListOfValues("vulpine"),
			Util.newArrayListOfValues(),
			Race.FOX_MORPH),

	MILK_CAT_MORPH(FluidTypeBase.MILK,
			BodyCoveringType.MILK,
			FluidFlavour.MILK,
			Util.newArrayListOfValues("feline"),
			Util.newArrayListOfValues(),
			Race.CAT_MORPH),

	MILK_SQUIRREL_MORPH(FluidTypeBase.MILK,
			BodyCoveringType.MILK,
			FluidFlavour.MILK,
			Util.newArrayListOfValues("squirrel"),
			Util.newArrayListOfValues(),
			Race.SQUIRREL_MORPH),

	MILK_RAT_MORPH(FluidTypeBase.MILK, // I don't get it. Everyone loves rats, but they don't wanna drink the rats' milk?
			BodyCoveringType.MILK,
			FluidFlavour.MILK,
			Util.newArrayListOfValues("rat"),
			Util.newArrayListOfValues(),
			Race.RAT_MORPH),

	MILK_RABBIT_MORPH(FluidTypeBase.MILK,
			BodyCoveringType.MILK,
			FluidFlavour.MILK,
			Util.newArrayListOfValues("rabbit"),
			Util.newArrayListOfValues(),
			Race.RABBIT_MORPH),

	MILK_BAT_MORPH(FluidTypeBase.MILK,
			BodyCoveringType.MILK,
			FluidFlavour.MILK,
			Util.newArrayListOfValues("bat"),
			Util.newArrayListOfValues(),
			Race.BAT_MORPH),

	MILK_ALLIGATOR_MORPH(FluidTypeBase.MILK,
			BodyCoveringType.MILK,
			FluidFlavour.MILK,
			Util.newArrayListOfValues("alligator"),
			Util.newArrayListOfValues(),
			Race.ALLIGATOR_MORPH),

	MILK_HORSE_MORPH(FluidTypeBase.MILK,
			BodyCoveringType.MILK,
			FluidFlavour.MILK,
			Util.newArrayListOfValues("equine"),
			Util.newArrayListOfValues(),
			Race.HORSE_MORPH),

	MILK_REINDEER_MORPH(FluidTypeBase.MILK,
			BodyCoveringType.MILK,
			FluidFlavour.MILK,
			Util.newArrayListOfValues("rangiferine"),
			Util.newArrayListOfValues(),
			Race.REINDEER_MORPH),

	MILK_HARPY(FluidTypeBase.MILK,
			BodyCoveringType.MILK,
			FluidFlavour.MILK,
			Util.newArrayListOfValues("avian"),
			Util.newArrayListOfValues(),
			Race.HARPY);

	private FluidTypeBase baseType;
	private BodyCoveringType bodyCoveringType;
	private FluidFlavour flavour;
	private List<String> descriptors;
	private List<FluidModifier> fluidModifiers;
	private Race race;

	private FluidType(FluidTypeBase baseType, BodyCoveringType bodyCoveringType, FluidFlavour flavour, List<String> descriptors, List<FluidModifier> fluidModifiers, Race race) {
		this.baseType = baseType;
		this.bodyCoveringType = bodyCoveringType;
		this.flavour = flavour;
		this.descriptors = descriptors;
		this.fluidModifiers = fluidModifiers;
		this.race = race;
	}

	/**
	 * Use instead of <i>valueOf()</i>.
	 */
	public static FluidType getTypeFromString(String value) {
		if(value.equals("CUM_IMP")) {
			value = "CUM_DEMON";

		} else if(value.equals("GIRL_CUM_IMP")) {
			value = "GIRL_CUM_DEMON";

		} else if(value.equals("MILK_IMP")) {
			value = "MILK_DEMON_COMMON";
		}
		return valueOf(value);
	}

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

	@Override
	public boolean isDefaultPlural() {
		return false;
	}

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

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

	@Override
	public String getDescriptor(GameCharacter gc) {
		return descriptors.get(Util.random.nextInt(descriptors.size()));
	}

	public FluidFlavour getFlavour() {
		return flavour;
	}

	@Override
	public BodyCoveringType getBodyCoveringType(Body body) {
		return bodyCoveringType;
	}

	public List<FluidModifier> getFluidModifiers() {
		return fluidModifiers;
	}

	@Override
	public Race getRace() {
		return race;
	}

	public FluidTypeBase getBaseType() {
		return baseType;
	}
}


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

/**
 * @since 0.2.8
 * @version 0.2.8
 * @author Innoxia
 */
public enum FootStructure {

	/**walk with feet flat on the ground*/
	PLANTIGRADE("plantigrade", "[npc.She] [npc.verb(walk)] with [npc.her] feet flat on the ground."),

	/**walk on toes with the heel permanently raised*/
	DIGITIGRADE("digitigrade", "[npc.She] [npc.verb(walk)] on [npc.her] [npc.toes], with [npc.her] heel being permanently raised."),

	/**walk on hoof with the rest of the foot permanently raised*/
	UNGULIGRADE("unguligrade", "[npc.She] [npc.verb(walk)] on [npc.her] [npc.toes], with the rest of [npc.her] foot being permanently raised.");

	private String name;
	private String description;

	private FootStructure(String name, String description) {
		this.name = name;
		this.description = description;
	}

	public String getName() {
		return name;
	}

	public String getDescription() {
		return description;
	}
}

repo_name: klorpa/Pedo

license: unknown


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

import com.lilithsthrone.utils.Util;

/**
 * @since 0.2.10
 * @version 0.3.1
 * @author Innoxia
 */
public class FootType {

	public static AbstractFootType HUMANOID = new AbstractFootType("humanoid",
			"foot",
			"feet",
			Util.newArrayListOfValues("masculine"),
			Util.newArrayListOfValues("feminine", "soft", "delicate", "slender"),
			"toe",
			"toes",
			Util.newArrayListOfValues("masculine"),
			Util.newArrayListOfValues("feminine", "soft", "delicate", "slender"),
			"footjob",
			"[npc.SheHasFull] human-like feet.",
			Util.newArrayListOfValues(FootStructure.PLANTIGRADE)) {
	};

	public static AbstractFootType PAWS = new AbstractFootType("paw-like",
			"paw",
			"paws",
			Util.newArrayListOfValues("masculine","padded"),
			Util.newArrayListOfValues("feminine", "soft", "padded", "delicate", "slender"),
			"toe",
			"toes",
			Util.newArrayListOfValues("masculine", "padded"),
			Util.newArrayListOfValues("feminine", "soft", "padded", "delicate", "slender"),
			"footjob",
			"[npc.SheHasFull] paw-like feet.",
			Util.newArrayListOfValues(
					FootStructure.PLANTIGRADE,
					FootStructure.DIGITIGRADE)) {
	};

	public static AbstractFootType HOOFS = new AbstractFootType("hoof-like",
			"hoof",
			"hoofs",
			Util.newArrayListOfValues("masculine","hard"),
			Util.newArrayListOfValues("feminine", "delicate", "hard"),
			"hoof",
			"hoofs",
			Util.newArrayListOfValues("masculine", "hard"),
			Util.newArrayListOfValues("feminine", "hard", "delicate"),
			"hoofjob",
			"[npc.SheHasFull] hoofs in place of feet.",
			Util.newArrayListOfValues(
					FootStructure.UNGULIGRADE)) {
	};

	public static AbstractFootType TALONS = new AbstractFootType("bird-like",
			"talon",
			"talons",
			Util.newArrayListOfValues("masculine","clawed"),
			Util.newArrayListOfValues("feminine", "clawed", "slender"),
			"claw",
			"claws",
			Util.newArrayListOfValues("masculine", "sharp"),
			Util.newArrayListOfValues("feminine", "sharp", "slender"),
			"clawjob",
			"[npc.SheHasFull] bird-like talons in place of feet.",
			Util.newArrayListOfValues(
					FootStructure.DIGITIGRADE)) {
	};

}


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

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.lilithsthrone.game.character.GameCharacter;
import com.lilithsthrone.game.character.body.Body;
import com.lilithsthrone.game.character.race.Race;
import com.lilithsthrone.game.dialogue.utils.UtilText;

/**
 * @since 0.1.83
 * @version 0.2.11
 * @author Innoxia
 */
public enum HairType implements BodyPartTypeInterface {
	HUMAN(BodyCoveringType.HAIR_HUMAN, Race.HUMAN),

	ANGEL(BodyCoveringType.HAIR_ANGEL, Race.ANGEL),

	DEMON_COMMON(BodyCoveringType.HAIR_DEMON, Race.DEMON),

	DOG_MORPH(BodyCoveringType.HAIR_CANINE_FUR, Race.DOG_MORPH),

	LYCAN(BodyCoveringType.HAIR_LYCAN_FUR, Race.WOLF_MORPH),

	FOX_MORPH(BodyCoveringType.HAIR_FOX_FUR, Race.FOX_MORPH),

	CAT_MORPH(BodyCoveringType.HAIR_FELINE_FUR, Race.CAT_MORPH),

	CAT_MORPH_SIDEFLUFF(BodyCoveringType.HAIR_FELINE_FUR, Race.CAT_MORPH),

	COW_MORPH(BodyCoveringType.HAIR_BOVINE_FUR, Race.COW_MORPH),

	ALLIGATOR_MORPH(BodyCoveringType.HAIR_SCALES_ALLIGATOR, Race.ALLIGATOR_MORPH),

	SQUIRREL_MORPH(BodyCoveringType.HAIR_SQUIRREL_FUR, Race.SQUIRREL_MORPH),

	RAT_MORPH(BodyCoveringType.HAIR_RAT_FUR, Race.RAT_MORPH),

	RABBIT_MORPH(BodyCoveringType.HAIR_RABBIT_FUR, Race.RABBIT_MORPH),

	BAT_MORPH(BodyCoveringType.HAIR_BAT_FUR, Race.BAT_MORPH),

	HORSE_MORPH(BodyCoveringType.HAIR_HORSE_HAIR, Race.HORSE_MORPH),

	REINDEER_MORPH(BodyCoveringType.HAIR_REINDEER_FUR, Race.REINDEER_MORPH),

	HARPY(BodyCoveringType.HAIR_HARPY, Race.HARPY);

	private BodyCoveringType coveringType;
	private Race race;

	private HairType(BodyCoveringType coveringType, Race race) {
		this.coveringType = coveringType;
		this.race = race;
	}

	/**
	 * Use instead of <i>valueOf()</i>.
	 */
	public static HairType getTypeFromString(String value) {
		if(value.equals("IMP")) {
			value = "DEMON_COMMON";
		}
		return valueOf(value);
	}

	@Override
	public String getDeterminer(GameCharacter gc) {
		return "a head of";
	}

	@Override
	public boolean isDefaultPlural() {
		switch(coveringType) {
			case HAIR_HARPY:
			case HAIR_SCALES_ALLIGATOR:
				return true;
			default:
				return false;
		}
	}

	@Override
	public String getNameSingular(GameCharacter gc) {
		switch(coveringType) {
			case HAIR_HARPY:
				return "head-feather";
			case HAIR_SCALES_ALLIGATOR:
				return "head-scale";
			case SLIME_HAIR:
				return "slime-hair";
			default:
				return "hair";
		}
	}

	@Override
	public String getNamePlural(GameCharacter gc) {
		switch(coveringType) {
			case HAIR_HARPY:
				return "head-feathers";
			case HAIR_SCALES_ALLIGATOR:
				return "head-scales";
			case SLIME_HAIR:
				return "slime-hair";
			default:
				return "hair";
		}
	}

	@Override
	public String getDescriptor(GameCharacter gc) {
		switch(this){
			case ANGEL:
				return UtilText.returnStringAtRandom("angelic");
			case CAT_MORPH:
				return UtilText.returnStringAtRandom("cat-like");
			case CAT_MORPH_SIDEFLUFF:
				return UtilText.returnStringAtRandom("cat-like");
			case COW_MORPH:
				return UtilText.returnStringAtRandom("cow-like");
			case DEMON_COMMON:
				return UtilText.returnStringAtRandom("demonic");
			case DOG_MORPH:
				return UtilText.returnStringAtRandom("dog-like");
			case SQUIRREL_MORPH:
				return UtilText.returnStringAtRandom("squirrel-like");
			case ALLIGATOR_MORPH:
				return UtilText.returnStringAtRandom("alligator-like");
			case HARPY:
				return UtilText.returnStringAtRandom("bird-like");
			case HORSE_MORPH:
				return UtilText.returnStringAtRandom("horse-like");
			case REINDEER_MORPH:
				return UtilText.returnStringAtRandom("reindeer-like");
			case HUMAN:
				return UtilText.returnStringAtRandom("");
			case LYCAN:
				return UtilText.returnStringAtRandom("wolf-like");
			case FOX_MORPH:
				return UtilText.returnStringAtRandom("fox-like");
			case BAT_MORPH:
				return UtilText.returnStringAtRandom("bat-like");
			case RAT_MORPH:
				return UtilText.returnStringAtRandom("rat-like");
			case RABBIT_MORPH:
				return UtilText.returnStringAtRandom("rabbit-like");
		}
		return "";
	}

	@Override
	public BodyCoveringType getBodyCoveringType(Body body) {
		return coveringType;
	}

	@Override
	public Race getRace() {
		return race;
	}

	@Override
	public String getTransformName() {
		switch(this){
			case ANGEL:
				return "angelic";
			case CAT_MORPH:
				return "feline";
			case CAT_MORPH_SIDEFLUFF:
				return UtilText.returnStringAtRandom("feline sidefluff");
			case DEMON_COMMON:
				return "demonic";
			case DOG_MORPH:
				return "canine";
			case COW_MORPH:
				return "bovine";
			case SQUIRREL_MORPH:
				return "squirrel";
			case ALLIGATOR_MORPH:
				return "alligator";
			case HARPY:
				return "harpy";
			case HORSE_MORPH:
				return "equine";
			case REINDEER_MORPH:
				return "reindeer";
			case HUMAN:
				return "human";
			case LYCAN:
				return "wolf";
			case FOX_MORPH:
				return "fox";
			case BAT_MORPH:
				return "bat";
			case RAT_MORPH:
				return "rat";
			case RABBIT_MORPH:
				return "rabbit";
		}
		return "";
	}

	private static Map<Race, List<HairType>> typesMap = new HashMap<>();
	public static List<HairType> getHairTypes(Race r) {
		if(typesMap.containsKey(r)) {
			return typesMap.get(r);
		}

		List<HairType> types = new ArrayList<>();
		for(HairType type : HairType.values()) {
			if(type.getRace()==r) {
				types.add(type);
			}
		}
		typesMap.put(r, types);
		return types;
	}
}


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

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.lilithsthrone.game.character.race.Race;
import com.lilithsthrone.utils.Util;

/**
 *
 * @since 0.1.0
 * @version 0.3.1
 * @author Innoxia
 */
public class HornType {

	//TODO If any more horn types are added, check to see that the potion TFs still work. (5 types is currently the maximum.)

	public static final AbstractHornType NONE = new AbstractHornType(
			BodyCoveringType.HORN,
			Race.NONE,
			2,
			"none",
			"",
			"",
			new ArrayList<>(),
			new ArrayList<>(),
			"
[npc.Name] now [npc.has] [style.boldTfGeneric(no horns)].",
			"") {
	};

	// Cows:

	public static final AbstractHornType BOVINE_CURVED = new AbstractHornType(
			BodyCoveringType.HORN,
			Race.COW_MORPH,
			2,
			"curved",
			"horn",
			"horns",
			Util.newArrayListOfValues("curved", "bovine"),
			Util.newArrayListOfValues("curved", "bovine", "smooth"),
			"slightly-curved #IFnpc.getTotalHorns()==1#THEN[npc.horn]#ELSE[npc.horns]#ENDIF."
					+ "
[npc.Name] now [npc.has] [npc.hornsDeterminer] [style.boldTfGeneric(curved #IFnpc.getTotalHorns()==1#THEN[npc.horn]#ELSE[npc.horns]#ENDIF)].",
			"[npc.HornsDeterminer] [npc.hornSize], [npc.hornColour(true)], curved #IFnpc.getTotalHorns()==1#THEN[npc.horn] grows#ELSE[npc.horns] grow#ENDIF out of the #IFnpc.getHornsPerRow()==1#THENmiddle#ELSEupper sides#ENDIF of [npc.her] forehead.") {
	};

	public static final AbstractHornType BOVINE_STRAIGHT = new AbstractHornType(
			BodyCoveringType.HORN,
			Race.COW_MORPH,
			2,
			"straight",
			"horn",
			"horns",
			Util.newArrayListOfValues("straight", "bovine"),
			Util.newArrayListOfValues("straight", "bovine", "smooth"),
			"sleek, straight #IFnpc.getTotalHorns()==1#THEN[npc.horn]#ELSE[npc.horns]#ENDIF."
					+ "
[npc.Name] now [npc.has] [npc.hornsDeterminer] [style.boldTfGeneric(straight #IFnpc.getTotalHorns()==1#THEN[npc.horn]#ELSE[npc.horns]#ENDIF)].",
			"[npc.HornsDeterminer] [npc.hornSize], [npc.hornColour(true)], straight #IFnpc.getTotalHorns()==1#THEN[npc.horn] grows#ELSE[npc.horns] grow#ENDIF out of the #IFnpc.getHornsPerRow()==1#THENmiddle#ELSEupper sides#ENDIF of [npc.her] forehead.") {
	};

	// Reindeer:

	public static final AbstractHornType REINDEER_RACK = new AbstractHornType(
			BodyCoveringType.ANTLER_REINDEER,
			Race.REINDEER_MORPH,
			2,
			"multi-branched",
			"antler",
			"antlers",
			Util.newArrayListOfValues("multi-branched", "reindeer"),
			Util.newArrayListOfValues("multi-branched", "reindeer"),
			"branching, multi-pronged #IFnpc.getTotalHorns()==1#THEN[npc.horn]#ELSE[npc.horns]#ENDIF."
					+ "
[npc.Name] now [npc.has] [npc.hornsDeterminer] [style.boldTfGeneric(reindeer-like #IFnpc.getTotalHorns()==1#THEN[npc.horn]#ELSE[npc.horns]#ENDIF)].",
			"[npc.HornsDeterminer] [npc.hornSize], [npc.hornColour(true)], multi-branched #IFnpc.getTotalHorns()==1#THEN[npc.horn] grows#ELSE[npc.horns] grow#ENDIF out of the #IFnpc.getHornsPerRow()==1#THENmiddle#ELSEupper sides#ENDIF of [npc.her] forehead.") {
	};

	// Horse:

	public static final AbstractHornType HORSE_STRAIGHT = new AbstractHornType(
			BodyCoveringType.HORN,
			Race.HORSE_MORPH,
			1,
			"unicorn",
			"horn",
			"horns",
			Util.newArrayListOfValues("straight", "twirling", "unicorn"),
			Util.newArrayListOfValues("straight", "twirling", "unicorn"),
			"straight, twirling unicorn's #IFnpc.getTotalHorns()==1#THEN[npc.horn]#ELSE[npc.horns]#ENDIF."
					+ "
[npc.Name] now [npc.has] [npc.hornsDeterminer] [style.boldTfGeneric(unicorn #IFnpc.getTotalHorns()==1#THEN[npc.horn]#ELSE[npc.horns]#ENDIF)].",
			"[npc.HornsDeterminer] [npc.hornSize], [npc.hornColour(true)], unicorn's #IFnpc.getTotalHorns()==1#THEN[npc.horn] grows#ELSE[npc.horns] grow#ENDIF out of the #IFnpc.getHornsPerRow()==1#THENmiddle#ELSEupper sides#ENDIF of [npc.her] forehead.") {
	};

	// Demons:

	public static final AbstractHornType CURLED = new AbstractHornType(
			BodyCoveringType.HORN,
			Race.DEMON,
			2,
			"curled",
			"horn",
			"horns",
			Util.newArrayListOfValues("curled", "demonic"),
			Util.newArrayListOfValues("curled", "demonic", "smooth"),
			"circular-curling #IFnpc.getTotalHorns()==1#THEN[npc.horn]#ELSE[npc.horns]#ENDIF."
					+ "
[npc.Name] now [npc.has] [npc.hornsDeterminer] [style.boldTfGeneric(curled #IFnpc.getTotalHorns()==1#THEN[npc.horn]#ELSE[npc.horns]#ENDIF)].",
			"[npc.HornsDeterminer] [npc.hornSize], [npc.hornColour(true)], circular-curling #IFnpc.getTotalHorns()==1#THEN[npc.horn] grows#ELSE[npc.horns] grow#ENDIF out of the #IFnpc.getHornsPerRow()==1#THENmiddle#ELSEupper sides#ENDIF of [npc.her] forehead.") {
	};

	public static final AbstractHornType SPIRAL = new AbstractHornType(
			BodyCoveringType.HORN,
			Race.DEMON,
			2,
			"spiral", //Rasen no Chikara
			"horn",
			"horns",
			Util.newArrayListOfValues("spiral", "demonic"),
			Util.newArrayListOfValues("spiral", "demonic", "smooth"),
			"twisted, spiralling #IFnpc.getTotalHorns()==1#THEN[npc.horn]#ELSE[npc.horns]#ENDIF."
					+ "
[npc.Name] now [npc.has] [npc.hornsDeterminer] [style.boldTfGeneric(spiral #IFnpc.getTotalHorns()==1#THEN[npc.horn]#ELSE[npc.horns]#ENDIF)].",
			"[npc.HornsDeterminer] [npc.hornSize], [npc.hornColour(true)], spiralling #IFnpc.getTotalHorns()==1#THEN[npc.horn] grows#ELSE[npc.horns] grow#ENDIF out of the #IFnpc.getHornsPerRow()==1#THENmiddle#ELSEupper sides#ENDIF of [npc.her] forehead.") {
	};

	public static final AbstractHornType CURVED = new AbstractHornType(
			BodyCoveringType.HORN,
			Race.DEMON,
			2,
			"curved",
			"horn",
			"horns",
			Util.newArrayListOfValues("curved", "demonic"),
			Util.newArrayListOfValues("curved", "demonic", "smooth"),
			"slightly-curved #IFnpc.getTotalHorns()==1#THEN[npc.horn]#ELSE[npc.horns]#ENDIF."
					+ "
[npc.Name] now [npc.has] [npc.hornsDeterminer] [style.boldTfGeneric(curved #IFnpc.getTotalHorns()==1#THEN[npc.horn]#ELSE[npc.horns]#ENDIF)].",
			"[npc.HornsDeterminer] [npc.hornSize], [npc.hornColour(true)], curved #IFnpc.getTotalHorns()==1#THEN[npc.horn] grows#ELSE[npc.horns] grow#ENDIF out of the #IFnpc.getHornsPerRow()==1#THENmiddle#ELSEupper sides#ENDIF of [npc.her] forehead.") {
	};

	public static final AbstractHornType SWEPT_BACK = new AbstractHornType(
			BodyCoveringType.HORN,
			Race.DEMON,
			2,
			"swept-back",
			"horn",
			"horns",
			Util.newArrayListOfValues("swept-back", "demonic"),
			Util.newArrayListOfValues("swept-back", "demonic", "smooth"),
			"sleek #IFnpc.getTotalHorns()==1#THEN[npc.horn]#ELSE[npc.horns]#ENDIF, before sweeping back and curving over [npc.her] head."
					+ "
[npc.Name] now [npc.has] [npc.hornsDeterminer] [style.boldTfGeneric(swept-back #IFnpc.getTotalHorns()==1#THEN[npc.horn]#ELSE[npc.horns]#ENDIF)].",
			"[npc.HornsDeterminer] [npc.hornSize], [npc.hornColour(true)], swept-back #IFnpc.getTotalHorns()==1#THEN[npc.horn] grows#ELSE[npc.horns] grow#ENDIF out of the #IFnpc.getHornsPerRow()==1#THENmiddle#ELSEupper sides#ENDIF of [npc.her] forehead.") {
	};

	public static final AbstractHornType STRAIGHT = new AbstractHornType(
			BodyCoveringType.HORN,
			Race.DEMON,
			2,
			"straight",
			"horn",
			"horns",
			Util.newArrayListOfValues("straight", "demonic"),
			Util.newArrayListOfValues("straight", "demonic", "smooth"),
			"sleek, straight horns."
					+ "
[npc.Name] now [npc.has] [npc.hornsDeterminer] [style.boldTfGeneric(straight #IFnpc.getTotalHorns()==1#THEN[npc.horn]#ELSE[npc.horns]#ENDIF)].",
			"[npc.HornsDeterminer] [npc.hornSize], [npc.hornColour(true)], straight #IFnpc.getTotalHorns()==1#THEN[npc.horn] grows#ELSE[npc.horns] grow#ENDIF out of the #IFnpc.getHornsPerRow()==1#THENmiddle#ELSEupper sides#ENDIF of [npc.her] forehead.") {
	};

	private static List<AbstractHornType> allHornTypes;
	private static Map<AbstractHornType, String> hornToIdMap = new HashMap<>();
	private static Map<String, AbstractHornType> idToHornMap = new HashMap<>();

	static {
		allHornTypes = new ArrayList<>();

		// Add in hard-coded horn types:
		Field[] fields = HornType.class.getFields();

		for(Field f : fields){
			if (AbstractHornType.class.isAssignableFrom(f.getType())) {

				AbstractHornType ct;
				try {
					ct = ((AbstractHornType) f.get(null));

					hornToIdMap.put(ct, f.getName());
					idToHornMap.put(f.getName(), ct);

					allHornTypes.add(ct);

				} catch (IllegalArgumentException | IllegalAccessException e) {
					e.printStackTrace();
				}
			}
		}
	}

	public static AbstractHornType getHornTypeFromId(String id) {
		id = Util.getClosestStringMatch(id, idToHornMap.keySet());
		return idToHornMap.get(id);
	}

	public static String getIdFromHornType(AbstractHornType hornType) {
		return hornToIdMap.get(hornType);
	}

	public static List<AbstractHornType> getAllHornTypes() {
		return allHornTypes;
	}

	private static Map<Race, List<AbstractHornType>> typesMap = new HashMap<>();
	public static List<AbstractHornType> getHornTypes(Race r) {
		if(typesMap.containsKey(r)) {
			return typesMap.get(r);
		}

		List<AbstractHornType> types = new ArrayList<>();
		for(AbstractHornType type : HornType.getAllHornTypes()) {
			if(type.getRace()==r) {
				types.add(type);
			}
		}
		typesMap.put(r, types);
		if(types.isEmpty()) {
			types.add(HornType.NONE);
		}
		return types;
	}
}


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

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.lilithsthrone.game.character.GameCharacter;
import com.lilithsthrone.game.character.body.valueEnums.LegConfiguration;
import com.lilithsthrone.game.character.race.Race;
import com.lilithsthrone.game.dialogue.utils.UtilText;
import com.lilithsthrone.game.inventory.InventorySlot;
import com.lilithsthrone.game.inventory.ItemTag;
import com.lilithsthrone.game.inventory.clothing.BodyPartClothingBlock;
import com.lilithsthrone.utils.Util;

/**
 * @since 0.1.0
 * @version 0.3.1
 * @author Innoxia
 */
public class LegType {

	public static AbstractLegType HUMAN = new AbstractLegType(BodyCoveringType.HUMAN,
			Race.HUMAN,
			FootStructure.PLANTIGRADE,
			FootType.HUMANOID,
			"a pair of",
			"leg",
			"legs",
			Util.newArrayListOfValues("masculine"),
			Util.newArrayListOfValues("feminine"),
			Util.newArrayListOfValues(""),
			Util.newArrayListOfValues(""),
			Util.newArrayListOfValues(""),
			Util.newArrayListOfValues(""),
			"They rapidly shift into normal-looking human legs, complete with human feet.
"
				+ "[npc.She] now [npc.has] [style.boldHuman(human legs and feet)], which are covered in [npc.legFullDescription].",
			"[npc.Her] legs and feet are human, and are [npc.materialCompositionDescriptor] [npc.legFullDescription(true)].",
			Util.newArrayListOfValues(
					LegConfiguration.BIPEDAL)) {
	};

	public static AbstractLegType ANGEL = new AbstractLegType(BodyCoveringType.ANGEL,
			Race.ANGEL,
			FootStructure.PLANTIGRADE,
			FootType.HUMANOID,
			"a pair of",
			"leg",
			"legs",
			Util.newArrayListOfValues("masculine", "radiant", "angelic"),
			Util.newArrayListOfValues("feminine", "radiant", "angelic"),
			Util.newArrayListOfValues("angelic"),
			Util.newArrayListOfValues("angelic"),
			Util.newArrayListOfValues("angelic"),
			Util.newArrayListOfValues("angelic"),
			"They quickly shift into a pair of smooth, slender legs, and [npc.she] [npc.verb(let)] out a gasp as a layer of flawless, angelic skin rapidly grows to cover them."
				+ " As they finish transforming, [npc.she] almost [npc.verb(lose)] [npc.her] balance as the bones in [npc.her] feet start to shift and rearrange themselves."
				+ " After a moment, they've transformed into slender, human-like feet, ending in soft, delicate toes.
"
				+ "[npc.Name] now [npc.has] [style.boldAngel(angelic legs and feet)], which are covered in [npc.legFullDescription].",
			"[npc.Her] legs and feet are human in shape, but are [npc.materialCompositionDescriptor] [npc.legFullDescription(true)].",
			Util.newArrayListOfValues(
					LegConfiguration.BIPEDAL)) {
	};

	public static AbstractLegType DEMON_COMMON = new AbstractLegType(BodyCoveringType.DEMON_COMMON,
			Race.DEMON,
			FootStructure.PLANTIGRADE,
			FootType.HUMANOID,
			"a pair of",
			"leg",
			"legs",
			Util.newArrayListOfValues("masculine", "demonic"),
			Util.newArrayListOfValues("feminine", "flawless", "demonic"),
			Util.newArrayListOfValues("demonic"),
			Util.newArrayListOfValues("demonic"),
			Util.newArrayListOfValues("demonic"),
			Util.newArrayListOfValues("demonic"),
			"-",
			"[npc.Her] legs and feet are human in shape, but are [npc.materialCompositionDescriptor] [npc.legFullDescription(true)].",
			Util.newArrayListOfValues(
					LegConfiguration.BIPEDAL)) {
		@Override
		public String getTransformationDescription(GameCharacter owner) {
			if (!owner.isShortStature()) {
				return UtilText.parse(owner,
						" They quickly shift into a pair of smooth, slender legs, and [npc.she] [npc.verb(let)] out a gasp as a layer of flawless, demonic skin rapidly grows to cover them."
						+ " As they finish transforming, [npc.she] almost [npc.verb(lose)] [npc.her] balance as the bones in [npc.her] feet start to shift and rearrange themselves."
						+ " After a moment, they've transformed into slender human-like feet, ending in soft, delicate toes.
"
						+ "[npc.Name] now [npc.has] [style.boldDemon(demonic legs and feet)], which are covered in [npc.legFullDescription]."
					+ "
");
			} else {
				return UtilText.parse(owner,
						" They quickly shift into a pair of smooth, slender legs, and [npc.she] [npc.verb(let)] out a gasp as a layer of flawless, impish skin rapidly grows to cover them."
						+ " As they finish transforming, [npc.she] almost [npc.verb(lose)] [npc.her] balance as the bones in [npc.her] feet start to shift and rearrange themselves."
						+ " After a moment, they've transformed into slender human-like feet, ending in soft, delicate toes.
"
						+ "[npc.Name] now [npc.has] [style.boldImp(impish legs and feet)], which are covered in [npc.legFullDescription]."
					+ "
");
			}
		}
	};

	public static AbstractLegType DEMON_HOOFED = new AbstractLegType(BodyCoveringType.DEMON_COMMON,
			Race.DEMON,
			FootStructure.UNGULIGRADE,
			FootType.HOOFS,
			"a pair of",
			"leg",
			"legs",
			Util.newArrayListOfValues("masculine", "demonic"),
			Util.newArrayListOfValues("feminine", "flawless", "demonic"),
			Util.newArrayListOfValues("demonic"),
			Util.newArrayListOfValues("demonic"),
			Util.newArrayListOfValues("demonic"),
			Util.newArrayListOfValues("demonic"),
			"-",
			"[npc.Her] demonic legs are [npc.materialCompositionDescriptor] [npc.legFullDescription(true)], and [npc.her] feet are formed into hard hoofs.",
			Util.newArrayListOfValues(
					LegConfiguration.BIPEDAL,
					LegConfiguration.TAUR)) {
		@Override
		public String getTransformationDescription(GameCharacter owner) {
			if (!owner.isShortStature()) {
				return UtilText.parse(owner,
							" They quickly shift into a pair of smooth, slender legs, and [npc.name] [npc.verb(let)] out a gasp as a layer of flawless, demonic skin rapidly grows to cover them."
							+ " As [npc.her] new skin spreads down to the ends of [npc.her] toes, they suddenly push together, and [npc.she] [npc.verb(let)] out a cry as a thick, hoof-like nail grows in their place,"
								+ " quickly transforming to turn [npc.her] feet into hard, demonic hoofs."
							+ " As the transformation ends, [npc.she] [npc.verb(see)] that [npc.her] new skin smoothly transitions into the [npc.skin] covering the rest of [npc.her] body at [npc.her] upper-thigh.
"
							+ "[npc.NameIsFull] left with [style.boldDemon(demonic legs and hoofed feet)], which are covered in [npc.legFullDescription]."
						+ "
");
			} else {
				return UtilText.parse(owner,
						" They quickly shift into a pair of smooth, slender legs, and [npc.name] [npc.verb(let)] out a gasp as a layer of flawless, demonic skin rapidly grows to cover them."
						+ " As [npc.her] new skin spreads down to the ends of [npc.her] toes, they suddenly push together, and [npc.she] [npc.verb(let)] out a cry as a thick, hoof-like nail grows in their place,"
							+ " quickly transforming to turn [npc.her] feet into hard, demonic hoofs."
						+ " As the transformation ends, [npc.she] [npc.verb(see)] that [npc.her] new skin smoothly transitions into the [npc.skin] covering the rest of [npc.her] body at [npc.her] upper-thigh.
"
						+ "[npc.NameIsFull] left with [style.boldImp(impish legs and hoofed feet)], which are covered in [npc.legFullDescription]."
					+ "
");
			}
		}
		@Override
		public String getTransformName() {
			return "demonic-hoofed";
		}
		private BodyPartClothingBlock clothingBlock = new BodyPartClothingBlock(
				Util.newArrayListOfValues(
						InventorySlot.FOOT),
				Race.DEMON,
				"Due to the shape of [npc.namePos] demonic hoofs, only hoof-compatible clothing can be worn in this slot.",
				Util.newArrayListOfValues(ItemTag.FITS_HOOFS, ItemTag.FITS_HOOFS_EXCLUSIVE));
		@Override
		public BodyPartClothingBlock getBodyPartClothingBlock() {
			return clothingBlock;
		}
	};

	public static AbstractLegType COW_MORPH = new AbstractLegType(BodyCoveringType.BOVINE_FUR,
			Race.COW_MORPH,
			FootStructure.UNGULIGRADE,
			FootType.HOOFS,
			"a pair of",
			"leg",
			"legs",
			Util.newArrayListOfValues("masculine", "hoofed", "furry", "fur-coated", "anthropomorphic, cow-like"),
			Util.newArrayListOfValues("feminine", "hoofed", "furry", "fur-coated", "anthropomorphic, cow-like"),
			Util.newArrayListOfValues("cow-like", "bovine"),
			Util.newArrayListOfValues("cow-like", "bovine"),
			Util.newArrayListOfValues("cow-like", "bovine"),
			Util.newArrayListOfValues("cow-like", "bovine"),
			"A layer of short, cow-like hair quickly grows over [npc.her] legs as they shift into a new form."
				+ " As [npc.her] new fur spreads down to the ends of [npc.her] toes, they suddenly push together, and [npc.she] [npc.verb(let)] out a cry as a thick, hoof-like nail grows in their place,"
					+ " before quickly transforming to turn [npc.her] feet into cow-like hoofs."
				+ " As the transformation ends, [npc.she] [npc.verb(see)] that [npc.her] new fur smoothly transitions into the [npc.skin] covering the rest of [npc.her] body at [npc.her] upper-thigh.
"
				+ "[npc.Name] now [npc.has] anthropomorphic, [style.boldCowMorph(cow-like legs and hoofed feet)], which are covered in [npc.legFullDescription].",
			"[npc.Her] legs are [npc.materialCompositionDescriptor] [npc.legFullDescription(true)], and [npc.her] feet are formed into anthropomorphic cow-like hoofs.",
			Util.newArrayListOfValues(
					LegConfiguration.BIPEDAL,
					LegConfiguration.TAUR)) {

		private BodyPartClothingBlock clothingBlock = new BodyPartClothingBlock(
				Util.newArrayListOfValues(
						InventorySlot.FOOT),
				Race.COW_MORPH,
				"Due to the shape of [npc.namePos] bovine hoofs, only hoof-compatible clothing can be worn in this slot.",
				Util.newArrayListOfValues(ItemTag.FITS_HOOFS, ItemTag.FITS_HOOFS_EXCLUSIVE));
		@Override
		public BodyPartClothingBlock getBodyPartClothingBlock() {
			return clothingBlock;
		}
	};

	public static AbstractLegType DOG_MORPH = new AbstractLegType(BodyCoveringType.CANINE_FUR,
			Race.DOG_MORPH,
			FootStructure.DIGITIGRADE,
			FootType.PAWS,
			"a pair of",
			"leg",
			"legs",
			Util.newArrayListOfValues("masculine", "furry", "fur-coated", "anthropomorphic, dog-like"),
			Util.newArrayListOfValues("feminine", "furry", "fur-coated", "anthropomorphic, dog-like"),
			Util.newArrayListOfValues("dog-like", "canine"),
			Util.newArrayListOfValues("dog-like", "canine"),
			Util.newArrayListOfValues("dog-like", "canine"),
			Util.newArrayListOfValues("dog-like", "canine"),
			"A layer of dog-like fur quickly grows over [npc.her] legs as they shift into a new form."
				+ " As [npc.her] new fur spreads down to the ends of [npc.her] toes, [npc.her] toenails thicken into little blunt claws, and leathery pads grow to cover [npc.her] soles, leaving [npc.herHim] with paw-like feet."
				+ " As the transformation ends, [npc.she] [npc.verb(see)] that [npc.her] new fur smoothly transitions into the [npc.skin] covering the rest of [npc.her] body at [npc.her] upper-thigh.
"
				+ "[npc.Name] now [npc.has] anthropomorphic, [style.boldDogMorph(dog-like legs and feet)], which are covered in [npc.legFullDescription].",
			"[npc.Her] legs are [npc.materialCompositionDescriptor] [npc.legFullDescription(true)], and [npc.her] feet are formed into anthropomorphic dog-like paws, complete with little blunt claws and leathery pads.",
			Util.newArrayListOfValues(
					LegConfiguration.BIPEDAL,
					LegConfiguration.TAUR)) {
	};

	public static AbstractLegType WOLF_MORPH = new AbstractLegType(BodyCoveringType.LYCAN_FUR,
			Race.WOLF_MORPH,
			FootStructure.DIGITIGRADE,
			FootType.PAWS,
			"a pair of",
			"leg",
			"legs",
			Util.newArrayListOfValues("masculine", "furry", "fur-coated", "anthropomorphic, wolf-like"),
			Util.newArrayListOfValues("feminine", "furry", "fur-coated", "anthropomorphic, wolf-like"),
			Util.newArrayListOfValues("wolf-like", "lupine"),
			Util.newArrayListOfValues("wolf-like", "lupine"),
			Util.newArrayListOfValues("wolf-like", "lupine"),
			Util.newArrayListOfValues("wolf-like", "lupine"),
			"A layer of wolf-like fur quickly grows over [npc.her] legs as they shift into a new form."
				+ " As [npc.her] new fur spreads down to the ends of [npc.her] toes, [npc.her] toenails thicken into sharp claws, and tough leathery pads grow to cover [npc.her] soles, leaving [npc.herHim] with paw-like feet."
				+ " As the transformation ends, [npc.she] [npc.verb(see)] that [npc.her] new fur smoothly transitions into the [npc.skin] covering the rest of [npc.her] body at [npc.her] upper-thigh.
"
				+ "[npc.Name] now [npc.has] anthropomorphic, [style.boldWolfMorph(wolf-like legs and feet)], which are covered in [npc.legFullDescription].",
			"[npc.Her] legs are [npc.materialCompositionDescriptor] [npc.legFullDescription(true)], and [npc.her] feet are formed into anthropomorphic wolf-like paws, complete with sharp claws and tough leathery pads.",
			Util.newArrayListOfValues(
					LegConfiguration.BIPEDAL,
					LegConfiguration.TAUR)) {
	};

	public static AbstractLegType FOX_MORPH = new AbstractLegType(BodyCoveringType.FOX_FUR,
			Race.FOX_MORPH,
			FootStructure.DIGITIGRADE,
			FootType.PAWS,
			"a pair of",
			"leg",
			"legs",
			Util.newArrayListOfValues("masculine", "furry", "fur-coated", "anthropomorphic, fox-like"),
			Util.newArrayListOfValues("feminine", "furry", "fur-coated", "anthropomorphic, fox-like"),
			Util.newArrayListOfValues("fox-like", "vulpine"),
			Util.newArrayListOfValues("fox-like", "vulpine"),
			Util.newArrayListOfValues("fox-like", "vulpine"),
			Util.newArrayListOfValues("fox-like", "vulpine"),
			"A layer of fox-like fur quickly grows over [npc.her] legs as they shift into a new form."
				+ " As [npc.her] new fur spreads down to the ends of [npc.her] toes, [npc.her] toenails thicken into sharp claws, and little pads grow to cover [npc.her] soles, leaving [npc.herHim] with paw-like feet."
				+ " As the transformation ends, [npc.she] [npc.verb(see)] that [npc.her] new fur smoothly transitions into the [npc.skin] covering the rest of [npc.her] body at [npc.her] upper-thigh.
"
				+ "[npc.Name] now [npc.has] anthropomorphic, [style.boldFoxMorph(fox-like legs and feet)], which are covered in [npc.legFullDescription].",
			"[npc.Her] legs are [npc.materialCompositionDescriptor] [npc.legFullDescription(true)], and [npc.her] feet are formed into anthropomorphic fox-like paws, complete with sharp claws and tough leathery pads.",
			Util.newArrayListOfValues(
					LegConfiguration.BIPEDAL,
					LegConfiguration.TAUR)) {
	};

	public static AbstractLegType SQUIRREL_MORPH = new AbstractLegType(BodyCoveringType.SQUIRREL_FUR,
			Race.SQUIRREL_MORPH,
			FootStructure.DIGITIGRADE,
			FootType.PAWS,
			"a pair of",
			"leg",
			"legs",
			Util.newArrayListOfValues("masculine", "furry", "fur-coated", "anthropomorphic, squirrel-like"),
			Util.newArrayListOfValues("feminine", "furry", "fur-coated", "anthropomorphic, squirrel-like"),
			Util.newArrayListOfValues("squirrel-like"),
			Util.newArrayListOfValues("squirrel-like"),
			Util.newArrayListOfValues("squirrel-like"),
			Util.newArrayListOfValues("squirrel-like"),
			"A layer of squirrel-like fur quickly grows over [npc.her] legs as they shift into a new form."
				+ " As [npc.her] new fur spreads down to the ends of [npc.her] toes, [npc.her] toenails thicken into sharp claws, and little pink pads grow to cover [npc.her] soles, leaving [npc.herHim] with paw-like feet."
				+ " As the transformation ends, [npc.she] [npc.verb(see)] that [npc.her] new fur smoothly transitions into the [npc.skin] covering the rest of [npc.her] body at [npc.her] upper-thigh.
"
				+ "[npc.Name] now [npc.has] anthropomorphic, [style.boldSquirrelMorph(squirrel-like legs and feet)], which are covered in [npc.legFullDescription].",
			"[npc.Her] legs are [npc.materialCompositionDescriptor] [npc.legFullDescription(true)], and [npc.her] feet are formed into anthropomorphic squirrel-like paws, complete with claws and pink pads.",
			Util.newArrayListOfValues(
					LegConfiguration.BIPEDAL,
					LegConfiguration.TAUR)) {
	};

	public static AbstractLegType RAT_MORPH = new AbstractLegType(BodyCoveringType.RAT_FUR,
			Race.RAT_MORPH,
			FootStructure.DIGITIGRADE,
			FootType.PAWS,
			"a pair of",
			"leg",
			"legs",
			Util.newArrayListOfValues("masculine", "furry", "fur-coated", "anthropomorphic, rat-like"),
			Util.newArrayListOfValues("feminine", "furry", "fur-coated", "anthropomorphic, rat-like"),
			Util.newArrayListOfValues("rat-like"),
			Util.newArrayListOfValues("rat-like"),
			Util.newArrayListOfValues("rat-like"),
			Util.newArrayListOfValues("rat-like"),
			"A layer of rat-like fur quickly grows over [npc.her] legs as they shift into a new form."
				+ " As [npc.her] new fur spreads down to the ends of [npc.her] toes, [npc.her] toenails thicken into sharp claws, and little pink pads grow to cover [npc.her] soles, leaving [npc.herHim] with paw-like feet."
				+ " As the transformation ends, [npc.she] [npc.verb(see)] that [npc.her] new fur smoothly transitions into the [npc.skin] covering the rest of [npc.her] body at [npc.her] upper-thigh.
"
				+ "[npc.Name] now [npc.has] anthropomorphic, [style.boldRatMorph(rat-like legs and feet)], which are covered in [npc.legFullDescription].",
			"[npc.Her] legs are [npc.materialCompositionDescriptor] [npc.legFullDescription(true)], and [npc.her] feet are formed into anthropomorphic rat-like paws, complete with claws and leathery pads.",
			Util.newArrayListOfValues(
					LegConfiguration.BIPEDAL,
					LegConfiguration.TAUR)) {
	};

	public static AbstractLegType RABBIT_MORPH = new AbstractLegType(BodyCoveringType.RABBIT_FUR,
			Race.RABBIT_MORPH,
			FootStructure.DIGITIGRADE,
			FootType.PAWS,
			"a pair of",
			"leg",
			"legs",
			Util.newArrayListOfValues("masculine", "furry", "fur-coated", "anthropomorphic, rabbit-like"),
			Util.newArrayListOfValues("feminine", "furry", "fur-coated", "anthropomorphic, rabbit-like"),
			Util.newArrayListOfValues("rabbit-like"),
			Util.newArrayListOfValues("rabbit-like"),
			Util.newArrayListOfValues("rabbit-like"),
			Util.newArrayListOfValues("rabbit-like"),
			"A layer of rabbit-like fur quickly grows over [npc.her] legs as they shift into a new form."
				+ " As [npc.her] new fur spreads down to the ends of [npc.her] toes, [npc.her] toenails thicken into blunt claws, and soft little pads grow to cover [npc.her] soles, leaving [npc.herHim] with long, paw-like feet."
				+ " As the transformation ends, [npc.she] [npc.verb(see)] that [npc.her] new fur smoothly transitions into the [npc.skin] covering the rest of [npc.her] body at [npc.her] upper-thigh.
"
				+ "[npc.Name] now [npc.has] anthropomorphic, [style.boldRabbitMorph(rabbit-like legs and feet)], which are covered in [npc.legFullDescription].",
			"[npc.Her] legs are [npc.materialCompositionDescriptor] [npc.legFullDescription(true)], and [npc.her] feet are formed into long, anthropomorphic, rabbit-like paws, complete with blunt claws and soft pads.",
			Util.newArrayListOfValues(
					LegConfiguration.BIPEDAL,
					LegConfiguration.TAUR)) {
	};

	public static AbstractLegType BAT_MORPH = new AbstractLegType(BodyCoveringType.BAT_FUR,
			Race.BAT_MORPH,
			FootStructure.DIGITIGRADE,
			FootType.PAWS,
			"a pair of",
			"leg",
			"legs",
			Util.newArrayListOfValues("masculine", "furry", "fur-coated", "anthropomorphic, bat-like"),
			Util.newArrayListOfValues("feminine", "furry", "fur-coated", "anthropomorphic, bat-like"),
			Util.newArrayListOfValues("bat-like"),
			Util.newArrayListOfValues("bat-like"),
			Util.newArrayListOfValues("bat-like"),
			Util.newArrayListOfValues("bat-like"),
			"A layer of bat-like fur quickly grows over [npc.her] legs as they shift into a new form."
				+ " As [npc.her] new fur spreads down to the ends of [npc.her] toes, [npc.her] toenails thicken into sharp claws, and little pink pads grow to cover [npc.her] soles, leaving [npc.herHim] with paw-like feet."
				+ " As the transformation ends, [npc.she] [npc.verb(see)] that [npc.her] new fur smoothly transitions into the [npc.skin] covering the rest of [npc.her] body at [npc.her] upper-thigh.
"
				+ "[npc.Name] now [npc.has] anthropomorphic, [style.boldBatMorph(bat-like legs and feet)], which are covered in [npc.legFullDescription].",
			"[npc.Her] legs are [npc.materialCompositionDescriptor] [npc.legFullDescription(true)], and [npc.her] feet are formed into anthropomorphic bat-like paws, complete with claws and leathery pads.",
			Util.newArrayListOfValues(
					LegConfiguration.BIPEDAL)) {
	};

	public static AbstractLegType CAT_MORPH = new AbstractLegType(BodyCoveringType.FELINE_FUR,
			Race.CAT_MORPH,
			FootStructure.DIGITIGRADE,
			FootType.PAWS,
			"a pair of",
			"leg",
			"legs",
			Util.newArrayListOfValues("masculine", "furry", "fur-coated", "anthropomorphic, cat-like"),
			Util.newArrayListOfValues("feminine", "furry", "fur-coated", "anthropomorphic, cat-like"),
			Util.newArrayListOfValues("cat-like", "feline"),
			Util.newArrayListOfValues("cat-like", "feline"),
			Util.newArrayListOfValues("cat-like", "feline"),
			Util.newArrayListOfValues("cat-like", "feline"),
			"A layer of cat-like fur quickly grows over [npc.her] legs as they shift into a new form."
				+ " As [npc.her] new fur spreads down to the ends of [npc.her] toes, [npc.her] toenails thicken into sharp, retractable claws, and little pink pads grow to cover [npc.her] soles, leaving [npc.herHim] with paw-like feet."
				+ " As the transformation ends, [npc.she] [npc.verb(see)] that [npc.her] new fur smoothly transitions into the [npc.skin] covering the rest of [npc.her] body at [npc.her] upper-thigh.
"
				+ "[npc.Name] now [npc.has] anthropomorphic, [style.boldCatMorph(cat-like legs and feet)], which are covered in [npc.legFullDescription].",
			"[npc.Her] legs are [npc.materialCompositionDescriptor] [npc.legFullDescription(true)], and [npc.her] feet are formed into anthropomorphic cat-like paws, complete with retractable claws and pink pads.",
			Util.newArrayListOfValues(
					LegConfiguration.BIPEDAL,
					LegConfiguration.TAUR)) {
	};

	public static AbstractLegType ALLIGATOR_MORPH = new AbstractLegType(BodyCoveringType.ALLIGATOR_SCALES,
			Race.ALLIGATOR_MORPH,
			FootStructure.PLANTIGRADE,
			FootType.HUMANOID,
			"a pair of",
			"leg",
			"legs",
			Util.newArrayListOfValues("masculine", "scaly", "reptilian", "anthropomorphic, alligator-like"),
			Util.newArrayListOfValues("feminine", "scaly", "reptilian", "anthropomorphic, alligator-like"),
			Util.newArrayListOfValues("alligator-like", "scaly", "reptilian"),
			Util.newArrayListOfValues("alligator-like", "scaly", "reptilian"),
			Util.newArrayListOfValues("alligator-like", "scaly", "reptilian"),
			Util.newArrayListOfValues("alligator-like", "scaly", "reptilian"),
			"A layer of alligator-like scales quickly grows over [npc.her] legs as they shift into a new form."
				+ " As [npc.her] new scales spread down to the ends of [npc.her] toes, [npc.her] toenails thicken into sharp claws, and little scales grow to cover [npc.her] soles, leaving [npc.herHim] with alligator-like feet."
				+ " As the transformation ends, [npc.she] [npc.verb(see)] that [npc.her] new scales smoothly transitions into the [npc.skin] covering the rest of [npc.her] body at [npc.her] upper-thigh.
"
				+ "[npc.Name] now [npc.has] anthropomorphic, [style.boldGatorMorph(alligator-like legs and feet)], which are covered in [npc.legFullDescription].",
			"[npc.Her] legs are [npc.materialCompositionDescriptor] [npc.legFullDescription(true)], and [npc.her] feet are formed into anthropomorphic alligator-like feet, complete with sharp claws.",
			Util.newArrayListOfValues(
					LegConfiguration.BIPEDAL,
					LegConfiguration.TAUR)) {
	};

	public static AbstractLegType HORSE_MORPH = new AbstractLegType(BodyCoveringType.HORSE_HAIR,
			Race.HORSE_MORPH,
			FootStructure.UNGULIGRADE,
			FootType.HOOFS,
			"a pair of",
			"leg",
			"legs",
			Util.newArrayListOfValues("masculine", "hair-coated", "anthropomorphic, horse-like"),
			Util.newArrayListOfValues("feminine", "hair-coated", "anthropomorphic, horse-like"),
			Util.newArrayListOfValues("horse-like", "equine"),
			Util.newArrayListOfValues("horse-like", "equine"),
			Util.newArrayListOfValues("horse-like", "equine"),
			Util.newArrayListOfValues("horse-like", "equine"),
			"A layer of short, horse-like hair quickly grows over [npc.her] legs as they shift into a new form."
				+ " As [npc.her] new fur spreads down to the ends of [npc.her] toes, they suddenly push together, and [npc.she] [npc.verb(let)] out a cry as a thick, hoof-like nail grows in their place,"
					+ " before quickly transforming to turn [npc.her] feet into horse-like hoofs."
				+ " As the transformation ends, [npc.she] [npc.verb(see)] that [npc.her] new hair smoothly transitions into the [npc.skin] covering the rest of [npc.her] body at [npc.her] upper-thigh.
"
				+ "[npc.Name] now [npc.has] anthropomorphic, [style.boldHorseMorph(horse-like legs and hoofed feet)], which are covered in [npc.legFullDescription].",
			"[npc.Her] legs are [npc.materialCompositionDescriptor] [npc.legFullDescription(true)], and [npc.her] feet are formed into anthropomorphic horse-like hoofs.",
			Util.newArrayListOfValues(
					LegConfiguration.BIPEDAL,
					LegConfiguration.TAUR)) {

		private BodyPartClothingBlock clothingBlock = new BodyPartClothingBlock(
				Util.newArrayListOfValues(
						InventorySlot.FOOT),
				Race.HORSE_MORPH,
				"Due to the shape of [npc.namePos] equine hoofs, only hoof-compatible clothing can be worn in this slot.",
				Util.newArrayListOfValues(ItemTag.FITS_HOOFS, ItemTag.FITS_HOOFS_EXCLUSIVE));
		@Override
		public BodyPartClothingBlock getBodyPartClothingBlock() {
			return clothingBlock;
		}
	};

	public static AbstractLegType REINDEER_MORPH = new AbstractLegType(BodyCoveringType.REINDEER_FUR,
			Race.REINDEER_MORPH,
			FootStructure.UNGULIGRADE,
			FootType.HOOFS,
			"a pair of",
			"leg",
			"legs",
			Util.newArrayListOfValues("masculine", "fur-coated", "anthropomorphic, reindeer-like"),
			Util.newArrayListOfValues("feminine", "fur-coated", "anthropomorphic, reindeer-like"),
			Util.newArrayListOfValues("reindeer-like"),
			Util.newArrayListOfValues("reindeer-like"),
			Util.newArrayListOfValues("reindeer-like"),
			Util.newArrayListOfValues("reindeer-like"),
			"A layer of furry, reindeer-like hair quickly grows over [npc.her] legs as they shift into a new form."
				+ " As [npc.her] new fur spreads down to the ends of [npc.her] toes, they suddenly push together, and [npc.she] [npc.verb(let)] out a cry as a crescent-shaped, cloven hoof grows in their place,"
					+ " before quickly transforming to turn [npc.her] feet into reindeer-like hoofs."
				+ " As the transformation ends, [npc.she] [npc.verb(see)] that [npc.her] new fur smoothly transitions into the [npc.skin] covering the rest of [npc.her] body at [npc.her] upper-thigh.
"
				+ "[npc.Name] now [npc.has] anthropomorphic, [style.boldReindeerMorph(reindeer-like legs and hoofed feet)], which are covered in [npc.legFullDescription].",
			"[npc.Her] legs are [npc.materialCompositionDescriptor] [npc.legFullDescription(true)], and [npc.her] feet are formed into anthropomorphic reindeer-like hoofs.",
			Util.newArrayListOfValues(
					LegConfiguration.BIPEDAL,
					LegConfiguration.TAUR)) {

		private BodyPartClothingBlock clothingBlock = new BodyPartClothingBlock(
				Util.newArrayListOfValues(
						InventorySlot.FOOT),
				Race.REINDEER_MORPH,
				"Due to the shape of [npc.namePos] reindeer-like hoofs, only hoof-compatible clothing can be worn in this slot.",
				Util.newArrayListOfValues(ItemTag.FITS_HOOFS, ItemTag.FITS_HOOFS_EXCLUSIVE));
		@Override
		public BodyPartClothingBlock getBodyPartClothingBlock() {
			return clothingBlock;
		}
	};

	public static AbstractLegType HARPY = new AbstractLegType(BodyCoveringType.FEATHERS,
			Race.HARPY,
			FootStructure.DIGITIGRADE,
			FootType.TALONS,
			"a pair of",
			"leg",
			"legs",
			Util.newArrayListOfValues("masculine", "clawed", "anthropomorphic, bird-like"),
			Util.newArrayListOfValues("feminine", "clawed", "anthropomorphic, bird-like"),
			Util.newArrayListOfValues("bird-like"),
			Util.newArrayListOfValues("bird-like"),
			Util.newArrayListOfValues("bird-like"),
			Util.newArrayListOfValues("bird-like"),
			"A layer of scaly, bird-like leather quickly grows over [npc.her] legs as they shift into a new form."
				+ " As [npc.her] new leathery skin spreads down to the ends of [npc.her] toes, [npc.her] feet start to undergo an extreme transformation."
				+ " [npc.Her] toes combine together and re-shape themselves into three forward-facing talons, as a fourth, thumb-like talon branches out behind them."
				+ " As the transformation ends, a layer of attractive feathers grow around [npc.her] upper-thigh, smoothly transitioning into the leathery skin which now covers [npc.her] lower-legs.
"
				+ "[npc.Name] now [npc.has] anthropomorphic, [style.boldHarpy(bird-like legs and talons in place of feet)], which are covered in [npc.legFullDescription].",
			"[npc.Her] upper thighs are [npc.materialCompositionDescriptor] [npc.legFullDescription(true)], which transition into leathery, bird-like skin just above [npc.her] knee."
				+ " While [npc.her] legs still retain a human-like shape, [npc.her] feet have transformed into bird-like talons.",
				Util.newArrayListOfValues(
						LegConfiguration.BIPEDAL)) {

		private BodyPartClothingBlock clothingBlock = new BodyPartClothingBlock(
				Util.newArrayListOfValues(
						InventorySlot.FOOT,
						InventorySlot.SOCK),
				Race.HARPY,
				"Due to the shape of [npc.namePos] bird-like talons, only claw-compatible clothing can be worn in this slot.",
				Util.newArrayListOfValues(ItemTag.FITS_TALONS_EXCLUSIVE, ItemTag.FITS_TALONS));
		@Override
		public BodyPartClothingBlock getBodyPartClothingBlock() {
			return clothingBlock;
		}
	};

	private static List<AbstractLegType> allLegTypes;
	private static Map<AbstractLegType, String> legToIdMap = new HashMap<>();
	private static Map<String, AbstractLegType> idToLegMap = new HashMap<>();

	static {
		allLegTypes = new ArrayList<>();

		// Add in hard-coded leg types:
		Field[] fields = LegType.class.getFields();

		for(Field f : fields){
			if (AbstractLegType.class.isAssignableFrom(f.getType())) {

				AbstractLegType ct;
				try {
					ct = ((AbstractLegType) f.get(null));

					legToIdMap.put(ct, f.getName());
					idToLegMap.put(f.getName(), ct);

					allLegTypes.add(ct);

				} catch (IllegalArgumentException | IllegalAccessException e) {
					e.printStackTrace();
				}
			}
		}
	}

	public static AbstractLegType getLegTypeFromId(String id) {
		if(id.equals("IMP")) {
			return LegType.DEMON_COMMON;
		}
		if(id.equals("LYCAN")) {
			return LegType.WOLF_MORPH;
		}

		id = Util.getClosestStringMatch(id, idToLegMap.keySet());
		return idToLegMap.get(id);
	}

	public static String getIdFromLegType(AbstractLegType legType) {
		return legToIdMap.get(legType);
	}

	public static List<AbstractLegType> getAllLegTypes() {
		return allLegTypes;
	}

	private static Map<Race, List<AbstractLegType>> typesMap = new HashMap<>();
	public static List<AbstractLegType> getLegTypes(Race r) {
		if(typesMap.containsKey(r)) {
			return typesMap.get(r);
		}

		List<AbstractLegType> types = new ArrayList<>();
		for(AbstractLegType type : LegType.getAllLegTypes()) {
			if(type.getRace()==r) {
				types.add(type);
			}
		}
		typesMap.put(r, types);
		return types;
	}

}


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

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

import com.lilithsthrone.game.character.GameCharacter;
import com.lilithsthrone.game.character.body.Body;
import com.lilithsthrone.game.character.body.valueEnums.OrificeModifier;
import com.lilithsthrone.game.character.race.Race;

/**
 * @since 0.1.83
 * @version 0.3.2
 * @author Innoxia
 */
public enum MouthType implements BodyPartTypeInterface {

	HUMAN("mouth", "mouths", BodyCoveringType.MOUTH, Race.HUMAN),

	ANGEL("mouth", "mouths", BodyCoveringType.MOUTH, Race.ANGEL),

	DEMON_COMMON("mouth", "mouths", BodyCoveringType.MOUTH, Race.DEMON),

	DOG_MORPH("mouth", "mouths", BodyCoveringType.MOUTH, Race.DOG_MORPH),

	WOLF_MORPH("mouth", "mouths", BodyCoveringType.MOUTH, Race.WOLF_MORPH),

	FOX_MORPH("mouth", "mouths", BodyCoveringType.MOUTH, Race.FOX_MORPH),

	CAT_MORPH("mouth", "mouths", BodyCoveringType.MOUTH, Race.CAT_MORPH),

	COW_MORPH("mouth", "mouths", BodyCoveringType.MOUTH, Race.COW_MORPH),

	SQUIRREL_MORPH("mouth", "mouths", BodyCoveringType.MOUTH, Race.SQUIRREL_MORPH),

	RAT_MORPH("mouth", "mouths", BodyCoveringType.MOUTH, Race.RAT_MORPH),

	RABBIT_MORPH("mouth", "mouths", BodyCoveringType.MOUTH, Race.RABBIT_MORPH),

	BAT_MORPH("mouth", "mouths", BodyCoveringType.MOUTH, Race.BAT_MORPH),

	ALLIGATOR_MORPH("mouth", "mouths", BodyCoveringType.MOUTH, Race.ALLIGATOR_MORPH),

	HORSE_MORPH("mouth", "mouths", BodyCoveringType.MOUTH, Race.HORSE_MORPH),

	REINDEER_MORPH("mouth", "mouths", BodyCoveringType.MOUTH, Race.REINDEER_MORPH),

	HARPY("beak", "beaks", BodyCoveringType.MOUTH, Race.HARPY);

	private String name;
	private String namePlural;
	private BodyCoveringType skinType;
	private Race race;
	private List<OrificeModifier> defaultRacialOrificeModifiers;

	private MouthType(String name, String namePlural, BodyCoveringType skinType, Race race, OrificeModifier... defaultRacialOrificeModifiers) {
		this.name = name;
		this.namePlural = namePlural;
		this.skinType = skinType;
		this.race = race;
		this.defaultRacialOrificeModifiers = new ArrayList<>();
		Collections.addAll(this.defaultRacialOrificeModifiers, defaultRacialOrificeModifiers);
	}

	/**
	 * Use instead of <i>valueOf()</i>.
	 */
	public static MouthType getTypeFromString(String value) {
		if(value.equals("IMP")) {
			value = "DEMON_COMMON";
		}
		return valueOf(value);
	}

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

	@Override
	public boolean isDefaultPlural() {
		return false;
	}

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

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

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

	@Override
	public BodyCoveringType getBodyCoveringType(Body body) {
		return skinType;
	}

	@Override
	public Race getRace() {
		return race;
	}

	public List<OrificeModifier> getDefaultRacialOrificeModifiers() {
		return defaultRacialOrificeModifiers;
	}
}


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

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

import com.lilithsthrone.game.character.GameCharacter;
import com.lilithsthrone.game.character.body.Body;
import com.lilithsthrone.game.character.body.valueEnums.BreastShape;
import com.lilithsthrone.game.character.body.valueEnums.OrificeModifier;
import com.lilithsthrone.game.character.race.Race;
import com.lilithsthrone.game.dialogue.utils.UtilText;
import com.lilithsthrone.utils.Util;

/**
 * @since 0.1.83
 * @version 0.3.1
 * @author Innoxia
 */
public enum NippleType implements BodyPartTypeInterface {

	HUMAN(Race.HUMAN),

	ANGEL(Race.ANGEL),

	DEMON_COMMON(Race.DEMON),

	DOG_MORPH(Race.DOG_MORPH),

	WOLF_MORPH(Race.WOLF_MORPH),

	FOX_MORPH(Race.FOX_MORPH),

	CAT_MORPH(Race.CAT_MORPH),

	COW_MORPH(Race.COW_MORPH),

	SQUIRREL_MORPH(Race.SQUIRREL_MORPH),

	RAT_MORPH(Race.RAT_MORPH),

	BAT_MORPH(Race.BAT_MORPH),

	RABBIT_MORPH(Race.RABBIT_MORPH),

	ALLIGATOR_MORPH(Race.ALLIGATOR_MORPH),

	HORSE_MORPH(Race.HORSE_MORPH),

	REINDEER_MORPH(Race.REINDEER_MORPH),

	HARPY(Race.HARPY);

	private Race race;
	private List<OrificeModifier> defaultRacialOrificeModifiers;

	private NippleType(Race race, OrificeModifier... defaultRacialOrificeModifiers) {
		this.race = race;
		this.defaultRacialOrificeModifiers = new ArrayList<>();
		Collections.addAll(this.defaultRacialOrificeModifiers, defaultRacialOrificeModifiers);
	}

	/**
	 * Use instead of <i>valueOf()</i>.
	 */
	public static NippleType getTypeFromString(String value) {
		if(value.equals("IMP")) {
			value = "DEMON_COMMON";
		}
		return valueOf(value);
	}

	@Override
	public String getDeterminer(GameCharacter gc) {
		if(gc.getBreastRows()==1) {
			return "a pair of";
		} else if(gc.getBreastRows()==2) {
			return "two pairs of";
		} else {
			return "three pairs of";
		}
	}

	@Override
	public boolean isDefaultPlural() {
		return true;
	}

	@Override
	public String getNameSingular(GameCharacter gc) {
		switch(gc.getNippleShape()) {
			case LIPS:
				return  UtilText.returnStringAtRandom("lipple", "nipple-lip");
			case NORMAL:
				if(gc.hasBreasts()) {
					return UtilText.returnStringAtRandom("nipple", "teat");

				} else {
					return "nipples";
				}
			case VAGINA:
				return UtilText.returnStringAtRandom("nipple-cunt", "nipple-pussy");
		}
		return "";
	}

	@Override
	public String getNamePlural(GameCharacter gc) {
		switch(gc.getNippleShape()) {
			case LIPS:
				return  UtilText.returnStringAtRandom("lipples", "nipple-lips");
			case NORMAL:
				if(gc.hasBreasts()) {
					return UtilText.returnStringAtRandom("nipples", "teats");

				} else {
					return "nipples";
				}
			case VAGINA:
				return UtilText.returnStringAtRandom("nipple-cunts", "nipple-pussies");
		}
		return "";
	}

	// Not used for now, due to being terrible:
	public String getNameCrotchSingular(GameCharacter gc) {
		if(gc.getBreastCrotchShape()==BreastShape.UDDERS) {
			switch(gc.getNippleShape()) {
				case LIPS:
					return  UtilText.returnStringAtRandom("udder-lipple", "udder-nipple-lip");
				case NORMAL:
					if(gc.hasBreasts()) {
						return UtilText.returnStringAtRandom("udder-nipple", "udder-teat");

					} else {
						return "udder-nipples";
					}
				case VAGINA:
					return UtilText.returnStringAtRandom("udder-nipple-cunt", "udder-nipple-pussy");
			}
		} else {
			switch(gc.getNippleShape()) {
				case LIPS:
					return  UtilText.returnStringAtRandom("crotch-lipple", "crotch-nipple-lip");
				case NORMAL:
					if(gc.hasBreasts()) {
						return UtilText.returnStringAtRandom("crotch-nipple", "crotch-teat");

					} else {
						return "crotch-nipples";
					}
				case VAGINA:
					return UtilText.returnStringAtRandom("crotch-nipple-cunt", "crotch-nipple-pussy");
			}
		}
		return "";
	}

	// Not used for now, due to being terrible:
	public String getNameCrotchPlural(GameCharacter gc) {
		if(gc.getBreastCrotchShape()==BreastShape.UDDERS) {
			switch(gc.getNippleShape()) {
				case LIPS:
					return  UtilText.returnStringAtRandom("udder-lipples", "udder-nipple-lips");
				case NORMAL:
					if(gc.hasBreasts()) {
						return UtilText.returnStringAtRandom("udder-nipples", "udder-teats");

					} else {
						return "udder-nipples";
					}
				case VAGINA:
					return UtilText.returnStringAtRandom("udder-nipple-cunts", "udder-nipple-pussies");
			}
		} else {
			switch(gc.getNippleShape()) {
				case LIPS:
					return  UtilText.returnStringAtRandom("crotch-lipples", "crotch-nipple-lips");
				case NORMAL:
					if(gc.hasBreasts()) {
						return UtilText.returnStringAtRandom("crotch-nipples", "crotch-teats");

					} else {
						return "crotch-nipples";
					}
				case VAGINA:
					return UtilText.returnStringAtRandom("crotch-nipple-cunts", "crotch-nipple-pussies");
			}
		}
		return "";
	}

	@Override
	public String getDescriptor(GameCharacter gc) {
		String descriptor[];

		switch(this){
			case ANGEL:
				descriptor = new String[] { "flawless", "perky" };
				break;
			case DEMON_COMMON:
				descriptor = new String[] { "demonic", "irresistible" };
				break;
			case HUMAN:
				descriptor = new String[] { "" };
				break;
			default:
				descriptor = new String[] { "" };
				break;
		}

		return descriptor[Util.random.nextInt(descriptor.length)];
	}

	@Override
	public BodyCoveringType getBodyCoveringType(Body body) {
		return BodyCoveringType.NIPPLES;
	}

	@Override
	public Race getRace() {
		return race;
	}

	public List<OrificeModifier> getDefaultRacialOrificeModifiers() {
		return defaultRacialOrificeModifiers;
	}
}


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

import com.lilithsthrone.game.character.GameCharacter;
import com.lilithsthrone.game.character.body.valueEnums.Capacity;
import com.lilithsthrone.game.character.body.valueEnums.OrificeElasticity;
import com.lilithsthrone.game.character.body.valueEnums.OrificeModifier;
import com.lilithsthrone.game.character.body.valueEnums.OrificePlasticity;
import com.lilithsthrone.game.character.body.valueEnums.Wetness;

/**
 * @since 0.1.83
 * @version 0.1.83
 * @author Innoxia
 */
public interface OrificeInterface {

	public Wetness getWetness(GameCharacter owner);
	public String setWetness(GameCharacter owner, int wetness);

	public Capacity getCapacity();
	public float getRawCapacityValue();
	public String setCapacity(GameCharacter owner, float capacity, boolean setStretchedValueToNewValue);
	public float getStretchedCapacity();
	public boolean setStretchedCapacity(float stretchedCapacity);

	public OrificeElasticity getElasticity();
	public String setElasticity(GameCharacter owner, int elasticity);

	public OrificePlasticity getPlasticity();
	public String setPlasticity(GameCharacter owner, int plasticity);

	public boolean isVirgin();
	public void setVirgin(boolean virgin);

	public boolean hasOrificeModifier(OrificeModifier modifier);
	public String addOrificeModifier(GameCharacter owner, OrificeModifier modifier);
	public String removeOrificeModifier(GameCharacter owner, OrificeModifier modifier);

}


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

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

import com.lilithsthrone.game.character.GameCharacter;
import com.lilithsthrone.game.character.body.Body;
import com.lilithsthrone.game.character.body.valueEnums.PenetrationModifier;
import com.lilithsthrone.game.character.body.valueEnums.PenisGirth;
import com.lilithsthrone.game.character.body.valueEnums.PenisSize;
import com.lilithsthrone.game.character.race.Race;
import com.lilithsthrone.game.dialogue.utils.UtilText;
import com.lilithsthrone.main.Main;
import com.lilithsthrone.utils.Util;

/**
 * @since 0.1.0
 * @version 0.2.11
 * @author Innoxia
 */
public enum PenisType implements BodyPartTypeInterface {
	NONE(null, TesticleType.NONE, Race.NONE),

	DILDO(BodyCoveringType.DILDO, TesticleType.DILDO, Race.NONE),

	HUMAN(BodyCoveringType.PENIS, TesticleType.HUMAN, Race.HUMAN),

	ANGEL(BodyCoveringType.PENIS, TesticleType.ANGEL, Race.ANGEL),

	BOVINE(BodyCoveringType.PENIS, TesticleType.BOVINE, Race.COW_MORPH, PenetrationModifier.TAPERED, PenetrationModifier.VEINY, PenetrationModifier.SHEATHED),

	DEMON_COMMON(BodyCoveringType.PENIS, TesticleType.DEMON_COMMON, Race.DEMON, PenetrationModifier.RIBBED, PenetrationModifier.TENTACLED, PenetrationModifier.PREHENSILE),

	CANINE(BodyCoveringType.PENIS, TesticleType.CANINE, Race.DOG_MORPH, PenetrationModifier.KNOTTED, PenetrationModifier.SHEATHED, PenetrationModifier.TAPERED),

	LUPINE(BodyCoveringType.PENIS, TesticleType.LUPINE, Race.WOLF_MORPH, PenetrationModifier.KNOTTED, PenetrationModifier.SHEATHED, PenetrationModifier.TAPERED),

	VULPINE(BodyCoveringType.PENIS, TesticleType.FOX_MORPH, Race.FOX_MORPH, PenetrationModifier.KNOTTED, PenetrationModifier.SHEATHED, PenetrationModifier.TAPERED),

	FELINE(BodyCoveringType.PENIS, TesticleType.FELINE, Race.CAT_MORPH, PenetrationModifier.BARBED, PenetrationModifier.SHEATHED),

	ALLIGATOR_MORPH(BodyCoveringType.PENIS, TesticleType.ALLIGATOR_MORPH, Race.ALLIGATOR_MORPH, PenetrationModifier.BLUNT),

	EQUINE(BodyCoveringType.PENIS, TesticleType.EQUINE, Race.HORSE_MORPH, PenetrationModifier.FLARED, PenetrationModifier.VEINY, PenetrationModifier.SHEATHED),

	REINDEER_MORPH(BodyCoveringType.PENIS, TesticleType.REINDEER_MORPH, Race.REINDEER_MORPH, PenetrationModifier.TAPERED, PenetrationModifier.SHEATHED),

	AVIAN(BodyCoveringType.PENIS, TesticleType.AVIAN, Race.HARPY, PenetrationModifier.SHEATHED),

	SQUIRREL(BodyCoveringType.PENIS, TesticleType.SQUIRREL, Race.SQUIRREL_MORPH, PenetrationModifier.SHEATHED),

	RAT_MORPH(BodyCoveringType.PENIS, TesticleType.RAT_MORPH, Race.RAT_MORPH, PenetrationModifier.SHEATHED),

	RABBIT_MORPH(BodyCoveringType.PENIS, TesticleType.RABBIT_MORPH, Race.RABBIT_MORPH, PenetrationModifier.SHEATHED),

	BAT_MORPH(BodyCoveringType.PENIS, TesticleType.BAT_MORPH, Race.BAT_MORPH, PenetrationModifier.SHEATHED);

	private BodyCoveringType skinType;
	private TesticleType testicleType;
	private Race race;
	private List<PenetrationModifier> defaultPenisModifiers;

	private PenisType(BodyCoveringType skinType, TesticleType testicleType, Race race, PenetrationModifier... defaultPenisModifiers) {
		this.skinType = skinType;
		this.race = race;
		this.testicleType=testicleType;

		this.defaultPenisModifiers = new ArrayList<>();
		Collections.addAll(this.defaultPenisModifiers, defaultPenisModifiers);
	}

	/**
	 * Use instead of <i>valueOf()</i>.
	 */
	public static PenisType getTypeFromString(String value) {
		if(value.equals("IMP")) {
			value = "DEMON_COMMON";
		}
		return valueOf(value);
	}

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

	@Override
	public boolean isDefaultPlural() {
		return false;
	}

	@Override
	public String getNameSingular(GameCharacter gc) {
		if(this==PenisType.DILDO) {
			return UtilText.returnStringAtRandom("dildo", "cock");
		} else {
			return UtilText.returnStringAtRandom("cock", "cock", "cock", "dick", "dick", "shaft");
		}
	}

	@Override
	public String getNamePlural(GameCharacter gc) {
		if(this==PenisType.DILDO) {
			return UtilText.returnStringAtRandom("dildoes", "cocks");
		} else {
			return UtilText.returnStringAtRandom("cocks", "cocks", "cocks", "dicks", "dicks", "shafts");
		}
	}

	@Override
	public String getDescriptor(GameCharacter gc) {
		// Randomly give a size/aroused or type-specific descriptor:
		switch(Util.random.nextInt(3)){
			case 0:
				switch(this){
					case ANGEL:
						return UtilText.returnStringAtRandom("angelic");
					case AVIAN:
						return UtilText.returnStringAtRandom("avian");
					case BOVINE:
						return UtilText.returnStringAtRandom("bovine", "bull-like", "bestial");
					case CANINE:
						return UtilText.returnStringAtRandom("canine", "dog-like", "bestial");
					case DEMON_COMMON:
						return UtilText.returnStringAtRandom("demonic");
					case EQUINE:
						return UtilText.returnStringAtRandom("equine", "horse-like", "bestial");
					case REINDEER_MORPH:
						return UtilText.returnStringAtRandom("rangiferine", "reindeer-like", "bestial");
					case FELINE:
						return UtilText.returnStringAtRandom("feline", "cat-like", "bestial");
					case ALLIGATOR_MORPH:
						return UtilText.returnStringAtRandom("reptilian", "alligator-like");
					case HUMAN:
						return UtilText.returnStringAtRandom("");
					case NONE:
						return UtilText.returnStringAtRandom("");
					case SQUIRREL:
						return UtilText.returnStringAtRandom("rodent", "squirrel-like");
					case LUPINE:
						return UtilText.returnStringAtRandom("lupine", "wolf-like", "bestial");
					case VULPINE:
						return UtilText.returnStringAtRandom("vulpine", "fox-like", "bestial");
					case BAT_MORPH:
						return UtilText.returnStringAtRandom("bat-", "bat-like");
					case RAT_MORPH:
						return UtilText.returnStringAtRandom("rodent", "rat-like");
					case RABBIT_MORPH:
						return UtilText.returnStringAtRandom("rabbit-", "rabbit-like");
					case DILDO:
						return UtilText.returnStringAtRandom("rubber", "rubbery", "silicone", "artificial");
				}
				break;
			case 1:
				return UtilText.returnStringAtRandom(
						gc.getPenisSize()==PenisSize.TWO_AVERAGE?"":gc.getPenisSize().getDescriptor(),
						gc.getPenisGirth()==PenisGirth.TWO_AVERAGE?"":gc.getPenisGirth().getName());
			default:
				if(Main.game.isInSex() && this!=PenisType.DILDO) {
					return UtilText.returnStringAtRandom("hard", "throbbing");
				} else {
					return UtilText.returnStringAtRandom(
							gc.getPenisSize()==PenisSize.TWO_AVERAGE?"":gc.getPenisSize().getDescriptor(),
							gc.getPenisGirth()==PenisGirth.TWO_AVERAGE?"":gc.getPenisGirth().getName());
				}
		}
		return "";
	}

	@Override
	public String getTransformName() {
		switch(this){
			case ANGEL:
				return "angelic";
			case AVIAN:
				return "harpy";
			case BOVINE:
				return "bovine";
			case CANINE:
				return "canine";
			case DEMON_COMMON:
				return "demonic";
			case EQUINE:
				return "equine";
			case REINDEER_MORPH:
				return "reindeer";
			case FELINE:
				return "feline";
			case HUMAN:
				return "human";
			case NONE:
				return "none";
			case SQUIRREL:
				return "squirrel";
			case ALLIGATOR_MORPH:
				return "alligator";
			case LUPINE:
				return "wolf";
			case VULPINE:
				return "fox";
			case BAT_MORPH:
				return "bat";
			case RAT_MORPH:
				return "rat";
			case RABBIT_MORPH:
				return "rabbit";
			case DILDO:
				return "artificial";
		}
		return "";
	}

	@Override
	public BodyCoveringType getBodyCoveringType(Body body) {
		return skinType;
	}

	@Override
	public Race getRace() {
		return race;
	}

	public String getPenisHeadName(GameCharacter gc) {
		return UtilText.returnStringAtRandom("head", "tip");
	}

	public String getPenisHeadDescriptor(GameCharacter gc) {
		for(PenetrationModifier mod : PenetrationModifier.values()) {
			if(gc.getPenisModifiers().contains(mod)) {
				switch(mod) {
					case BLUNT:
						return UtilText.returnStringAtRandom("blunt");
					case FLARED:
						return UtilText.returnStringAtRandom("wide", "flared", "flat");
					case TAPERED:
						return UtilText.returnStringAtRandom("tapered", "pointed");
					case KNOTTED:
					case PREHENSILE:
					case RIBBED:
					case SHEATHED:
					case BARBED:
					case TENTACLED:
					case VEINY:
						break;
				}
			}
		}
		return "";
	}

	public String getCumName(GameCharacter gc) {
		String prefix = "";
		switch(this){
			case BOVINE:
				prefix = UtilText.returnStringAtRandom("bull-", "cow-", "bovine-");
				break;
			case CANINE:
				prefix = UtilText.returnStringAtRandom("dog-", "canine-");
				break;
			case EQUINE:
				prefix = UtilText.returnStringAtRandom("horse-", "equine-");
				break;
			case FELINE:
				prefix = UtilText.returnStringAtRandom("cat-", "feline-");
				break;
			case NONE:
				return UtilText.returnStringAtRandom("");
			case ALLIGATOR_MORPH:
				prefix = UtilText.returnStringAtRandom("alligator-");
				break;
			case ANGEL:
				prefix = UtilText.returnStringAtRandom("angel-");
				break;
			case AVIAN:
				prefix = UtilText.returnStringAtRandom("harpy-", "avian-");
				break;
			case BAT_MORPH:
				prefix = UtilText.returnStringAtRandom("bat-");
				break;
			case DEMON_COMMON:
				prefix = UtilText.returnStringAtRandom("demon-");
				break;
			case HUMAN:
				break;
			case LUPINE:
				prefix = UtilText.returnStringAtRandom("wolf-", "lupine-");
				break;
			case VULPINE:
				prefix = UtilText.returnStringAtRandom("fox-", "vulpine-");
				break;
			case RAT_MORPH:
				prefix = UtilText.returnStringAtRandom("rat-", "rodent-");
				break;
			case RABBIT_MORPH:
				prefix = UtilText.returnStringAtRandom("rabbit-");
				break;
			case REINDEER_MORPH:
				prefix = UtilText.returnStringAtRandom("reindeer-");
				break;
			case SQUIRREL:
				prefix = UtilText.returnStringAtRandom("squirrel-", "rodent-");
				break;
			case DILDO:
				prefix = UtilText.returnStringAtRandom("stored", "preserved");
				break;
		}
		if(Math.random()>0.5f && !prefix.isEmpty()) {
			return prefix + UtilText.returnStringAtRandom("cum", "cream", "jism", "jizz", "seed", "spooge");
		} else {
			return UtilText.returnStringAtRandom("cum", "cream", "jism", "jizz", "load", "seed", "spooge");
		}
	}

	public String getCumDescriptor() {
		switch(this){
			case DEMON_COMMON:
				return UtilText.returnStringAtRandom("corruptive", "corrupted", "potent", "thick", "hot");
			case NONE:
				return UtilText.returnStringAtRandom("");
			default:
				return UtilText.returnStringAtRandom("potent", "thick", "hot");
		}
	}

	public TesticleType getTesticleType() {
		return testicleType;
	}

	public List<PenetrationModifier> getDefaultPenisModifiers() {
		return defaultPenisModifiers;
	}

}


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

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.lilithsthrone.game.character.GameCharacter;
import com.lilithsthrone.game.character.body.Body;
import com.lilithsthrone.game.character.race.Race;
import com.lilithsthrone.game.dialogue.utils.UtilText;

/**
 * @since 0.1.83
 * @version 0.2.11
 * @author Innoxia
 */
public enum SkinType implements BodyPartTypeInterface {
	HUMAN(BodyCoveringType.HUMAN, Race.HUMAN),

	ANGEL(BodyCoveringType.ANGEL, Race.ANGEL),

	COW_MORPH(BodyCoveringType.BOVINE_FUR, Race.COW_MORPH),

	DEMON_COMMON(BodyCoveringType.DEMON_COMMON, Race.DEMON),

	DOG_MORPH(BodyCoveringType.CANINE_FUR, Race.DOG_MORPH),

	LYCAN(BodyCoveringType.LYCAN_FUR, Race.WOLF_MORPH),

	FOX_MORPH(BodyCoveringType.FOX_FUR, Race.FOX_MORPH),

	CAT_MORPH(BodyCoveringType.FELINE_FUR, Race.CAT_MORPH),

	SQUIRREL_MORPH(BodyCoveringType.SQUIRREL_FUR, Race.SQUIRREL_MORPH),

	RAT_MORPH(BodyCoveringType.RAT_FUR, Race.RAT_MORPH),

	RABBIT_MORPH(BodyCoveringType.RABBIT_FUR, Race.RABBIT_MORPH),

	BAT_MORPH(BodyCoveringType.BAT_FUR, Race.BAT_MORPH),

	ALLIGATOR_MORPH(BodyCoveringType.ALLIGATOR_SCALES, Race.ALLIGATOR_MORPH),

	HORSE_MORPH(BodyCoveringType.HORSE_HAIR, Race.HORSE_MORPH),

	REINDEER_MORPH(BodyCoveringType.REINDEER_FUR, Race.REINDEER_MORPH),

	HARPY(BodyCoveringType.FEATHERS, Race.HARPY);

	private BodyCoveringType coveringType;
	private Race race;

	private SkinType(BodyCoveringType coveringType, Race race) {
		this.coveringType = coveringType;
		this.race = race;
	}

	/**
	 * Use instead of <i>valueOf()</i>.
	 */
	public static SkinType getTypeFromString(String value) {
		if(value.equals("IMP")) {
			value = "DEMON_COMMON";
		}
		return valueOf(value);
	}

	@Override
	public String getDeterminer(GameCharacter gc) {
		return "a layer of";
	}

	@Override
	public boolean isDefaultPlural() {
		switch(coveringType) {
			case HAIR_HARPY:
				return true;
			case ALLIGATOR_SCALES:
				return true;
			default:
				return false;
		}
	}

	@Override
	public String getNameSingular(GameCharacter gc) {
		switch(coveringType) {
			case HAIR_HARPY:
				return "feather";
			case ALLIGATOR_SCALES:
				return "scale";
			case SLIME:
				return "slime";
			default:
				return coveringType.getName(gc);
		}
	}

	@Override
	public String getNamePlural(GameCharacter gc) {
		switch(coveringType) {
			case HAIR_HARPY:
				return "feathers";
			case ALLIGATOR_SCALES:
				return "scales";
			case SLIME:
				return "slime";
			default:
				return coveringType.getNamePlural(gc);
		}
	}

	@Override
	public String getTransformName() {
		switch(this){
			case CAT_MORPH:
				return "feline";
			case COW_MORPH:
				return "bovine";
			case DEMON_COMMON:
				return "demonic";
			case DOG_MORPH:
				return "canine";
			case HARPY:
				return "harpy";
			case HORSE_MORPH:
				return "equine";
			case REINDEER_MORPH:
				return "reindeer";
			case LYCAN:
				return "wolf";
			case FOX_MORPH:
				return "fox";
			case SQUIRREL_MORPH:
				return "squirrel";
			case ALLIGATOR_MORPH:
				return "alligator";
			case RAT_MORPH:
				return "rat";
			case RABBIT_MORPH:
				return "rabbit";
			case ANGEL:
				return "angel";
			case BAT_MORPH:
				return "bat";
			case HUMAN:
				return "human";
		}
		return "";
	}

	@Override
	public String getDescriptor(GameCharacter gc) {
		switch(this){
			case ANGEL:
				return UtilText.returnStringAtRandom("angelic");
			case CAT_MORPH:
				return UtilText.returnStringAtRandom("cat-like");
			case COW_MORPH:
				return UtilText.returnStringAtRandom("cow-like");
			case DEMON_COMMON:
				return UtilText.returnStringAtRandom("demonic");
			case DOG_MORPH:
				return UtilText.returnStringAtRandom("dog-like");
			case SQUIRREL_MORPH:
				return UtilText.returnStringAtRandom("squirrel-like");
			case ALLIGATOR_MORPH:
				return UtilText.returnStringAtRandom("alligator-like");
			case HARPY:
				return UtilText.returnStringAtRandom("bird-like");
			case HORSE_MORPH:
				return UtilText.returnStringAtRandom("horse-like");
			case REINDEER_MORPH:
				return UtilText.returnStringAtRandom("reindeer-like");
			case HUMAN:
				return UtilText.returnStringAtRandom("");
			case LYCAN:
				return UtilText.returnStringAtRandom("wolf-like");
			case FOX_MORPH:
				return UtilText.returnStringAtRandom("fox-like");
			case BAT_MORPH:
				return UtilText.returnStringAtRandom("bat-like");
			case RAT_MORPH:
				return UtilText.returnStringAtRandom("rat-like");
			case RABBIT_MORPH:
				return UtilText.returnStringAtRandom("rabbit-like");
		}
		return "";
	}

	@Override
	public BodyCoveringType getBodyCoveringType(Body body) {
		return coveringType;
	}

	@Override
	public Race getRace() {
		return race;
	}

	private static Map<Race, List<SkinType>> typesMap = new HashMap<>();
	public static List<SkinType> getSkinTypes(Race r) {
		if(typesMap.containsKey(r)) {
			return typesMap.get(r);
		}

		List<SkinType> types = new ArrayList<>();
		for(SkinType type : SkinType.values()) {
			if(type.getRace()==r) {
				types.add(type);
			}
		}
		typesMap.put(r, types);
		return types;
	}
}


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

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.lilithsthrone.game.PropertyValue;
import com.lilithsthrone.game.character.GameCharacter;
import com.lilithsthrone.game.character.body.Body;
import com.lilithsthrone.game.character.race.Race;
import com.lilithsthrone.game.dialogue.utils.UtilText;
import com.lilithsthrone.main.Main;
import com.lilithsthrone.utils.Util;

/**
 * @since 0.1.0
 * @version 0.3.5.1
 * @author Innoxia
 */
public enum TailType implements BodyPartTypeInterface {
	NONE(null, Race.NONE, false, false, false),

	DEMON_COMMON(BodyCoveringType.DEMON_COMMON, Race.DEMON, true, true, true),
	DEMON_HAIR_TIP(BodyCoveringType.DEMON_COMMON, Race.DEMON, true, false, true),
	DEMON_HORSE(BodyCoveringType.HAIR_DEMON, Race.DEMON, false, false, false),

	DOG_MORPH(BodyCoveringType.CANINE_FUR, Race.DOG_MORPH, false, false, false),
	DOG_MORPH_STUBBY(BodyCoveringType.CANINE_FUR, Race.DOG_MORPH, false, false, false),

	LYCAN(BodyCoveringType.LYCAN_FUR, Race.WOLF_MORPH, false, false, true),

	FOX_MORPH(BodyCoveringType.FOX_FUR, Race.FOX_MORPH, false, false, true),
	FOX_MORPH_MAGIC(BodyCoveringType.FOX_FUR, Race.FOX_MORPH, true, false, true),

	COW_MORPH(BodyCoveringType.BOVINE_FUR, Race.COW_MORPH, false, false, false),

	CAT_MORPH(BodyCoveringType.FELINE_FUR, Race.CAT_MORPH, true, false, true),
	CAT_MORPH_SHORT(BodyCoveringType.FELINE_FUR, Race.CAT_MORPH, false, false, false),
	CAT_MORPH_TUFTED(BodyCoveringType.FELINE_FUR, Race.CAT_MORPH, true, false, true),

	SQUIRREL_MORPH(BodyCoveringType.SQUIRREL_FUR, Race.SQUIRREL_MORPH, false, false, true),

	BAT_MORPH(BodyCoveringType.BAT_SKIN, Race.BAT_MORPH, true, false, false),

	RAT_MORPH(BodyCoveringType.RAT_SKIN, Race.RAT_MORPH, true, true, true),

	RABBIT_MORPH(BodyCoveringType.RABBIT_FUR, Race.RABBIT_MORPH, false, false, false),

	ALLIGATOR_MORPH(BodyCoveringType.ALLIGATOR_SCALES, Race.ALLIGATOR_MORPH, false, false, true),

	HORSE_MORPH(BodyCoveringType.HAIR_HORSE_HAIR, Race.HORSE_MORPH, false, false, false),
	HORSE_MORPH_ZEBRA(BodyCoveringType.HAIR_HORSE_HAIR, Race.HORSE_MORPH, false, false, false),

	REINDEER_MORPH(BodyCoveringType.REINDEER_FUR, Race.REINDEER_MORPH, false, false, false),

	HARPY(BodyCoveringType.FEATHERS, Race.HARPY, false, false, true);

	private BodyCoveringType skinType;
	private Race race;
	private boolean prehensile;
	private boolean suitableForPenetration;
	private boolean suitableForSleepHugging;

	private TailType(BodyCoveringType skinType, Race race, boolean prehensile, boolean suitableForPenetration, boolean suitableForSleepHugging) {
		this.skinType = skinType;
		this.race = race;
		this.prehensile = prehensile;
		this.suitableForPenetration = suitableForPenetration;
		this.suitableForSleepHugging = suitableForSleepHugging;
	}

	/**
	 * Use instead of <i>valueOf()</i>.
	 */
	public static TailType getTypeFromString(String value) {
		if(value.equals("IMP")) {
			value = "DEMON_COMMON";
		}
		return valueOf(value);
	}

	@Override
	public boolean isDefaultPlural() {
		return false;
	}

	@Override
	public String getDeterminer(GameCharacter gc) {
		if(gc==null) {
			return "";
		}
		if(gc.getTailCount()==1) {
			switch(this){
				case HARPY:
					return "a plume of";
				default:
					return "";
			}
		} else {
			switch(this){
				case HARPY:
					return Util.intToString(gc.getTailCount())+" plumes of";
				default:
					return Util.intToString(gc.getTailCount());
			}
		}
	}

	@Override
	public String getNameSingular(GameCharacter gc) {
		switch(this){
			case HARPY:
				return UtilText.returnStringAtRandom("tail feathers");
			default:
				return UtilText.returnStringAtRandom("tail");
		}
	}

	@Override
	public String getNamePlural(GameCharacter gc) {
		switch(this){
			case HARPY:
				return UtilText.returnStringAtRandom("tail feathers");
			default:
				return UtilText.returnStringAtRandom("tails");
		}
	}

	@Override
	public String getDescriptor(GameCharacter gc) {
		switch(this){
			case CAT_MORPH:
				return UtilText.returnStringAtRandom("cat-like");
			case CAT_MORPH_SHORT:
				return UtilText.returnStringAtRandom("cat-like", "short");
			case CAT_MORPH_TUFTED:
				return UtilText.returnStringAtRandom("cat-like", "tufted");
			case COW_MORPH:
				return UtilText.returnStringAtRandom("cow-like", "tufted");
			case DEMON_COMMON:
				return UtilText.returnStringAtRandom("spaded", "demonic");
			case DEMON_HAIR_TIP:
				return UtilText.returnStringAtRandom("hair-tipped", "demonic");
			case DEMON_HORSE:
				return UtilText.returnStringAtRandom("horse-like");
			case DOG_MORPH:
				return UtilText.returnStringAtRandom("dog-like");
			case DOG_MORPH_STUBBY:
				return UtilText.returnStringAtRandom("stubby", "dog-like");
			case ALLIGATOR_MORPH:
				return UtilText.returnStringAtRandom("alligator-like");
			case HARPY:
				return UtilText.returnStringAtRandom("colourful", "bird-like");
			case HORSE_MORPH:
				return UtilText.returnStringAtRandom("horse-like");
			case HORSE_MORPH_ZEBRA:
				return UtilText.returnStringAtRandom("zebra-like");
			case REINDEER_MORPH:
				return UtilText.returnStringAtRandom("reindeer-like");
			case LYCAN:
				return UtilText.returnStringAtRandom("wolf-like");
			case FOX_MORPH:
				return UtilText.returnStringAtRandom("fox-like", "fluffy");
			case FOX_MORPH_MAGIC:
				return UtilText.returnStringAtRandom("arcane", "fox-like", "fluffy");
			case SQUIRREL_MORPH:
				return UtilText.returnStringAtRandom("squirrel-like", "fluffy");
			case NONE:
				return UtilText.returnStringAtRandom("");
			case RAT_MORPH:
				return UtilText.returnStringAtRandom("rat-like");
			case BAT_MORPH:
				return UtilText.returnStringAtRandom("bat-like");
			case RABBIT_MORPH:
				return UtilText.returnStringAtRandom("rabbit-like", "fluffy");
		}

		return "";
	}

	@Override
	public String getTransformName() {
		switch(this){
			case CAT_MORPH:
				return "feline";
			case CAT_MORPH_SHORT:
				return "short feline";
			case CAT_MORPH_TUFTED:
				return "tufted feline";
			case COW_MORPH:
				return "bovine";
			case DEMON_COMMON:
				return "demonic spaded";
			case DEMON_HAIR_TIP:
				return "demonic hair-tipped";
			case DEMON_HORSE:
				return "demonic horse";
			case DOG_MORPH:
				return "canine";
			case DOG_MORPH_STUBBY:
				return "stubby canine";
			case HARPY:
				return "harpy plume";
			case HORSE_MORPH:
				return "equine";
			case HORSE_MORPH_ZEBRA:
				return "zebra";
			case REINDEER_MORPH:
				return "reindeer";
			case LYCAN:
				return "wolf";
			case FOX_MORPH:
				return "fox";
			case SQUIRREL_MORPH:
				return "squirrel";
			case FOX_MORPH_MAGIC:
				return "arcane fox";
			case ALLIGATOR_MORPH:
				return "alligator";
			case NONE:
				return "none";
			case RAT_MORPH:
				return "rat";
			case BAT_MORPH:
				return "bat";
			case RABBIT_MORPH:
				return "rabbit";
		}
		return "";
	}

	public String getTailTipName(GameCharacter gc) {
		switch(this){
			default:
				return UtilText.returnStringAtRandom("tip");
		}
	}

	public String getTailTipDescriptor(GameCharacter gc) {
		switch(this){
			case DEMON_COMMON:
				return UtilText.returnStringAtRandom("spaded");
			default:
				return UtilText.returnStringAtRandom("");
		}
	}

	@Override
	public BodyCoveringType getBodyCoveringType(Body body) {
		return skinType;
	}

	@Override
	public Race getRace() {
		return race;
	}

	public boolean isPrehensile() {
		return prehensile;
	}

	/**
	 * Takes into account whether player has 'Allow furry tail penetrations' turned on or off.
	 * @return
	 */
	public boolean isSuitableForPenetration() {
		return prehensile && (suitableForPenetration || Main.getProperties().hasValue(PropertyValue.furryTailPenetrationContent));
	}

	public boolean isSuitableForSleepHugging() {
		return suitableForSleepHugging;
	}

	private static Map<Race, List<TailType>> typesMap = new HashMap<>();
	public static List<TailType> getTailTypes(Race r) {
		if(typesMap.containsKey(r)) {
			return typesMap.get(r);
		}

		List<TailType> types = new ArrayList<>();
		for(TailType type : TailType.values()) {
			if(type.getRace()==r && type!=TailType.FOX_MORPH_MAGIC) {
				types.add(type);
			}
		}
		typesMap.put(r, types);
		return types;
	}

	public static List<TailType> getTailTypesSuitableForTransformation(List<TailType> options) {
		if (!options.contains(TailType.NONE)) {
			return options;
		}

		List<TailType> duplicatedOptions = new ArrayList<>(options);
		duplicatedOptions.remove(TailType.NONE);
		return duplicatedOptions;
	}
}


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

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.lilithsthrone.game.character.GameCharacter;
import com.lilithsthrone.game.character.body.Body;
import com.lilithsthrone.game.character.race.Race;
import com.lilithsthrone.game.dialogue.utils.UtilText;
import com.lilithsthrone.utils.Util;

/**
 * @since 0.2.8
 * @version 0.2.8
 * @author Innoxia
 */
public enum TentacleType implements BodyPartTypeInterface {
	NONE(null, Race.NONE, false),

	DEMON_COMMON(BodyCoveringType.DEMON_COMMON, Race.DEMON, true);

	private BodyCoveringType skinType;
	private Race race;
	private boolean suitableForPenetration;

	private TentacleType(BodyCoveringType skinType, Race race, boolean suitableForPenetration) {
		this.skinType = skinType;
		this.race = race;
		this.suitableForPenetration = suitableForPenetration;
	}

	/**
	 * Use instead of <i>valueOf()</i>.
	 */
	public static TentacleType getTypeFromString(String value) {
		return valueOf(value);
	}

	@Override
	public boolean isDefaultPlural() {
		return false;
	}

	@Override
	public String getDeterminer(GameCharacter gc) {
		if(gc.getTentacleCount()==1) {
			switch(this){
				default:
					return "";
			}
		} else {
			switch(this){
				default:
					return Util.intToString(gc.getTentacleCount());
			}
		}

	}

	@Override
	public String getNameSingular(GameCharacter gc) {
		switch(this){
			default:
				return UtilText.returnStringAtRandom("tentacle");
		}
	}

	@Override
	public String getNamePlural(GameCharacter gc) {
		switch(this){
			default:
				return UtilText.returnStringAtRandom("tentacles");
		}
	}

	@Override
	public String getDescriptor(GameCharacter gc) {
		switch(this){
			case DEMON_COMMON:
				return UtilText.returnStringAtRandom("demonic");
			case NONE:
				return UtilText.returnStringAtRandom("");
		}

		return "";
	}

	@Override
	public String getTransformName() {
		switch(this){
			case DEMON_COMMON:
				return "demonic";
			case NONE:
				return "none";
		}
		return "";
	}

	public String getTentacleTipName(GameCharacter gc) {
		switch(this){
			default:
				return UtilText.returnStringAtRandom("end");
		}
	}

	public String getTentacleTipDescriptor(GameCharacter gc) {
		switch(this){
			case DEMON_COMMON:
				return UtilText.returnStringAtRandom("rounded");
			default:
				return UtilText.returnStringAtRandom("");
		}
	}

	@Override
	public BodyCoveringType getBodyCoveringType(Body body) {
		return skinType;
	}

	@Override
	public Race getRace() {
		return race;
	}

	/**
	 * Takes into account whether player has 'Allow furry tail penetrations' turned on or off.
	 * @return
	 */
	public boolean isSuitableForPenetration() {
		return suitableForPenetration;
	}

	private static Map<Race, List<TentacleType>> typesMap = new HashMap<>();
	public static List<TentacleType> getTentacleTypes(Race r) {
		if(typesMap.containsKey(r)) {
			return typesMap.get(r);
		}

		List<TentacleType> types = new ArrayList<>();
		for(TentacleType type : TentacleType.values()) {
			if(type.getRace()==r) {
				types.add(type);
			}
		}
		typesMap.put(r, types);
		return types;
	}
}