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

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import com.lilithsthrone.game.Game;
import com.lilithsthrone.game.character.GameCharacter;
import com.lilithsthrone.game.dialogue.utils.UtilText;
import com.lilithsthrone.main.Main;
import com.lilithsthrone.utils.Colour;
import com.lilithsthrone.utils.SvgUtil;
import com.lilithsthrone.utils.Util;

/**
 * @since 0.1.0
 * @version 0.2.11
 * @author Innoxia
 */
public enum Attribute {

	HEALTH_MAXIMUM(0,
			1,
			1000,
			"health",
			"Health",
			"healthIcon",
			Colour.ATTRIBUTE_HEALTH,
			"health", "sickness", null) {
				@Override
				public String getDescription(GameCharacter owner) {
					return UtilText.parse(owner,
							"The amount of stamina and determination [npc.name] [npc.has]. [npc.She] will be defeated in combat if this reaches 0.
"
								+ "Extra health is added to the 'bonus' value from:
"
								+""+ GameCharacter.HEALTH_CALCULATION + "");
				}
			},

	MANA_MAXIMUM(0,
			1,
			1000,
			"aura",
			"Aura",
			"manaIcon",
			Colour.ATTRIBUTE_MANA,
			"aura-boost", "aura-drain", null) {
				@Override
				public String getDescription(GameCharacter owner) {
					return UtilText.parse(owner,
							"A measure of the amount of arcane energy [npc.name] [npc.has] in [npc.her] aura.
"
								+ "Extra aura is added to the 'bonus' value from:
"
								+ "" + GameCharacter.MANA_CALCULATION + "");
				}
			},

	EXPERIENCE(0,
			0,
			1000000,
			"experience",
			"Experience",
			"experienceIcon",
			Colour.GENERIC_EXPERIENCE,
			"learning", "forgetfulness", null) {
				@Override
				public String getDescription(GameCharacter owner) {
					return UtilText.parse(owner,
							"How much progress [npc.name] [npc.has] made to the next level.");
				}
			},

	ACTION_POINTS(0,
			0,
			10,
			"action points",
			"Action points",
			"action_points",
			Colour.GENERIC_ACTION_POINTS,
			"initiative", "lethargy", null) {
				@Override
				public String getDescription(GameCharacter owner) {
					return UtilText.parse(owner,
							"How many action points [npc.nameHasFull] available to spend on moves in combat.");
				}
			},

	AROUSAL(0,
			0,
			100,
			"arousal",
			"Arousal",
			"arousalIcon",
			Colour.ATTRIBUTE_AROUSAL,
			"long-lasting", "prematurity", null) {
				@Override
				public String getDescription(GameCharacter owner) {
					if(owner.isPlayer())
						return "How aroused you currently are. You will orgasm when your arousal maxes out.";
					else
						return UtilText.parse(owner,
								"How aroused [npc.name] is. [npc.She] will orgasm when [npc.her] arousal maxes out.");
				}
			},

	LUST(0,
			0,
			100,
			"lust",
			"Lust",
			"arousalIcon",
			Colour.ATTRIBUTE_LUST,
			"passion", "indifference", null) {
				@Override
				public String getDescription(GameCharacter owner) {
					if(owner.isPlayer()) {
						return "How desperate for sexual contact you are. Your lust will move towards your resting lust value over time.
"
								+ "Resting Lust = " + GameCharacter.RESTING_LUST_CALCULATION + "";
					} else {
						return UtilText.parse(owner,
								"How desperate for sexual contact [npc.name] is.");
					}
				}
			},

	MAJOR_PHYSIQUE(0,
			0,
			100,
			"physique",
			"Physique",
			"strengthIcon",
			Colour.ATTRIBUTE_PHYSIQUE,
			"power", "weakness", Util.newArrayListOfValues("+2 Energy per 1 physique")) {
						@Override
						public String getDescription(GameCharacter owner) {
							return UtilText.parse(owner,
									"A measure of how physically healthy [npc.name] [npc.is], physique passively increases [npc.her]"
											+ " maximum health.");
						}
					},

	MAJOR_ARCANE(0,
			0,
			100,
			"arcane",
			"Arcane",
			"intelligenceIcon",
			Colour.ATTRIBUTE_ARCANE,
			"arcane-boost", "arcane-drain", Util.newArrayListOfValues("+2 Aura per 1 arcane")) {
						@Override
						public String getDescription(GameCharacter owner) {
							return UtilText.parse(owner,
										"A measure of [npc.namePos] affinity with the arcane. This passively increases [npc.her]"
												+ " maximum aura.");
						}
					},

	MAJOR_CORRUPTION(0,
			0,
			100,
			"corruption",
			"Corruption",
			"corruptionIcon",
			Colour.ATTRIBUTE_CORRUPTION,
			"corruption", "purity", Util.newArrayListOfValues("-0.5 arousal resistance per 1 physical corruption",
					"+0.5 arousal damage per 1 physical corruption")) {
						@Override
						public String getDescription(GameCharacter owner) {
							if(owner.isPlayer()) {
								return "Corruption is a measure of your perversion and depravity, and affects which sex actions you are comfortable performing.";
							} else {
								return UtilText.parse(owner,
										"Corruption is a measure of [npc.namePos] perversion and depravity. It does not reflect how good or evil [npc.she] is.");
							}
						}
					},

	// Miscellaneous attributes:

	ENCHANTMENT_LIMIT(0,
			0,
			1000,
			"enchantment capacity",
			"Enchantment capacity",
			"enchantmentLimitIcon",
			Colour.GENERIC_ENCHANTMENT,
			"harnessing", "clumsiness", null) {
				@Override
				public String getDescription(GameCharacter owner) {
					return UtilText.parse(owner,
								"The total amount of clothing and tattoo enchantments [npc.nameIsFull] able to handle without incurring massive penalties.");
				}
			},

	FERTILITY(10, -100, 100, "fertility", "Fertility", "shieldIcon", Colour.GENERIC_SEX, "fertility", "infertility", null) {
		@Override
		public String getDescription(GameCharacter owner) {
			return "Increases the likelihood of becoming pregnant.";
		}
	},

	VIRILITY(10, -100, 100, "virility", "Virility", "shieldIcon", Colour.GENERIC_SEX, "virility", "sterility", null) {
		@Override
		public String getDescription(GameCharacter owner) {
			return "Increases the likelihood of impregnating someone.";
		}
	},

	SPELL_COST_MODIFIER(0, 0, 100, "spell efficiency", "Spell efficiency", "shieldIcon", Colour.ATTRIBUTE_MANA, "proficiency", "incompetence", null) {
		@Override
		public String getDescription(GameCharacter owner) {
			return "Reduces the cost of casting spells.";
		}
	},

	// Combat attributes:

	CRITICAL_DAMAGE(150, 100, 500, "critical power", "Critical power", "shieldIcon", Colour.ATTRIBUTE_HEALTH, "impact", "failure", null) {
		@Override
		public String getDescription(GameCharacter owner) {
			return "Each point gives 1% extra critical power.";
		}
	},

	ENERGY_SHIELDING(0, -100, 100, "health shielding", "Health shielding", "shieldIcon", Colour.ATTRIBUTE_HEALTH, "endurance", "vulnerability", null) {
		@Override
		public String getDescription(GameCharacter owner) {
			return "This value is applied to health shielding at the start of each combat turn.";
		}
	},

	// Resistances:

	RESISTANCE_PHYSICAL(0, -100, 100, "physical shielding", "Physical shielding", "shieldIcon", Colour.DAMAGE_TYPE_PHYSICAL, "toughness", "softness", null) {
		@Override
		public String getDescription(GameCharacter owner) {
			return "Reduces physical damage taken.";
		}
	},

	RESISTANCE_LUST(0, -100, 100, "lust shielding", "Lust shielding", "shieldIcon", Colour.GENERIC_SEX, "chastity", "temptation", null) {
		@Override
		public String getDescription(GameCharacter owner) {
			return "Reduces lust damage taken.";
		}
	},

	RESISTANCE_FIRE(0, -100, 100, "fire shielding", "Fire shielding", "shieldIcon", Colour.DAMAGE_TYPE_FIRE, "extinguishing", "flammability", null) {
		@Override
		public String getDescription(GameCharacter owner) {
			return "Reduces fire damage taken.";
		}
	},

	RESISTANCE_ICE(0, -100, 100, "cold shielding", "Cold shielding", "shieldIcon", Colour.DAMAGE_TYPE_COLD, "warmth", "frostbite", null) {
		@Override
		public String getDescription(GameCharacter owner) {
			return "Reduces cold damage taken.";
		}
	},

	RESISTANCE_POISON(0, -100, 100, "poison shielding", "Poison shielding", "shieldIcon", Colour.DAMAGE_TYPE_POISON, "anti-venom", "sickness", null) {
		@Override
		public String getDescription(GameCharacter owner) {
			return "Reduces poison damage taken.";
		}
	},

	// Damages:

	DAMAGE_UNARMED(0, -100, 100, "unarmed damage", "Unarmed damage", "swordIcon", Colour.ATTRIBUTE_HEALTH, "martial arts", "martial incompetence", null) {
		@Override
		public String getDescription(GameCharacter owner) {
			return "Increases damage dealt from unarmed attacks, including special attacks obtained from non-human bodyparts.";
		}
	},

	DAMAGE_MELEE_WEAPON(0, -100, 100, "melee weapon damage", "Melee Weapon damage", "swordIcon", Colour.ATTRIBUTE_HEALTH, "melee mastery", "melee incompetence", null) {
		@Override
		public String getDescription(GameCharacter owner) {
			return "Increases damage dealt from attacks by melee weapons.";
		}
	},

	DAMAGE_RANGED_WEAPON(0, -100, 100, "ranged weapon damage", "Ranged weapon damage", "swordIcon", Colour.ATTRIBUTE_HEALTH, "ranged mastery", "ranged incompetence", null) {
		@Override
		public String getDescription(GameCharacter owner) {
			return "Increases damage dealt from attacks by ranged weapons.";
		}
	},

	DAMAGE_SPELLS(0, -100, 100, "spell damage", "Spell damage", "swordIcon", Colour.ATTRIBUTE_MANA, "arcane power", "arcane dulling", null) {
		@Override
		public String getDescription(GameCharacter owner) {
			return "Increases spell damage.";
		}
	},

	DAMAGE_PHYSICAL(0, -100, 100, "physical damage", "Physical damage", "swordIcon", Colour.DAMAGE_TYPE_PHYSICAL, "force", "softness", null) {
		@Override
		public String getDescription(GameCharacter owner) {
			return "Increases physical damage.";
		}
	},

	DAMAGE_LUST(0, -100, 100, "lust damage", "Lust damage", "swordIcon", Colour.GENERIC_SEX, "seduction", "repulsion", null) {
		@Override
		public String getDescription(GameCharacter owner) {
			return "Increases lust damage.";
		}
	},

	DAMAGE_FIRE(0, -100, 100, "fire damage", "Fire damage", "swordIcon", Colour.DAMAGE_TYPE_FIRE, "inferno", "dying embers", null) {
		@Override
		public String getDescription(GameCharacter owner) {
			return "Increases fire damage.";
		}
	},

	DAMAGE_ICE(0, -100, 100, "cold damage", "Cold damage", "swordIcon", Colour.DAMAGE_TYPE_COLD, "blizzard", "slush", null) {
		@Override
		public String getDescription(GameCharacter owner) {
			return "Increases cold damage.";
		}
	},

	DAMAGE_POISON(0, -100, 100, "poison damage", "Poison damage", "swordIcon", Colour.DAMAGE_TYPE_POISON, "venom", "dilution", null) {
		@Override
		public String getDescription(GameCharacter owner) {
			return "Increases poison damage.";
		}
	},

	// Racial:

	DAMAGE_ANGEL(0, -100, 100, "angelic damage", "Angelic damage", "swordIcon", Colour.RACE_ANGEL, "angelic-obliteration", "angelic-mercy", null) {
		@Override
		public String getDescription(GameCharacter owner) {
			return "Increases damage vs angels.";
		}
	},
	DAMAGE_CAT_MORPH(0, -100, 100, "cat-morph damage", "Cat-morph damage", "swordIcon", Colour.RACE_CAT_MORPH, "cat-morph-obliteration", "cat-morph-mercy", null) {
		@Override
		public String getDescription(GameCharacter owner) {
			return "Increases damage vs cat-morphs.";
		}
	},
	DAMAGE_COW_MORPH(0, -100, 100, "cow-morph damage", "Cow-morph damage", "swordIcon", Colour.RACE_COW_MORPH, "cow-morph-obliteration", "cow-morph-mercy", null) {
		@Override
		public String getDescription(GameCharacter owner) {
			return "Increases damage vs cow-morphs.";
		}
	},
	DAMAGE_DEMON(0, -100, 100, "demonic damage", "Demonic damage", "swordIcon", Colour.RACE_DEMON, "demonic-obliteration", "demonic-mercy", null) {
		@Override
		public String getDescription(GameCharacter owner) {
			return "Increases damage vs demons.";
		}
	},
	DAMAGE_DOG_MORPH(0, -100, 100, "dog-morph damage", "Dog-morph damage", "swordIcon", Colour.RACE_DOG_MORPH, "dog-morph-obliteration", "dog-morph-mercy", null) {
		@Override
		public String getDescription(GameCharacter owner) {
			return "Increases damage vs dog-morphs.";
		}
	},
	DAMAGE_HARPY(0, -100, 100, "harpy damage", "Harpy damage", "swordIcon", Colour.RACE_HARPY, "harpy-obliteration", "harpy-mercy", null) {
		@Override
		public String getDescription(GameCharacter owner) {
			return "Increases damage vs harpies.";
		}
	},
	DAMAGE_HORSE_MORPH(0, -100, 100, "horse-morph damage", "Horse-morph damage", "swordIcon", Colour.RACE_HORSE_MORPH, "horse-morph-obliteration", "horse-morph-mercy", null) {
		@Override
		public String getDescription(GameCharacter owner) {
			return "Increases damage vs horse-morphs.";
		}
	},
	DAMAGE_IMP(0, -100, 100, "imp damage", "Imp damage", "swordIcon", Colour.RACE_IMP, "impish-obliteration", "impish-mercy", null) {
		@Override
		public String getDescription(GameCharacter owner) {
			return "Increases damage vs imps.";
		}
	},
	DAMAGE_REINDEER_MORPH(0, -100, 100, "reindeer-morph damage", "Reindeer-morph damage", "swordIcon", Colour.RACE_REINDEER_MORPH, "reindeer-morph-obliteration", "reindeer-morph-mercy", null) {
		@Override
		public String getDescription(GameCharacter owner) {
			return "Increases damage vs reindeer-morphs.";
		}
	},
	DAMAGE_HUMAN(0, -100, 100, "human damage", "Human damage", "swordIcon", Colour.RACE_HUMAN, "human-obliteration", "human-mercy", null) {
		@Override
		public String getDescription(GameCharacter owner) {
			return "Increases damage vs humans.";
		}
	},
	DAMAGE_SQUIRREL_MORPH(0, -100, 100, "squirrel-morph damage", "Squirrel-morph damage", "swordIcon", Colour.RACE_SQUIRREL_MORPH, "squirrel-morph-obliteration", "squirrel-morph-mercy", null) {
		@Override
		public String getDescription(GameCharacter owner) {
			return "Increases damage vs squirrel-morphs.";
		}
	},
	DAMAGE_RAT_MORPH(0, -100, 100, "rat-morph damage", "Rat-morph damage", "swordIcon", Colour.RACE_RAT_MORPH, "rat-morph-obliteration", "rat-morph-mercy", null) {
		@Override
		public String getDescription(GameCharacter owner) {
			return "Increases damage vs rat-morphs.";
		}
	},
	DAMAGE_RABBIT_MORPH(0, -100, 100, "rabbit-morph damage", "Rabbit-morph damage", "swordIcon", Colour.RACE_RABBIT_MORPH, "rabbit-morph-obliteration", "rabbit-morph-mercy", null) {
		@Override
		public String getDescription(GameCharacter owner) {
			return "Increases damage vs rabbit-morphs.";
		}
	},
	DAMAGE_BAT_MORPH(0, -100, 100, "bat-morph damage", "Bat-morph damage", "swordIcon", Colour.RACE_BAT_MORPH, "bat-morph-obliteration", "bat-morph-mercy", null) {
		@Override
		public String getDescription(GameCharacter owner) {
			return "Increases damage vs bat-morphs.";
		}
	},
	DAMAGE_ALLIGATOR_MORPH(0, -100, 100, "alligator-morph damage", "Alligator-morph damage", "swordIcon", Colour.RACE_ALLIGATOR_MORPH, "alligator-morph-obliteration", "alligator-morph-mercy", null) {
		@Override
		public String getDescription(GameCharacter owner) {
			return "Increases damage vs alligator-morphs.";
		}
	},
	DAMAGE_WOLF_MORPH(0, -100, 100, "wolf-morph damage", "Wolf-morph damage", "swordIcon", Colour.RACE_WOLF_MORPH, "wolf-morph-obliteration", "wolf-morph-mercy", null) {
		@Override
		public String getDescription(GameCharacter owner) {
			return "Increases damage vs wolf-morphs.";
		}
	},
	DAMAGE_FOX_MORPH(0, -100, 100, "fox-morph damage", "Fox-morph damage", "swordIcon", Colour.RACE_FOX_MORPH, "fox-morph-obliteration", "fox-morph-mercy", null) {
		@Override
		public String getDescription(GameCharacter owner) {
			return "Increases damage vs fox-morphs.";
		}
	},
	DAMAGE_SLIME(0, -100, 100, "slime damage", "Slime damage", "swordIcon", Colour.RACE_SLIME, "slime-obliteration", "slime-mercy", null) {
		@Override
		public String getDescription(GameCharacter owner) {
			return "Increases damage vs slimes.";
		}
	},
	DAMAGE_ELEMENTAL(0, -100, 100, "elemental damage", "Elemental damage", "swordIcon", Colour.SPELL_SCHOOL_ARCANE, "elemental-obliteration", "elemental-mercy", null) {
		@Override
		public String getDescription(GameCharacter owner) {
			return "Increases damage vs elementals.";
		}
	},

//	RESISTANCE_ANGEL(0, -100, 100, "angelic resistance", "Angelic resistance", "shieldIcon", Colour.RACE_ANGEL, "angelic-immunity", "angelic-vulnerability", null) {
//		@Override
//		public String getDescription(GameCharacter owner) {
//			return "Increases resistance vs damage inflicted by angels.";
//		}
//	},
//	RESISTANCE_CAT_MORPH(0, -100, 100, "cat-morph resistance", "Cat-morph resistance", "shieldIcon", Colour.RACE_CAT_MORPH, "cat-morph-immunity", "cat-morph-vulnerability", null) {
//		@Override
//		public String getDescription(GameCharacter owner) {
//			return "Increases resistance vs damage inflicted by cat-morphs.";
//		}
//	},
//	RESISTANCE_COW_MORPH(0, -100, 100, "cow-morph resistance", "Cow-morph resistance", "shieldIcon", Colour.RACE_COW_MORPH, "cow-morph-immunity", "cow-morph-vulnerability", null) {
//		@Override
//		public String getDescription(GameCharacter owner) {
//			return "Increases resistance vs damage inflicted by cow-morphs.";
//		}
//	},
//	RESISTANCE_DEMON(0, -100, 100, "demonic resistance", "Demonic resistance", "shieldIcon", Colour.RACE_DEMON, "demonic-immunity", "demonic-vulnerability", null) {
//		@Override
//		public String getDescription(GameCharacter owner) {
//			return "Increases resistance vs damage inflicted by demons.";
//		}
//	},
//	RESISTANCE_DOG_MORPH(0, -100, 100, "dog-morph resistance", "Dog-morph resistance", "shieldIcon", Colour.RACE_DOG_MORPH, "dog-morph-immunity", "dog-morph-vulnerability", null) {
//		@Override
//		public String getDescription(GameCharacter owner) {
//			return "Increases resistance vs damage inflicted by dog-morphs.";
//		}
//	},
//	RESISTANCE_HARPY(0, -100, 100, "harpy resistance", "Harpy resistance", "shieldIcon", Colour.RACE_HARPY, "harpy-immunity", "harpy-vulnerability", null) {
//		@Override
//		public String getDescription(GameCharacter owner) {
//			return "Increases resistance vs damage inflicted by harpies.";
//		}
//	},
//	RESISTANCE_HORSE_MORPH(0, -100, 100, "horse-morph resistance", "Horse-morph resistance", "shieldIcon", Colour.RACE_HORSE_MORPH, "horse-morph-immunity", "horse-morph-vulnerability", null) {
//		@Override
//		public String getDescription(GameCharacter owner) {
//			return "Increases resistance vs damage inflicted by horse-morphs.";
//		}
//	},
//	RESISTANCE_IMP(0, -100, 100, "imp resistance", "Imp resistance", "shieldIcon", Colour.RACE_IMP, "impish-immunity", "impish-vulnerability", null) {
//		@Override
//		public String getDescription(GameCharacter owner) {
//			return "Increases resistance vs damage inflicted by imps.";
//		}
//	},
//	RESISTANCE_REINDEER_MORPH(0, -100, 100, "reindeer-morph resistance", "Reindeer-morph resistance", "shieldIcon", Colour.RACE_REINDEER_MORPH, "reindeer-morph-immunity", "reindeer-morph-vulnerability", null) {
//		@Override
//		public String getDescription(GameCharacter owner) {
//			return "Increases resistance vs damage inflicted by reindeer-morphs.";
//		}
//	},
//	RESISTANCE_HUMAN(0, -100, 100, "human resistance", "Human resistance", "shieldIcon", Colour.RACE_HUMAN, "human-immunity", "human-vulnerability", null) {
//		@Override
//		public String getDescription(GameCharacter owner) {
//			return "Increases resistance vs damage inflicted by humans.";
//		}
//	},
//	RESISTANCE_SQUIRREL_MORPH(0, -100, 100, "squirrel-morph resistance", "Squirrel-morph resistance", "shieldIcon", Colour.RACE_SQUIRREL_MORPH, "squirrel-morph-immunity", "squirrel-morph-vulnerability", null) {
//		@Override
//		public String getDescription(GameCharacter owner) {
//			return "Increases resistance vs damage inflicted by squirrel-morphs.";
//		}
//	},
//	RESISTANCE_RAT_MORPH(0, -100, 100, "rat-morph resistance", "Rat-morph resistance", "shieldIcon", Colour.RACE_RAT_MORPH, "rat-morph-immunity", "rat-morph-vulnerability", null) {
//		@Override
//		public String getDescription(GameCharacter owner) {
//			return "Increases resistance vs damage inflicted by rat-morphs.";
//		}
//	},
//	RESISTANCE_RABBIT_MORPH(0, -100, 100, "rabbit-morph resistance", "Rabbit-morph resistance", "shieldIcon", Colour.RACE_RABBIT_MORPH, "rabbit-morph-immunity", "rabbit-morph-vulnerability", null) {
//		@Override
//		public String getDescription(GameCharacter owner) {
//			return "Increases resistance vs damage inflicted by rabbit-morphs.";
//		}
//	},
//	RESISTANCE_BAT_MORPH(0, -100, 100, "bat-morph resistance", "Bat-morph resistance", "shieldIcon", Colour.RACE_BAT_MORPH, "bat-morph-immunity", "bat-morph-vulnerability", null) {
//		@Override
//		public String getDescription(GameCharacter owner) {
//			return "Increases resistance vs damage inflicted by bat-morphs.";
//		}
//	},
//	RESISTANCE_ALLIGATOR_MORPH(0, -100, 100, "alligator-morph resistance", "Alligator-morph resistance", "shieldIcon", Colour.RACE_ALLIGATOR_MORPH, "alligator-morph-immunity", "alligator-morph-vulnerability", null) {
//		@Override
//		public String getDescription(GameCharacter owner) {
//			return "Increases resistance vs damage inflicted by alligator-morphs.";
//		}
//	},
//	RESISTANCE_WOLF_MORPH(0, -100, 100, "wolf-morph resistance", "Wolf-morph resistance", "shieldIcon", Colour.RACE_WOLF_MORPH, "wolf-morph-immunity", "wolf-morph-vulnerability", null) {
//		@Override
//		public String getDescription(GameCharacter owner) {
//			return "Increases resistance vs damage inflicted by wolf-morphs.";
//		}
//	},
//	RESISTANCE_FOX_MORPH(0, -100, 100, "fox-morph resistance", "Fox-morph resistance", "shieldIcon", Colour.RACE_FOX_MORPH, "fox-morph-immunity", "fox-morph-vulnerability", null) {
//		@Override
//		public String getDescription(GameCharacter owner) {
//			return "Increases resistance vs damage inflicted by fox-morphs.";
//		}
//	},
//	RESISTANCE_SLIME(0, -100, 100, "slime resistance", "Slime resistance", "shieldIcon", Colour.RACE_SLIME, "slime-immunity", "slime-vulnerability", null) {
//		@Override
//		public String getDescription(GameCharacter owner) {
//			return "Increases resistance vs damage inflicted by slimes.";
//		}
//	},
//	RESISTANCE_ELEMENTAL(0, -100, 100, "elemental resistance", "Elemental resistance", "swordIcon", Colour.SPELL_SCHOOL_ARCANE, "elemental-immunity", "elemental-vulnerability", null) {
//		@Override
//		public String getDescription(GameCharacter owner) {
//			return "Increases resistance vs elementals.";
//		}
//	}
	;

	private int baseValue;
	private	int lowerLimit;
	private	int upperLimit;
	private String name;
	private String nameAbbreviation;
	private String positiveEnchantment;
	private String negativeEnchantment;
	private Colour colour;
	public static final List<Attribute> attributeBonusesForEnchanting = new ArrayList<>();
	public static final List<Attribute> baseAttributesGood = new ArrayList<>();
	private List<String> extraEffects;
	private String SVGString;

	static {
		attributeBonusesForEnchanting.add(Attribute.CRITICAL_DAMAGE);

		attributeBonusesForEnchanting.add(Attribute.SPELL_COST_MODIFIER);

		attributeBonusesForEnchanting.add(Attribute.RESISTANCE_PHYSICAL);
		attributeBonusesForEnchanting.add(Attribute.RESISTANCE_FIRE);
		attributeBonusesForEnchanting.add(Attribute.RESISTANCE_ICE);
		attributeBonusesForEnchanting.add(Attribute.RESISTANCE_POISON);

		attributeBonusesForEnchanting.add(Attribute.DAMAGE_PHYSICAL);
		attributeBonusesForEnchanting.add(Attribute.DAMAGE_SPELLS);
		attributeBonusesForEnchanting.add(Attribute.DAMAGE_FIRE);
		attributeBonusesForEnchanting.add(Attribute.DAMAGE_ICE);
		attributeBonusesForEnchanting.add(Attribute.DAMAGE_POISON);

		baseAttributesGood.add(Attribute.MAJOR_PHYSIQUE);
		baseAttributesGood.add(Attribute.MAJOR_ARCANE);
	}

	private Attribute(int baseValue,
			int lowerLimit,
			int upperLimit,
			String name,
			String nameAbbreviation,
			String pathName,
			Colour colour,
			String positiveEnchantment,
			String negativeEnchantment,
			List<String> extraEffects) {

		this.baseValue = baseValue;
		this.lowerLimit = lowerLimit;
		this.upperLimit = upperLimit;
		this.name = name;
		this.nameAbbreviation = nameAbbreviation;
		this.colour = colour;
		this.positiveEnchantment = positiveEnchantment;
		this.negativeEnchantment = negativeEnchantment;
		this.extraEffects = extraEffects;

		try {
			InputStream is = this.getClass().getResourceAsStream("/com/lilithsthrone/res/UIElements/" + pathName + ".svg");
			if(is==null) {
				System.err.println("Error! Attribute icon file does not exist (Trying to read from '"+pathName+"')!");
			}
			SVGString = Util.inputStreamToString(is);

			SVGString = SvgUtil.colourReplacement(this.toString(), colour, SVGString);

			is.close();

		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public static Attribute[] getCoreAttributes() {
		return new Attribute[] { MAJOR_PHYSIQUE, MAJOR_ARCANE, MAJOR_CORRUPTION };
	}

	public static Attribute getAttributeFromId(String attributeId) {
		if(Main.isVersionOlderThan(Game.loadingVersion, "0.2.12.6")) {
			if(attributeId.startsWith("RESISTANCE_ELEMENTAL")) {
				attributeId = "RESISTANCE_ELEMENTAL";
			} else if(attributeId.startsWith("DAMAGE_ELEMENTAL")) {
				attributeId = "DAMAGE_ELEMENTAL";
			} else if(attributeId.equals("CORRUPTION")) {
				attributeId = "MAJOR_CORRUPTION";
			} else if(attributeId.equals("STRENGTH") || attributeId.equals("MAJOR_STRENGTH")) {
				attributeId = "MAJOR_PHYSIQUE";
			}
		}

		return Attribute.valueOf(attributeId);
	}

	public int getBaseValue() {
		return baseValue;
	}

	public int getLowerLimit() {
		return lowerLimit;
	}

	public int getUpperLimit() {
		return upperLimit;
	}

	public String getName() {
		return name;
	}

	public String getColouredName(String tag) {
		return "<"+tag+" style='color:"+this.getColour().toWebHexString()+";'>"+name+"</"+tag+">";
	}

	public String getAbbreviatedName() {
		return nameAbbreviation;
	}

	public abstract String getDescription(GameCharacter owner);

	public Colour getColour() {
		return colour;
	}

	public String getAttributeChangeText(GameCharacter target, float value) {
		if(target==null) {
			return "";
		}

		if (value > 0) {
			return UtilText.parse(target,
					"
"
						+ "[npc.Name] [npc.verb(gain)] " + value + " " + this.getName() + "!"
					+ "
");

		} else if (value < 0) {
			return UtilText.parse(target,
					"
"
						+ "[npc.Name] [npc.verb(lose)] " + value + " " + this.getName() + "!"
					+ "
");

		} else {
			return UtilText.parse(target,
					"
"
						+ "[npc.NamePos] " + this.getName() + " remains unchanged..."
					+ "
");
		}

	}

	private StringBuilder descriptionSB = new StringBuilder();

	public String getEffectsAsStringList() {
		descriptionSB = new StringBuilder();

		if (extraEffects != null)
			for (String s : extraEffects)
				descriptionSB.append("
" + s);

		return descriptionSB.toString();
	}

	public String getPositiveEnchantment() {
		return positiveEnchantment;
	}

	public String getNegativeEnchantment() {
		return negativeEnchantment;
	}

	public String getSVGString() {
		return SVGString;
	}

}


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

/**
 * @since 0.1.99
 * @version 0.1.99
 * @author Innoxia
 */
public class AttributeRange {
	private float minimum, maximum;

	public AttributeRange(float minimum, float maximum) {
		super();
		this.minimum = minimum;
		this.maximum = maximum;
	}

	public float getMinimum() {
		return minimum;
	}

	public float getMaximum() {
		return maximum;
	}

	public float getMedian() {
		return (maximum+minimum)/2;
	}

	public float getRandomVariance() {
		return (float) (Math.random()*(maximum-minimum));
	}
}

repo_name: klorpa/Pedo

license: unknown


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

import com.lilithsthrone.game.character.effects.StatusEffect;
import com.lilithsthrone.utils.Colour;

/**
 * @since 0.1.65
 * @version 0.1.79
 * @author Innoxia
 */
public enum CorruptionLevel {

	/**A character at this level: Will not want any sexual relations with anyone but the person they love.*/
	ZERO_PURE("pure", 0, 5, Colour.CORRUPTION_STAGE_ZERO, 0) {
		@Override
		public StatusEffect getRelatedStatusEffect() {
			return StatusEffect.CORRUPTION_PERK_0;
		}

		@Override
		public boolean isAbleToPerformCorruptiveAction(CorruptionLevel action) {
			switch(action){
				case ZERO_PURE:
						return true;
				case ONE_VANILLA:
						return true;
				case TWO_HORNY:
						return true;
				case THREE_DIRTY:
						return false;
				case FOUR_LUSTFUL:
						return false;
				case FIVE_CORRUPT:
						return false;
				default:
						return false;
			}
		}
	},
	/**A character at this level: Will be open to the idea of having multiple sexual partners, and will be willing to have sex with defeated enemies. Their in-sex options will be limited, however, to quite vanilla acts.*/
	ONE_VANILLA("vanilla", 5, 15, Colour.CORRUPTION_STAGE_ONE, 0.1f) {
		@Override
		public StatusEffect getRelatedStatusEffect() {
			return StatusEffect.CORRUPTION_PERK_1;
		}

		@Override
		public boolean isAbleToPerformCorruptiveAction(CorruptionLevel action) {
			switch(action){
				case ZERO_PURE:
						return true;
				case ONE_VANILLA:
						return true;
				case TWO_HORNY:
						return true;
				case THREE_DIRTY:
						return true;
				case FOUR_LUSTFUL:
						return false;
				case FIVE_CORRUPT:
						return false;
				default:
						return false;
			}
		}
	},
	/**A character at this level: Will have sex with pretty much anything, but won't do anything too crazy.*/
	TWO_HORNY("horny", 15, 35, Colour.CORRUPTION_STAGE_TWO, 0.25f) {
		@Override
		public StatusEffect getRelatedStatusEffect() {
			return StatusEffect.CORRUPTION_PERK_2;
		}

		@Override
		public boolean isAbleToPerformCorruptiveAction(CorruptionLevel action) {
			switch(action){
				case ZERO_PURE:
						return true;
				case ONE_VANILLA:
						return true;
				case TWO_HORNY:
						return true;
				case THREE_DIRTY:
						return true;
				case FOUR_LUSTFUL:
						return true;
				case FIVE_CORRUPT:
						return false;
				default:
						return false;
			}
		}
	},
	/**A character at this level: This is where the character starts to really lose themselves to corruption. Rough sex.*/
	THREE_DIRTY("dirty", 35, 65, Colour.CORRUPTION_STAGE_THREE, 0.5f) {
		@Override
		public StatusEffect getRelatedStatusEffect() {
			return StatusEffect.CORRUPTION_PERK_3;
		}

		@Override
		public boolean isAbleToPerformCorruptiveAction(CorruptionLevel action) {
			return true;
		}
	},
	/**A character at this level: A complete sex fiend. Will do anything, with anyone, anywhere and anyhow.*/
	FOUR_LUSTFUL("lustful", 65, 95, Colour.CORRUPTION_STAGE_FOUR, 1f) {
		@Override
		public StatusEffect getRelatedStatusEffect() {
			return StatusEffect.CORRUPTION_PERK_4;
		}

		@Override
		public boolean isAbleToPerformCorruptiveAction(CorruptionLevel action) {
			return true;
		}
	},
	/**A character at this level: Is completely lost to corruption.*/
	FIVE_CORRUPT("corrupt", 95, 100, Colour.CORRUPTION_STAGE_FIVE, 2f) {
		@Override
		public StatusEffect getRelatedStatusEffect() {
			return StatusEffect.CORRUPTION_PERK_5;
		}

		@Override
		public boolean isAbleToPerformCorruptiveAction(CorruptionLevel action) {
			return true;
		}
	};

	private String name;
	private int minimumValue, maximumValue;
	private Colour colour;
	private float corruptionBypass;

	private CorruptionLevel(String name, int minimumValue, int maximumValue, Colour colour, float corruptionBypass) {
		this.name = name;
		this.minimumValue = minimumValue;
		this.maximumValue = maximumValue;
		this.colour = colour;
		this.corruptionBypass=corruptionBypass;
	}

	public abstract StatusEffect getRelatedStatusEffect();

	public abstract boolean isAbleToPerformCorruptiveAction(CorruptionLevel action);

	public String getName() {
		return name;
	}

	public int getMinimumValue() {
		return minimumValue;
	}

	public int getMaximumValue() {
		return maximumValue;
	}

	public Colour getColour() {
		return colour;
	}

	public float getCorruptionBypass() {
		return corruptionBypass;
	}

	public static CorruptionLevel getCorruptionLevelFromValue(float value){
		for(CorruptionLevel al : CorruptionLevel.values()) {
			if(value>=al.getMinimumValue() && value<al.getMaximumValue())
				return al;
		}
		return FIVE_CORRUPT;
	}
}


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

import com.lilithsthrone.game.character.effects.StatusEffect;
import com.lilithsthrone.main.Main;
import com.lilithsthrone.utils.Colour;

/**
 * @since 0.1.65
 * @version 0.2.1
 * @author Innoxia
 */
public enum IntelligenceLevel {

	ZERO_AIRHEAD("arcane impotence", 0, 5, Colour.INTELLIGENCE_STAGE_ZERO) {
		@Override
		public StatusEffect getRelatedStatusEffect() {
			if(Main.game.isInNewWorld()) {
				return StatusEffect.INTELLIGENCE_PERK_0;
			} else {
				return StatusEffect.INTELLIGENCE_PERK_0_OLD_WORLD;
			}
		}
	},

	ONE_AVERAGE("arcane potential", 5, 15, Colour.INTELLIGENCE_STAGE_ONE) {
		@Override
		public StatusEffect getRelatedStatusEffect() {
			return StatusEffect.INTELLIGENCE_PERK_1;
		}
	},

	TWO_SMART("arcane proficiency", 15, 35, Colour.INTELLIGENCE_STAGE_TWO) {
		@Override
		public StatusEffect getRelatedStatusEffect() {
			return StatusEffect.INTELLIGENCE_PERK_2;
		}
	},

	THREE_BRAINY("arcane prowess", 35, 65, Colour.INTELLIGENCE_STAGE_THREE) {
		@Override
		public StatusEffect getRelatedStatusEffect() {
			return StatusEffect.INTELLIGENCE_PERK_3;
		}
	},

	FOUR_GENIUS("arcane mastery", 65, 95, Colour.INTELLIGENCE_STAGE_FOUR) {
		@Override
		public StatusEffect getRelatedStatusEffect() {
			return StatusEffect.INTELLIGENCE_PERK_4;
		}
	},

	FIVE_POLYMATH("arcane brilliance", 95, 100, Colour.INTELLIGENCE_STAGE_FIVE) {
		@Override
		public StatusEffect getRelatedStatusEffect() {
			return StatusEffect.INTELLIGENCE_PERK_5;
		}
	};

	private String name;
	private int minimumValue, maximumValue;
	private Colour colour;

	private IntelligenceLevel(String name, int minimumValue, int maximumValue, Colour colour) {
		this.name = name;
		this.minimumValue = minimumValue;
		this.maximumValue = maximumValue;
		this.colour = colour;
	}

	public abstract StatusEffect getRelatedStatusEffect();

	public String getName() {
		return name;
	}

	public int getMinimumValue() {
		return minimumValue;
	}

	public int getMaximumValue() {
		return maximumValue;
	}

	public Colour getColour() {
		return colour;
	}

	public static IntelligenceLevel getIntelligenceLevelFromValue(float value){
		for(IntelligenceLevel al : IntelligenceLevel.values()) {
			if(value>=al.getMinimumValue() && value<al.getMaximumValue())
				return al;
		}
		return FIVE_POLYMATH;
	}

}


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

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

import com.lilithsthrone.game.PropertyValue;
import com.lilithsthrone.game.character.GameCharacter;
import com.lilithsthrone.game.character.effects.StatusEffect;
import com.lilithsthrone.game.character.fetishes.Fetish;
import com.lilithsthrone.game.character.fetishes.FetishDesire;
import com.lilithsthrone.game.character.npc.NPC;
import com.lilithsthrone.game.character.npc.NPCFlagValue;
import com.lilithsthrone.game.dialogue.utils.UtilText;
import com.lilithsthrone.game.sex.Sex;
import com.lilithsthrone.game.sex.SexPace;
import com.lilithsthrone.main.Main;
import com.lilithsthrone.utils.Colour;

/**
 * @since 0.1.97
 * @version 0.2.11
 * @author Innoxia
 */
public enum LustLevel {

	ZERO_COLD("cold", 0, 10, 0.5f, Colour.LUST_STAGE_ZERO, SexPace.SUB_RESISTING, SexPace.DOM_GENTLE) {
		@Override
		public StatusEffect getRelatedStatusEffect() {
			return StatusEffect.LUST_PERK_0;
		}
	},

	ONE_HORNY("horny", 10, 25, 0.75f, Colour.LUST_STAGE_ONE, SexPace.SUB_NORMAL, SexPace.DOM_NORMAL) {
		@Override
		public StatusEffect getRelatedStatusEffect() {
			return StatusEffect.LUST_PERK_1;
		}
	},

	TWO_AMOROUS("sensual", 25, 50, 1f, Colour.LUST_STAGE_TWO, SexPace.SUB_NORMAL, SexPace.DOM_NORMAL) {
		@Override
		public StatusEffect getRelatedStatusEffect() {
			return StatusEffect.LUST_PERK_2;
		}
	},

	THREE_LUSTFUL("amorous", 50, 75, 1.25f, Colour.LUST_STAGE_THREE, SexPace.SUB_NORMAL, SexPace.DOM_NORMAL) {
		@Override
		public StatusEffect getRelatedStatusEffect() {
			return StatusEffect.LUST_PERK_3;
		}
	},

	FOUR_IMPASSIONED("lustful", 75, 90, 1.5f, Colour.LUST_STAGE_FOUR, SexPace.SUB_EAGER, SexPace.DOM_ROUGH) {
		@Override
		public StatusEffect getRelatedStatusEffect() {
			return StatusEffect.LUST_PERK_4;
		}
	},

	FIVE_BURNING("impassioned", 90, 100, 1.5f, Colour.LUST_STAGE_FIVE, SexPace.SUB_EAGER, SexPace.DOM_ROUGH) {
		@Override
		public StatusEffect getRelatedStatusEffect() {
			return StatusEffect.LUST_PERK_5;
		}
	};

	private String name;
	private int minimumValue, maximumValue;
	private float arousalModifier;
	private Colour colour;
	private SexPace sexPaceSubmissive;
	private SexPace sexPaceDominant;

	private LustLevel(String name, int minimumValue, int maximumValue, float arousalModifier, Colour colour, SexPace sexPaceSubmissive, SexPace sexPaceDominant) {
		this.name = name;
		this.minimumValue = minimumValue;
		this.maximumValue = maximumValue;
		this.arousalModifier = arousalModifier;
		this.colour = colour;
		this.sexPaceSubmissive = sexPaceSubmissive;
		this.sexPaceDominant = sexPaceDominant;
	}

	public abstract StatusEffect getRelatedStatusEffect();

	public String getName() {
		return name;
	}

	public int getMinimumValue() {
		return minimumValue;
	}

	public int getMaximumValue() {
		return maximumValue;
	}

	public int getMedianValue() {
		return (minimumValue + maximumValue) / 2;
	}

	public float getArousalModifier() {
		return arousalModifier;
	}

	public Colour getColour() {
		return colour;
	}

	public static LustLevel getLustLevelFromValue(float value){
		for(LustLevel al : LustLevel.values()) {
			if(value>=al.getMinimumValue() && value<al.getMaximumValue()) {
				return al;
			}
		}
		return FIVE_BURNING;
	}

	public SexPace getSexPaceSubmissive() {
		return sexPaceSubmissive;
	}

	public SexPace getSexPaceDominant() {
		return sexPaceDominant;
	}

	public SexPace getSexPace(boolean consensual, GameCharacter character) {
		SexPace pace;
		if(Sex.isDom(character)) {
			pace = getSexPaceDominant();

			if((character.hasFetish(Fetish.FETISH_SUBMISSIVE) && !character.hasFetish(Fetish.FETISH_SADIST) && !character.hasFetish(Fetish.FETISH_DOMINANT))
					|| character.getFetishDesire(Fetish.FETISH_SADIST) == FetishDesire.ZERO_HATE) {
				pace = SexPace.DOM_GENTLE;

			} else if(character.getFetishDesire(Fetish.FETISH_SADIST).isNegative()) {
				pace = SexPace.DOM_NORMAL;

			} else if(character.hasFetish(Fetish.FETISH_SADIST)) {
				return SexPace.DOM_ROUGH;

			} else { // Hate sex:
				for(GameCharacter target : Sex.getAllParticipants()) {
					if(!Sex.isDom(target) && character.getAffection(target)<AffectionLevel.NEGATIVE_TWO_DISLIKE.getMaximumValue()) {
						return SexPace.DOM_ROUGH;
					}
				}
			}

		} else {
			pace = getSexPaceSubmissive();
			if(character.hasFetish(Fetish.FETISH_NON_CON_SUB) || ((character instanceof NPC) && ((NPC)character).hasFlag(NPCFlagValue.genericNPCBetrayedByPlayer))) {
				pace = SexPace.SUB_RESISTING;
			}
		}

		if(pace==SexPace.SUB_RESISTING && !Main.getProperties().hasValue(PropertyValue.nonConContent)) {
			pace = SexPace.SUB_NORMAL;
		}

		if(pace==SexPace.DOM_ROUGH
				&& ((!character.hasFetish(Fetish.FETISH_DOMINANT) && !character.hasFetish(Fetish.FETISH_SADIST) && !character.hasFetish(Fetish.FETISH_NON_CON_DOM))
						|| (character.getFetishDesire(Fetish.FETISH_SADIST).isNegative()))) {
			pace = SexPace.DOM_NORMAL;
		}

		return pace;
	}

	public List<String> getStatusEffectModifierDescription(boolean consensual, GameCharacter character) {
		List<String> modifiersList = new ArrayList<>();

		if(Main.game.isInSex()) {
			switch(this.getSexPace(consensual, character)) {
				case DOM_GENTLE:
					if(!character.isPlayer()) {
						modifiersList.add("Prefers gentle pace");
					}
					break;
				case DOM_NORMAL:
					if(!character.isPlayer()) {
						modifiersList.add("Prefers normal pace");
					}
					break;
				case DOM_ROUGH:
					if(!character.isPlayer()) {
						if(!character.hasFetish(Fetish.FETISH_DOMINANT) && !character.hasFetish(Fetish.FETISH_SADIST)) {
							modifiersList.add("Prefers normal pace");
							modifiersList.add("(Rough pace requires "+Fetish.FETISH_DOMINANT.getName(character)
													+", "+Fetish.FETISH_NON_CON_DOM.getName(character)+", or "+Fetish.FETISH_SADIST.getName(character)+" fetish)");
						} else {
							modifiersList.add("Prefers rough pace");
						}
					}
					break;
				case SUB_EAGER:
					if(!character.isPlayer()) {
						modifiersList.add("Prefers eager pace");
					}
					break;
				case SUB_NORMAL:
					if(!character.isPlayer()) {
						modifiersList.add("Prefers normal pace");
					}
					break;
				case SUB_RESISTING:
					if(!character.isPlayer()) {
						if(character.hasFetish(Fetish.FETISH_NON_CON_SUB)) {
							modifiersList.add("Always prefers resisting pace due to "+Fetish.FETISH_NON_CON_SUB.getName(character)+" fetish");
						} else {
							modifiersList.add("Prefers resisting pace");
						}
					}
					break;
			}

			int gains = (int)(this.getArousalModifier()*100);
			modifiersList.add((gains>=100?"[style.boldArousal("+gains+"%)]":"[style.boldBad("+gains+"%)]")+" arousal gains");

		}

		return modifiersList;
	}

	public String getStatusEffectDescription(boolean consensual, GameCharacter character) {
		StringBuilder sb = new StringBuilder();

		if(Main.game.isInSex()) {
			switch(this.getSexPace(consensual, character)) {
				case DOM_GENTLE:
					switch(this) {
						case ZERO_COLD:
							sb.append("[npc.NameIsFull] not really interested in having sex at all right now, and as a result, [npc.she] [npc.verb(want)] to take things slow and gentle.");
							break;
						case ONE_HORNY:
							sb.append("[npc.NameIsFull] currently quite horny, but [npc.is] still in control of [npc.her] lust, allowing [npc.her] to keep a cool head and concentrate on taking things slow and gentle.");
							break;
						case TWO_AMOROUS:
							sb.append("[npc.NameIsFull] currently feeling more than a little lustful, but [npc.is] still able to concentrate on taking things slow and gentle.");
							break;
						case THREE_LUSTFUL:
							sb.append("[npc.NameIsFull] currently burning with lust, but [npc.is] still able to concentrate on taking things slow and gentle.");
							break;
						case FOUR_IMPASSIONED:
							sb.append("[npc.NameIsFull] completely burning with lust, but [npc.is] still able to concentrate on taking things slow and gentle.");
							break;
						case FIVE_BURNING:
							sb.append("[npc.NameIsFull] completely overwhelmed with lust, but, somehow, [npc.is] still able to concentrate on taking things slow and gentle.");
							break;
					}
					break;
				case DOM_NORMAL:
				case SUB_NORMAL:
					switch(this) {
						case ZERO_COLD:
							sb.append("Although [npc.nameIsFull]n't really interested in having sex at all right now, [npc.she] [npc.is] still able to force [npc.herself] to act as though [npc.sheIs] turned on and horny.");
							break;
						case ONE_HORNY:
							sb.append("[npc.NameIsFull] currently quite horny, and [npc.is] more than happy to have sex at the moment.");
							break;
						case TWO_AMOROUS:
							sb.append("[npc.NameIsFull] currently feeling more than a little lustful, and [npc.is] very happy to be having sex right at this moment.");
							break;
						case THREE_LUSTFUL:
							sb.append("[npc.NameIsFull] currently burning with lust, and [npc.is] ecstatic to be having sex right at this moment.");
							break;
						case FOUR_IMPASSIONED:
							sb.append("[npc.NameIsFull] completely burning with lust, but [npc.is] still able to prevent [npc.herself] from getting too carried away with things.");
							break;
						case FIVE_BURNING:
							sb.append("[npc.NameIsFull] completely overwhelmed with lust, but, somehow, [npc.is] still able to prevent [npc.herself] from getting too carried away with things.");
							break;
					}
					break;
				case DOM_ROUGH:
				case SUB_EAGER:
					switch(this) {
						case ZERO_COLD:
							sb.append("Although [npc.nameIsFull]n't really interested in having sex at all right now, [npc.she] [npc.is] still able to force [npc.herself] to act as though [npc.sheIs] extremely turned on.");
							break;
						case ONE_HORNY:
							sb.append("[npc.NameIsFull] currently quite horny, and [npc.is] more than happy to have sex at the moment.");
							break;
						case TWO_AMOROUS:
							sb.append("[npc.NameIsFull] currently feeling more than a little lustful, and [npc.is] very happy to be having sex right at this moment.");
							break;
						case THREE_LUSTFUL:
							sb.append("[npc.NameIsFull] currently burning with lust, and [npc.is] ecstatic to be having sex right at this moment.");
							break;
						case FOUR_IMPASSIONED:
							sb.append("[npc.NameIsFull] completely burning with lust, and [npc.is] really starting to get carried away with things.");
							break;
						case FIVE_BURNING:
							sb.append("[npc.NameIsFull] completely overwhelmed with lust, and [npc.has] totally lost [npc.herself] to the pleasure of having sex.");
							break;
					}
					break;
				case SUB_RESISTING:
					switch(this) {
						case ZERO_COLD:
							sb.append("[npc.NameIsFull] not at all interested in having sex right now, and [npc.is] desperately trying to resist what's currently happening to [npc.herHim].");
							break;
						case ONE_HORNY:
							sb.append("[npc.NameIsFull] currently quite horny, but, despite this, [npc.sheIs] not at all happy with [npc.her] current situation, and [npc.is] desperately resisting sex.");
							break;
						case TWO_AMOROUS:
							sb.append("[npc.NameIsFull] currently feeling more than a little lustful, but, despite this, [npc.sheIs] not at all happy with [npc.her] current situation, and [npc.is] desperately resisting sex.");
							break;
						case THREE_LUSTFUL:
							sb.append("[npc.NameIsFull] currently burning with lust, but, despite this, [npc.sheIs] not at all happy with [npc.her] current situation, and [npc.is] desperately resisting sex.");
							break;
						case FOUR_IMPASSIONED:
							sb.append("[npc.NameIsFull] completely burning with lust, but, despite this, [npc.sheIs] not at all happy with [npc.her] current situation, and [npc.is] desperately resisting sex.");
							break;
						case FIVE_BURNING:
							sb.append("[npc.NameIsFull] completely overwhelmed with lust, but, despite this, [npc.sheIs] not at all happy with [npc.her] current situation, and [npc.is] desperately resisting sex.");
							break;
					}
					break;
			}

		} else {
			switch(this) {
				case ZERO_COLD:
					sb.append("[npc.NameIsFull] not really interested in having sex at all right now.");
					break;
				case ONE_HORNY:
					sb.append("[npc.NameIsFull] currently quite horny, but [npc.is] still in control of [npc.her] lust.");
					if(Main.game.isOpportunisticAttackersEnabled() && character.isPlayer())
						sb.append("
Opportunistic Attackers
It seems you're beginning to attract trouble.");
					break;
				case TWO_AMOROUS:
					sb.append("[npc.NameIsFull] currently feeling more than a little lustful, and [npc.is] thinking about sex quite a lot.");
					if(Main.game.isOpportunisticAttackersEnabled() && character.isPlayer())
						sb.append("
Opportunistic Attackers
You can feel more and more troublesome gazes.");
					break;
				case THREE_LUSTFUL:
					sb.append("[npc.NameIsFull] currently burning with lust, and [npc.is] struggling to think of anything other than sex.");
					if(Main.game.isOpportunisticAttackersEnabled() && character.isPlayer())
						sb.append("
Opportunistic Attackers
Your lust-filled aura can no longer be denied.");
					break;
				case FOUR_IMPASSIONED:
					sb.append("[npc.NameIsFull] completely burning with lust, and [npc.is] struggling to think of anything other than sex.");
					if(Main.game.isOpportunisticAttackersEnabled() && character.isPlayer())
						sb.append("
Opportunistic Attackers
Almost every passerby turns to you with lustful gazes.");
					break;
				case FIVE_BURNING:
					sb.append("[npc.NameIsFull] completely overwhelmed with lust, and [npc.is] incapable of thinking of anything but sex.");
					if(Main.game.isOpportunisticAttackersEnabled() && character.isPlayer())
						sb.append("
Opportunistic Attackers
Everyone can tell you're completely filled with lust. Some will probably try take advantage.");
					break;
			}
		}

		return UtilText.parse(character, sb.toString());

	}
}


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

import com.lilithsthrone.game.character.GameCharacter;
import com.lilithsthrone.game.dialogue.utils.UtilText;
import com.lilithsthrone.utils.Colour;

/**
 * @since 0.1.82
 * @version 0.1.82
 * @author Innoxia
 */
public enum ObedienceLevel {

	NEGATIVE_FIVE_REBELLIOUS("rebellious", -100, -90, Colour.AFFECTION_NEGATIVE_FIVE),

	NEGATIVE_FOUR_DEFIANT("defiant", -90, -70, Colour.AFFECTION_NEGATIVE_FOUR),

	NEGATIVE_THREE_STRONG_INSUBORDINATE("insubordinate", -70, -50, Colour.AFFECTION_NEGATIVE_THREE),

	NEGATIVE_TWO_UNRULY("unruly", -50, -30, Colour.AFFECTION_NEGATIVE_TWO),

	NEGATIVE_ONE_DISOBEDIENT("disobedient", -30, -10, Colour.AFFECTION_NEGATIVE_ONE),

	ZERO_FREE_WILLED("free-willed", -10, 10, Colour.AFFECTION_NEUTRAL),

	POSITIVE_ONE_AGREEABLE("agreeable", 10, 30, Colour.AFFECTION_POSITIVE_ONE),

	POSITIVE_TWO_OBEDIENT("obedient", 30, 50, Colour.AFFECTION_POSITIVE_TWO),

	POSITIVE_THREE_DISCIPLINED("disciplined", 50, 70, Colour.AFFECTION_POSITIVE_THREE),

	POSITIVE_FOUR_DUTIFUL("dutiful", 70, 90, Colour.AFFECTION_POSITIVE_FOUR),

	POSITIVE_FIVE_SUBSERVIENT("subservient", 90, 100, Colour.AFFECTION_POSITIVE_FIVE);

	private String name;
	private int minimumValue, maximumValue;
	private Colour colour;

	private ObedienceLevel(String name, int minimumValue, int maximumValue, Colour colour) {
		this.name = name;
		this.minimumValue = minimumValue;
		this.maximumValue = maximumValue;
		this.colour = colour;
	}

	private static StringBuilder sb = new StringBuilder();
	public static String getDescription(GameCharacter character, ObedienceLevel affectionLevel, boolean withColour, boolean longDescription) {
		sb.setLength(0);

		switch(affectionLevel) {
			case NEGATIVE_FIVE_REBELLIOUS:
				if(withColour) {
					sb.append(UtilText.parse(character, "[npc.Name] [npc.is] rebellious"+(longDescription?", and outright [npc.verb(refuse)] to obey any command.":".")));
				} else {
					sb.append(UtilText.parse(character, "[npc.Name] [npc.is] rebellious"+(longDescription?", and outright [npc.verb(refuse)] to obey any command.":".")));
				}
				break;
			case NEGATIVE_FOUR_DEFIANT:
				if(withColour) {
					sb.append(UtilText.parse(character, "[npc.Name] [npc.is] defiant"+(longDescription?", and only [npc.verb(obey)] commands when [npc.sheIs] physically forced to.":".")));
				} else {
					sb.append(UtilText.parse(character, "[npc.Name] [npc.is] defiant"+(longDescription?", and only [npc.verb(obey)] commands when [npc.sheIs] physically forced to.":".")));
				}
				break;
			case NEGATIVE_THREE_STRONG_INSUBORDINATE:
				if(withColour) {
					sb.append(UtilText.parse(character, "[npc.Name] [npc.is] insubordinate"+(longDescription?", and sometimes [npc.verb(refuse)] to obey commands.":".")));
				} else {
					sb.append(UtilText.parse(character, "[npc.Name] [npc.is] insubordinate"+(longDescription?", and sometimes [npc.verb(refuse)] to obey commands.":".")));
				}
				break;
			case NEGATIVE_TWO_UNRULY:
				if(withColour) {
					sb.append(UtilText.parse(character, "[npc.Name] [npc.is] unruly"
							+(longDescription?", and will refuse to obey commands if [npc.she] [npc.verb(think)] that [npc.she] can get away with it.":".")));
				} else {
					sb.append(UtilText.parse(character, "[npc.Name] [npc.is] unruly"+(longDescription?", and will refuse to obey commands if [npc.she] [npc.verb(think)] that [npc.she] can get away with it.":".")));
				}
				break;
			case NEGATIVE_ONE_DISOBEDIENT:
				if(withColour) {
					sb.append(UtilText.parse(character, "[npc.Name] [npc.is] disobedient"+(longDescription?", and will often complain about having to follow orders.":".")));
				} else {
					sb.append(UtilText.parse(character, "[npc.Name] [npc.is] disobedient"+(longDescription?", and will often complain about having to follow orders.":".")));
				}
				break;
			case ZERO_FREE_WILLED:
				if(withColour) {
					sb.append(UtilText.parse(character, "[npc.Name] [npc.is] free-willed"+(longDescription?", and will do whatever [npc.she] [npc.verb(want)].":".")));
				} else {
					sb.append(UtilText.parse(character, "[npc.Name] [npc.is] free-willed"+(longDescription?" and will do whatever [npc.she] [npc.verb(want)].":".")));
				}
				break;
			case POSITIVE_ONE_AGREEABLE:
				if(withColour) {
					sb.append(UtilText.parse(character, "[npc.Name] [npc.is] agreeable"+(longDescription?", and will carry out most orders without complaint.":".")));
				} else {
					sb.append(UtilText.parse(character, "[npc.Name] [npc.is] agreeable"+(longDescription?", and will carry out most orders without complaint.":".")));
				}
				break;
			case POSITIVE_TWO_OBEDIENT:
				if(withColour) {
					sb.append(UtilText.parse(character, "[npc.Name] [npc.is] obedient"+(longDescription?", and will do almost anything that [npc.sheIs] told.":".")));
				} else {
					sb.append(UtilText.parse(character, "[npc.Name] [npc.is] obedient"+(longDescription?", and will do almost anything that [npc.sheIs] told.":".")));
				}
				break;
			case POSITIVE_THREE_DISCIPLINED:
				if(withColour) {
					sb.append(UtilText.parse(character, "[npc.Name] [npc.is] disciplined"+(longDescription?", and will carry out any order without complaint.":".")));
				} else {
					sb.append(UtilText.parse(character, "[npc.Name] [npc.is] disciplined"+(longDescription?", and will carry out any order without complaint.":".")));
				}
				break;
			case POSITIVE_FOUR_DUTIFUL:
				if(withColour) {
					sb.append(UtilText.parse(character, "[npc.Name] [npc.is] dutiful"+(longDescription?", and will often go above and beyond whatever's asked of [npc.herHim].":".")));
				} else {
					sb.append(UtilText.parse(character, "[npc.Name] [npc.is] dutiful"+(longDescription?", and will often go above and beyond whatever's asked of [npc.herHim].":".")));
				}
				break;
			case POSITIVE_FIVE_SUBSERVIENT:
				if(withColour) {
					sb.append(UtilText.parse(character, "[npc.Name] [npc.is] subservient"+(longDescription?", and will do absolutely anything that [npc.sheIs] ordered to do.":".")));
				} else {
					sb.append(UtilText.parse(character, "[npc.Name] [npc.is] subservient"+(longDescription?", and will do absolutely anything that [npc.sheIs] ordered to do.":".")));
				}
				break;
		}

		return sb.toString();
	}

	public String getName() {
		return name;
	}

	public int getMinimumValue() {
		return minimumValue;
	}

	public int getMaximumValue() {
		return maximumValue;
	}

	public int getMedianValue() {
		return (minimumValue + maximumValue) / 2;
	}

	public Colour getColour() {
		return colour;
	}

	public static ObedienceLevel getObedienceLevelFromValue(float value){
		for(ObedienceLevel al : ObedienceLevel.values()) {
			if(value>=al.getMinimumValue() && value<al.getMaximumValue())
				return al;
		}
		return POSITIVE_FIVE_SUBSERVIENT;
	}
}


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

import com.lilithsthrone.utils.Colour;

/**
 * @since 0.1.95
 * @version 0.1.95
 * @author Innoxia
 */
public enum ObedienceLevelBasic {

	/** -100 to -30*/
	DISOBEDIENT("disobedient", -100, -30, Colour.AFFECTION_NEGATIVE_FIVE),

	/** -30 to 30*/
	NEUTRAL("neutral", -30, 30, Colour.AFFECTION_NEUTRAL),

	/** 30 to 100*/
	OBEDIENT("obedient", 30, 100, Colour.AFFECTION_POSITIVE_FIVE);

	private String name;
	private int minimumValue, maximumValue;
	private Colour colour;

	private ObedienceLevelBasic(String name, int minimumValue, int maximumValue, Colour colour) {
		this.name = name;
		this.minimumValue = minimumValue;
		this.maximumValue = maximumValue;
		this.colour = colour;
	}

	public String getName() {
		return name;
	}

	public int getMinimumValue() {
		return minimumValue;
	}

	public int getMaximumValue() {
		return maximumValue;
	}

	public int getMedianValue() {
		return (minimumValue + maximumValue) / 2;
	}

	public Colour getColour() {
		return colour;
	}

	public static ObedienceLevelBasic getObedienceLevelFromValue(float value){
		for(ObedienceLevelBasic al : ObedienceLevelBasic.values()) {
			if(value>=al.getMinimumValue() && value<al.getMaximumValue())
				return al;
		}
		return OBEDIENT;
	}
}


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

import com.lilithsthrone.game.character.effects.StatusEffect;
import com.lilithsthrone.utils.Colour;

/**
 * @since 0.1.65
 * @version 0.1.79
 * @author Innoxia
 */
public enum PhysiqueLevel {

	ZERO_WEAK("frail", 0, 5, Colour.PHYSIQUE_STAGE_ZERO) {
		@Override
		public StatusEffect getRelatedStatusEffect() {
			return StatusEffect.PHYSIQUE_PERK_0;
		}
	},

	ONE_AVERAGE("average", 5, 15, Colour.PHYSIQUE_STAGE_ONE) {
		@Override
		public StatusEffect getRelatedStatusEffect() {
			return StatusEffect.PHYSIQUE_PERK_1;
		}
	},

	TWO_STRONG("fit", 15, 35, Colour.PHYSIQUE_STAGE_TWO) {
		@Override
		public StatusEffect getRelatedStatusEffect() {
			return StatusEffect.PHYSIQUE_PERK_2;
		}
	},

	THREE_POWERFUL("powerful", 35, 65, Colour.PHYSIQUE_STAGE_THREE) {
		@Override
		public StatusEffect getRelatedStatusEffect() {
			return StatusEffect.PHYSIQUE_PERK_3;
		}
	},

	FOUR_MIGHTY("mighty", 65, 95, Colour.PHYSIQUE_STAGE_FOUR) {
		@Override
		public StatusEffect getRelatedStatusEffect() {
			return StatusEffect.PHYSIQUE_PERK_4;
		}
	},

	FIVE_HERCULEAN("herculean", 95, 100, Colour.PHYSIQUE_STAGE_FIVE) {
		@Override
		public StatusEffect getRelatedStatusEffect() {
			return StatusEffect.PHYSIQUE_PERK_5;
		}
	};

	private String name;
	private int minimumValue, maximumValue;
	private Colour colour;

	private PhysiqueLevel(String name, int minimumValue, int maximumValue, Colour colour) {
		this.name = name;
		this.minimumValue = minimumValue;
		this.maximumValue = maximumValue;
		this.colour = colour;
	}

	public abstract StatusEffect getRelatedStatusEffect();

	public String getName() {
		return name;
	}

	public int getMinimumValue() {
		return minimumValue;
	}

	public int getMaximumValue() {
		return maximumValue;
	}

	public Colour getColour() {
		return colour;
	}

	public static PhysiqueLevel getPhysiqueLevelFromValue(float value){
		for(PhysiqueLevel al : PhysiqueLevel.values()) {
			if(value>=al.getMinimumValue() && value<al.getMaximumValue())
				return al;
		}
		return FIVE_HERCULEAN;
	}
}


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

import com.lilithsthrone.game.character.GameCharacter;
import com.lilithsthrone.game.character.body.types.AntennaType;
import com.lilithsthrone.game.dialogue.utils.UtilText;
import com.lilithsthrone.utils.Util;

/**
 * @since 0.1.83
 * @version 0.3.1
 * @author Innoxia
 */
public class Antenna implements BodyPartInterface {

	protected AntennaType type;
	protected int rows;

	public Antenna(AntennaType type) {
		this.type = type;
	}

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

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

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

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

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

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

	public String setType(GameCharacter owner, AntennaType type) {
		if (type == getType()) {
			if(type == AntennaType.NONE) {
				return UtilText.parse(owner, "
[style.colourDisabled([npc.Name] already [npc.verb(lack)] antennae, so nothing happens...)]
");
			} else {
				return UtilText.parse(owner, "
[style.colourDisabled([npc.Name] already [npc.has] the [npc.antennae] of [npc.a_antennaRace], so nothing happens...)]
");
			}
		}

		UtilText.transformationContentSB.setLength(0);

		if(this.type == AntennaType.NONE) {
			UtilText.transformationContentSB.append(
					"
"
						+ "[npc.Name] [npc.verb(rub)] at [npc.her] forehead as [npc.she] [npc.verb(feel)] it growing hot and sensitive, and as [npc.she] [npc.do] so, something starts pushing out from under [npc.her] [npc.faceSkin].");
		} else {
			UtilText.transformationContentSB.append(
					"
"
						+ "[npc.Name] [npc.verb(feel)] an odd tingling sensation at the base of [npc.her] [npc.antennae], and [npc.she] [npc.verb(gasp)] as [npc.she] [npc.verb(feel)] them start to transform.");
		}

		switch (type) {
			case NONE:
				UtilText.transformationContentSB.append(
							" Pieces of [npc.her] [npc.antennae] fall to the floor as they start to crumble away, and within moments they've completely disappeared."
							+ "
"
							+ "[npc.Name] now [npc.has] [style.boldTfGeneric(no antennae)].");
				break;
		}

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

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

	public int getAntennaRows() {
		return rows;
	}

	public String setAntennaRows(GameCharacter owner, int rows) {
		rows = Math.max(1, Math.min(rows, 3));

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

		this.rows = rows;

		if (owner.getAntennaType() == AntennaType.NONE) {
			return "
[style.colourDisabled(Nothing happens...)]
";
		}

		if(owner.getAntennaRows() > rows) {
			return UtilText.parse(owner,
					"
"
						+ "A tingling feeling spreads over [npc.namePos] [npc.antennae], before moving down and concentrating into [npc.her] forehead."
						+ " [npc.She] can't help but let out a little cry as [npc.she] [npc.verb(feel)] some of them [style.boldShrink(falling away)] and disappearing back down into [npc.her] [npc.faceSkin].
"
						+ "After a few moments, [npc.sheIs] left with [style.boldTfGeneric("+getDeterminer(owner)+" [npc.antennae])]."
					+ "
");

		} else {
			return UtilText.parse(owner,
					"
"
						+ "A tingling feeling spreads over [npc.namePos] [npc.antennae], before moving down and concentrating into [npc.her] forehead."
						+ " [npc.She] can't help but let out a little cry as [npc.she] [npc.verb(feel)] new [npc.antennae] [style.boldGrow(pushing up)] and growing out of [npc.her] [npc.faceSkin].
"
						+ "After a few moments, [npc.sheIs] left with [style.boldTfGeneric("+getDeterminer(owner)+" [npc.antennae])]."
					+ "
");

		}
	}

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


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

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

import com.lilithsthrone.game.character.GameCharacter;
import com.lilithsthrone.game.character.body.types.AnusType;
import com.lilithsthrone.game.character.body.valueEnums.BodyHair;
import com.lilithsthrone.game.character.body.valueEnums.Capacity;
import com.lilithsthrone.game.character.body.valueEnums.OrificeModifier;
import com.lilithsthrone.game.dialogue.utils.UtilText;
import com.lilithsthrone.game.sex.Sex;
import com.lilithsthrone.game.sex.SexAreaOrifice;
import com.lilithsthrone.main.Main;
import com.lilithsthrone.utils.Util;

/**
 * @since 0.1.83
 * @version 0.3.1
 * @author Innoxia
 */
public class Anus implements BodyPartInterface {

	// Asshole variables:
	protected AnusType type;
	protected OrificeAnus orificeAnus;
	protected boolean bleached;
	protected BodyHair assHair;

	public Anus(AnusType type, int wetness, float capacity, int elasticity, int plasticity, boolean virgin) {
		this.type = type;

		orificeAnus = new OrificeAnus(wetness, capacity, elasticity, plasticity, virgin, type.getDefaultRacialOrificeModifiers());

		bleached = false;
		assHair = BodyHair.ZERO_NONE;
	}

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

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

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

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

	@Override
	public String getDescriptor(GameCharacter owner) {
		List<String> descriptorList = new ArrayList<String>();

		for(OrificeModifier om : orificeAnus.getOrificeModifiers()) {
			descriptorList.add(om.getName());
		}

		String wetnessDescriptor = orificeAnus.getWetness(owner).getDescriptor();
		if(Main.game.isInSex() && Sex.getAllParticipants().contains(owner)) {
			if(Sex.hasLubricationTypeFromAnyone(owner, SexAreaOrifice.ANUS)) {
				wetnessDescriptor = "wet";
			}
		}
		descriptorList.add(wetnessDescriptor);
		if(owner.getAssHair().getValue()>=BodyHair.FOUR_NATURAL.getValue() && Main.game.isAssHairEnabled()) {
			descriptorList.add("hairy");
		}

		if(owner.isAnusBestial()) {
			descriptorList.add(Util.randomItemFrom(Util.newArrayListOfValues(
					"feral",
					owner.getAssRace().getName(true)+"-",
					"bestial",
					"animalistic")));
		} else {
			descriptorList.add(type.getDescriptor(owner));
		}

		descriptorList.add(Capacity.getCapacityFromValue(orificeAnus.getStretchedCapacity()).getDescriptor().replaceAll(" ", "-"));

		return Util.randomItemFrom(descriptorList);
	}

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

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

	public OrificeAnus getOrificeAnus() {
		return orificeAnus;
	}

	public boolean isBleached() {
		return bleached;
	}

	public String setAssBleached(GameCharacter owner, boolean bleached) {
		if(this.bleached == bleached) {
			return "
[style.colourDisabled(Nothing happens...)]
";
		}

		this.bleached = bleached;

		if(bleached) {
			if(owner.isPlayer()) {
				return "
[style.boldTfSex(Your asshole is now bleached!)]
";
			} else {
				return UtilText.parse(owner,
						"
[style.boldTfSex([npc.NamePos] asshole is now bleached!)]
");
			}
		} else {
			if(owner.isPlayer()) {
				return "
[style.boldTfSex(Your asshole is no longer bleached!)]
";
			} else {
				return UtilText.parse(owner,
						"
[style.boldTfSex([npc.NamePos] asshole is no longer bleached!)]
");
			}
		}
	}

	public BodyHair getAssHair() {
		return assHair;
	}

	public Covering getAssHairType(GameCharacter owner) {
		return owner.getCovering(owner.getBodyHairCoveringType(owner.getAssType().getRace()));
	}

	public String setAssHair(GameCharacter owner, BodyHair assHair) {
		if(owner==null) {
			this.assHair=assHair;
			return "";
		}
		String transformation = "";

		if(getAssHair() == assHair) {
			return "
[style.colourDisabled(Nothing happens...)]
";

		} else {
			switch(assHair) {
				case ZERO_NONE:
					transformation = UtilText.parse(owner, "
There is no longer any trace of "+getAssHairType(owner).getFullDescription(owner, true)+" around [npc.namePos] asshole.
");
					break;
				case ONE_STUBBLE:
					transformation = UtilText.parse(owner, "
[npc.Name] now [npc.has] a stubbly patch of "+getAssHairType(owner).getFullDescription(owner, true)+" around [npc.her] asshole.
");
					break;
				case TWO_MANICURED:
					transformation = UtilText.parse(owner, "
[npc.Name] now [npc.has] a well-manicured patch of "+getAssHairType(owner).getFullDescription(owner, true)+" around [npc.her] asshole.
");
					break;
				case THREE_TRIMMED:
					transformation = UtilText.parse(owner, "
[npc.Name] now [npc.has] a trimmed patch of "+getAssHairType(owner).getFullDescription(owner, true)+" around [npc.her] asshole.
");
					break;
				case FOUR_NATURAL:
					transformation = UtilText.parse(owner, "
[npc.Name] now [npc.has] a natural amount of "+getAssHairType(owner).getFullDescription(owner, true)+" around [npc.her] asshole.
");
					break;
				case FIVE_UNKEMPT:
					transformation = UtilText.parse(owner, "
[npc.Name] now [npc.has] a unkempt bush of "+getAssHairType(owner).getFullDescription(owner, true)+" around [npc.her] asshole.
");
					break;
				case SIX_BUSHY:
					transformation = UtilText.parse(owner, "
[npc.Name] now [npc.has] a thick, bushy mass of "+getAssHairType(owner).getFullDescription(owner, true)+" around [npc.her] asshole.
");
					break;
				case SEVEN_WILD:
					transformation = UtilText.parse(owner, "
[npc.Name] now [npc.has] a wild, bushy mass of "+getAssHairType(owner).getFullDescription(owner, true)+" around [npc.her] asshole.
");
					break;
			}
		}

		this.assHair = assHair;

		return transformation;
	}

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

}


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

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

import com.lilithsthrone.game.character.GameCharacter;
import com.lilithsthrone.game.character.body.types.AbstractArmType;
import com.lilithsthrone.game.character.body.valueEnums.BodyHair;
import com.lilithsthrone.game.dialogue.utils.UtilText;
import com.lilithsthrone.main.Main;
import com.lilithsthrone.utils.Util;

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

	public static final int MAXIMUM_ROWS = 3;

	protected AbstractArmType type;
	protected int armRows;
	protected BodyHair underarmHair;

	public Arm(AbstractArmType type, int armRows) {
		this.type = type;
		this.armRows = armRows;
		underarmHair = BodyHair.ZERO_NONE;
	}

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

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

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

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

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

	@Override
	public String getDescriptor(GameCharacter gc) {
		List<String> descriptorList = new ArrayList<>();

		descriptorList.add(type.getDescriptor(gc));
		descriptorList.add(type.getDescriptor(gc));
		descriptorList.add(Util.randomItemFrom(gc.getBodyShape().getLimbDescriptors()));

		return Util.randomItemFrom(descriptorList);
	}

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

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

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

			if (owner.isPlayer()) {
				UtilText.transformationContentSB.append(
						"
"
							+ "Your [pc.arms+] suddenly feel hot and itchy, and you gasp as you realise that they're starting to transform."
							+ " You let out a painful cry as your upper limbs twist and transform, leaving you powerless to do anything other than look on as they reshape themselves into a new form.");
			} else {
				UtilText.transformationContentSB.append(
						"
"
							+ "[npc.Name] fidgets about as [npc.she] feels [npc.her] [npc.arms+] growing hot and itchy, and [npc.she] gasps as [npc.she] realises that they're starting to transform."
							+ " [npc.She] lets out a painful cry as [npc.her] upper limbs twist and transform, leaving [npc.her] powerless to do anything other than look on as they reshape themselves into a new form.");
			}
		}

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

		UtilText.transformationContentSB.append(type.getTransformationDescription(owner)+"
");

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

	public int getArmRows() {
		return armRows;
	}

	public String setArmRows(GameCharacter owner, int armRows) {
		int currentArmRows = getArmRows();
		armRows = Math.max(1, Math.min(armRows, MAXIMUM_ROWS));
		if (armRows == currentArmRows) {
			return "
[style.colourDisabled(Nothing happens...)]
";
		}

		UtilText.transformationContentSB.setLength(0);

		if (armRows < currentArmRows) {
			boolean losesTwoPairs = (armRows + 2) == currentArmRows;
			if (owner.isPlayer()) {
				UtilText.transformationContentSB.append(
						"
"
							+ "You feel a strange pressure building up around the base of "
							+ (losesTwoPairs
								? "your two extra pairs"
								: (armRows == 2
									? "the lowest of your extra pairs"
									: "your extra pair"))
							+ " of [pc.arms], and before you can react, they rapidly shrink away into the [pc.skin] of your torso.
"
							+ "You now have [style.boldTfLesser(" + Util.intToString(armRows) + " pair"+ (armRows > 1 ? "s" : "") + " of [pc.arms])], covered in [pc.armFullDescriptionColour]."
						+ "
");
			} else {
				UtilText.transformationContentSB.append(UtilText.parse(owner,
						"
"
							+ "[npc.Name] glances worriedly down at "
							+ (losesTwoPairs
								? "[npc.her] two extra pairs"
								: (armRows == 2
									? "the lowest of [npc.her] extra pairs"
									: "[npc.her] extra pair"))
							+ " of [npc.arms], and before [npc.she] can react, they rapidly shrink away into the [npc.skin] of [npc.her] torso.
"
							+ "[npc.She] now has [style.boldTfLesser(" + Util.intToString(armRows) + " pair"+ (armRows > 1 ? "s" : "") + " of [npc.arms])], covered in [npc.armFullDescriptionColour]."
						+ "
"));
			}

		} else {
			boolean gainsTwoPairs = (armRows - 2) == currentArmRows;
			if (owner.isPlayer()) {
				UtilText.transformationContentSB.append(
						"
"
							+ "You feel a strange pressure building up down the sides of your torso, and before you have time to react, "
								+ (gainsTwoPairs
									? "two extra pairs"
									: "an extra pair")
							+ " of [pc.arms] rapidly grow out of the [pc.skin] of your lower torso.
"
							+ "You now have [style.boldTfLesser(" + Util.intToString(armRows) + " pair"+ (armRows > 1 ? "s" : "") + " of [pc.arms])], covered in [pc.armFullDescriptionColour]."
						+ "
");
			} else {
				UtilText.transformationContentSB.append(UtilText.parse(owner,
						"
"
							+ "[npc.Name] glances worriedly down at [npc.her] torso, and before [npc.she] can react, "
								+ (gainsTwoPairs
									? "two extra pairs"
									: "an extra pair")
							+ " of [npc.arms] rapidly grow out of the [npc.skin] of [npc.her] lower torso.
"
							+ "[npc.She] now has [style.boldTfLesser(" + Util.intToString(armRows) + " pair"+ (armRows > 1 ? "s" : "") + " of [npc.arms])], covered in [npc.armFullDescriptionColour]."
						+ "
"));
			}
		}

		this.armRows = armRows;

		UtilText.transformationContentSB.append(UtilText.parse(owner,
				"
"
					+ owner.postTransformationCalculation()
				+ "
"));

		return UtilText.transformationContentSB.toString();
	}

	public BodyHair getUnderarmHair() {
		return underarmHair;
	}

	public Covering getUnderarmHairType(GameCharacter owner) {
		return owner.getCovering(owner.getBodyHairCoveringType(owner.getArmType().getRace()));
	}

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

		if(getUnderarmHair() == underarmHair) {
			return "
[style.colourDisabled(Nothing happens...)]
";

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

			switch(underarmHair) {
				case ZERO_NONE:
					UtilText.transformationContentSB.append(UtilText.parse(owner, "
There is no longer any trace of "+getUnderarmHairType(owner).getFullDescription(owner, true)+" in [npc.her] armpits.
"));
					break;
				case ONE_STUBBLE:
					UtilText.transformationContentSB.append(UtilText.parse(owner, "
[npc.Name] now [npc.has] stubbly patches of "+getUnderarmHairType(owner).getFullDescription(owner, true)+" in [npc.her] armpits.
"));
					break;
				case TWO_MANICURED:
					UtilText.transformationContentSB.append(UtilText.parse(owner, "
[npc.Name] now [npc.has] a well-manicured patch of "+getUnderarmHairType(owner).getFullDescription(owner, true)+" in [npc.her] armpits.
"));
					break;
				case THREE_TRIMMED:
					UtilText.transformationContentSB.append(UtilText.parse(owner, "
[npc.Name] now [npc.has] trimmed patches of "+getUnderarmHairType(owner).getFullDescription(owner, true)+" in [npc.her] armpits.
"));
					break;
				case FOUR_NATURAL:
					UtilText.transformationContentSB.append(UtilText.parse(owner, "
[npc.Name] now [npc.has] a natural amount of "+getUnderarmHairType(owner).getFullDescription(owner, true)+" in [npc.her] armpits.
"));
					break;
				case FIVE_UNKEMPT:
					UtilText.transformationContentSB.append(UtilText.parse(owner, "
[npc.Name] now [npc.has] an unkempt mass of "+getUnderarmHairType(owner).getFullDescription(owner, true)+" in [npc.her] armpits.
"));
					break;
				case SIX_BUSHY:
					UtilText.transformationContentSB.append(UtilText.parse(owner, "
[npc.Name] now [npc.has] thick, bushy masses of "+getUnderarmHairType(owner).getFullDescription(owner, true)+" in [npc.her] armpits.
"));
					break;
				case SEVEN_WILD:
					UtilText.transformationContentSB.append(UtilText.parse(owner, "
[npc.Name] now [npc.has] wild, bushy masses of "+getUnderarmHairType(owner).getFullDescription(owner, true)+" in [npc.her] armpits.
"));
					break;
			}
		}

		this.underarmHair = underarmHair;

		return UtilText.transformationContentSB.toString();
	}

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


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

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

import com.lilithsthrone.game.character.GameCharacter;
import com.lilithsthrone.game.character.body.types.AbstractAssType;
import com.lilithsthrone.game.character.body.valueEnums.AssSize;
import com.lilithsthrone.game.character.body.valueEnums.HipSize;
import com.lilithsthrone.game.dialogue.utils.UtilText;
import com.lilithsthrone.main.Main;
import com.lilithsthrone.utils.Util;

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

	protected AbstractAssType type;
	protected int assSize;
	protected int hipSize;

	protected Anus anus;

	public Ass(AbstractAssType type, int size, int wetness, float capacity, int elasticity, int plasticity, boolean virgin) {
		this.type = type;
		assSize = size;
		hipSize = size;

		anus = new Anus(type.getAnusType(), wetness, capacity, elasticity, plasticity, virgin);
	}

	public Anus getAnus() {
		return anus;
	}

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

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

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

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

	@Override
	public String getDescriptor(GameCharacter gc) {
		List<String> list = new ArrayList<>();

		list.add(type.getDescriptor(gc));
		list.add(this.getAssSize().getDescriptor());

		return Util.randomItemFrom(list);
	}

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

	public String setType(GameCharacter owner, AbstractAssType type) {
		if(!Main.game.isStarted() || owner==null) {
			this.type = type;
			anus.setType(type.getAnusType());
			if(owner!=null) {
				owner.resetAreaKnownByCharacters(CoverableArea.ANUS);
				owner.postTransformationCalculation();
			}
			return "";
		}

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

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

			if (owner.isPlayer()) {
				UtilText.transformationContentSB.append("
"
						+ "Your [pc.ass] starts to noticeably soften and become very sensitive, and you let out a lewd moan as the transformation moves down into your [pc.asshole] as well."
						+ " Panting and sighing, you continue letting out the occasional [pc.moan] as your [pc.ass] finishes shifting into a new form.
");
			} else {
				UtilText.transformationContentSB.append(
						"
"
						+ "[npc.NamePos] [npc.ass] starts to soften and become very sensitive, and [npc.she] lets out [npc.a_moan+] as the transformation moves down into [npc.her] [npc.asshole] as well."
						+ " Panting and sighing, [npc.she] continues letting out the occasional [npc.moan] as [npc.her] [npc.ass] finishes shifting into a new form.
");
			}
		}

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

		UtilText.transformationContentSB.append(type.getTransformationDescription(owner)+"
");

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

	public AssSize getAssSize() {
		return AssSize.getAssSizeFromInt(assSize);
	}

	/**
	 * Sets assSize attribute.

	 * Value is bound to >=0 && <=AssSize.SEVEN_GIGANTIC.getValue()
	 *
	 * @param owner The character to change.
	 * @param assSize Value to set assSize to.
	 * @return Description of the change.
	 */
	public String setAssSize(GameCharacter owner, int assSize) {
		int oldSize = this.assSize;
		this.assSize = Math.max(0, Math.min(assSize, AssSize.SEVEN_GIGANTIC.getValue()));

		if(owner==null) {
			return "";
		}

		int sizeChange = this.assSize - oldSize;

		if (sizeChange == 0) {
			if(owner.isPlayer()) {
				return "
[style.colourDisabled(The size of your ass doesn't change...)]
";
			} else {
				return UtilText.parse(owner, "
[style.colourDisabled(The size of [npc.namePos] ass doesn't change...)]
");
			}
		}

		String sizeDescriptor = getAssSize().getDescriptor();
		if (sizeChange > 0) {
			if (owner.isPlayer()) {
				return "
"
							+ "You feel a little off-balance as your [pc.ass] suddenly seems to get heavier, and as you give it an experimental shake, you find that it's definitely [style.boldGrow(grown larger)].
"
							+ "You now have [style.boldSex(" + UtilText.generateSingularDeterminer(sizeDescriptor) + " " + sizeDescriptor + " ass)]!"
						+ "
";
			} else {
				return UtilText.parse(owner,
						"
"
							+ "[npc.Name] looks to be a little off-balance as [npc.her] [npc.ass] suddenly seems to get bigger, and as [npc.she] gives it an experimental shake, [npc.she] discovers that it's definitely [style.boldGrow(grown larger)].
"
							+ "[npc.She] now has [style.boldSex(" + UtilText.generateSingularDeterminer(sizeDescriptor) + " " + sizeDescriptor + " ass)]!"
						+ "
");
			}
		} else {
			if (owner.isPlayer()) {
				return "
"
							+ "You suddenly feel like a weight has been lifted from your rear end, and, giving your [pc.ass] an experimental shake, you discover that it's [style.boldShrink(shrunk)].
"
							+ "You now have [style.boldSex(" + UtilText.generateSingularDeterminer(sizeDescriptor) + " " + sizeDescriptor + " ass)]!"
						+ "
";
			} else {
				return UtilText.parse(owner,
						"
"
							+ "[npc.Name] looks to be a little off-balance as [npc.her] [npc.ass] suddenly seems to get smaller, and as [npc.she] gives it an experimental shake, [npc.she] discovers that it's definitely [style.boldShrink(shrunk)].
"
							+ "[npc.She] now has [style.boldSex(" + UtilText.generateSingularDeterminer(sizeDescriptor) + " " + sizeDescriptor + " ass)]!"
						+ "
");
			}
		}
	}

	public HipSize getHipSize() {
		return HipSize.getHipSizeFromInt(hipSize);
	}

	/**
	 * Sets hipSize attribute.

	 * Value is bound to >=0 && <=HipSize.SEVEN_ABSURDLY_WIDE.getValue()
	 *
	 * @param owner The character to change.
	 * @param hipSize Value to set hipSize to.
	 * @return Description of the change.
	 */
	public String setHipSize(GameCharacter owner, int hipSize) {
		int oldSize = this.hipSize;
		this.hipSize = Math.max(0, Math.min(hipSize, HipSize.SEVEN_ABSURDLY_WIDE.getValue()));
		int sizeChange = this.hipSize - oldSize;

		if (sizeChange == 0) {
			if(owner.isPlayer()) {
				return "
[style.colourDisabled(The size of your hips doesn't change...)]
";
			} else {
				return UtilText.parse(owner, "
[style.colourDisabled(The size of [npc.namePos] hips doesn't change...)]
");
			}
		}

		String styledSizeDescriptor = "[style.boldSex("+ getHipSize().getDescriptor() + " hips)]";
		if (sizeChange > 0) {
			if (owner.isPlayer()) {
				return "
"
							+ "You inhale sharply in surprise as you feel your hips reshape themselves, pushing out and [style.boldGrow(growing wider)].
"
							+ "You now have " + styledSizeDescriptor + "!"
						+ "
";
			} else {
				return UtilText.parse(owner,
						"
"
							+ "[npc.Name] inhales sharply in surprise as [npc.she] feels [npc.her] hips reshape themselves, pushing out and [style.boldGrow(growing wider)].
"
							+ "[npc.She] now has " + styledSizeDescriptor + "!"
						+ "
");
			}
		} else {
			if (owner.isPlayer()) {
				return "
"
							+ "You inhale sharply in surprise as you feel your hips collapse inwards and reshape themselves as they get [style.boldShrink(narrower)].
"
							+ "You now have " + styledSizeDescriptor + "!"
						+ "
";
			} else {
				return UtilText.parse(owner,
						"
"
							+ "[pc.Name] inhales sharply in surprise as [npc.she] feels [npc.her] hips collapse inwards and reshape themselves as they get [style.boldShrink(narrower)].
"
							+ "[npc.She] now has " + styledSizeDescriptor + "!"
						+ "
");
			}
		}
	}

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

}