code:
package com.lilithsthrone.game.occupantManagement;

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.effects.Perk;
import com.lilithsthrone.game.character.fetishes.Fetish;
import com.lilithsthrone.game.character.npc.NPC;
import com.lilithsthrone.game.dialogue.DialogueFlagValue;
import com.lilithsthrone.game.dialogue.eventLog.EventLogEntry;
import com.lilithsthrone.main.Main;
import com.lilithsthrone.utils.Colour;
import com.lilithsthrone.utils.Util;
import com.lilithsthrone.utils.Util.Value;
import com.lilithsthrone.world.Cell;
import com.lilithsthrone.world.WorldType;
import com.lilithsthrone.world.places.AbstractPlaceType;
import com.lilithsthrone.world.places.PlaceType;
import com.lilithsthrone.world.places.PlaceUpgrade;

/**
 * @since 0.1.87
 * @version 0.3.5
 * @author Innoxia
 */
public enum SlaveJob {

	/*
		restaurant
			w&m
		bar
			sleazy (obedience not counted, but income is less)
			allow groping
	 */

	IDLE(Colour.BASE_GREY_DARK, -1, -1, "Idle", "Idle",
			"Do not assign any job to this slave.",
			0, 0,
			0,
			0, 0,
			null,
			null,
			null,
			null, null) {
		@Override
		public boolean isAvailable(int hour, GameCharacter character) {
			return true;
		}
	},

	CLEANING(Colour.BASE_BLUE_LIGHT, 20, 2, "maid", "manservant",
			"Assign this slave to help Rose keep the house clean, deal with visitors, and perform all sorts of menial housework.",
			0, 0.5f,
			80,
			0f, 0.1f,
			null,
			null,
			null,
			WorldType.LILAYAS_HOUSE_GROUND_FLOOR, PlaceType.LILAYA_HOME_CORRIDOR) {
		@Override
		public EventLogEntry getHourlyEvent(long hour, NPC slave, List<NPC> otherNPCsPresent) {
			return new EventLogEntry(Main.game.getDayNumber()-1*24l+hour, "[style.colourDisabled(Nothing)]", "");
		}

		@Override
		public void sendToWorkLocation(int hour, GameCharacter slave) {
			if(slave.getLocationPlace().getPlaceType().equals(PlaceType.LILAYA_HOME_CORRIDOR)) {
				slave.moveToAdjacentMatchingCellType(false);

			} else {
				// 50/50 of being upstairs or downstairs:
				WorldType worldTypeToUse = WorldType.LILAYAS_HOUSE_FIRST_FLOOR;
				if(Math.random()>0.5f) {
					worldTypeToUse = WorldType.LILAYAS_HOUSE_GROUND_FLOOR;
				}

				slave.setRandomLocation(worldTypeToUse, PlaceType.LILAYA_HOME_CORRIDOR, false);
			}
		}
	},

	LIBRARY(Colour.BASE_TEAL, 5, 1.5f, "librarian", "librarian",
			"Assign this slave to work in Lilaya's library.",
			0, 0.25f,
			80,
			0, 0.1f,
			null,
			null,
			null,
			WorldType.LILAYAS_HOUSE_GROUND_FLOOR, PlaceType.LILAYA_HOME_LIBRARY),

	KITCHEN(Colour.BASE_TAN, 5, 2, "cook", "cook",
			"Assign this slave to work in Lilaya's kitchen as a cook.",
			0, 0.25f,
			80,
			0, 0.05f,
			null,
			null,
			null,
			WorldType.LILAYAS_HOUSE_GROUND_FLOOR, PlaceType.LILAYA_HOME_KITCHEN),

	LAB_ASSISTANT(Colour.BASE_GREEN_LIME, 1, 1, "lab assistant", "lab assistant",
			"Assign this slave to help Lilaya in her lab.",
			0, 0.25f,
			100,
			0, 0.2f,
			null,
			null,
			null,
			WorldType.LILAYAS_HOUSE_GROUND_FLOOR, PlaceType.LILAYA_HOME_LAB) {
		@Override
		public boolean isAvailable(int hour, GameCharacter character) {
			if(hour<6 || hour>=22) {
				return false;
			}
			return super.isAvailable(hour, character);
		}
		@Override
		public String getAvailabilityText(int hour, GameCharacter character) {
			if(hour<6 || hour>=22) {
				return "Slaves cannot work in Lilaya's lab while she is sleeping!";
			}
			return super.getAvailabilityText(hour, character);
		}
	},

	TEST_SUBJECT(Colour.BASE_RED_LIGHT, 5, 3, "test subject", "test subject",
			"Allow Lilaya to use this slave as a test subject for her experiments.",
			-0.5f, 0.5f,
			150,
			0, 0,
			Util.newArrayListOfValues(
					SlaveJobSetting.TEST_SUBJECT_ALLOW_TRANSFORMATIONS_FEMALE,
					SlaveJobSetting.TEST_SUBJECT_ALLOW_TRANSFORMATIONS_MALE), null,
			null,
			WorldType.LILAYAS_HOUSE_GROUND_FLOOR, PlaceType.LILAYA_HOME_LAB) {
		@Override
		public float getAffectionGain(int hour, GameCharacter slave) {
			if(slave.hasFetish(Fetish.FETISH_TRANSFORMATION_RECEIVING)) {
				return 0.5f;
			} else {
				return -0.5f;
			}
		}
		@Override
		public boolean isAvailable(int hour, GameCharacter character) {
			if(hour<6 || hour>=22) {
				return false;
			}
			return super.isAvailable(hour, character);
		}
		@Override
		public String getAvailabilityText(int hour, GameCharacter character) {
			if(hour<6 || hour>=22) {
				return "Slaves cannot work in Lilaya's lab while she is sleeping!";
			}
			return super.getAvailabilityText(hour, character);
		}
	},

	PUBLIC_STOCKS(Colour.BASE_PINK_LIGHT, 5, 2, "public use", "public use",
			"Assign this slave to be locked in the public-use stocks in slaver ally.",
			-5f, 1f,
			0,
			0, 0,
			Util.newArrayListOfValues(
					SlaveJobSetting.SEX_ORAL,
					SlaveJobSetting.SEX_VAGINAL,
					SlaveJobSetting.SEX_ANAL,
					SlaveJobSetting.SEX_NIPPLES),
			null,
			null,
			WorldType.SLAVER_ALLEY, PlaceType.SLAVER_ALLEY_PUBLIC_STOCKS) {
		@Override
		public float getAffectionGain(int hour, GameCharacter slave) {
			if(slave.hasFetish(Fetish.FETISH_NON_CON_SUB)) {
				return 1f;
			} else {
				return -5f;
			}
		}
	},

	PROSTITUTE(Colour.BASE_PINK_DEEP, 10, 2.5f, "Prostitute", "Prostitute",
			"Assign this slave to work as a prostitute at the brothel 'Angel's Kiss'.",
			-0.25f, 0.5f,
			200,
			0, 0.5f,
			Util.newArrayListOfValues(
					SlaveJobSetting.SEX_ORAL,
					SlaveJobSetting.SEX_VAGINAL,
					SlaveJobSetting.SEX_ANAL,
					SlaveJobSetting.SEX_NIPPLES),
			null,
			null,
			WorldType.ANGELS_KISS_FIRST_FLOOR, PlaceType.ANGELS_KISS_BEDROOM) {

		@Override
		public float getAffectionGain(int hour, GameCharacter slave) {
			if(slave.hasFetish(Fetish.FETISH_CUM_ADDICT)) {
				return 1f;
			} else {
				return -0.25f;
			}
		}

		@Override
		public boolean isAvailable(int hour, GameCharacter character) {
			if(!Main.game.getDialogueFlags().hasFlag(DialogueFlagValue.prostitutionLicenseObtained)) {
				return false;
			}
			return super.isAvailable(hour, character);
		}

		@Override
		public String getAvailabilityText(int hour, GameCharacter character) {
			if(!Main.game.getDialogueFlags().hasFlag(DialogueFlagValue.prostitutionLicenseObtained)) {
				return "You do not have permission from Angel to send your slaves to work in her brothel!";

			} else if(character.getOwner().getSlavesWorkingJob(hour, this)>=this.getSlaveLimit()) {
				return "You have already assigned the maximum number of slaves to this job!";

			} else if(character.getHomeLocationPlace().getPlaceType().equals(PlaceType.SLAVER_ALLEY_SLAVERY_ADMINISTRATION)) {
				return "Slaves cannot work out of the cells at slavery administration. Move them into a room first!";

			} else {
				return "This job is available!";
			}
		}
	},

	MILKING(Colour.BASE_YELLOW_LIGHT, -1, 2, "Dairy Cow", "Dairy Bull",
			"Assign this slave to the cow stalls, ready for milking or breeding (or perhaps both). Income is based off of the assigned slave's milk, cum, and girlcum production.",
			-0.25f, 1f,
			0,
			0, 0,
			Util.newArrayListOfValues(
					SlaveJobSetting.MILKING_MILK_DISABLE,
					SlaveJobSetting.MILKING_MILK_CROTCH_DISABLE,
					SlaveJobSetting.MILKING_CUM_DISABLE,
					SlaveJobSetting.MILKING_GIRLCUM_DISABLE,
					SlaveJobSetting.MILKING_MILK_AUTO_SELL,
					SlaveJobSetting.MILKING_MILK_CROTCH_AUTO_SELL,
					SlaveJobSetting.MILKING_CUM_AUTO_SELL,
					SlaveJobSetting.MILKING_GIRLCUM_AUTO_SELL),
			Util.newHashMapOfValues(
					new Value<>("Room Preference", Util.newArrayListOfValues(
							SlaveJobSetting.MILKING_INDUSTRIAL,
							SlaveJobSetting.MILKING_REGULAR,
							SlaveJobSetting.MILKING_ARTISAN,
							SlaveJobSetting.MILKING_NO_PREFERENCE))),
			Util.newArrayListOfValues(
					SlaveJobSetting.MILKING_NO_PREFERENCE),
			WorldType.LILAYAS_HOUSE_GROUND_FLOOR,
			PlaceType.LILAYA_HOME_ROOM_WINDOW_GROUND_FLOOR) {

		@Override
		public int getSlaveLimit() {
			return Main.game.getOccupancyUtil().getMilkingRooms().size()*8;
		}

		@Override
		public float getAffectionGain(int hour, GameCharacter slave) {
			float aff = this.affectionGain;
			if(slave.hasFetish(Fetish.FETISH_LACTATION_SELF)) {
				aff = 2f;
			}
			Cell c = this.getWorkDestinationCell(hour, slave);
			return aff + (c==null?0:c.getPlace().getHourlyAffectionChange());
		}

		@Override
		public boolean isAvailable(int hour, GameCharacter character) {
			return Main.game.getPlayer().getSlavesWorkingJob(hour, SlaveJob.MILKING) < getSlaveLimit();
		}

		public String getAvailabilityText(int hour, GameCharacter character) {
			if(!isAvailable(hour, character)) {
				return "Not enough space in milking rooms!";

			} else if(character.getHomeLocationPlace().getPlaceType().equals(PlaceType.SLAVER_ALLEY_SLAVERY_ADMINISTRATION)) {
				return "Slaves cannot work out of the cells at slavery administration. Move them into a room first!";

			}

			return super.getAvailabilityText(hour, character);
		}

		@Override
		public WorldType getWorldLocation(GameCharacter character) {
			Cell c = MilkingRoom.getMilkingCell(character, false);
			if(c==null) {
				return null;
			}
			return c.getType();
		}

		@Override
		public AbstractPlaceType getPlaceLocation(GameCharacter character) {
			Cell c = MilkingRoom.getMilkingCell(character, false);
			if(c==null) {
				return null;
			}
			return c.getPlace().getPlaceType();
		}

		@Override
		public Cell getWorkDestinationCell(int hour, GameCharacter slave) {
			return MilkingRoom.getMilkingCell(slave, false);
		}

		@Override
		public void sendToWorkLocation(int hour, GameCharacter slave) {
			Cell c = MilkingRoom.getMilkingCell(slave, true);
			if(c!=null) {
				if(c.getType()!=slave.getWorldLocation() || c.getLocation()!=slave.getLocation()) {
					slave.setLocation(c.getType(), c.getLocation(), false);
				}

			} else {
				slave.returnToHome();
			}
		}
	},

	OFFICE(Colour.BASE_LILAC,
			4,
			2,
			"office worker",
			"office worker",
			"Assign this slave to work in the office which you've had outfitted here in Lilaya's house.",
			0, 0,
			100,
			0, 1f,
			null, null,
			null,
			WorldType.LILAYAS_HOUSE_GROUND_FLOOR, PlaceType.LILAYA_HOME_ROOM_WINDOW_GROUND_FLOOR) {

		private Cell getOfficeCell() {
			List<Cell> cells = Main.game.getWorlds().get(WorldType.LILAYAS_HOUSE_GROUND_FLOOR).getCells(PlaceUpgrade.LILAYA_OFFICE);
			if(!cells.isEmpty()) {
				return cells.get(0);
			}
			cells = Main.game.getWorlds().get(WorldType.LILAYAS_HOUSE_FIRST_FLOOR).getCells(PlaceUpgrade.LILAYA_OFFICE);
			if(!cells.isEmpty()) {
				return cells.get(0);
			}
			return null;
		}

		@Override
		public int getSlaveLimit() {
			if(getOfficeCell()==null) {
				return 0;
			}
			return 4;
		}

		@Override
		public boolean isAvailable(int hour, GameCharacter character) {
			return Main.game.getPlayer().getSlavesWorkingJob(hour, SlaveJob.OFFICE) < getSlaveLimit();
		}

		public String getAvailabilityText(int hour, GameCharacter character) {
			if(!isAvailable(hour, character)) {
				return "There isn't enough office space to assign this job!";

			} else if(character.getHomeLocationPlace().getPlaceType().equals(PlaceType.SLAVER_ALLEY_SLAVERY_ADMINISTRATION)) {
				return "Slaves cannot work out of the cells at slavery administration. Move them into a room first!";
			}

			return super.getAvailabilityText(hour, character);
		}

		@Override
		public WorldType getWorldLocation(GameCharacter character) {
			Cell c = getOfficeCell();
			if(c==null) {
				return null;
			}
			return c.getType();
		}

		@Override
		public AbstractPlaceType getPlaceLocation(GameCharacter character) {
			Cell c = getOfficeCell();
			if(c==null) {
				return null;
			}
			return c.getPlace().getPlaceType();
		}

		@Override
		public Cell getWorkDestinationCell(int hour, GameCharacter slave) {
			return getOfficeCell();
		}

		@Override
		public void sendToWorkLocation(int hour, GameCharacter slave) {
			Cell c = getOfficeCell();
			if(c!=null) {
				if(c.getType()!=slave.getWorldLocation() || c.getLocation()!=slave.getLocation()) {
					slave.setLocation(c.getType(), c.getLocation(), false);
				}
			} else {
				slave.returnToHome();
			}
		}
	},

	BEDROOM(Colour.BASE_PERIWINKLE, 4, -1f, "bedroom", "bedroom",
			"Assign this slave to wait upon you in your bedroom.",
			0, 0.25f,
			0,
			0, 0,
			Util.newArrayListOfValues(
					SlaveJobSetting.BEDROOM_GREETING,
					SlaveJobSetting.BEDROOM_CLEAN,
					SlaveJobSetting.BEDROOM_WAKE_UP,
					SlaveJobSetting.BEDROOM_HELP_WASH),
			Util.newHashMapOfValues(
					new Value<>("Sleeping Arrangements",
						Util.newArrayListOfValues(
							SlaveJobSetting.BEDROOM_SLEEP_FLOOR,
							SlaveJobSetting.BEDROOM_SLEEP_ON_BED,
							SlaveJobSetting.BEDROOM_SLEEP_IN_BED))),
			Util.newArrayListOfValues(
					SlaveJobSetting.BEDROOM_SLEEP_ON_BED),
			WorldType.LILAYAS_HOUSE_FIRST_FLOOR,
			PlaceType.LILAYA_HOME_ROOM_PLAYER),
	;

	private Colour colour;
	private int slaveLimit;
	private float hourlyFatigue;
	private String nameFeminine;
	private String nameMasculine;
	private String description;
	private float obedienceGain;
	protected float affectionGain;
	private int income;
	private float obedienceIncomeModifier;
	private float affectionIncomeModifier;
	private List<SlaveJobSetting> mutualSettings;
	private Map<String, List<SlaveJobSetting>> mutuallyExclusiveSettings;
	private List<SlaveJobSetting> defaultMutuallyExclusiveSettings;
	private WorldType worldLocation;
	private AbstractPlaceType placeLocation;

	private SlaveJob(
			Colour colour,
			int slaveLimit,
			float hourlyFatigue,
			String nameFeminine,
			String nameMasculine,
			String description,
			float affectionGain,
			float obedienceGain,
			int income,
			float affectionIncomeModifier,
			float obedienceIncomeModifier,
			List<SlaveJobSetting> mutualSettings,
			Map<String, List<SlaveJobSetting>> mutuallyExclusiveSettings,
			List<SlaveJobSetting> defaultMutuallyExclusiveSettings,
			WorldType worldLocation,
			AbstractPlaceType placeLocation) {
		this.colour = colour;
		this.slaveLimit = slaveLimit;
		this.hourlyFatigue = hourlyFatigue;
		this.nameFeminine = nameFeminine;
		this.nameMasculine = nameMasculine;
		this.description = description;
		this.obedienceGain = obedienceGain;
		this.affectionGain = affectionGain;
		this.income = income;
		this.obedienceIncomeModifier = obedienceIncomeModifier;
		this.affectionIncomeModifier = affectionIncomeModifier;

		if(mutualSettings == null) {
			this.mutualSettings = new ArrayList<>();
		} else {
			this.mutualSettings = mutualSettings;
		}

		if(mutuallyExclusiveSettings == null) {
			this.mutuallyExclusiveSettings = new HashMap<>();
		} else {
			this.mutuallyExclusiveSettings = mutuallyExclusiveSettings;
		}

		if(defaultMutuallyExclusiveSettings == null) {
			this.defaultMutuallyExclusiveSettings = new ArrayList<>();
		} else {
			this.defaultMutuallyExclusiveSettings = defaultMutuallyExclusiveSettings;
		}

		this.worldLocation = worldLocation;
		this.placeLocation = placeLocation;
	}

	public Colour getColour() {
		return colour;
	}

	public int getSlaveLimit() {
		return slaveLimit;
	}

	public float getHourlyFatigue() {
		return hourlyFatigue;
	}

	public String getName(GameCharacter character) {
		if(character.isFeminine()) {
			return nameFeminine;
		} else {
			return nameMasculine;
		}
	}

	public String getNameFeminine() {
		return nameFeminine;
	}

	public String getNameMasculine() {
		return nameMasculine;
	}

	public String getDescription() {
		return description;
	}

	public float getObedienceGain(int hour, GameCharacter slave) {
		Cell c = this.getWorkDestinationCell(hour, slave);
		return obedienceGain + (c==null?0:c.getPlace().getHourlyObedienceChange());
	}

	public float getAffectionGain(int hour, GameCharacter slave) {
		Cell c = this.getWorkDestinationCell(hour, slave);
		return affectionGain + (c==null?0:c.getPlace().getHourlyAffectionChange());
	}

	public int getIncome() {
		return income;
	}

	public int getFinalHourlyIncomeAfterModifiers(GameCharacter character) {
		int value = (int)(Math.max(0, (income + ((getAffectionIncomeModifier()*character.getAffection(Main.game.getPlayer()))) + ((getObedienceIncomeModifier()*character.getObedienceValue())))));

		if(this==SlaveJob.MILKING) {
			value = 0;
			if(character.getBreastRawStoredMilkValue()>0  && !character.hasSlaveJobSetting(this, SlaveJobSetting.MILKING_MILK_DISABLE)) {
				int milked = MilkingRoom.getActualMilkPerHour(character);
				value += (milked * character.getMilk().getValuePerMl());
			}
			if(character.hasBreastsCrotch() && character.getBreastCrotchRawStoredMilkValue()>0  && !character.hasSlaveJobSetting(this, SlaveJobSetting.MILKING_MILK_CROTCH_DISABLE)) {
				int milked = MilkingRoom.getActualCrotchMilkPerHour(character);
				value += (milked * character.getMilkCrotch().getValuePerMl());
			}
			if(character.hasPenis() && character.getPenisRawStoredCumValue()>0  && !character.hasSlaveJobSetting(this, SlaveJobSetting.MILKING_CUM_DISABLE)) {
				int milked = MilkingRoom.getActualCumPerHour(character);
				value += (milked * character.getCum().getValuePerMl());
			}
			if(character.hasVagina() && !character.hasSlaveJobSetting(this, SlaveJobSetting.MILKING_GIRLCUM_DISABLE)) {
				int milked = MilkingRoom.getActualGirlcumPerHour(character);
				value += (milked * character.getGirlcum().getValuePerMl());
			}
		}

		if(character.isSlave()) {
			if(character.getOwner().hasTrait(Perk.JOB_OFFICE_WORKER, true)) {
				return (int) (1.25f * value);
			} else if((character.getOwner().hasTrait(Perk.JOB_MAID, true) || character.getOwner().hasTrait(Perk.JOB_BUTLER, true)) && this==SlaveJob.CLEANING) {
				return 2 * value;
			}
		}

		return value;
	}

	public static int getFinalDailyIncomeAfterModifiers(GameCharacter character) {
		int value = 0;

		for(int i=0; i<24; i++) {
			value += character.getSlaveJob(i).getFinalHourlyIncomeAfterModifiers(character);
		}

		return value;
	}

	public float getObedienceIncomeModifier() {
		return obedienceIncomeModifier;
	}

	public float getAffectionIncomeModifier() {
		return affectionIncomeModifier;
	}

	public List<SlaveJobSetting> getMutualSettings() {
		return mutualSettings;
	}

	public Map<String, List<SlaveJobSetting>> getMutuallyExclusiveSettings() {
		return mutuallyExclusiveSettings;
	}

	public List<SlaveJobSetting> getDefaultMutuallyExclusiveSettings() {
		return defaultMutuallyExclusiveSettings;
	}

	public WorldType getWorldLocation(GameCharacter character) {
		return worldLocation;
	}

	public AbstractPlaceType getPlaceLocation(GameCharacter character) {
		return placeLocation;
	}

	public Cell getWorkDestinationCell(int hour, GameCharacter slave) {
		WorldType wType = slave.getSlaveJob(hour).getWorldLocation(slave);
		if(wType==null) {
			return null;
		}
		return Main.game.getWorlds().get(wType).getRandomUnoccupiedCell(slave.getSlaveJob(hour).getPlaceLocation(slave));
	}

	public void sendToWorkLocation(int hour, GameCharacter slave) {
		if(slave.getSlaveJob(hour).getWorldLocation(slave)!=null
				&& slave.getSlaveJob(hour).getPlaceLocation(slave)!=null
				&& (slave.getSlaveJob(hour).getWorldLocation(slave)!=slave.getWorldLocation() || slave.getSlaveJob(hour).getPlaceLocation(slave)!=slave.getLocationPlace().getPlaceType())) {
			slave.setRandomUnoccupiedLocation(slave.getSlaveJob(hour).getWorldLocation(slave), slave.getSlaveJob(hour).getPlaceLocation(slave), false);
		}
	}

	public boolean isAvailable(int hour, GameCharacter character) {
		return character.getSlaveJob(hour)==this
				|| (!character.getHomeLocationPlace().getPlaceType().equals(PlaceType.SLAVER_ALLEY_SLAVERY_ADMINISTRATION) && character.getOwner().getSlavesWorkingJob(hour, this)<this.getSlaveLimit());
	}

	public String getAvailabilityText(int hour, GameCharacter character) {
		if(character.getOwner().getSlavesWorkingJob(hour, this)>=this.getSlaveLimit()) {
			return "You have already assigned the maximum number of slaves to this job!";

		} else if(character.getHomeLocationPlace().getPlaceType().equals(PlaceType.SLAVER_ALLEY_SLAVERY_ADMINISTRATION)) {
			return "Slaves cannot work out of the cells at slavery administration. Move them into a room first!";

		} else {
			return "This job is unavailable!";
		}
	}

	public EventLogEntry getHourlyEvent(long hour, NPC slave, List<NPC> otherNPCsPresent) {
//		return new EventLogEntry(Main.game.getDayNumber()-1*24l+hour, "[style.colourDisabled(Nothing)]", "");
		return null;
	}

}


code:
package com.lilithsthrone.game.occupantManagement;

/**
 * @since 0.1.87
 * @version 0.1.87
 * @author Innoxia
 */
public enum SlaveJobHours {

	NONE("None", "Do not assign any hours to this slave.", 0, 0),

	DAY_NORMAL("Day shift", "Get this slave to work eight hours over the course of the day.", 9, 8),
	DAY_LONG("Day shift +", "Get this slave to work sixteen hours over the course of the day.", 6, 16),

	NIGHT_NORMAL("Night shift", "Get this slave to work eight hours over the course of the night.", 20, 8),
	NIGHT_LONG("Night shift +", "Get this slave to work sixteen hours over the course of the night.", 16, 16),

	TWENTY_FOUR_HOURS("24 hours", "Assign every hour as a work hour.", 0, 24);

	private String name;
	private String description;
	private int startHour;
	private int length;

	private SlaveJobHours(String name, String description, int startHour, int length) {
		this.name = name;
		this.description = description;
		this.startHour = startHour;
		this.length = length;
	}

	public String getName() {
		return name;
	}

	public String getDescription() {
		return description;
	}

	public int getStartHour() {
		return startHour;
	}

	public int getLength() {
		return length;
	}
}

repo_name: klorpa/Pedo

license: unknown


code:
package com.lilithsthrone.game.occupantManagement;

import com.lilithsthrone.utils.Colour;

/**
 * @since 0.1.87
 * @version 0.3.5.1
 * @author Innoxia
 */
public enum SlaveJobSetting {

	SEX_ORAL(Colour.GENERIC_SEX, "Allow Oral", "Oral", "Allow this slave to perform oral on others."),
	SEX_VAGINAL(Colour.GENERIC_SEX, "Allow Vaginal", "Vaginal", "Allow this slave to receive vaginal sex."),
	SEX_ANAL(Colour.GENERIC_SEX, "Allow Anal", "Anal", "Allow this slave to receive anal sex."),
	SEX_NIPPLES(Colour.GENERIC_SEX, "Allow Nipples", "Nipples", "Allow this slave to receive penetrative nipple sex."),

	MILKING_NO_PREFERENCE(Colour.BASE_GREY, "No Preference", "NP", "Set this slave to work in any available milking room."),
	MILKING_INDUSTRIAL(Colour.GENERIC_MINOR_BAD, "Industrial Milking", "IN", "Set this slave to work in a milking room with industrial milkers."),
	MILKING_REGULAR(Colour.BASE_YELLOW_LIGHT, "Regular Milking", "RG", "Set this slave to work in a milking room with regular milkers."),
	MILKING_ARTISAN(Colour.GENERIC_MINOR_GOOD, "Artisan Milking", "AR", "Set this slave to work in a milking room with artisan milkers."),
	MILKING_MILK_DISABLE(Colour.BASE_YELLOW_LIGHT, "Forbid Milk", "DM", "Do not allow this slave's milk to be collected."),
	MILKING_MILK_CROTCH_DISABLE(Colour.BASE_YELLOW_LIGHT, "Forbid Udder-milk", "DU", "Do not allow this slave's udders to be milked."),
	MILKING_CUM_DISABLE(Colour.BASE_BLUE_LIGHT, "Forbid Cum", "DC", "Do not allow this slave's cum to be collected."),
	MILKING_GIRLCUM_DISABLE(Colour.BASE_PINK_LIGHT, "Forbid Girlcum", "DG", "Do not allow this slave's girlcum to be collected."),

	MILKING_MILK_AUTO_SELL(Colour.CURRENCY_GOLD, "Auto-sell Milk", "SM", "Set this slave's milk to be automatically sold instead of stored."),
	MILKING_MILK_CROTCH_AUTO_SELL(Colour.CURRENCY_GOLD, "Auto-sell Udder-milk", "SCM", "Set this slave's crotch-milk to be automatically sold instead of stored."),
	MILKING_CUM_AUTO_SELL(Colour.CURRENCY_GOLD, "Auto-sell Cum", "SC", "Set this slave's cum to be automatically sold instead of stored."),
	MILKING_GIRLCUM_AUTO_SELL(Colour.CURRENCY_GOLD, "Auto-sell Girlcum", "SG", "Set this slave's girlcum to be automatically sold instead of stored."),

	TEST_SUBJECT_ALLOW_TRANSFORMATIONS_FEMALE(Colour.FEMININE, "Feminine TF", "TF (F)", "Allow this slave to receive feminine transformations."),
	TEST_SUBJECT_ALLOW_TRANSFORMATIONS_MALE(Colour.MASCULINE, "Masculine TF", "TF (M)", "Allow this slave to receive masculine transformations."),

	BEDROOM_GREETING(Colour.GENERIC_MINOR_GOOD, "Greeting", "BG", "Instruct this slave to greet you whenever you enter your room."),
	BEDROOM_CLEAN(Colour.BASE_BLUE_LIGHT, "Cleaning", "BC", "Tell this slave to keep your room clean."),
	BEDROOM_WAKE_UP(Colour.BASE_YELLOW_LIGHT, "Waking", "BK", "Allow this slave to serve as your alarm clock, allowing them to rouse you from your slumber at the instructed time."),
	BEDROOM_HELP_WASH(Colour.BASE_AQUA, "Washing", "BW", "Have this slave assist you in the bathroom when you wash yourself. (This will override the slave's 'Cleanliness' permissions, as they will get washed with you.)"),

	BEDROOM_SLEEP_FLOOR(Colour.GENERIC_MINOR_BAD, "Sleep on floor", "BSF", "Tell this slave that they must sleep on the floor of your room."),
	BEDROOM_SLEEP_ON_BED(Colour.BASE_PURPLE_LIGHT, "Sleep on bed", "BSO", "Permit this slave to sleep on your bed, but not under the covers."),
	BEDROOM_SLEEP_IN_BED(Colour.BASE_PINK, "Sleep in bed", "BSI", "Permit this slave to sleep in your bed beside you, under the covers."),

	;

	private Colour colour;
	private String name;
	private String tag;
	private String description;

	private SlaveJobSetting(Colour colour, String name, String tag, String description) {
		this.colour = colour;
		this.name = name;
		this.tag = tag;
		this.description = description;
	}

	public Colour getColour() {
		return colour;
	}

	public String getName() {
		return name;
	}

	public String getTag() {
		return tag;
	}

	public String getDescription() {
		return description;
	}

	public String getDailyEffectsDescription() {
		return null;
	}

	public String applyDailyEffects() {
		return null;
	}

}


code:
package com.lilithsthrone.game.occupantManagement;

import java.util.List;

import com.lilithsthrone.utils.Colour;
import com.lilithsthrone.utils.Util;

/**
 * @since 0.1.87
 * @version 0.3.5
 * @author Innoxia
 */
public enum SlavePermission {

	BEHAVIOUR(Colour.BASE_TEAL,
			"Behaviour",
			Util.newArrayListOfValues(
					SlavePermissionSetting.BEHAVIOUR_SLUTTY,
					SlavePermissionSetting.BEHAVIOUR_SEDUCTIVE,
					SlavePermissionSetting.BEHAVIOUR_STANDARD,
					SlavePermissionSetting.BEHAVIOUR_PROFESSIONAL,
					SlavePermissionSetting.BEHAVIOUR_WHOLESOME),
			true),

	GENERAL(Colour.TRANSFORMATION_GENERIC,
			"General",
			Util.newArrayListOfValues(
					SlavePermissionSetting.GENERAL_SILENCE,
					SlavePermissionSetting.GENERAL_CRAWLING,
					SlavePermissionSetting.GENERAL_HOUSE_FREEDOM,
					SlavePermissionSetting.GENERAL_OUTSIDE_FREEDOM),
			false),

	SEX(Colour.GENERIC_SEX,
			"Sex",
			Util.newArrayListOfValues(
					SlavePermissionSetting.SEX_MASTURBATE,
					SlavePermissionSetting.SEX_INITIATE_SLAVES,
					SlavePermissionSetting.SEX_INITIATE_PLAYER,
					SlavePermissionSetting.SEX_RECEIVE_SLAVES,
					SlavePermissionSetting.SEX_IMPREGNATED,
					SlavePermissionSetting.SEX_IMPREGNATE),
			false),

	PREGNANCY(Colour.BASE_PURPLE_LIGHT,
			"Pregnancy",
			Util.newArrayListOfValues(
					SlavePermissionSetting.PREGNANCY_PROMISCUITY_PILLS,
					SlavePermissionSetting.PREGNANCY_NO_PILLS,
					SlavePermissionSetting.PREGNANCY_VIXENS_VIRILITY),
			true),

	DIET(Colour.BODY_SIZE_TWO,
			"Diet",
			Util.newArrayListOfValues(
					SlavePermissionSetting.FOOD_DIET_EXTREME,
					SlavePermissionSetting.FOOD_DIET,
					SlavePermissionSetting.FOOD_NORMAL,
					SlavePermissionSetting.FOOD_PLUS,
					SlavePermissionSetting.FOOD_LAVISH),
			true),

	EXERCISE(Colour.MUSCLE_TWO,
			"Exercise",
			Util.newArrayListOfValues(
					SlavePermissionSetting.EXERCISE_FORBIDDEN,
					SlavePermissionSetting.EXERCISE_REST,
					SlavePermissionSetting.EXERCISE_NORMAL,
					SlavePermissionSetting.EXERCISE_TRAINING,
					SlavePermissionSetting.EXERCISE_BODY_BUILDING),
			true),

	CLEANLINESS(Colour.BASE_BLUE_LIGHT,
			"Cleanliness",
			Util.newArrayListOfValues(
					SlavePermissionSetting.CLEANLINESS_WASH_CLOTHES,
					SlavePermissionSetting.CLEANLINESS_WASH_BODY),
			false);

	private Colour colour;
	private String name;
	private List<SlavePermissionSetting> settings;
	private boolean mutuallyExclusiveSettings;

	private SlavePermission(Colour colour, String name, List<SlavePermissionSetting> settings, boolean mutuallyExclusiveSettings) {
		this.colour = colour;
		this.name = name;
		this.settings = settings;
		this.mutuallyExclusiveSettings = mutuallyExclusiveSettings;
	}

	public Colour getColour() {
		return colour;
	}

	public String getName() {
		return name;
	}

	public List<SlavePermissionSetting> getSettings() {
		return settings;
	}

	public boolean isMutuallyExclusiveSettings() {
		return mutuallyExclusiveSettings;
	}

}


code:
package com.lilithsthrone.game.occupantManagement;

import com.lilithsthrone.game.character.body.valueEnums.BodySize;
import com.lilithsthrone.game.character.body.valueEnums.Muscle;
import com.lilithsthrone.utils.Util;

/**
 * @since 0.1.87
 * @version 0.3.5
 * @author Innoxia
 */
public enum SlavePermissionSetting {

	// General/Misc.:

	GENERAL_SILENCE("Silence", "Forbid this slave from talking.", false),
	GENERAL_CRAWLING("Crawling", "Forbid this slave from walking, forcing them to crawl around on all fours.", false),
	GENERAL_HOUSE_FREEDOM("House Freedom", "Grant this slave the freedom to walk around Lilaya's house in their free time.", false),
	GENERAL_OUTSIDE_FREEDOM("Outside Freedom", "Grant this slave the freedom to leave Lilaya's house in their free time.", false),

	// Behaviour:
	BEHAVIOUR_WHOLESOME("Wholesome", "Get this slave to act in a loving and wholesome manner around you. [style.italics(This will only take effect if they like you or are obedient.)]", false),
	BEHAVIOUR_PROFESSIONAL("Professional", "Get this slave to act in a professional manner when interacting with you. [style.italics(This will only take effect if they like you or are obedient.)]", false),
	BEHAVIOUR_STANDARD("Standard", "Do not give this slave any instructions as to how they should act around you.", true),
	BEHAVIOUR_SEDUCTIVE("Seductive", "Get this slave to act in a refined, seductive manner when interacting with you. [style.italics(This will only take effect if they like you or are obedient.)]", false),
	BEHAVIOUR_SLUTTY("Slutty", "Get this slave to act in a trashy, slutty manner when interacting with you. [style.italics(This will only take effect if they like you or are obedient.)]", false),

	// Sex:

	SEX_MASTURBATE("Masturbation", "Allow this slave to masturbate.", false),
	SEX_INITIATE_SLAVES("Initiate Sex", "Allow this slave to initiate sex with any other slave that has the 'Sex Toy' permission enabled.", false),
	SEX_INITIATE_PLAYER("Use You", "Allow this slave to use you for sexual relief. This will allow them to initiate sex with you at any time.", false),
	SEX_RECEIVE_SLAVES("Sex Toy", "Allow this slave to be used for sexual relief by any of your slaves with the 'Initiate Sex' permission enabled.", false),
	SEX_IMPREGNATED("Breeding Bitch", "Allow this slave to be impregnated during sexual events with any other slave that has the 'Slave Stud' permission enabled.", false),
	SEX_IMPREGNATE("Slave Stud", "Allow this slave to impregnate any other slave that has the 'Breeding Bitch' permission enabled during sexual events.", false),

	// Pregnancy:

	PREGNANCY_PROMISCUITY_PILLS("Promiscuity Pills", "Keep this slave on Promiscuity Pills, ensuring that they won't get pregnant.", false),
	PREGNANCY_NO_PILLS("No Pills", "Don't give this slave any sort of fertility modification pills, resulting in a natural chance of them getting pregnant.", true),
	PREGNANCY_VIXENS_VIRILITY("Vixen's Virility", "Keep this slave on Vixen's Virility, greatly increasing both their fertility and virility.", false),

	// Diet/Body size:

	FOOD_DIET_EXTREME(Util.capitaliseSentence(BodySize.ZERO_SKINNY.getName(false)),
			"Severely limit the amount of food available to this slave, which will result in a large daily change to their body size,"
					+ " eventually making them "+BodySize.ZERO_SKINNY.getName(false)+".",
			false),

	FOOD_DIET(Util.capitaliseSentence(BodySize.ONE_SLENDER.getName(false)),
			"Restrict the amount of food available to this slave, which will result in a daily change to their body size,"
					+ " eventually making them "+BodySize.ONE_SLENDER.getName(false)+".",
			false),

	FOOD_NORMAL(Util.capitaliseSentence(BodySize.TWO_AVERAGE.getName(false)),
			"Give this slave a healthy amount of food, which will result in a daily change to their body size,"
					+ " eventually making them "+BodySize.TWO_AVERAGE.getName(false)+".",
			true),

	FOOD_PLUS(Util.capitaliseSentence(BodySize.THREE_LARGE.getName(false)),
			"Give this slave an extra meal every day, which will result in a daily change to their body size,"
					+ " eventually making them "+BodySize.THREE_LARGE.getName(false)+".",
			false),

	FOOD_LAVISH(Util.capitaliseSentence(BodySize.FOUR_HUGE.getName(false)),
			"Make an abundance of food available to this slave, which will result in a large daily change to their body size,"
					+ " eventually making them "+BodySize.FOUR_HUGE.getName(false)+".",
			false),

	// Exercise/Muscle:

	EXERCISE_FORBIDDEN(Util.capitaliseSentence(Muscle.ZERO_SOFT.getName(false)),
			"Forbid this slave from performing any strenuous activities, which will result in their muscles getting a lot smaller every day,"
					+ " eventually making them "+Muscle.ZERO_SOFT.getName(false)+".",
			false),

	EXERCISE_REST(Util.capitaliseSentence(Muscle.ONE_LIGHTLY_MUSCLED.getName(false)),
			"Do not give this slave any exercise routine, which will result in a daily change to their muscle mass,"
					+ " eventually making them "+Muscle.ONE_LIGHTLY_MUSCLED.getName(false)+".",
			false),

	EXERCISE_NORMAL(Util.capitaliseSentence(Muscle.TWO_TONED.getName(false)),
			"Set this slave to perform a healthy amount of exercise, which will result in a daily change to their muscle mass,"
					+ " eventually making them "+Muscle.TWO_TONED.getName(false)+".",
			true),

	EXERCISE_TRAINING(Util.capitaliseSentence(Muscle.THREE_MUSCULAR.getName(false)),
			"Give this slave a workout routine, which will result in a daily change to their muscle mass,"
					+ " eventually making them "+Muscle.THREE_MUSCULAR.getName(false)+".",
			false),

	EXERCISE_BODY_BUILDING(Util.capitaliseSentence(Muscle.FOUR_RIPPED.getName(false)),
			"Give this slave a strenuous exercise routine, which will result in their muscles getting a lot bigger every day,"
					+ " eventually making them "+Muscle.FOUR_RIPPED.getName(false)+".",
			false),

	// Claenliness:

	CLEANLINESS_WASH_CLOTHES("Wash Clothing", "Tell this slave to keep their clothing washed and clean.", true),
	CLEANLINESS_WASH_BODY("Wash Body", "Tell this slave to keep their body washed and clean, which will keep their orifices free of creampies.", true)
	;

	private String name;
	private String description;
	private boolean defaultValue;

	private SlavePermissionSetting(String name, String description, boolean defaultValue) {
		this.name = name;
		this.description = description;
		this.defaultValue = defaultValue;
	}

	public String getName() {
		return name;
	}

	public String getDescription() {
		return description;
	}

	public boolean isDefaultValue() {
		return defaultValue;
	}

}


code:
package com.lilithsthrone.game.settings;

/**
 * @since 0.1.78
 * @version 0.2.11
 * @author Innoxia
 */
public enum ContentPreferenceValue {

	ZERO_NONE("off", 0),

	ONE_MINIMAL("minimal", 1),

	TWO_LOW("low", 5),

	THREE_AVERAGE("average", 10),

	FOUR_HIGH("high", 20),

	FIVE_ABUNDANT("abundant", 40);

	private String name;
	private int value;

	private ContentPreferenceValue(String name, int value) {
		this.name= name;
		this.value=value;
	}

	public int getValue() {
		return value;
	}

	public String getName() {
		return name;
	}
}


code:
package com.lilithsthrone.game.settings;

import com.lilithsthrone.utils.Colour;

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

	NORMAL("Human", "The way the game is meant to be played. No level scaling and no damage modifications.", Colour.RACE_HUMAN, false, 1, 1),

	LEVEL_SCALING("Morph", "Enemies level up alongside your character, but do normal damage.", Colour.RACE_CAT_MORPH, true, 1, 1),

	HARD("Demon", "Enemies level up alongside your character and do 200% damage.", Colour.RACE_DEMON, true, 2, 1),

	NIGHTMARE("Lilin", "Enemies level up alongside your character, do 200% damage, and take only 50% damage from all sources.", Colour.BASE_PURPLE, true, 2, 0.5f),

	HELL("Lilith", "Enemies are always 2x your character's level, do 400% damage, and take only 25% damage from all sources. Be prepared to lose. A lot.", Colour.BASE_CRIMSON, true, 4, 0.25f);

	private String name;
	private String description;
	private Colour colour;
	private boolean isNPCLevelScaling;
	private float damageModifierNPC;
	private float damageModifierPlayer;

	private DifficultyLevel(String name, String description, Colour colour, boolean isNPCLevelScaling, float damageModifierNPC, float damageModifierPlayer) {
		this.name = name;
		this.description = description;
		this.colour = colour;
		this.isNPCLevelScaling = isNPCLevelScaling;
		this.damageModifierNPC = damageModifierNPC;
		this.damageModifierPlayer = damageModifierPlayer;
	}

	public String getName() {
		return name;
	}

	public String getDescription() {
		return description;
	}

	public Colour getColour() {
		return colour;
	}

	public boolean isNPCLevelScaling() {
		return isNPCLevelScaling;
	}

	public float getDamageModifierNPC() {
		return damageModifierNPC;
	}

	public float getDamageModifierPlayer() {
		return damageModifierPlayer;
	}
}


code:
package com.lilithsthrone.game.settings;

/**
 * @since 0.1.95
 * @version 0.2.3
 * @author FeiFongWong
 */
public enum ForcedFetishTendency {

	BOTTOM_HEAVY("Bottoming+", "Forced fetishes will almost always add bottoming and remove topping activities and behaviours."),

	BOTTOM("Bottoming", "While NPC tastes still matter, forced fetishes will usually add bottoming and remove topping activities and behaviours."),

	NEUTRAL("Neutral", "Forced fetishes will be determined solely by the tastes and whims of the controlling NPC, and the inherent randomness of the universe."),

	TOP ("Topping", "While NPC tastes still matter, forced fetishes will usually add topping and remove bottoming activities and behaviours."),

	TOP_HEAVY("Topping+", "Forced fetishes will almost always add topping and remove bottoming activities and behaviours.");

	private String name;
	private String description;

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

	}

	public String getName() {
		return name;
	}

	public String getDescription() {
		return description;
	}

}


code:
package com.lilithsthrone.game.settings;

/**
 * @since 0.1.95
 * @version 0.2.3
 * @author FeiFongWong
 */
public enum ForcedTFTendency {

	FEMININE_HEAVY("Feminine+", "There is a strong chance that forced transformations will make you more feminine regardless of NPC tastes."),

	FEMININE("Feminine", "While NPC tastes still matter, forced transformations will often make you more feminine."),

	NEUTRAL("Neutral", "Gender effects of forced transformations will be determined solely by the tastes and whims of the controlling NPC, and the inherent randomness of the universe."),

	MASCULINE("Masculine", "While NPC tastes still matter, forced transformations will often make you more masculine."),

	MASCULINE_HEAVY("Masculine+", "There is a strong chance that forced transformations will make you more masculine regardless of NPC tastes.");

	private String name;
	private String description;

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

	}

	public String getName() {
		return name;
	}

	public String getDescription() {
		return description;
	}

}


code:
package com.lilithsthrone.game.settings;

import java.util.regex.Pattern;

import com.lilithsthrone.utils.Util;

import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;

/**
 * @since 0.1.83
 * @version 0.1.83
 * @author Pimgd
 */
public class KeyCodeWithModifiers {

	private final KeyCode keyCode;
	private final boolean controlModifier;
	private final boolean shiftModifier;

	public static KeyCodeWithModifiers fromString(String source) {
		if (source == null || source.isEmpty()) {
			return null;
		}

		boolean usesShiftModifier = false;
		boolean usesControlModifier = false;
		KeyCode keyCode = null;
		if (!source.equals("+") && source.contains("+")) {
			String[] splitted = source.split(Pattern.quote("+"));
			for (int i = 0; i < splitted.length - 1; i++) {
				if ("SHIFT".equals(splitted[i])) {
					usesShiftModifier = true;
				} else if ("CTRL".equals(splitted[i])) {
					usesControlModifier = true;
				}
			}
			keyCode = KeyCode.valueOf(splitted[splitted.length -1]);
		} else {
			keyCode = KeyCode.valueOf(source);
		}

		return new KeyCodeWithModifiers(keyCode, usesControlModifier, usesShiftModifier);
	}

	public KeyCodeWithModifiers(KeyCode keyCode) {
		this(keyCode, false, false);
	}

	public KeyCodeWithModifiers(KeyCode keyCode, boolean controlModifier, boolean shiftModifier) {
		this.keyCode = keyCode;
		this.controlModifier = controlModifier;
		this.shiftModifier = shiftModifier;
	}

	public KeyCode getKeyCode() {
		return keyCode;
	}

	public boolean isControlModifier() {
		return controlModifier;
	}

	public boolean isShiftModifier() {
		return shiftModifier;
	}

	public boolean matches(KeyEvent keyEvent) {
		return keyEvent.getCode() == keyCode &&
				keyEvent.isControlDown() == controlModifier &&
				keyEvent.isShiftDown() == shiftModifier;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + (controlModifier ? 1231 : 1237);
		result = prime * result + ((keyCode == null) ? 0 : keyCode.hashCode());
		result = prime * result + (shiftModifier ? 1231 : 1237);
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		KeyCodeWithModifiers other = (KeyCodeWithModifiers) obj;
		return keyCode == other.keyCode &&
				shiftModifier == other.shiftModifier &&
				controlModifier == other.controlModifier;
	}

	@Override
	public String toString() {
		return (shiftModifier ? "SHIFT+" : "")
				+ (controlModifier ? "CTRL+" : "")
				+ keyCode.toString();
	}

	public String getFullName() {
		return (shiftModifier ? "SHIFT+" : "")
				+ (controlModifier ? "CTRL+" : "")
				+ keyCode.getName();
	}

	public String asHotkey() {
		return (shiftModifier ? "SHIFT + " : "")
				+ (controlModifier ? "CTRL + " : "")
				+ Util.getKeyCodeCharacter(keyCode);
	}
}


code:
package com.lilithsthrone.game.settings;

import javafx.scene.input.KeyCode;

/**
 * @since 0.1.61
 * @version 0.3.1
 * @author Innoxia
 */
public enum KeyboardAction {

	MENU("Menu", new KeyCodeWithModifiers(KeyCode.ESCAPE), null),

	FULL_SCREEN("Fullscreen Toggle", new KeyCodeWithModifiers(KeyCode.F11), null),

	MOVE_NORTH("Move North", new KeyCodeWithModifiers(KeyCode.W), new KeyCodeWithModifiers(KeyCode.UP)),
	MOVE_WEST("Move West", new KeyCodeWithModifiers(KeyCode.A), new KeyCodeWithModifiers(KeyCode.LEFT)),
	MOVE_SOUTH("Move South", new KeyCodeWithModifiers(KeyCode.S), new KeyCodeWithModifiers(KeyCode.DOWN)),
	MOVE_EAST("Move East", new KeyCodeWithModifiers(KeyCode.D), new KeyCodeWithModifiers(KeyCode.RIGHT)),

	MOVE_RESPONSE_CURSOR_NORTH("Response Cursor Up", new KeyCodeWithModifiers(KeyCode.W, false, true), new KeyCodeWithModifiers(KeyCode.UP, false, true)),
	MOVE_RESPONSE_CURSOR_WEST("Response Cursor Left", new KeyCodeWithModifiers(KeyCode.A, false, true), new KeyCodeWithModifiers(KeyCode.LEFT, false, true)),
	MOVE_RESPONSE_CURSOR_SOUTH("Response Cursor Down", new KeyCodeWithModifiers(KeyCode.S, false, true), new KeyCodeWithModifiers(KeyCode.DOWN, false, true)),
	MOVE_RESPONSE_CURSOR_EAST("Response Cursor Right", new KeyCodeWithModifiers(KeyCode.D, false, true), new KeyCodeWithModifiers(KeyCode.RIGHT, false, true)),

	QUICKSAVE("Quicksave", new KeyCodeWithModifiers(KeyCode.F5), null),
	QUICKLOAD("Quickload", new KeyCodeWithModifiers(KeyCode.F9), null),

	MENU_SELECT("Select", new KeyCodeWithModifiers(KeyCode.SPACE), new KeyCodeWithModifiers(KeyCode.ENTER)),
	INVENTORY("Inventory", new KeyCodeWithModifiers(KeyCode.I), new KeyCodeWithModifiers(KeyCode.TAB)),
	JOURNAL("Phone", new KeyCodeWithModifiers(KeyCode.P), new KeyCodeWithModifiers(KeyCode.J)),
	MAP("Map", new KeyCodeWithModifiers(KeyCode.M), null),
	CHARACTERS("Characters", new KeyCodeWithModifiers(KeyCode.C), null),
	ZOOM("Zoom", new KeyCodeWithModifiers(KeyCode.Z), null),

	SCROLL_UP("Scroll Up", new KeyCodeWithModifiers(KeyCode.PAGE_UP), null),
	SCROLL_DOWN("Scroll Down", new KeyCodeWithModifiers(KeyCode.PAGE_DOWN), null),

	RESPOND_1("Response 1", new KeyCodeWithModifiers(KeyCode.DIGIT1), null),
	RESPOND_2("Response 2", new KeyCodeWithModifiers(KeyCode.DIGIT2), null),
	RESPOND_3("Response 3", new KeyCodeWithModifiers(KeyCode.DIGIT3), null),
	RESPOND_4("Response 4", new KeyCodeWithModifiers(KeyCode.DIGIT4), null),
	RESPOND_5("Response 5", new KeyCodeWithModifiers(KeyCode.DIGIT5), null),
	RESPOND_6("Response 6", new KeyCodeWithModifiers(KeyCode.DIGIT1, false, true), null),
	RESPOND_7("Response 7", new KeyCodeWithModifiers(KeyCode.DIGIT2, false, true), null),
	RESPOND_8("Response 8", new KeyCodeWithModifiers(KeyCode.DIGIT3, false, true), null),
	RESPOND_9("Response 9", new KeyCodeWithModifiers(KeyCode.DIGIT4, false, true), null),
	RESPOND_10("Response 10", new KeyCodeWithModifiers(KeyCode.DIGIT5, false, true), null),
	RESPOND_11("Response 11", new KeyCodeWithModifiers(KeyCode.DIGIT1, true, false), null),
	RESPOND_12("Response 12", new KeyCodeWithModifiers(KeyCode.DIGIT2, true, false), null),
	RESPOND_13("Response 13", new KeyCodeWithModifiers(KeyCode.DIGIT3, true, false), null),
	RESPOND_14("Response 14", new KeyCodeWithModifiers(KeyCode.DIGIT4, true, false), null),
	RESPOND_0("Response 15", new KeyCodeWithModifiers(KeyCode.DIGIT5, true, false), new KeyCodeWithModifiers(KeyCode.BACK_SPACE)),

	RESPOND_NEXT_TAB("Next Response Tab", new KeyCodeWithModifiers(KeyCode.E, false, true), null),
	RESPOND_PREVIOUS_TAB("Previous Response Tab", new KeyCodeWithModifiers(KeyCode.Q, false, true), null),

	RESPOND_NEXT_PAGE("Next Response Page", new KeyCodeWithModifiers(KeyCode.E), null),
	RESPOND_PREVIOUS_PAGE("Previous Response Page", new KeyCodeWithModifiers(KeyCode.Q), null);

	private String name;
	private KeyCodeWithModifiers primaryDefault, secondaryDefault;

	private KeyboardAction(String name, KeyCodeWithModifiers primaryDefault, KeyCodeWithModifiers secondaryDefault) {
		this.name = name;
		this.primaryDefault = primaryDefault;
		this.secondaryDefault = secondaryDefault;
	}

	public String getName() {
		return name;
	}

	public KeyCodeWithModifiers getPrimaryDefault() {
		return primaryDefault;
	}

	public KeyCodeWithModifiers getSecondaryDefault() {
		return secondaryDefault;
	}
}


code:
package com.lilithsthrone.game.sex;

/**
 * @since 0.1.0
 * @version 0.3.4
 * @author Innoxia
 */
public enum ArousalIncrease {

	/**This is a special action.*/
	NEGATIVE_MAJOR(-30),

	/**This is a special action for if the player has the denial fetish.*/
	NEGATIVE(-20),

//	/**Calm down a little.*/
//	NEGATIVE_MINOR(-10),

	/**This action is not very arousing at all for this partner. For example, if the other partner is masturbating out-of-sight.*/
	ZERO_NONE(0.1f),

	/**This action is minimally arousing for this partner. For example, the player is masturbating in front of them.*/
	ONE_MINIMUM(0.5f),

	/**This action is not very arousing for this partner. For example, sucking the other partner's cock while receiving no stimulation for themselves.*/
	TWO_LOW(1f),

	/**This action is of an average amount of arousal. Equating to mild stimulation of your genitals (same level as masturbation).*/
	THREE_NORMAL(1.5f),

	/**This action is highly arousing or causing a large amount of stimulation. Most penetrative sex actions should fall into this category.*/
	FOUR_HIGH(2),

	/**This action is causing an unusually large amount of stimulation, of the equivalent level as an orgasm. Only very special actions, such as having a demon's vagina squeezing down on your cock, should cause this much arousal.*/
	FIVE_EXTREME(5);

	private float arousalIncreaseValue;

	private ArousalIncrease(float arousalIncreaseValue) {
		this.arousalIncreaseValue = arousalIncreaseValue;
	}

	public float getArousalIncreaseValue() {
		return arousalIncreaseValue;
	}
}


code:
package com.lilithsthrone.game.sex;

/**
 * @since 0.3.1
 * @version 0.3.1
 * @author Innoxia
 */
public enum CondomFailure {

	NONE,

	SABOTAGED,

	CUM_OVERLOAD,

	MINERAL_OIL_SELF_CUM,

	MINERAL_OIL_SALIVA,
	MINERAL_OIL_MILK,
	MINERAL_OIL_GIRLCUM,
	MINERAL_OIL_CUM;

}


code:
package com.lilithsthrone.game.sex;

import com.lilithsthrone.game.character.GameCharacter;
import com.lilithsthrone.game.sex.sexActions.SexActionInterface;

/**
 * @since 0.3.1
 * @version 0.3.1
 * @author Innoxia
 */
public class InitialSexActionInformation {

	private GameCharacter performer;
	private GameCharacter target;
	private SexActionInterface sexAction;
	private boolean appendDescription;
	private boolean appendEffects;

	public InitialSexActionInformation(GameCharacter performer, GameCharacter target, SexActionInterface sexAction, boolean appendDescription, boolean appendEffects) {
		this.performer = performer;
		this.target = target;
		this.sexAction = sexAction;
		this.appendDescription = appendDescription;
		this.appendEffects = appendEffects;
	}

	public GameCharacter getPerformer() {
		return performer;
	}

	public GameCharacter getTarget() {
		return target;
	}

	public SexActionInterface getSexAction() {
		return sexAction;
	}

	public boolean isAppendDescription() {
		return appendDescription;
	}

	public boolean isAppendEffects() {
		return appendEffects;
	}

}


code:
package com.lilithsthrone.game.sex;

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

/**
 * @since 0.1.6?
 * @version 0.2.9
 * @author Innoxia
 */
public enum LubricationType {

	SALIVA("saliva", "saliva", false),

	MILK("[npc.milk]", "milk", false),

	PRECUM("precum", "precum", false),

	CUM("[npc.cum]", "cum", false),

	GIRLCUM("girlcum", "girlcum", false),

	ANAL_LUBE("anal lubricant", "anal lubricant", false), // This is only present if the anus has been transformed to be 'wetter' than usual

	SLIME("slime", "slime", false),

	OTHER("lubrication", "lubrication", false);

	private String name;
	private String nullOwnerName;
	private boolean plural;

	private LubricationType(String name, String nullOwnerName, boolean plural){
		this.name = name;
		this.nullOwnerName = nullOwnerName;
		this.plural = plural;
	}

	public boolean isPlural() {
		return plural;
	}

	public String getName(GameCharacter owner) {
		if(owner==null) {
			return nullOwnerName;
		}
		return UtilText.parse(owner, name);
	};
}


code:
package com.lilithsthrone.game.sex;

/**
 * Flags for use in NPC.calculateGenericSexEffects() to restrict outcomes.
 *
 * @since 0.3.4
 * @version 0.3.5.1
 * @author Innoxia
 */
public enum NPCGenericSexFlag {

	NO_DESCRIPTION_NEEDED,

	PREVENT_CREAMPIE;

}


code:
package com.lilithsthrone.game.sex;

/**
 * @since 0.1.97
 * @version 0.3.3
 * @author Innoxia
 */
public enum OrgasmCumTarget {

	// Specials:
	LILAYA_PANTIES("into Lilaya's panties", false),

	WALL("up the wall", false),
	FLOOR("onto floor", false),

	INSIDE("inside", true),
	INSIDE_SWITCH_DOUBLE("inside (double)", true),

	ASS("over ass", true),
	GROIN("over groin", true),
	BREASTS("onto breasts", true),
	FACE("over face", true),
	HAIR("into hair", true),
	STOMACH("onto stomach", true),
	LEGS("onto legs", true),
	FEET("onto feet", true),
	BACK("over back", true),

	SELF_GROIN("onto self groin", false),
	SELF_STOMACH("onto self stomach", false),
	SELF_LEGS("onto self legs", false),
	SELF_FEET("onto self feet", false),
	SELF_BREASTS("onto self breasts", false),
	SELF_FACE("onto self face", false);

	private String name;
	private boolean requiresPartner;

	private OrgasmCumTarget(String name, boolean requiresPartner) {
		this.name = name;
		this.requiresPartner = requiresPartner;
	}

	public String getName() {
		return name;
	}

	public boolean isRequiresPartner() {
		return requiresPartner;
	}

}


code:
package com.lilithsthrone.game.sex;

import com.lilithsthrone.game.character.GameCharacter;
import com.lilithsthrone.game.character.body.valueEnums.BodyMaterial;
import com.lilithsthrone.game.character.effects.StatusEffect;
import com.lilithsthrone.game.dialogue.utils.UtilText;

/**
 * @since 0.1.65
 * @version 0.3.4
 * @author Innoxia
 */
public enum PregnancyDescriptor {

	ALREADY_PREGNANT {
		@Override
		public String getDescriptor(GameCharacter characterBeingImpregnated, GameCharacter characterProvidingCum, boolean directSexInsemination) {
			boolean isSlime = characterBeingImpregnated.getBodyMaterial()==BodyMaterial.SLIME;
			boolean selfcest = characterBeingImpregnated.equals(characterProvidingCum);

			StringBuilder sb = new StringBuilder();

			sb.append("
");
			if(characterBeingImpregnated.isPlayer()){
				if(characterProvidingCum==null) {
					sb.append("You feel cum ");
					if(isSlime) {
						sb.append("dispersing through your slimy body, seeking to impregnate your core");
					} else {
						sb.append("deep in your [pc.pussy+]");
					}
					sb.append(", but because [style.boldSex(you're already pregnant, you don't have to worry about it)]!");

				} else {
					sb.append("You feel ");
					if(selfcest) {
						sb.append("your own");
					} else {
						sb.append("[npc.namePos]");
					}
					if(isSlime) {
						sb.append("[npc.cum+] dispersing through your slimy body, seeking to impregnate your core");
					} else {
						sb.append("[npc.cum+] deep in your [pc.pussy+]");
					}
					sb.append(", but because [style.boldSex(you're already pregnant, you don't have to worry about it)]!");
				}

			} else {
				if(characterProvidingCum==null) {
					sb.append("[npc.NameIsFull] already pregnant, [style.boldSex(so there's no chance that ");
					if(selfcest) {
						sb.append("[npc.she] has knocked [npc.herself] up");
					} else {
						sb.append("[npc.she] has been impregnated");
					}
					sb.append(")]!");

				} else {
					sb.append("[npc.NameIsFull] already pregnant, [style.boldSex(so there's no chance that ");
					if(directSexInsemination) {
						if(selfcest) {
							sb.append("[npc.she] has knocked [npc.herself] up");
						} else {
							sb.append("[npc2.nameHas] knocked [npc.herHim] up");
						}
					} else {
						if(selfcest) {
							sb.append("[npc.she] has impregnated [npc.herself]");
						} else {
							sb.append("[npc2.nameHas] impregnated [npc.herHim]");
						}
					}
					sb.append(")]!");
				}
			}
			sb.append("
");

			if(characterProvidingCum!=null) {
				return UtilText.parse(characterBeingImpregnated, characterProvidingCum, sb.toString());
			} else {
				return UtilText.parse(characterBeingImpregnated, sb.toString());
			}
		}
	},

	NO_CHANCE {
		@Override
		public String getDescriptor(GameCharacter characterBeingImpregnated, GameCharacter characterProvidingCum, boolean directSexInsemination) {
			boolean isSlime = characterBeingImpregnated.getBodyMaterial()==BodyMaterial.SLIME;
			boolean selfcest = characterBeingImpregnated.equals(characterProvidingCum);

			StringBuilder sb = new StringBuilder();

			sb.append("
");
			if(characterBeingImpregnated.isPlayer()){
				if(characterProvidingCum==null) {
					sb.append("Despite feeling cum ");
					if(isSlime) {
						sb.append("dispersing through your slimy body, seeking to impregnate your core");
					} else {
						sb.append("deep in your womb");
					}
					sb.append(", you feel that [style.boldSex(you aren't going to get pregnant from this)].");

				} else {
					sb.append("Despite feeling ");
					if(selfcest) {
						sb.append("your own");
					} else {
						sb.append("[npc.namePos]");
					}
					if(isSlime) {
						sb.append("[npc.cum+] dispersing through your slimy body, seeking to impregnate your core");
					} else {
						sb.append("[npc.cum+] deep in your womb");
					}
					sb.append(", you feel that [style.boldSex(you aren't going to get pregnant from this)].");
				}

			} else {
				if(characterProvidingCum==null) {
					sb.append("Despite having [npc.her] ");
					if(isSlime) {
						sb.append("slimy body");
					} else {
						sb.append("womb");
					}
					if(selfcest) {
						sb.append(" filled with [npc.her] own seed, [style.boldSex(there's no chance that [npc.nameHasFull] impregnated [npc.herself])].");
					} else {
						sb.append(" filled with cum, [style.boldSex(there's no chance that [npc.nameHasFull] been impregnated)].");
					}

				} else {
					sb.append("Despite having [npc.her] ");
					if(isSlime) {
						sb.append("slimy body");
					} else {
						sb.append("womb");
					}
					if(selfcest) {
						sb.append(" filled with [npc.her] own seed, [style.boldSex(there's no chance that [npc.nameHasFull] impregnated [npc.herself])].");
					} else {
						sb.append(" filled with [npc2.namePos] [npc2.cum+], [style.boldSex(there's no chance that [npc.nameHasFull] been impregnated)].");
					}
				}
			}
			sb.append("
");

			if(characterProvidingCum!=null) {
				return UtilText.parse(characterBeingImpregnated, characterProvidingCum, sb.toString());
			} else {
				return UtilText.parse(characterBeingImpregnated, sb.toString());
			}
		}
	},

	LOW_CHANCE {
		@Override
		public String getDescriptor(GameCharacter characterBeingImpregnated, GameCharacter characterProvidingCum, boolean directSexInsemination) {
			boolean isSlime = characterBeingImpregnated.getBodyMaterial()==BodyMaterial.SLIME;
			boolean selfcest = characterBeingImpregnated.equals(characterProvidingCum);

			StringBuilder sb = new StringBuilder();

			sb.append("
");
			if(characterBeingImpregnated.isPlayer()){
				sb.append("You feel ");
				if(selfcest) {
					sb.append("your own [npc.cum+]");
				} else {
					if(characterProvidingCum==null) {
						sb.append("cum");
					} else {
						sb.append("[npc2.namePos] [npc2.cum+]");
					}
				}
				if(isSlime) {
					sb.append(" dispersing through your slimy body, seeking to impregnate your core");
				} else {
					sb.append(" deep in your womb");
				}
				if(characterBeingImpregnated.hasStatusEffect(StatusEffect.PREGNANT_0)) {
					sb.append(", and you realise that [style.boldSex(if you aren't already pregnant, there's a small chance you are now)]!");
				} else {
					sb.append(", and you realise that [style.boldSex(there's a small chance you'll get pregnant)]!");
				}

			} else {
				sb.append("After having [npc.her] ");
				if(isSlime) {
					sb.append("slimy body");
				} else {
					sb.append("womb");
				}
				if(selfcest) {
					sb.append(" filled with [npc.her] own seed,");
				} else {
					if(characterProvidingCum==null) {
						sb.append(" filled with cum,");
					} else {
						sb.append(" filled with [npc2.namePos] [npc2.cum+],");
					}
				}
				if(characterBeingImpregnated.hasStatusEffect(StatusEffect.PREGNANT_0)) {
					sb.append(" [npc.name] [npc.verb(realise)] that [style.boldSex(if [npc.she] isn't already pregnant, there's a small chance [npc.she] is now)]!");
				} else {
					sb.append(" [npc.name] [npc.verb(realise)] that [style.boldSex(there's a small chance [npc.she]'ll get pregnant)]!");
				}
			}
			sb.append("
");

			if(characterProvidingCum!=null) {
				return UtilText.parse(characterBeingImpregnated, characterProvidingCum, sb.toString());
			} else {
				return UtilText.parse(characterBeingImpregnated, sb.toString());
			}
		}
	},

	AVERAGE_CHANCE {
		@Override
		public String getDescriptor(GameCharacter characterBeingImpregnated, GameCharacter characterProvidingCum, boolean directSexInsemination) {
			boolean isSlime = characterBeingImpregnated.getBodyMaterial()==BodyMaterial.SLIME;
			boolean selfcest = characterBeingImpregnated.equals(characterProvidingCum);

			StringBuilder sb = new StringBuilder();

			sb.append("
");
			if(characterBeingImpregnated.isPlayer()){
				sb.append("You feel ");
				if(selfcest) {
					sb.append("your own [npc.cum+]");
				} else {
					if(characterProvidingCum==null) {
						sb.append("cum");
					} else {
						sb.append("[npc2.namePos] [npc2.cum+]");
					}
				}
				if(isSlime) {
					sb.append(" dispersing through your slimy body, seeking to impregnate your core");
				} else {
					sb.append(" deep in your womb");
				}
				if(characterBeingImpregnated.hasStatusEffect(StatusEffect.PREGNANT_0)) {
					sb.append(", and you realise that [style.boldSex(if you aren't already pregnant, there's a chance you are now)]!");
				} else {
					sb.append(", and you realise that [style.boldSex(there's a chance you'll get pregnant)]!");
				}

			} else {
				sb.append("After having [npc.her] ");
				if(isSlime) {
					sb.append("slimy body");
				} else {
					sb.append("womb");
				}
				if(selfcest) {
					sb.append(" filled with [npc.her] own seed,");
				} else {
					if(characterProvidingCum==null) {
						sb.append(" filled with cum,");
					} else {
						sb.append(" filled with [npc2.namePos] [npc2.cum+],");
					}
				}
				if(characterBeingImpregnated.hasStatusEffect(StatusEffect.PREGNANT_0)) {
					sb.append(" [npc.name] [npc.verb(realise)] that [style.boldSex(if [npc.she] isn't already pregnant, there's a chance [npc.she] is now)]!");
				} else {
					sb.append(" [npc.name] [npc.verb(realise)] that [style.boldSex(there's a chance [npc.she]'ll get pregnant)]!");
				}
			}
			sb.append("
");

			if(characterProvidingCum!=null) {
				return UtilText.parse(characterBeingImpregnated, characterProvidingCum, sb.toString());
			} else {
				return UtilText.parse(characterBeingImpregnated, sb.toString());
			}
		}
	},

	HIGH_CHANCE {
		@Override
		public String getDescriptor(GameCharacter characterBeingImpregnated, GameCharacter characterProvidingCum, boolean directSexInsemination) {
			boolean isSlime = characterBeingImpregnated.getBodyMaterial()==BodyMaterial.SLIME;
			boolean selfcest = characterBeingImpregnated.equals(characterProvidingCum);

			StringBuilder sb = new StringBuilder();

			sb.append("
");
			if(characterBeingImpregnated.isPlayer()){
				sb.append("You feel ");
				if(selfcest) {
					sb.append("your own [npc.cum+]");
				} else {
					if(characterProvidingCum==null) {
						sb.append("cum");
					} else {
						sb.append("[npc2.namePos] [npc2.cum+]");
					}
				}
				if(isSlime) {
					sb.append(" dispersing through your slimy body, seeking to impregnate your core");
				} else {
					sb.append(" deep in your womb");
				}
				if(characterBeingImpregnated.hasStatusEffect(StatusEffect.PREGNANT_0)) {
					sb.append(", and you realise that [style.boldSex(if you aren't already pregnant, there's a high chance you are now)]!");
				} else {
					sb.append(", and you realise that [style.boldSex(there's a high chance you'll get pregnant)]!");
				}

			} else {
				sb.append("After having [npc.her] ");
				if(isSlime) {
					sb.append("slimy body");
				} else {
					sb.append("womb");
				}
				if(selfcest) {
					sb.append(" filled with [npc.her] own seed,");
				} else {
					if(characterProvidingCum==null) {
						sb.append(" filled with cum,");
					} else {
						sb.append(" filled with [npc2.namePos] [npc2.cum+],");
					}
				}
				if(characterBeingImpregnated.hasStatusEffect(StatusEffect.PREGNANT_0)) {
					sb.append(" [npc.name] [npc.verb(realise)] that [style.boldSex(if [npc.she] isn't already pregnant, there's a high chance [npc.she] is now)]!");
				} else {
					sb.append(" [npc.name] [npc.verb(realise)] that [style.boldSex(there's a high chance [npc.she]'ll get pregnant)]!");
				}
			}
			sb.append("
");

			if(characterProvidingCum!=null) {
				return UtilText.parse(characterBeingImpregnated, characterProvidingCum, sb.toString());
			} else {
				return UtilText.parse(characterBeingImpregnated, sb.toString());
			}
		}
	},

	CERTAINTY {
		@Override
		public String getDescriptor(GameCharacter characterBeingImpregnated, GameCharacter characterProvidingCum, boolean directSexInsemination) {
			boolean isSlime = characterBeingImpregnated.getBodyMaterial()==BodyMaterial.SLIME;
			boolean selfcest = characterBeingImpregnated.equals(characterProvidingCum);

			StringBuilder sb = new StringBuilder();

			sb.append("
");
			if(characterBeingImpregnated.isPlayer()){
				sb.append("You feel ");
				if(selfcest) {
					sb.append("your own [npc.cum+]");
				} else {
					if(characterProvidingCum==null) {
						sb.append("cum");
					} else {
						sb.append("[npc2.namePos] [npc2.cum+]");
					}
				}
				if(isSlime) {
					sb.append(" dispersing through your slimy body, seeking to impregnate your core");
				} else {
					sb.append(" deep in your womb");
				}
				if(characterBeingImpregnated.hasStatusEffect(StatusEffect.PREGNANT_0)) {
					sb.append(", and you realise that [style.boldSex(if you aren't already pregnant, you certainly are now)]!");
				} else {
					sb.append(", and you realise that [style.boldSex(it's a certainty that you've been impregnated)]!");
				}

			} else {
				sb.append("After having [npc.her] ");
				if(isSlime) {
					sb.append("slimy body");
				} else {
					sb.append("womb");
				}
				if(selfcest) {
					sb.append(" filled with [npc.her] own seed,");
				} else {
					if(characterProvidingCum==null) {
						sb.append(" filled with cum,");
					} else {
						sb.append(" filled with [npc2.namePos] [npc2.cum+],");
					}
				}
				if(characterBeingImpregnated.hasStatusEffect(StatusEffect.PREGNANT_0)) {
					sb.append(" [npc.name] [npc.verb(realise)] that [style.boldSex(if [npc.she] isn't already pregnant, [npc.she] certainly is now)]!");
				} else {
					sb.append(" [npc.name] [npc.verb(realise)] that [style.boldSex(it's a certainty that [npc.sheHas] been impregnated)]!");
				}
			}
			sb.append("
");

			if(characterProvidingCum!=null) {
				return UtilText.parse(characterBeingImpregnated, characterProvidingCum, sb.toString());
			} else {
				return UtilText.parse(characterBeingImpregnated, sb.toString());
			}
		}
	};

	public abstract String getDescriptor(GameCharacter characterBeingImpregnated, GameCharacter characterProvidingCum, boolean directSexInsemination);

	public static PregnancyDescriptor getPregnancyDescriptorBasedOnProbability(float probability) {
		if (probability <= 0) {
			return PregnancyDescriptor.NO_CHANCE;
		} else if (probability <= 0.15f) {
			return PregnancyDescriptor.LOW_CHANCE;
		} else if (probability <= 0.3f) {
			return PregnancyDescriptor.AVERAGE_CHANCE;
		} else if (probability < 1) {
			return PregnancyDescriptor.HIGH_CHANCE;
		} else {
			return PregnancyDescriptor.CERTAINTY;
		}
	}
}