code:
package com.lilithsthrone.rendering;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import com.lilithsthrone.game.PropertyValue;
import com.lilithsthrone.game.character.GameCharacter;
import com.lilithsthrone.game.character.attributes.ArousalLevel;
import com.lilithsthrone.game.character.attributes.Attribute;
import com.lilithsthrone.game.character.attributes.CorruptionLevel;
import com.lilithsthrone.game.character.attributes.IntelligenceLevel;
import com.lilithsthrone.game.character.attributes.LustLevel;
import com.lilithsthrone.game.character.attributes.PhysiqueLevel;
import com.lilithsthrone.game.character.body.types.HornType;
import com.lilithsthrone.game.character.body.types.TailType;
import com.lilithsthrone.game.character.body.types.WingType;
import com.lilithsthrone.game.character.body.valueEnums.Femininity;
import com.lilithsthrone.game.character.effects.StatusEffect;
import com.lilithsthrone.game.character.fetishes.Fetish;
import com.lilithsthrone.game.character.markings.Tattoo;
import com.lilithsthrone.game.character.npc.NPC;
import com.lilithsthrone.game.character.race.Subspecies;
import com.lilithsthrone.game.combat.Combat;
import com.lilithsthrone.game.combat.CombatMove;
import com.lilithsthrone.game.combat.Spell;
import com.lilithsthrone.game.dialogue.DialogueNode;
import com.lilithsthrone.game.dialogue.DialogueNodeType;
import com.lilithsthrone.game.dialogue.eventLog.EventLogEntry;
import com.lilithsthrone.game.dialogue.utils.CharactersPresentDialogue;
import com.lilithsthrone.game.dialogue.utils.InventoryDialogue;
import com.lilithsthrone.game.dialogue.utils.InventoryInteraction;
import com.lilithsthrone.game.dialogue.utils.MapTravelType;
import com.lilithsthrone.game.dialogue.utils.PhoneDialogue;
import com.lilithsthrone.game.dialogue.utils.UtilText;
import com.lilithsthrone.game.inventory.AbstractCoreItem;
import com.lilithsthrone.game.inventory.CharacterInventory;
import com.lilithsthrone.game.inventory.InventorySlot;
import com.lilithsthrone.game.inventory.Rarity;
import com.lilithsthrone.game.inventory.ShopTransaction;
import com.lilithsthrone.game.inventory.clothing.AbstractClothing;
import com.lilithsthrone.game.inventory.clothing.BodyPartClothingBlock;
import com.lilithsthrone.game.inventory.clothing.ClothingType;
import com.lilithsthrone.game.inventory.enchanting.TFEssence;
import com.lilithsthrone.game.inventory.item.AbstractItem;
import com.lilithsthrone.game.inventory.weapon.AbstractWeapon;
import com.lilithsthrone.game.settings.KeyboardAction;
import com.lilithsthrone.game.sex.Sex;
import com.lilithsthrone.game.sex.SexAreaInterface;
import com.lilithsthrone.game.sex.SexAreaOrifice;
import com.lilithsthrone.game.sex.SexAreaPenetration;
import com.lilithsthrone.game.sex.positions.slots.SexSlotGeneric;
import com.lilithsthrone.main.Main;
import com.lilithsthrone.utils.BaseColour;
import com.lilithsthrone.utils.Colour;
import com.lilithsthrone.utils.Pathing;
import com.lilithsthrone.utils.Units;
import com.lilithsthrone.utils.Util;
import com.lilithsthrone.utils.Vector2i;
import com.lilithsthrone.world.Cell;
import com.lilithsthrone.world.World;
import com.lilithsthrone.world.WorldType;
import com.lilithsthrone.world.places.AbstractGlobalPlaceType;
import com.lilithsthrone.world.places.AbstractPlaceType;
import com.lilithsthrone.world.places.PlaceType;
import com.lilithsthrone.world.places.Population;

/**
 * @since 0.1.0
 * @version 0.3.5.5
 * @author Innoxia
 */
public enum RenderingEngine {
	ENGINE;

	private static boolean zoomedIn = true;
	private static boolean renderedDisabledMap = false;

	private static int pageLeft = 0;
	private static int pageRight = 0;

	private boolean renderingTattoosLeft = false;
	private boolean renderingTattoosRight = false;

	public static final int INVENTORY_PAGES = 5;
	public static final int ITEMS_PER_PAGE = 24;

	public static Colour[] orgasmColours = new Colour[]{Colour.AROUSAL_STAGE_ZERO, Colour.AROUSAL_STAGE_ONE, Colour.AROUSAL_STAGE_TWO, Colour.AROUSAL_STAGE_THREE, Colour.AROUSAL_STAGE_FOUR, Colour.AROUSAL_STAGE_FIVE, Colour.GENERIC_ARCANE};

	public static InventorySlot[] mainInventorySlots = {
			InventorySlot.EYES,			InventorySlot.HEAD,			InventorySlot.HAIR,		InventorySlot.HORNS,
			InventorySlot.NECK,			InventorySlot.TORSO_OVER,	InventorySlot.MOUTH,	InventorySlot.WINGS,
			InventorySlot.STOMACH,		InventorySlot.TORSO_UNDER,	InventorySlot.CHEST,	InventorySlot.NIPPLE,
			InventorySlot.WRIST,		InventorySlot.HIPS,			InventorySlot.HAND,		InventorySlot.FINGER,
			InventorySlot.ANKLE,		InventorySlot.LEG,			InventorySlot.GROIN,	InventorySlot.TAIL};

	public static InventorySlot[] secondaryInventorySlots = {InventorySlot.SOCK, InventorySlot.FOOT, InventorySlot.ANUS, InventorySlot.PENIS, InventorySlot.VAGINA};

	private static InventorySlot[] piercingSlots = {
			InventorySlot.PIERCING_EAR,		InventorySlot.PIERCING_NOSE,
			InventorySlot.PIERCING_LIP,		InventorySlot.PIERCING_TONGUE,
			InventorySlot.PIERCING_NIPPLE,	InventorySlot.PIERCING_STOMACH,
			InventorySlot.PIERCING_PENIS,	InventorySlot.PIERCING_VAGINA };

	private RenderingEngine() {
	}

	private StringBuilder inventorySB = new StringBuilder(), equippedPanelSB = new StringBuilder();

	public String getInventoryPanel(GameCharacter charactersInventoryToRender, boolean buyback) {
		return "
"
					+getInventoryDiv(Main.game.getPlayer(), false) + getInventoryDiv(charactersInventoryToRender, buyback)
				+"
";
	}

	private String getInventoryEquippedPanel(GameCharacter charactersInventoryToRender) {

		equippedPanelSB.setLength(0);

		if(charactersInventoryToRender == null) {
			equippedPanelSB.append("
");

			for (InventorySlot invSlot : mainInventorySlots) {
				equippedPanelSB.append("

");
			}

			String weaponStyle = "width:46%; margin:2%; background-color:"+Colour.BACKGROUND.toWebHexString()+";";
			String piercingStyle = "width:40%; margin:5%; background-color:"+Colour.BACKGROUND.toWebHexString()+";";

			equippedPanelSB.append("
"
					+ "
");

			equippedPanelSB.append("

");

			equippedPanelSB.append("

");

			for (InventorySlot invSlot : piercingSlots) {
				equippedPanelSB.append("

");
			}
			equippedPanelSB.append("
");

			equippedPanelSB.append("
");

			for (InventorySlot invSlot : secondaryInventorySlots) {
				equippedPanelSB.append("

");
			}

			equippedPanelSB.append("
"
										+ "
"
											+SVGImages.SVG_IMAGE_PROVIDER.getTattooSwitchClothing()
										+"
"
									+ "

");

			equippedPanelSB.append("
");

			return equippedPanelSB.toString();
		}

		Set<InventorySlot> blockedSlots = new HashSet<>();

		for (AbstractClothing c : charactersInventoryToRender.getClothingCurrentlyEquipped()) {
			if (c.getClothingType().getIncompatibleSlots(charactersInventoryToRender, c.getSlotEquippedTo()) != null) {
				for (InventorySlot is : c.getClothingType().getIncompatibleSlots(charactersInventoryToRender, c.getSlotEquippedTo())) {
					blockedSlots.add(is);
				}
			}
		}

		// EQUIPPED:
		equippedPanelSB.append("
");

		Map<InventorySlot, List<AbstractClothing>> concealedSlots = charactersInventoryToRender.getInventorySlotsConcealed();

		for (InventorySlot invSlot : mainInventorySlots) {
			appendEquippedClothingSlot(charactersInventoryToRender, invSlot, blockedSlots, concealedSlots, false);
		}

		equippedPanelSB.append("
");

		// Render weapons & piercings:
		equippedPanelSB.append("
");

		String weaponStyle = "width:46%; margin:2%;";
		String weaponStyleNoEssences = "width:46%; margin:2%; border:2px solid "+Colour.GENERIC_BAD.toWebHexString()+";";
		String piercingStyle = "width:40%; margin:5%;";
		if(charactersInventoryToRender.getArmRows()>1) {
			weaponStyle = "width:31%; margin:1%;";
			weaponStyleNoEssences = "width:31%; margin:1%; border:1% solid "+Colour.GENERIC_BAD.toWebHexString()+";";
			piercingStyle = "width:35%; margin:5.5% 7.5%;";
		}

		int essenceCount = charactersInventoryToRender.getEssenceCount(TFEssence.ARCANE);

		// Main weapon:
		AbstractWeapon weaponInSlot = charactersInventoryToRender.getMainWeapon(0);
		if (weaponInSlot != null) {
			equippedPanelSB.append(
					"<div class='inventory-item-slot" + getClassRarityIdentifier(weaponInSlot.getRarity()) + "' style='"+(essenceCount<weaponInSlot.getWeaponType().getArcaneCost()?weaponStyleNoEssences:weaponStyle)+"'>"
						+ "
"+weaponInSlot.getSVGEquippedString(charactersInventoryToRender)+"
"
						+ "

"
					+ "
");
		} else {
			equippedPanelSB.append("

");
		}
		// Multiple arms:
		if(charactersInventoryToRender.getArmRows()>1) {
			weaponInSlot = charactersInventoryToRender.getMainWeapon(1);
			if (weaponInSlot != null) {
				equippedPanelSB.append(
						"<div class='inventory-item-slot" + getClassRarityIdentifier(weaponInSlot.getRarity()) + "' style='"+(essenceCount<weaponInSlot.getWeaponType().getArcaneCost()?weaponStyleNoEssences:weaponStyle)+"'>"
							+ "
"+weaponInSlot.getSVGEquippedString(charactersInventoryToRender)+"
"
							+ "

"
						+ "
");
			} else {
				equippedPanelSB.append("

");
			}
			weaponInSlot = charactersInventoryToRender.getMainWeapon(2);
			if (weaponInSlot != null) {
				equippedPanelSB.append(
						"<div class='inventory-item-slot" + getClassRarityIdentifier(weaponInSlot.getRarity()) + "' style='"+(essenceCount<weaponInSlot.getWeaponType().getArcaneCost()?weaponStyleNoEssences:weaponStyle)+"'>"
							+ "
"+weaponInSlot.getSVGEquippedString(charactersInventoryToRender)+"
"
							+ "

"
						+ "
");

			} else if (charactersInventoryToRender.getArmRows()==2) {
				equippedPanelSB.append("

");

			} else {
				equippedPanelSB.append("

");
			}
		}

		// Offhand weapon:
		weaponInSlot = charactersInventoryToRender.getOffhandWeapon(0);
		if (weaponInSlot != null) {
			equippedPanelSB.append("<div class='inventory-item-slot" + getClassRarityIdentifier(weaponInSlot.getRarity()) + "' style='"+(essenceCount<weaponInSlot.getWeaponType().getArcaneCost()?weaponStyleNoEssences:weaponStyle)+"'>"
						+ "
"+weaponInSlot.getSVGEquippedString(charactersInventoryToRender)+"
"
						+ "

"
					+ "
");
		} else if (charactersInventoryToRender.getMainWeapon(0) != null && charactersInventoryToRender.getMainWeapon(0).getWeaponType().isTwoHanded()) {
			equippedPanelSB.append("

");

		} else {
			equippedPanelSB.append("

");
		}
		// Multiple arms:
		if(charactersInventoryToRender.getArmRows()>1) {
			weaponInSlot = charactersInventoryToRender.getOffhandWeapon(1);
			if (weaponInSlot != null) {
				equippedPanelSB.append("<div class='inventory-item-slot" + getClassRarityIdentifier(weaponInSlot.getRarity()) + "' style='"+(essenceCount<weaponInSlot.getWeaponType().getArcaneCost()?weaponStyleNoEssences:weaponStyle)+"'>"
							+ "
"+weaponInSlot.getSVGEquippedString(charactersInventoryToRender)+"
"
							+ "

"
						+ "
");
			} else if (charactersInventoryToRender.getMainWeapon(1) != null && charactersInventoryToRender.getMainWeapon(1).getWeaponType().isTwoHanded()) {
				equippedPanelSB.append("

");

			} else {
				equippedPanelSB.append("

");
			}
			weaponInSlot = charactersInventoryToRender.getOffhandWeapon(2);
			if (weaponInSlot != null) {
				equippedPanelSB.append("<div class='inventory-item-slot" + getClassRarityIdentifier(weaponInSlot.getRarity()) + "' style='"+(essenceCount<weaponInSlot.getWeaponType().getArcaneCost()?weaponStyleNoEssences:weaponStyle)+"'>"
							+ "
"+weaponInSlot.getSVGEquippedString(charactersInventoryToRender)+"
"
							+ "

"
						+ "
");
			} else if (charactersInventoryToRender.getArmRows()==2 || (charactersInventoryToRender.getMainWeapon(2) != null && charactersInventoryToRender.getMainWeapon(2).getWeaponType().isTwoHanded())) {
				equippedPanelSB.append("

");

			} else {
				equippedPanelSB.append("

");
			}
		}

		//piercingSlots
		for (InventorySlot invSlot : piercingSlots) {

			AbstractClothing clothing = charactersInventoryToRender.getClothingInSlot(invSlot);

			if(!charactersInventoryToRender.isPlayer() && concealedSlots.keySet().contains(invSlot)) {
				equippedPanelSB.append("
"
						+ "
"+SVGImages.SVG_IMAGE_PROVIDER.getConcealedIcon()+"
"
					+ "
");

			} else {
				if (clothing != null) {
					// add to content:
					equippedPanelSB.append(
							// If slot is sealed:
							"
"

								// Picture:
								+ "
"+clothing.getSVGEquippedString(charactersInventoryToRender)+"
"

								// If clothing is displaced:
								+ (!clothing.getDisplacedList().isEmpty() ? "
" + SVGImages.SVG_IMAGE_PROVIDER.getDisplacedIcon() + "
" : "")
								// If clothing is cummed in:
								+ (clothing.isDirty() ? "
" + SVGImages.SVG_IMAGE_PROVIDER.getCummedInIcon() + "
" : "")
								// If clothing is too masculine:
								+ (clothing.getClothingType().getFemininityMaximum() < charactersInventoryToRender.getFemininityValue() ? "
" + SVGImages.SVG_IMAGE_PROVIDER.getMasculineWarningIcon() + "
" : "")
								// If clothing is too feminine:
								+ (clothing.getClothingType().getFemininityMinimum() > charactersInventoryToRender.getFemininityValue() ? "
" + SVGImages.SVG_IMAGE_PROVIDER.getFeminineWarningIcon() + "
" : "")

								+ "
" + "
" + "
");
				} else {
					// add to content:
					if (blockedSlots.contains(invSlot)) {
						equippedPanelSB.append("
" + "
");

					} else {
						boolean bypassesPiercing = !charactersInventoryToRender.getBody().getBodyMaterial().isRequiresPiercing();

						switch(invSlot){
							case PIERCING_VAGINA:
								if(!charactersInventoryToRender.hasVagina() || (!bypassesPiercing && !charactersInventoryToRender.isPiercedVagina())) {
									equippedPanelSB.append("
" + "
");
								} else {
									equippedPanelSB.append("

");
								}
								break;
							case PIERCING_EAR:
								if(!bypassesPiercing && !charactersInventoryToRender.isPiercedEar()) {
									equippedPanelSB.append("
" + "
");
								} else {
									equippedPanelSB.append("

");
								}
								break;
							case PIERCING_LIP:
								if(!bypassesPiercing && !charactersInventoryToRender.isPiercedLip()) {
									equippedPanelSB.append("
" + "
");
								} else {
									equippedPanelSB.append("

");
								}
								break;
							case PIERCING_NIPPLE:
								if(!bypassesPiercing && !charactersInventoryToRender.isPiercedNipple()) {
									equippedPanelSB.append("
" + "
");
								} else {
									equippedPanelSB.append("

");
								}
								break;
							case PIERCING_NOSE:
								if(!bypassesPiercing && !charactersInventoryToRender.isPiercedNose()) {
									equippedPanelSB.append("
" + "
");
								} else {
									equippedPanelSB.append("

");
								}
								break;
							case PIERCING_PENIS:
								if(!charactersInventoryToRender.hasPenis() || (!bypassesPiercing && !charactersInventoryToRender.isPiercedPenis())) {
									equippedPanelSB.append("
" + "
");
								} else {
									equippedPanelSB.append("

");
								}
								break;
							case PIERCING_STOMACH:
								if(!bypassesPiercing && !charactersInventoryToRender.isPiercedNavel()) {
									equippedPanelSB.append("
" + "
");
								} else {
									equippedPanelSB.append("

");
								}
								break;
							case PIERCING_TONGUE:
								if(!bypassesPiercing && !charactersInventoryToRender.isPiercedTongue()) {
									equippedPanelSB.append("
" + "
");
								} else {
									equippedPanelSB.append("

");
								}
								break;
							default:
								break;
						}
					}
				}
			}
		}
		equippedPanelSB.append("
");

		equippedPanelSB.append("
");

		for (InventorySlot invSlot : secondaryInventorySlots) {
			appendEquippedClothingSlot(charactersInventoryToRender, invSlot, blockedSlots, concealedSlots, true);
		}

		equippedPanelSB.append("
");
		if(charactersInventoryToRender.isPlayer()) {
			equippedPanelSB.append("
"
										+(this.isRenderingTattoosLeft()
											?SVGImages.SVG_IMAGE_PROVIDER.getTattooSwitchTattoo()
											:SVGImages.SVG_IMAGE_PROVIDER.getTattooSwitchClothing())
									+"
"
									+ "

");

		} else {
			equippedPanelSB.append("
"
										+(this.isRenderingTattoosRight()
												?SVGImages.SVG_IMAGE_PROVIDER.getTattooSwitchTattoo()
												:SVGImages.SVG_IMAGE_PROVIDER.getTattooSwitchClothing())
									+"
"
									+ "

");
		}
		equippedPanelSB.append("
");

		equippedPanelSB.append("
");

		return equippedPanelSB.toString();
	}

	private void appendEquippedClothingSlot(GameCharacter charactersInventoryToRender, InventorySlot invSlot, Set<InventorySlot> blockedSlots, Map<InventorySlot, List<AbstractClothing>> concealedSlots, boolean isSecondary) {
		String inventorySlotId = "inventory-item-slot";
		if(isSecondary) {
			inventorySlotId = "inventory-item-slot secondary";
		}

		if(!charactersInventoryToRender.isPlayer() && concealedSlots.keySet().contains(invSlot)) {
			equippedPanelSB.append("
"
					+ "
"+SVGImages.SVG_IMAGE_PROVIDER.getConcealedIcon()+"
"
				+ "
");

		} else {
			if((charactersInventoryToRender.isPlayer() && !this.isRenderingTattoosLeft()) || (!charactersInventoryToRender.isPlayer() && !this.isRenderingTattoosRight())
					&& !invSlot.isJewellery()) {
				AbstractClothing clothing = charactersInventoryToRender.getClothingInSlot(invSlot);

				BodyPartClothingBlock block = invSlot.getBodyPartClothingBlock(charactersInventoryToRender);
				if (clothing != null) {
					// add to content:
					equippedPanelSB.append(
							// If slot is sealed:
							"
"

								+ (block!=null?"
" + Subspecies.getMainSubspeciesOfRace(block.getRace()).getSVGStringDesaturated(charactersInventoryToRender) + "
":"")

								// Picture:
								+ "
"+clothing.getSVGEquippedString(charactersInventoryToRender)+"
"

//								+ (charactersInventoryToRender.getScarInSlot(invSlot)!=null ? "
" + SVGImages.SVG_IMAGE_PROVIDER.getScarIcon() + "
" : "")
								// If clothing is displaced:
								+ (!clothing.getDisplacedList().isEmpty() ? "
" + SVGImages.SVG_IMAGE_PROVIDER.getDisplacedIcon() + "
" : "")
								// If clothing is cummed in:
								+ (clothing.isDirty() ? "
" + SVGImages.SVG_IMAGE_PROVIDER.getCummedInIcon() + "
" : "")
								// If clothing is too masculine:
								+ (clothing.getClothingType().getFemininityMaximum() < charactersInventoryToRender.getFemininityValue() ? "
" + SVGImages.SVG_IMAGE_PROVIDER.getMasculineWarningIcon() + "
" : "")
								// If clothing is too feminine:
								+ (clothing.getClothingType().getFemininityMinimum() > charactersInventoryToRender.getFemininityValue() ? "
" + SVGImages.SVG_IMAGE_PROVIDER.getFeminineWarningIcon() + "
" : "")

								+ "
" + "
"
							+ "
");

				} else {
					// add to content:
					if (blockedSlots.contains(invSlot)) {
						equippedPanelSB.append("
"
													+ (charactersInventoryToRender.isDirtySlot(invSlot) ? "
" + SVGImages.SVG_IMAGE_PROVIDER.getCummedInIcon() + "
" : "")
													+ "

"
												+ "
");

					} else if (block != null) {
						equippedPanelSB.append(
								"
"
									+ (charactersInventoryToRender.isDirtySlot(invSlot) ? "
" + SVGImages.SVG_IMAGE_PROVIDER.getCummedInIcon() + "
" : "")
									+ "

"
									+ "
" + Subspecies.getMainSubspeciesOfRace(block.getRace()).getSVGStringDesaturated(charactersInventoryToRender) + "
"
								+ "
");

					} else {
						boolean disabled = false;
						switch(invSlot){
							case HORNS:
								disabled = charactersInventoryToRender.getHornType().equals(HornType.NONE);
								break;
							case PENIS:
								disabled = !charactersInventoryToRender.hasPenisIgnoreDildo();
								break;
							case TAIL:
								disabled = charactersInventoryToRender.getTailType()==TailType.NONE;
								break;
							case VAGINA:
								disabled = !charactersInventoryToRender.hasVagina();
								break;
							case WINGS:
								disabled = charactersInventoryToRender.getWingType()==WingType.NONE;
								break;
							default:
								break;
						}

						equippedPanelSB.append("
"
								+ (charactersInventoryToRender.isDirtySlot(invSlot) ? "
" + SVGImages.SVG_IMAGE_PROVIDER.getCummedInIcon() + "
" : "")
								+ "
");
					}
				}

			} else {
				// Tattoos:

				Tattoo tattoo = charactersInventoryToRender.getTattooInSlot(invSlot);

				if (tattoo != null) {
					// add to content:
					equippedPanelSB.append(
							// If slot is sealed:
							"
"
								// Picture:
								+ "
"+tattoo.getSVGImage(charactersInventoryToRender)+"
"

								// If scarred:
								+ (charactersInventoryToRender.getScarInSlot(invSlot)!=null ? "
" + SVGImages.SVG_IMAGE_PROVIDER.getScarIcon() + "
" : "")

								+ "
" + "
"
							+ "
");

				} else {
					// add to content:
					if (blockedSlots.contains(invSlot)) {
						equippedPanelSB.append("
"
													+ (charactersInventoryToRender.getScarInSlot(invSlot)!=null ? "
" + SVGImages.SVG_IMAGE_PROVIDER.getScarIcon() + "
" : "")
													+ "

"
												+ "
");

					} else {
						boolean disabled = false;
						switch(invSlot){
							case HORNS:
								disabled = charactersInventoryToRender.getHornType().equals(HornType.NONE);
								break;
							case PENIS:
								disabled = !charactersInventoryToRender.hasPenisIgnoreDildo();
								break;
							case TAIL:
								disabled = charactersInventoryToRender.getTailType()==TailType.NONE;
								break;
							case VAGINA:
								disabled = !charactersInventoryToRender.hasVagina();
								break;
							case WINGS:
								disabled = charactersInventoryToRender.getWingType()==WingType.NONE;
								break;
							default:
								break;
						}

						equippedPanelSB.append("
"
								+ (charactersInventoryToRender.getScarInSlot(invSlot)!=null ? "
" + SVGImages.SVG_IMAGE_PROVIDER.getScarIcon() + "
" : "")
								+ "
");
					}
				}

			}
		}
	}

	private String getInventoryDiv(GameCharacter charactersInventoryToRender, boolean buyback) {

		inventorySB.setLength(0);

		String idModifier = charactersInventoryToRender==null?"FLOOR_":(charactersInventoryToRender.isPlayer()?"PLAYER_":"NPC_"+charactersInventoryToRender.getId()+"_");

		inventorySB.append("
");

		if(charactersInventoryToRender != null) {
			inventorySB.append(
					"
"
					+ ""
						+(charactersInventoryToRender.isPlayer()
							?"Your Inventory | Page "+(pageLeft+1)+""
							:(UtilText.parse(charactersInventoryToRender, "[npc.NamePos]"))+" Inventory | "+(buyback?"[style.colourCurrency(Buyback)]":"Page "+(pageRight+1))+"")
					+"
");

		} else {
			inventorySB.append(
					"
"
						+(InventoryDialogue.getNPCInventoryInteraction() ==  InventoryInteraction.CHARACTER_CREATION
								?"Your wardrobe"
								:"In this Area")
						+" | Page "+(pageRight+1)+""
					+"
");
		}

		// Buttons:
		int totalUniques = 0;
		String pageIdMod = "";
		int currentPage = 0;
		boolean renderQuestTab = true;
		boolean hasQuestItems = false;
		if(charactersInventoryToRender == null) {
			totalUniques = Main.game.getPlayerCell().getInventory().getUniqueItemCount() - Main.game.getPlayerCell().getInventory().getUniqueQuestItemCount()
					+ Main.game.getPlayerCell().getInventory().getUniqueClothingCount() - Main.game.getPlayerCell().getInventory().getUniqueQuestClothingCount()
					+ Main.game.getPlayerCell().getInventory().getUniqueWeaponCount() - Main.game.getPlayerCell().getInventory().getUniqueQuestWeaponCount();
			pageIdMod = "INV_PAGE_RIGHT_";
			currentPage = pageRight;
		} else {
//			renderQuestTab = charactersInventoryToRender.isPlayer();
			hasQuestItems = charactersInventoryToRender.isCarryingQuestItems();
			totalUniques = charactersInventoryToRender.getUniqueItemCount() - charactersInventoryToRender.getUniqueQuestItemCount()
					+ charactersInventoryToRender.getUniqueClothingCount() - charactersInventoryToRender.getUniqueQuestClothingCount()
					+ charactersInventoryToRender.getUniqueWeaponCount() - charactersInventoryToRender.getUniqueQuestWeaponCount();
			pageIdMod = (charactersInventoryToRender.isPlayer()?"INV_PAGE_LEFT_":"INV_PAGE_RIGHT_");
			currentPage = (charactersInventoryToRender.isPlayer()?pageLeft:pageRight);
		}

		inventorySB.append(
				"
"
					+ "
"
							+ "
"+SVGImages.SVG_IMAGE_PROVIDER.getInventoryIcon()+"
"
							+ "
"+(currentPage==0?SVGImages.SVG_IMAGE_PROVIDER.getCounterOne():SVGImages.SVG_IMAGE_PROVIDER.getCounterOneDisabled())+"
"
							+ (!buyback
									?"

"
									:"

")
					+ "
"
					+ "
"
							+ "
"+(totalUniques>1*ITEMS_PER_PAGE?SVGImages.SVG_IMAGE_PROVIDER.getInventoryIcon():SVGImages.SVG_IMAGE_PROVIDER.getInventoryIconDisabled())+"
"
							+ "
"+(currentPage==1?SVGImages.SVG_IMAGE_PROVIDER.getCounterTwo():SVGImages.SVG_IMAGE_PROVIDER.getCounterTwoDisabled())+"
"
							+ (totalUniques>1*ITEMS_PER_PAGE && !buyback
									?"

"
									:"

")
					+ "
"
					+ "
"
							+ "
"+(totalUniques>2*ITEMS_PER_PAGE?SVGImages.SVG_IMAGE_PROVIDER.getInventoryIcon():SVGImages.SVG_IMAGE_PROVIDER.getInventoryIconDisabled())+"
"
							+ "
"+(currentPage==2?SVGImages.SVG_IMAGE_PROVIDER.getCounterThree():SVGImages.SVG_IMAGE_PROVIDER.getCounterThreeDisabled())+"
"
							+ (totalUniques>2*ITEMS_PER_PAGE && !buyback
									?"

"
									:"

")
					+ "
"
					+ "
"
							+ "
"+(totalUniques>3*ITEMS_PER_PAGE?SVGImages.SVG_IMAGE_PROVIDER.getInventoryIcon():SVGImages.SVG_IMAGE_PROVIDER.getInventoryIconDisabled())+"
"
							+ "
"+(currentPage==3?SVGImages.SVG_IMAGE_PROVIDER.getCounterFour():SVGImages.SVG_IMAGE_PROVIDER.getCounterFourDisabled())+"
"
							+ (totalUniques>3*ITEMS_PER_PAGE && !buyback
									?"

"
									:"

")
					+ "
"
					+ "
"
						+ "
"+(totalUniques>4*ITEMS_PER_PAGE?SVGImages.SVG_IMAGE_PROVIDER.getInventoryIcon():SVGImages.SVG_IMAGE_PROVIDER.getInventoryIconDisabled())+"
"
						+ "
"+(currentPage==4?SVGImages.SVG_IMAGE_PROVIDER.getCounterFive():SVGImages.SVG_IMAGE_PROVIDER.getCounterFiveDisabled())+"
"
						+ (totalUniques>4*ITEMS_PER_PAGE && !buyback
								?"

"
								:"

")
					+ "
"
					+ (renderQuestTab
							?"
"
								+ "
"+(hasQuestItems?SVGImages.SVG_IMAGE_PROVIDER.getQuestInventoryIcon():SVGImages.SVG_IMAGE_PROVIDER.getQuestInventoryIconDisabled())+"
"
								+ (hasQuestItems && !buyback
									?"

"
									:"

")
							+ "
"
							:"")
				+ "
");

		inventorySB.append("
");
		if(buyback) {
			for (int i = Main.game.getPlayer().getBuybackStack().size() - 1; i >= 0; i--) {

				ShopTransaction itemBuyback = Main.game.getPlayer().getBuybackStack().get(i);

				if (itemBuyback != null) {
					// Clothing:
					if (itemBuyback.getAbstractItemSold() instanceof AbstractClothing) {
						inventorySB.append(getBuybackItemPanel(itemBuyback, "CLOTHING_" + i));

					// Weapon:
					} else if (itemBuyback.getAbstractItemSold() instanceof AbstractWeapon) {
						inventorySB.append(getBuybackItemPanel(itemBuyback, "WEAPON_" + i));

					// Item:
					} else {
						inventorySB.append(getBuybackItemPanel(itemBuyback, "ITEM_" + i));
					}
				}
			}

			// Fill space:
			for (int i = 24; i > Main.game.getPlayer().getBuybackStack().size(); i--) {
				inventorySB.append("

");
			}

		} else {
			inventorySB.append(getInventoryIconsForPage(currentPage, charactersInventoryToRender, idModifier));
		}
		inventorySB.append("
");

		String style = "box-sizing:border-box; float:left; background-color:"+Colour.BACKGROUND_ALT.toWebHexString()+"; border-radius:5px; padding:0 2px 0 2px; margin:0 1%; text-align:center;";
		String buttonStyle = "width:5.25%; border:0; text-align:center; padding:0; margin:0 0.75%; float:left;";
		boolean transferDisabled = InventoryDialogue.getNPCInventoryInteraction()!=InventoryInteraction.FULL_MANAGEMENT;
		if(charactersInventoryToRender!=null) {
			// 85% is the encompassing width
			if(charactersInventoryToRender.isPlayer()) {
				inventorySB.append(
						"
"+ UtilText.formatAsEssences(charactersInventoryToRender.getEssenceCount(TFEssence.ARCANE), "b", true) +"
"
						+ "
"+ UtilText.formatAsMoney(charactersInventoryToRender.getMoney(), "b") +"
"
						+ "
[style."+(transferDisabled?"colourDisabled":"colourMinorGood")+"(>)]
"
						+ "
[style."+(transferDisabled?"colourDisabled":"colourGood")+"(>)]
"
						+ "
[style."+(transferDisabled?"colourDisabled":"colourExcellent")+"(>)]
");
			} else {

				inventorySB.append(
						"
[style."+(transferDisabled?"colourDisabled":"colourExcellent")+"(<)]
"
						+ "
[style."+(transferDisabled?"colourDisabled":"colourGood")+"(<)]
"
						+ "
[style."+(transferDisabled?"colourDisabled":"colourMinorGood")+"(<)]
"
						+ "
"+ (transferDisabled?UtilText.formatAsMoney("[style.colourUnknown(Unknown)]", "b"):UtilText.formatAsMoney(charactersInventoryToRender.getMoney(), "b")) +"
"
						+ "
"+ UtilText.formatAsEssences(charactersInventoryToRender.getEssenceCount(TFEssence.ARCANE), "b", true) +"
");
			}

		} else {
			inventorySB.append(
					"
[style."+(transferDisabled?"colourDisabled":"colourExcellent")+"(<)]
"
					+ "
[style."+(transferDisabled?"colourDisabled":"colourGood")+"(<)]
"
					+ "
[style."+(transferDisabled?"colourDisabled":"colourMinorGood")+"(<)]
"
					+ "
"+ UtilText.formatAsMoney(Main.game.getPlayerCell().getInventory().getMoney(), "b") +"
");
		}

		inventorySB.append("
");

//		inventorySB.append("");

		return inventorySB.toString();
	}

	public String getGiftDiv(GameCharacter receiver) {
		inventorySB.setLength(0);

		Map<AbstractCoreItem, Integer> giftsAvailable = new HashMap<>();
		for(Entry<AbstractItem, Integer> entry : Main.game.getPlayer().getAllItemsInInventory().entrySet()) {
			if(receiver.getGiftReaction(entry.getKey(), false) != null) {
				giftsAvailable.put(entry.getKey(), entry.getValue());
			}
		}
		for(Entry<AbstractClothing, Integer> entry : Main.game.getPlayer().getAllClothingInInventory().entrySet()) {
			if(receiver.getGiftReaction(entry.getKey(), false) != null) {
				giftsAvailable.put(entry.getKey(), entry.getValue());
			}
		}
		for(Entry<AbstractWeapon, Integer> entry : Main.game.getPlayer().getAllWeaponsInInventory().entrySet()) {
			if(receiver.getGiftReaction(entry.getKey(), false) != null) {
				giftsAvailable.put(entry.getKey(), entry.getValue());
			}
		}

		if(giftsAvailable.isEmpty()) {
			inventorySB.append("
"
					+ "
"
						+"No Suitable Gifts In Inventory"
					+"
"
					+ "
");
		} else {
			inventorySB.append("
"
					+ "
"
						+"Available Gifts"
					+"
"
					+ "
");

			appendDivsForGiftsToInventory(inventorySB, giftsAvailable, "GIFT_");

			for (int i = 8-giftsAvailable.size(); i > 0; i--) {
				inventorySB.append("

");
			}

			inventorySB.append("
"
					+ "
");
		}

		return inventorySB.toString();
	}

	private static StringBuilder pageSB = new StringBuilder();
	private static String getInventoryIconsForPage(int page, GameCharacter charactersInventoryToRender, String idModifier) {
		int uniqueItemCount = 0;
		pageSB.setLength(0);

		if(charactersInventoryToRender == null) {
			for(Entry<AbstractWeapon, Integer> entry : Main.game.getPlayerCell().getInventory().getAllWeaponsInInventory().entrySet()) {
				if(uniqueItemCount >= page*ITEMS_PER_PAGE && uniqueItemCount < (page+1)*ITEMS_PER_PAGE) {
					pageSB.append(getInventoryItemDiv(Main.game.getPlayerCell().getInventory(), entry.getKey(), entry.getValue(), idModifier+"WEAPON_"));
				}
				uniqueItemCount++;
			}

			for(Entry<AbstractClothing, Integer> entry : Main.game.getPlayerCell().getInventory().getAllClothingInInventory().entrySet()) {
				if(uniqueItemCount >= page*ITEMS_PER_PAGE && uniqueItemCount < (page+1)*ITEMS_PER_PAGE) {
					pageSB.append(getInventoryItemDiv(Main.game.getPlayerCell().getInventory(), entry.getKey(), entry.getValue(), idModifier+"CLOTHING_"));
				}
				uniqueItemCount++;
			}

			for(Entry<AbstractItem, Integer> entry : Main.game.getPlayerCell().getInventory().getAllItemsInInventory().entrySet()) {
				if(uniqueItemCount >= page*ITEMS_PER_PAGE && uniqueItemCount < (page+1)*ITEMS_PER_PAGE) {
					pageSB.append(getInventoryItemDiv(Main.game.getPlayerCell().getInventory(), entry.getKey(), entry.getValue(), idModifier+"ITEM_"));
				}
				uniqueItemCount++;
			}

		} else {
			if(page==5) { // Quest:
				for(Entry<AbstractWeapon, Integer> entry : charactersInventoryToRender.getAllWeaponsInInventory().entrySet()) {
					if(entry.getKey().getRarity()==Rarity.QUEST && charactersInventoryToRender.isPlayer()) {
						if(uniqueItemCount < ITEMS_PER_PAGE) {
							pageSB.append(getInventoryItemDiv(charactersInventoryToRender, entry.getKey(), entry.getValue(), idModifier+"WEAPON_"));
						}
						uniqueItemCount++;
					}
				}

				for(Entry<AbstractClothing, Integer> entry : charactersInventoryToRender.getAllClothingInInventory().entrySet()) {
					if(entry.getKey().getRarity()==Rarity.QUEST && charactersInventoryToRender.isPlayer()) {
						if(uniqueItemCount < ITEMS_PER_PAGE) {
							pageSB.append(getInventoryItemDiv(charactersInventoryToRender, entry.getKey(), entry.getValue(), idModifier+"CLOTHING_"));
						}
						uniqueItemCount++;
					}
				}

				for(Entry<AbstractItem, Integer> entry : charactersInventoryToRender.getAllItemsInInventory().entrySet()) {
					if(entry.getKey().getRarity()==Rarity.QUEST && charactersInventoryToRender.isPlayer()) {
						if(uniqueItemCount < ITEMS_PER_PAGE) {
							pageSB.append(getInventoryItemDiv(charactersInventoryToRender, entry.getKey(), entry.getValue(), idModifier+"ITEM_"));
						}
						uniqueItemCount++;
					}
				}

			} else {
				for(Entry<AbstractWeapon, Integer> entry : charactersInventoryToRender.getAllWeaponsInInventory().entrySet()) {
					if(entry.getKey().getRarity()!=Rarity.QUEST || !charactersInventoryToRender.isPlayer()) {
						if(uniqueItemCount >= page*ITEMS_PER_PAGE && uniqueItemCount < (page+1)*ITEMS_PER_PAGE) {
							pageSB.append(getInventoryItemDiv(charactersInventoryToRender, entry.getKey(), entry.getValue(), idModifier+"WEAPON_"));
						}
						uniqueItemCount++;
					}
				}

				for(Entry<AbstractClothing, Integer> entry : charactersInventoryToRender.getAllClothingInInventory().entrySet()) {
					if(entry.getKey().getRarity()!=Rarity.QUEST || !charactersInventoryToRender.isPlayer()) {
						if(uniqueItemCount >= page*ITEMS_PER_PAGE && uniqueItemCount < (page+1)*ITEMS_PER_PAGE) {
							pageSB.append(getInventoryItemDiv(charactersInventoryToRender, entry.getKey(), entry.getValue(), idModifier+"CLOTHING_"));
						}
						uniqueItemCount++;
					}
				}

				for(Entry<AbstractItem, Integer> entry : charactersInventoryToRender.getAllItemsInInventory().entrySet()) {
					if(entry.getKey().getRarity()!=Rarity.QUEST || !charactersInventoryToRender.isPlayer()) {
						if(uniqueItemCount >= page*ITEMS_PER_PAGE && uniqueItemCount < (page+1)*ITEMS_PER_PAGE) {
							pageSB.append(getInventoryItemDiv(charactersInventoryToRender, entry.getKey(), entry.getValue(), idModifier+"ITEM_"));
						}
						uniqueItemCount++;
					}
				}
			}
		}

		// Fill space:
		for (int i = uniqueItemCount - (page==5?0:page)*ITEMS_PER_PAGE ; i < ITEMS_PER_PAGE; i++) {
			pageSB.append("

");
		}

		return pageSB.toString();
	}

	private static StringBuilder itemSB = new StringBuilder();
	private static String getInventoryItemDiv(GameCharacter charactersInventoryToRender, AbstractCoreItem item, int count, String idPrefix) {
		itemSB.setLength(0);
		boolean known = true;
		if(item instanceof AbstractClothing) {
			known = ((AbstractClothing)item).isEnchantmentKnown();
		}
		itemSB.append("
"
						+ "
"+item.getSVGString()+"
");

		if (item instanceof AbstractClothing && ((AbstractClothing)item).isDirty()) {
			itemSB.append("
" + SVGImages.SVG_IMAGE_PROVIDER.getCummedInIcon() + "
");
		}
		String overlay = "<div class='overlay";
		String last_layer = "";

		if (charactersInventoryToRender!=null && InventoryDialogue.getNPCInventoryInteraction() == InventoryInteraction.TRADING) {

			NPC npc = InventoryDialogue.getInventoryNPC();
			if(charactersInventoryToRender.isPlayer()) {
				boolean isAbleToBeSold = true;

				if(item instanceof AbstractItem) {
					AbstractItem abItem = (AbstractItem)item;
					isAbleToBeSold = abItem.getItemType().isAbleToBeSold();
				} else if(item instanceof AbstractWeapon) {
					AbstractWeapon abItem = (AbstractWeapon)item;
					isAbleToBeSold = abItem.getWeaponType().isAbleToBeSold();
				} else if(item instanceof AbstractClothing) {
					AbstractClothing abItem = (AbstractClothing)item;
					isAbleToBeSold = abItem.getClothingType().isAbleToBeSold();
				}

				if (npc.willBuy(item) && isAbleToBeSold) {
					last_layer = getItemPriceDiv(item.getPrice(npc.getBuyModifier()));
				} else {
					overlay += " dark";
				}
			} else {
				last_layer = getItemPriceDiv(item.getPrice(npc.getSellModifier()));
			}
		} else {
			boolean nonPlayerInv = charactersInventoryToRender!=null && !charactersInventoryToRender.isPlayer();
			boolean isTraderInv = nonPlayerInv && ((NPC) charactersInventoryToRender).isTrader();

			if (item instanceof AbstractItem) {
				AbstractItem abItem = (AbstractItem)item;
				if (nonPlayerInv
						|| (Main.game.isInSex() && (isTraderInv || !abItem.isAbleToBeUsedInSex()))
						|| (Main.game.isInCombat()
								&& (!abItem.isAbleToBeUsedInCombat() || Main.game.getPlayer().isStunned() || Combat.isCombatantDefeated(Main.game.getPlayer())))) {
					overlay += " disabled";
				}

			} else if (item instanceof AbstractClothing) {
				AbstractClothing clothing = (AbstractClothing)item;
				if (Main.game.isInCombat() || (Main.game.isInSex() && (isTraderInv || !clothing.getClothingType().isAbleToBeEquippedDuringSex(clothing.getClothingType().getEquipSlots().get(0))))) {
					overlay += " disabled";
				}

			} else if (item instanceof AbstractWeapon && (Main.game.isInCombat() || Main.game.isInSex())) {
				overlay += " disabled";
			}
		}
		itemSB.append(overlay+"' id='" + idPrefix + item.hashCode() + "'>"+getItemCountDiv(count)+last_layer+"

");
		return itemSB.toString();
	}

	private static String getInventoryItemDiv(CharacterInventory inventory, AbstractCoreItem item, int count, String idPrefix) {
		itemSB.setLength(0);
		boolean known = true;
		if(item instanceof AbstractClothing) {
			known = ((AbstractClothing)item).isEnchantmentKnown();
		}
		itemSB.append("
"
						+ "
"+item.getSVGString()+"
");

		if (item instanceof AbstractClothing && ((AbstractClothing)item).isDirty()) {
			itemSB.append("
" + SVGImages.SVG_IMAGE_PROVIDER.getCummedInIcon() + "
");
		}
		String overlay = "<div class='overlay";
		String last_layer = "";

		if (item instanceof AbstractItem) {
			AbstractItem abItem = (AbstractItem)item;
			if ((Main.game.isInSex() && !abItem.isAbleToBeUsedInSex())
					|| (Main.game.isInCombat() && (!abItem.isAbleToBeUsedInCombat() || Main.game.getPlayer().isStunned() || Combat.isCombatantDefeated(Main.game.getPlayer())))) {
				overlay += " disabled";
			}

		} else if (item instanceof AbstractClothing) {
			AbstractClothing clothing = (AbstractClothing)item;
			if (Main.game.isInCombat() || (Main.game.isInSex() && !clothing.getClothingType().isAbleToBeEquippedDuringSex(clothing.getClothingType().getEquipSlots().get(0)))) {
				overlay += " disabled";
			}

		} else if (item instanceof AbstractWeapon && (Main.game.isInCombat() || Main.game.isInSex())) {
			overlay += " disabled";
		}

		itemSB.append(overlay+"' id='" + idPrefix + item.hashCode() + "'>"+getItemCountDiv(count)+last_layer+"

");
		return itemSB.toString();
	}

	private static void appendDivsForGiftsToInventory(StringBuilder stringBuilder, Map<AbstractCoreItem, Integer> map, String idPrefix) {
		for (Entry<? extends AbstractCoreItem, Integer> entry : map.entrySet()) {
			boolean known = true;
			if(entry.getKey() instanceof AbstractClothing) {
				known = ((AbstractClothing)entry.getKey()).isEnchantmentKnown();
			}
			stringBuilder.append(
					"
"
						+ "
"
							+entry.getKey().getSVGString()
						+"
"
						+ "
"
							+ getItemCountDiv(true, entry.getValue())
						+"
"
					+ "
");
		}
	}

	private static String getItemCountDiv(int amount) {
		return getItemCountDiv(false, amount);
	}

	private static String getItemCountDiv(boolean countSingles, int amount) {
		if (amount > 1 || countSingles) {
			return "
x" + amount + "
";
		}
		return "";
	}

	private static String getItemPriceDiv(int price) {
		return "
"
				+ UtilText.formatAsItemPrice(price)
			+ "
";
	}

	private static String getBuybackItemPanel(ShopTransaction itemBuyback, String id) {
		return "
"
					+ "
"+itemBuyback.getAbstractItemSold().getSVGString()+"
"
					+ "
"
						+ getItemCountDiv(itemBuyback.getCount())+getItemPriceDiv(itemBuyback.getPrice())
					+ "
"
				+ "
";
	}

	// DecimalFormat decimalFormatter = new DecimalFormat("#,###");
	private StringBuilder uiAttributeSB = new StringBuilder();

	private DialogueNode renderedDialogueNode = null;

	private String getDefaultAttributeColumnHeader() {
		String mainTitle = Main.game.getPlayer().getWorldLocation().getName();
		String mainTitleColour = Main.game.getPlayer().getWorldLocation().getColour().toWebHexString();

		AbstractPlaceType place = Main.game.getPlayer().getWorldLocation().getStandardPlace();

		if(Main.game.getPlayer().getLocationPlace()!=null) {
			place = Main.game.getPlayer().getLocationPlace().getPlaceType();
		}

		String placeTitle = place.getName();
		String placeColour = place.getColourString();

		if(Main.game.isInGlobalMap()) {
			mainTitle = place.getName();
			mainTitleColour = place.getColourString();

			placeTitle = place.isLand()?"Terrestrial":"Aquatic";
			placeColour = place.isLand()?Colour.SPELL_SCHOOL_EARTH.toWebHexString():Colour.SPELL_SCHOOL_WATER.toWebHexString();
		}

		return "
"
					+ "
"
						+ Util.capitaliseSentence(mainTitle)
					+ "
"
				+ "
"
				+ "
"
					+ "
"
						+ Util.capitaliseSentence(placeTitle)
					+"
"
				+ "
";
	}

	public void renderAttributesPanelLeft() {
		uiAttributeSB.setLength(0);

		uiAttributeSB.append(
				"");

		if(Main.game.isInSex()) {
			// Name box:
			uiAttributeSB.append(
				"
"
					+ "
"
						+ "
Dominant"+(Sex.getDominantParticipants(true).size()>1?"s":"")+""
								:Colour.SUBMISSIVE.toWebHexString()+";'>Submissive"+(Sex.getSubmissiveParticipants(true).size()>1?"s":"")+"")
						+"
"
					+ "
"
				+ "
"
				+ "
");

			if(Sex.isDom(Main.game.getPlayer())) {
				for(GameCharacter character : Sex.getDominantParticipants(true).keySet()) {
					uiAttributeSB.append(getCharacterPanelSexDiv(Sex.getDominantParticipants(true).size()>1, character.isPlayer()?"PLAYER_":"NPC_"+character.getId()+"_", character));
				}

			} else {
				for(GameCharacter character : Sex.getSubmissiveParticipants(true).keySet()) {
					uiAttributeSB.append(getCharacterPanelSexDiv(Sex.getSubmissiveParticipants(true).size()>1, character.isPlayer()?"PLAYER_":"NPC_"+character.getId()+"_", character));
				}
			}

			uiAttributeSB.append("
");

		} else if(Main.game.isInCombat()) {

			// Name box:
			uiAttributeSB.append(
				"
"
					+ "
"
						+ "
"
								+ "Allies"
						+"
"
					+ "
"
				+ "
"
				+ "
");

			uiAttributeSB.append(getCharacterPanelDiv(Combat.getAllies(Main.game.getPlayer()).size()>0, "PLAYER_", Main.game.getPlayer()));

			for(GameCharacter character : Combat.getAllies(Main.game.getPlayer())) {
				uiAttributeSB.append(getCharacterPanelDiv(true, "NPC_"+character.getId()+"_", character));
			}

			uiAttributeSB.append("
");

		} else {
			// Default place name box:
			uiAttributeSB.append("
"
									+ getDefaultAttributeColumnHeader()
									+"
"
							+ "
");

			uiAttributeSB.append(getCharacterPanelDiv(!Main.game.getPlayer().getCompanions().isEmpty(), "PLAYER_", Main.game.getPlayer()));

			for(GameCharacter character : Main.game.getPlayer().getCompanions()) {
				uiAttributeSB.append(getCharacterPanelDiv(true, "NPC_"+character.getId()+"_", character));
//				for(GameCharacter characterCompanion : character.getCompanions()) {
//					uiAttributeSB.append(getCharacterPanelDiv(true, "NPC_"+characterCompanion.getId()+"_", characterCompanion));
//
//				}
			}

			uiAttributeSB.append("
");
		}

		uiAttributeSB.append("
");

		Colour background = Colour.BACKGROUND_DAY;
		switch(Main.game.getCurrentDayPeriod()) {
			case CIVIL_TWILIGHT:
				background = Colour.BACKGROUND_TWILIGHT;
				break;
			case DAY:
				break;
			case ASTRONOMICAL_TWILIGHT:
			case NAUTICAL_TWILIGHT:
			case NIGHT:
				background = Colour.BACKGROUND_NIGHT;
				break;
		}

		uiAttributeSB.append("
");
		if(Main.game.getCurrentDialogueNode().getDialogueNodeType() == DialogueNodeType.INVENTORY && Main.game.isEnchantmentCapacityEnabled()) {
			int enchantmentPointsUsed = Main.game.getPlayer().getEnchantmentPointsUsedTotal();
			uiAttributeSB.append(UtilText.parse(
					"
"
						+ "
"
							+ "[style.colourEnchantment("+Util.capitaliseSentence(Attribute.ENCHANTMENT_LIMIT.getName())+")]: "
							+ (enchantmentPointsUsed>Main.game.getPlayer().getAttributeValue(Attribute.ENCHANTMENT_LIMIT)
									?"[style.colourBad("
									:(enchantmentPointsUsed==Main.game.getPlayer().getAttributeValue(Attribute.ENCHANTMENT_LIMIT)
											?"[style.colourGood("
											:"[style.colourMinorGood("))
							+ enchantmentPointsUsed + ")]" + "/" + Math.round(Main.game.getPlayer().getAttributeValue(Attribute.ENCHANTMENT_LIMIT))
						+ "
"
					+"
"));

		} else {
			uiAttributeSB.append("
"
									+ "
"
										+"
"
											+SVGImages.SVG_IMAGE_PROVIDER.getCalendarIcon()
										+ "
"
										+ (Main.getProperties().hasValue(PropertyValue.calendarDisplay)
											? Main.game.getDisplayDate(false)
											:"Day "+Main.game.getDayNumber())
									+ "
"
								+"
");

			uiAttributeSB.append("
"
									+ "
");

			if(Main.game.getPlayer().getClothingInSlot(InventorySlot.WRIST)!=null
					&& (Main.game.getPlayer().getClothingInSlot(InventorySlot.WRIST).getClothingType().equals(ClothingType.WRIST_WOMENS_WATCH)
							|| Main.game.getPlayer().getClothingInSlot(InventorySlot.WRIST).getClothingType().equals(ClothingType.WRIST_MENS_WATCH))) {
				uiAttributeSB.append(
								"
"
										+Main.game.getPlayer().getClothingInSlot(InventorySlot.WRIST).getSVGEquippedString(Main.game.getPlayer())
								+ "
");

			} else {
				uiAttributeSB.append(
						"
"
								+SVGImages.SVG_IMAGE_PROVIDER.getJournalIcon()
						+ "
");
			}

			uiAttributeSB.append(Units.time(Main.game.getDateNow())
							+ "
"
						+ "
");
		}
		uiAttributeSB.append("
");

		if(Main.game.getCurrentDialogueNode().getDialogueNodeType() == DialogueNodeType.INVENTORY || Main.game.isInCombat() || Main.game.isInSex()) {
			uiAttributeSB.append(getInventoryEquippedPanel(Main.game.getPlayer()));

		} else {
			uiAttributeSB.append("
" + renderedHTMLMap() + "
");
		}

		uiAttributeSB.append("");

		if (Main.mainController != null) {
			if (Main.game.getCurrentDialogueNode() != null) {
				if (renderedDialogueNode != Main.game.getCurrentDialogueNode()) {
					renderedDialogueNode = Main.game.getCurrentDialogueNode();

				}
			}
		}

		Main.mainController.setAttributePanelContent(uiAttributeSB.toString());
	}

	public static GameCharacter getCharacterToRender() {
		if(Main.game.getCurrentDialogueNode().getDialogueNodeType() == DialogueNodeType.CHARACTERS_PRESENT || Main.game.getCurrentDialogueNode() == PhoneDialogue.CONTACTS_CHARACTER) {
			return (NPC) CharactersPresentDialogue.characterViewed;
		}

		if(Main.game.isInSex()) {
			if(Sex.isMasturbation()) {
				return null;
			}
			return Sex.getTargetedPartner(Main.game.getPlayer());
		}

		if(Main.game.isInCombat()) {
			return Combat.getTargetedCombatant(Main.game.getPlayer());
		}

		if(InventoryDialogue.getInventoryNPC()!=null && Main.game.getCurrentDialogueNode().getDialogueNodeType() == DialogueNodeType.INVENTORY) {
			return InventoryDialogue.getInventoryNPC();
		}

		if(Main.game.getDialogueFlags().getManagementCompanion()!=null) {
			return Main.game.getDialogueFlags().getManagementCompanion();
		}

		return Main.game.getActiveNPC();
	}

	public static String getEntryBackgroundColour(boolean alternative) {
		if(alternative) {
			return Colour.BACKGROUND_ALT.toWebHexString();
		}
		return Colour.BACKGROUND.toWebHexString();
	}

	public boolean isRenderingCharactersRightPanel() {
		return Main.game.isInSex()
				|| Main.game.isInCombat()
				|| (getCharacterToRender()!=null
					&& (Main.game.getCurrentDialogueNode().getDialogueNodeType() == DialogueNodeType.CHARACTERS_PRESENT
						|| Main.game.getCurrentDialogueNode() == PhoneDialogue.CONTACTS_CHARACTER
						|| Main.game.getDialogueFlags().getManagementCompanion()!=null
						|| (Main.game.getCurrentDialogueNode().getDialogueNodeType()==DialogueNodeType.INVENTORY && InventoryDialogue.getInventoryNPC()!=null)));
	}

	public void renderAttributesPanelRight() {
		uiAttributeSB.setLength(0);

		uiAttributeSB.append(
				""
					+ " ");

		if(isRenderingCharactersRightPanel()) {
//			System.out.println("1: "+(Main.game.getCurrentDialogueNode().getDialogueNodeType()==DialogueNodeType.CHARACTERS_PRESENT));
//			System.out.println("2: "+(Main.game.getCurrentDialogueNode()==PhoneDialogue.CONTACTS_CHARACTER));
//			System.out.println("3: "+(Main.game.getDialogueFlags().getManagementCompanion()!=null));
//			System.out.println("4: "+(Main.game.getCurrentDialogueNode().getDialogueNodeType()==DialogueNodeType.INVENTORY && InventoryDialogue.getInventoryNPC()!=null));

			if(Main.game.isInSex()) {
				// Name box:
				uiAttributeSB.append(
						"
"
						+ "
"
							+ "
Dominant"+(Sex.getDominantParticipants(true).size()>1?"s":"")
									:Colour.BASE_PINK_LIGHT.toWebHexString()+";'>Submissive"+(Sex.getSubmissiveParticipants(true).size()>1?"s":""))
							+"
"
						+ "
"
					+ "
"
					+ "
");

				if(!Sex.isDom(Main.game.getPlayer())) {
					for(GameCharacter character : Sex.getDominantParticipants(true).keySet()) {
						uiAttributeSB.append(getCharacterPanelSexDiv(Sex.getDominantParticipants(true).size()>1, "NPC_"+character.getId()+"_", character));
					}

				} else {
					for(GameCharacter character : Sex.getSubmissiveParticipants(true).keySet()) {
						uiAttributeSB.append(getCharacterPanelSexDiv(Sex.getSubmissiveParticipants(true).size()>1, "NPC_"+character.getId()+"_", character));
					}
				}
				uiAttributeSB.append("
");

			} else if(Main.game.isInCombat()) {

				// Name box:
				uiAttributeSB.append(
					"
"
						+ "
"
							+ "
"
								+ (Combat.getEnemies(Main.game.getPlayer()).size()>1?"Enemies":"Enemy")
							+"
"
						+ "
"
					+ "
"
					+ "
");

				for(GameCharacter character : Combat.getEnemies(Main.game.getPlayer())) {
					uiAttributeSB.append(getCharacterPanelDiv(Combat.getEnemies(Main.game.getPlayer()).size()>1, "NPC_"+character.getId()+"_", character));
				}

				uiAttributeSB.append("
");

			} else {
				// Default place name box:
				uiAttributeSB.append("
"
										+ getDefaultAttributeColumnHeader()
									+"
"
									+ "
");

				uiAttributeSB.append(getCharacterPanelDiv(true, "NPC_"+getCharacterToRender().getId()+"_", getCharacterToRender()));

				uiAttributeSB.append("
");

			}

			uiAttributeSB.append("
");
			if(Main.game.getCurrentDialogueNode().getDialogueNodeType() == DialogueNodeType.INVENTORY && Main.game.isEnchantmentCapacityEnabled() && getCharacterToRender()!=null) {
				int enchantmentPointsUsed = getCharacterToRender().getEnchantmentPointsUsedTotal();
				uiAttributeSB.append(UtilText.parse(
						"
"
							+ "
"
								+ "[style.colourEnchantment("+Util.capitaliseSentence(Attribute.ENCHANTMENT_LIMIT.getName())+")]: "
								+ (enchantmentPointsUsed>getCharacterToRender().getAttributeValue(Attribute.ENCHANTMENT_LIMIT)
										?"[style.colourBad("
										:(enchantmentPointsUsed==getCharacterToRender().getAttributeValue(Attribute.ENCHANTMENT_LIMIT)
												?"[style.colourGood("
												:"[style.colourMinorGood("))
								+ enchantmentPointsUsed + ")]" + "/" + Math.round(getCharacterToRender().getAttributeValue(Attribute.ENCHANTMENT_LIMIT))
							+ "
"
						+"
"));

			} else {
				uiAttributeSB.append(
								"
"
										+ "
"
											+ (getCharacterToRender()==null
												?"No Character"
												:UtilText.parse(getCharacterToRender(), "[npc.NamePos] Inventory"))
										+ "
"
								+ "
");
			}
			uiAttributeSB.append("
");

			uiAttributeSB.append(getInventoryEquippedPanel(getCharacterToRender()));

		} else {
			uiAttributeSB.append("
");

			AbstractPlaceType place = Main.game.getPlayer().getWorldLocation().getStandardPlace();
			if(Main.game.getPlayer().getLocationPlace()!=null) {
				place = Main.game.getPlayer().getLocationPlace().getPlaceType();
			}
			// Default place name box:
			uiAttributeSB.append(
					"
"
						+ getDefaultAttributeColumnHeader()
					+ "
");

			// Characters Present:
			uiAttributeSB.append("
"
								+ "
Characters Present
");
			List <NPC> charactersPresent = Main.game.getCharactersPresent();
			if(charactersPresent.isEmpty() && (place.getPopulation()==null || place.getPopulation().getSpecies().isEmpty())) {
				uiAttributeSB.append("
None...
");

			} else {
				int count = 0;
				for(NPC character : charactersPresent) {
//					if(!character.isRaceConcealed()) {
						uiAttributeSB.append(
								"
"
									+ "
"
										+ "
"
											+ (character.isRaceConcealed()?SVGImages.SVG_IMAGE_PROVIDER.getRaceUnknown():character.getMapIcon())
										+ "
"
									+ "
"
									+"
"
										+(!character.getArtworkList().isEmpty() && Main.getProperties().hasValue(PropertyValue.artwork)?"📷 ":"")
											+UtilText.parse(character, "[npc.Name(A)]")
										+ "

"
										+ "

"
									+"
"
								+ "
");
//					} else {
//						uiAttributeSB.append(
//								"
"
//									+ "
"
//										+ "
"
//											+ (character.isRaceConcealed()?SVGImages.SVG_IMAGE_PROVIDER.getRaceUnknown():character.getMapIcon())
//										+ "
"
//									+ "
"
//									+"
"
//										+(!character.getArtworkList().isEmpty() && Main.getProperties().hasValue(PropertyValue.artwork)?"📷 ":"")+ (character.isPlayerKnowsName()?character.getName("A"):"Unknown person")
//										+ "

"
//										+ "

"
//									+"
"
//								+ "
");
//					}//The commented section remove the ability to click the character to see the character present dialogue and the overlay that contain the stats. Clicking on the icon will still bring you to the character present dialogue
					count++;
				}

				Population pop = place.getPopulation();
				if(pop!=null && !pop.getSpecies().isEmpty()) {
					uiAttributeSB.append(
								"
"
									+ "
"
										+ "
"
											+ (pop.getSpecies().size()>1
													?SVGImages.SVG_IMAGE_PROVIDER.getPeopleIcon()
													:pop.getSpecies().keySet().iterator().next().getSVGString(null))
										+ "
"
									+ "
"
									+"
"
										+Util.capitaliseSentence(pop.getDensity().getName())+" "+pop.getType().getName()
										+ "

"
									+"
"
								+ "
");

//								"
"+Util.capitaliseSentence(pop.getDensity().getName())+" "+pop.getType().getName()+"
");
				}
			}
			uiAttributeSB.append("
");

			// Items Present:
			uiAttributeSB.append("
"
								+ "
Items Present
");

			int count = 0;
			if(Main.game.isInNewWorld()) {
				for(Entry<AbstractWeapon, Integer> entry : Main.game.getPlayerCell().getInventory().getAllWeaponsInInventory().entrySet()) {
					if(count%2==0) {
						uiAttributeSB.append(
								"
"
										+entry.getValue()+"x "+UtilText.parse(entry.getKey().getName(false, true))
										+ "

"
								+"
");
					} else {
						uiAttributeSB.append(
								"
"
										+entry.getValue()+"x "+UtilText.parse(entry.getKey().getName(false, true))
										+ "

"
								+"
");
					}
					count++;
				}
				for(Entry<AbstractClothing, Integer> entry : Main.game.getPlayerCell().getInventory().getAllClothingInInventory().entrySet()) {
					if(count%2==0) {
						uiAttributeSB.append(
								"
"
										+entry.getValue()+"x "+UtilText.parse(entry.getKey().getName(false, true))
										+ "

"
								+"
");
					} else {
						uiAttributeSB.append(
								"
"
										+entry.getValue()+"x "+UtilText.parse(entry.getKey().getName(false, true))
										+ "

"
								+"
");
					}
					count++;
				}
				for(Entry<AbstractItem, Integer> entry : Main.game.getPlayerCell().getInventory().getAllItemsInInventory().entrySet()) {
					if(count%2==0) {
						uiAttributeSB.append(
								"
"
										+entry.getValue()+"x "+UtilText.parse(entry.getKey().getName(false, true))
										+ "

"
								+"
");
					} else {
						uiAttributeSB.append(
								"
"
										+entry.getValue()+"x "+UtilText.parse(entry.getKey().getName(false, true))
										+ "

"
								+"
");
					}
					count++;
				}
			}
			if(count==0) {
				uiAttributeSB.append("
None...
");
			}
			uiAttributeSB.append(
					"
");

			// Event log:
			uiAttributeSB.append(
					"
"
						+ "
"
							+ "
Event Log
"
							+ "
");

			if(Main.game.getEventLog().isEmpty()) {
				uiAttributeSB.append("
No events yet...
");
			}

			count = 0;

			if(Main.game.getEventLog().size()>50) {
				List<EventLogEntry> youveCatToBeKittenMeRightMeow = new ArrayList<>(Main.game.getEventLog().subList(Main.game.getEventLog().size()-50, Main.game.getEventLog().size()));
				Collections.reverse(youveCatToBeKittenMeRightMeow);
				for(EventLogEntry event : youveCatToBeKittenMeRightMeow) {
					if(count%2==0) {
						uiAttributeSB.append("
"+UtilText.parse(event.getFormattedEntry())+"
");
					} else {
						uiAttributeSB.append("
"+UtilText.parse(event.getFormattedEntry())+"
");
					}
					count++;
				}

			} else {
				List<EventLogEntry> youveCatToBeKittenMeRightMeow = new ArrayList<>(Main.game.getEventLog());
				Collections.reverse(youveCatToBeKittenMeRightMeow);
				for(EventLogEntry event : youveCatToBeKittenMeRightMeow) {
					if(count%2==0) {
						uiAttributeSB.append("
"+UtilText.parse(event.getFormattedEntry())+"
");
					} else {
						uiAttributeSB.append("
"+UtilText.parse(event.getFormattedEntry())+"
");
					}
					count++;
				}
			}
			uiAttributeSB.append("
"
					+ "
");

		}

		uiAttributeSB.append("");

		if (Main.mainController != null) {
			if (Main.game.getCurrentDialogueNode() != null) {
				if (renderedDialogueNode != Main.game.getCurrentDialogueNode()) {
					renderedDialogueNode = Main.game.getCurrentDialogueNode();
				}
			}
		}

		Main.mainController.setRightPanelContent(uiAttributeSB.toString());
	}

	private StringBuilder mapSB = new StringBuilder();

	private Colour getPlayerIconColour(boolean isDangerous) {
		if(isDangerous) {
			return Colour.BASE_RED;
		} else {
			switch(Main.game.getPlayer().getFemininity()) {
				case ANDROGYNOUS:
					return Femininity.ANDROGYNOUS.getColour();
				case FEMININE:
				case FEMININE_STRONG:
					return Femininity.FEMININE_STRONG.getColour();
				case MASCULINE:
				case MASCULINE_STRONG:
					return Femininity.MASCULINE_STRONG.getColour();
			}
			return Main.game.getPlayer().getFemininity().getColour();
		}
	}

	public String getFullMap(WorldType world, boolean withFastTravel, boolean withNPCIcons) {

//		long t1 = System.nanoTime();

		mapSB.setLength(0);

		Cell[][] grid = Main.game.getWorlds().get(world).getGrid();
		int divWidth = (Math.min(70, grid.length*10));
		if(withFastTravel) {
			mapSB.append("
"
					+ "
");
		} else {
			mapSB.append("
");
		}

		float width = 100f/grid.length;
		for(int i=grid[0].length-1; i>=0; i--) {
			for(int j=0; j<grid.length; j++) {
				Cell c = grid[j][i];

				boolean worldMap = world==WorldType.WORLD_MAP;
				boolean discovered = c.isDiscovered() || Main.game.isMapReveal();
				boolean showPathing = Main.game.getPlayer().getWorldLocation().equals(world) || Pathing.getMapTravelType()==MapTravelType.TELEPORT;
				boolean path = Pathing.getPathingCells().contains(c);
				boolean endPath = Pathing.getEndPoint()!=null && new Vector2i(j, i).equals(Pathing.getEndPoint());
				boolean dangerousTile = c.getPlace().getPlaceType().isDangerous();
				AbstractPlaceType placeType = c.getPlace().getPlaceType();

				String background;
				if(placeType.equals(PlaceType.GENERIC_IMPASSABLE)) {
					background = "background:transparent;";
				} else {
					background = dangerousTile && discovered //&& !worldMap
							?getDangerousBackground(placeType)
							:discovered
								?"background-color:"+placeType.getBackgroundColourString()+";"
								:"background-color:"+Colour.MAP_BACKGROUND_UNEXPLORED.toWebHexString()+";";
				}

				if(!discovered || placeType.equals(PlaceType.GENERIC_IMPASSABLE)) {
					mapSB.append("

");

				} else {
					String border = (c.getPlace() != null && !placeType.getColourString().isEmpty()
										?"border:1px solid; border-color:"+placeType.getColourString()+";"
										:"border:1px solid; border-color:#ffffff;")
									+ (grid.length>25
											?"width:"+(width)+"%; margin:0; border-radius:0; border-width:0.5px 0.5px 0.5px 0.5px; border-style:solid; border-color:"
//												+(dangerousTile
//														?BaseColour.RED_DARK.toWebHexString()
//														:Colour.GENERIC_GOOD.toWebHexString())
													+"#222"
												+";"
											:"");

					boolean playerOnTile = Main.game.getPlayer().getWorldLocation()==world && Main.game.getPlayer().getLocation().getX()==j && Main.game.getPlayer().getLocation().getY()==i;
					if(worldMap && Main.game.getPlayer().getWorldLocation()!=WorldType.WORLD_MAP) {
						playerOnTile = Main.game.getPlayer().getGlobalLocation().getX()==j && Main.game.getPlayer().getGlobalLocation().getY()==i;
					}

					boolean canTeleportToTile = !placeType.equals(PlaceType.GENERIC_IMPASSABLE)
										&& ((Main.game.getPlayer().getMana()>=Spell.TELEPORT.getModifiedCost(Main.game.getPlayer()) && c.isTravelledTo() && Main.game.getPlayer().isAbleToTeleport()) || Main.game.isDebugMode());

//					if(path) {
//						background = "background-color: "+(dangerousTile?Colour.GENERIC_MINOR_BAD:Colour.GENERIC_MINOR_GOOD).toWebHexString()+";";
//					}

					mapSB.append(
							"
"
								+(playerOnTile?"

":"")
								+(showPathing && endPath && !playerOnTile?"

":"")
								+(showPathing && path && !endPath && !playerOnTile
										?"

"
										:"")
								+ (c.getPlace() != null && c.getPlace().getSVGString()!=null
									? "
"
											+c.getPlace().getSVGString()+"
"
									: "")
								+(playerOnTile && (c.getPlace() == null || c.getPlace().getSVGString()==null)
										?getPlayerIcon(dangerousTile)
										:"")
								);

					if(withNPCIcons) {
						appendNPCIcon(Main.game.getWorlds().get(world), j, i, width);
					}
//					appendNotVisitedLayer(Main.game.getWorlds().get(world), j, i);

					mapSB.append("
");
				}
			}
		}

		if(withFastTravel) {
			String buttonStyle= "width:60%; min-width:0; margin:0 20% 4px 20%;";
			mapSB.append("
"
						+ "
"
							+ "
[style.bold(Fast Travel)]
");

			for(MapTravelType type : MapTravelType.values()) {
				if(!type.isAvailable(null, Main.game.getPlayer())) {
					mapSB.append("
"
							+Util.capitaliseSentence(type.getName())
						+ "
");

				} else if(Pathing.getMapTravelType()==type){
					mapSB.append("
"
							+ ""+Util.capitaliseSentence(type.getName())+""
						+ "
");

				} else {
					mapSB.append("
"
							+ ""+Util.capitaliseSentence(type.getName())+""
						+ "
");
				}
			}

			mapSB.append(
					"
"
					+ "
");//style='margin-bottom:28px;'

			boolean travelDestinationSelected = !Pathing.getEndPoint().equals(Main.game.getPlayer().getLocation())
					|| (Pathing.getMapTravelType()==MapTravelType.TELEPORT && !Main.game.getPlayer().getWorldLocation().equals(Pathing.getDestinationWorld()));

			if(!travelDestinationSelected) {
				if(!world.equals(Main.game.getPlayer().getWorldLocation()) && Pathing.getMapTravelType()!=MapTravelType.TELEPORT) {
					mapSB.append("[style.italicsBad(You cannot use this fast travel method to travel between different maps.)]");

				} else if(Main.game.getSavedDialogueNode()!=null && Main.game.getSavedDialogueNode().isTravelDisabled()) {
					mapSB.append("[style.italicsBad(You cannot fast travel while in the middle of a scene!)]");

				} else if(!Pathing.getMapTravelType().isAvailable(null, Main.game.getPlayer())){
					mapSB.append("[style.italicsBad("+Pathing.getMapTravelType().getUnavailablilityDescription(null, Main.game.getPlayer())+")]");

				} else {
					mapSB.append(Pathing.getMapTravelType().getUseInstructions());
				}

			} else {
				int minutes = Pathing.getTravelTime()/60;
				int hours = minutes/60;
				String time =
						hours>0
							?Util.capitaliseSentence(Util.intToString(hours))+" hour"+(hours==1?"":"s")
								+(minutes%60==0
									?""
									:", "+Util.intToString(minutes%60)+" minute"+(minutes==1?"":"s"))
							:(minutes==0
								?"Less than a minute"
								:Util.capitaliseSentence(Util.intToString(minutes%60))+" minute"+(minutes==1?"":"s"));

				int dangerousTiles = Pathing.getDangerousTilesCrossed();

				switch(Pathing.getMapTravelType()) {
					case FLYING:
						mapSB.append("Estimated travel time:
"+(hours>0?"[style.boldMinorBad(":"[style.boldMinorGood(")+time+")]"
								+"

"
								+ (dangerousTiles==0
									?"[style.colourGood(Zero)] dangerous tiles will be encountered, as you fly over any in your way!"
									:"[style.colourBad(One)] dangerous tile will be encountered (that being your destination)."));
						break;
					case TELEPORT:
						mapSB.append("Estimated travel time:
[style.boldExcellent(Five seconds)]"
								+ "

"
								+ (dangerousTiles==0
									?"[style.colourGood(Zero)] dangerous tiles will be encountered, as you teleport past them all!"
									:"[style.colourBad(One)] dangerous tile will be encountered (that being your destination)."));
						break;
					case WALK_DANGEROUS:
					case WALK_SAFE:
						mapSB.append("Estimated travel time:
"+(hours>0?"[style.boldMinorBad(":"[style.boldMinorGood(")+time+")]"
								+"

"+(dangerousTiles>0?"[style.colourBad(":"[style.colourGood(")+Util.capitaliseSentence(Util.intToString(dangerousTiles))+")] dangerous tile"+(dangerousTiles==1?"":"s")+" will be encountered!");
						break;
				}
			}

			mapSB.append("
");

//			if(travelDestinationSelected) {
//				mapSB.append("
"
//						+ "Go"
//					+ "
");
//			} else {
//				mapSB.append("
"
//						+ "Go"
//					+ "
");
//			}

			mapSB.append("
");
		}

		mapSB.append("
");

//		long t2 = System.nanoTime();
//		System.out.println(Main.game.getAllNPCs().size()+" Full map: "+(t2-t1)/1000000000f);

		return mapSB.toString();
	}

	private String getPlayerIcon(boolean dangerous) {
		if (dangerous) {
			return ("
" + SVGImages.SVG_IMAGE_PROVIDER.getPlayerMapDangerousIcon() + "
");
		} else {
			if(Main.game.getPlayer().getFemininityValue()<=Femininity.MASCULINE.getMaximumFemininity()) {
				return ("
" + SVGImages.SVG_IMAGE_PROVIDER.getPlayerMapIconMasculine() + "
");

			} else if(Main.game.getPlayer().getFemininityValue()<=Femininity.ANDROGYNOUS.getMaximumFemininity()) {
				return ("
" + SVGImages.SVG_IMAGE_PROVIDER.getPlayerMapIconAndrogynous() + "
");

			} else{
				return ("
" + SVGImages.SVG_IMAGE_PROVIDER.getPlayerMapIconFeminine() + "
");
			}
		}
	}

	private static String getDangerousBackground(AbstractPlaceType placeType) {
		if(placeType instanceof AbstractGlobalPlaceType) {
			return "background:"+placeType.getBackgroundColourString()+";";
		}

		String backgroundColour1;
		String backgroundColour2;
		try {
			backgroundColour1 = placeType.getBackgroundColour().getShades()[0];
			backgroundColour2 = placeType.getBackgroundColour().toWebHexString();
		} catch (Exception e) {
			backgroundColour1 = Colour.TEXT_GREY_DARK.toWebHexString();
			backgroundColour2 = placeType.getBackgroundColourString();
		}

		return "background: repeating-linear-gradient("
				+"135deg,"
				+backgroundColour1+","
				+backgroundColour1+" 20%,"

				+backgroundColour2+" 20%,"
				+backgroundColour2+" 40%"
				+");";
	}

	public String renderedHTMLMap() {

//		long t1 = System.nanoTime();

		mapSB.setLength(0);

		Colour background = Colour.BACKGROUND_DAY;
		String mapCornerGlow = "";
		switch(Main.game.getCurrentDayPeriod()) {
			case CIVIL_TWILIGHT:
			case NAUTICAL_TWILIGHT:
				background = Colour.BACKGROUND_TWILIGHT;
				mapCornerGlow = SVGImages.SVG_IMAGE_PROVIDER.getCornerGlowTwilight();
				break;
			case DAY:
				break;
			case ASTRONOMICAL_TWILIGHT:
			case NIGHT:
				mapCornerGlow = SVGImages.SVG_IMAGE_PROVIDER.getCornerGlowNight();
				background = Colour.BACKGROUND_NIGHT;
				break;
		}

		mapSB.append("
");

//		if(!Main.game.isInNewWorld()) {
//			mapSB.append("

");
//			renderedDisabledMap = true;
//		}

		int mapSize = zoomedIn ? 2 : 3;
		float unit = zoomedIn ? 18f : 13.25f;

		String tileWidthStyle = "width:" + unit + "%; border-width:1%; margin:"+(zoomedIn?1:0.5)+"%;";

		Vector2i playerPosition = Main.game.getPlayer().getLocation();

		// It looks messy, but it works...
		for (int y = playerPosition.getY() + mapSize; y >= playerPosition.getY() - mapSize; y--) {
			for (int x = playerPosition.getX() - mapSize; x <= playerPosition.getX() + mapSize; x++) {

				if (x = 0 && y = 0) {// If within  bounds of map:
					AbstractPlaceType placeType = Main.game.getActiveWorld().getCell(x, y).getPlace().getPlaceType();

					if (Main.game.getActiveWorld().getCell(x, y).isDiscovered() || Main.game.isMapReveal()) { // If the tile is discovered:

						if (placeType.equals(PlaceType.GENERIC_IMPASSABLE)) {
							mapSB.append("

");

						} else {
							// This is the "move North" tile:
							if (y == playerPosition.getY() + 1 && x == playerPosition.getX() && !placeType.equals(PlaceType.GENERIC_IMPASSABLE)) {
								if(Main.game.getActiveWorld().getCell(x, y).getPlace().isDangerous()) {
									mapSB.append("
");

								} else {
									mapSB.append("<div class='map-tile movement' id='upButton' style='"+tileWidthStyle+" background:"+placeType.getBackgroundColourString()+"; border-color:"+
												(Main.game.getPlayer().getFemininityValue()<=Femininity.MASCULINE.getMaximumFemininity()
														?Colour.MASCULINE_PLUS
														:(Main.game.getPlayer().getFemininityValue()<=Femininity.ANDROGYNOUS.getMaximumFemininity()
																?Colour.ANDROGYNOUS
																		:Colour.FEMININE_PLUS)).toWebHexString()+";'>");
								}

								// Put place icon onto tile:
								if (Main.game.getActiveWorld().getCell(x, y).getPlace().getSVGString() != null) {
									mapSB.append("

" + Main.game.getActiveWorld().getCell(x, y).getPlace().getSVGString() + "

");
								}

								mapSB.append(""
										+ (Main.getProperties().hotkeyMapPrimary.get(KeyboardAction.MOVE_NORTH) == null ? "" : Main.getProperties().hotkeyMapPrimary.get(KeyboardAction.MOVE_NORTH).getFullName()) + "");

								appendNPCIcon(Main.game.getActiveWorld(), x, y, unit);
								appendItemsInAreaIcon(x, y);
								appendNotVisitedLayer(Main.game.getActiveWorld(), x, y);

								// Close the tile's div:
								mapSB.append("
");

								// This is the "move South" tile:
							} else if (y == playerPosition.getY() - 1 && x == playerPosition.getX() && !placeType.equals(PlaceType.GENERIC_IMPASSABLE)) {
								if(Main.game.getActiveWorld().getCell(x, y).getPlace().isDangerous()) {
									mapSB.append("
");

								} else {
									mapSB.append("<div class='map-tile movement' id='downButton' style='"+tileWidthStyle+" background:"+placeType.getBackgroundColourString()+"; border-color:"+
												(Main.game.getPlayer().getFemininityValue()<=Femininity.MASCULINE.getMaximumFemininity()
														?Colour.MASCULINE_PLUS
														:(Main.game.getPlayer().getFemininityValue()<=Femininity.ANDROGYNOUS.getMaximumFemininity()
																?Colour.ANDROGYNOUS
																		:Colour.FEMININE_PLUS)).toWebHexString()+";'>");
								}

								// Put place icon onto tile:
								if (Main.game.getActiveWorld().getCell(x, y).getPlace().getSVGString() != null) {
									mapSB.append("

" + Main.game.getActiveWorld().getCell(x, y).getPlace().getSVGString() + "

");
								}

								mapSB.append(""
										+ (Main.getProperties().hotkeyMapPrimary.get(KeyboardAction.MOVE_SOUTH) == null ? "" : Main.getProperties().hotkeyMapPrimary.get(KeyboardAction.MOVE_SOUTH).getFullName()) + "");

								appendNPCIcon(Main.game.getActiveWorld(), x, y, unit);
								appendItemsInAreaIcon(x, y);
								appendNotVisitedLayer(Main.game.getActiveWorld(), x, y);

								// Close the tile's div:
								mapSB.append("
");

								// This is the "move West" tile:
							} else if (y == playerPosition.getY() && x == playerPosition.getX() - 1 && !placeType.equals(PlaceType.GENERIC_IMPASSABLE)) {
								if(Main.game.getActiveWorld().getCell(x, y).getPlace().isDangerous()) {
									mapSB.append("
");

								} else {
									mapSB.append("<div class='map-tile movement' id='leftButton' style='"+tileWidthStyle+" background:"+placeType.getBackgroundColourString()+"; border-color:"+
												(Main.game.getPlayer().getFemininityValue()<=Femininity.MASCULINE.getMaximumFemininity()
														?Colour.MASCULINE_PLUS
														:(Main.game.getPlayer().getFemininityValue()<=Femininity.ANDROGYNOUS.getMaximumFemininity()
																?Colour.ANDROGYNOUS
																		:Colour.FEMININE_PLUS)).toWebHexString()+";'>");
								}

								// Put place icon onto tile:
								if (Main.game.getActiveWorld().getCell(x, y).getPlace().getSVGString() != null) {
									mapSB.append("

" + Main.game.getActiveWorld().getCell(x, y).getPlace().getSVGString() + "

");
								}

								mapSB.append(""
										+ (Main.getProperties().hotkeyMapPrimary.get(KeyboardAction.MOVE_WEST) == null ? "" : Main.getProperties().hotkeyMapPrimary.get(KeyboardAction.MOVE_WEST).getFullName()) + "");

								appendNPCIcon(Main.game.getActiveWorld(), x, y, unit);
								appendItemsInAreaIcon(x, y);
								appendNotVisitedLayer(Main.game.getActiveWorld(), x, y);

								// Close the tile's div:
								mapSB.append("
");

								// This is the "move East" tile:
							} else if (y == playerPosition.getY() && x == playerPosition.getX() + 1 && !placeType.equals(PlaceType.GENERIC_IMPASSABLE)) {
								if(Main.game.getActiveWorld().getCell(x, y).getPlace().isDangerous()) {
									mapSB.append("
");

								} else {
									mapSB.append("<div class='map-tile movement' id='rightButton' style='"+tileWidthStyle+" background:"+placeType.getBackgroundColourString()+"; border-color:"+
												(Main.game.getPlayer().getFemininityValue()<=Femininity.MASCULINE.getMaximumFemininity()
														?Colour.MASCULINE_PLUS
														:(Main.game.getPlayer().getFemininityValue()<=Femininity.ANDROGYNOUS.getMaximumFemininity()
																?Colour.ANDROGYNOUS
																		:Colour.FEMININE_PLUS)).toWebHexString()+";'>");
								}

								// Put place icon onto tile:
								if (Main.game.getActiveWorld().getCell(x, y).getPlace().getSVGString() != null) {
									mapSB.append("

" + Main.game.getActiveWorld().getCell(x, y).getPlace().getSVGString() + "

");
								}

								mapSB.append(""
										+ (Main.getProperties().hotkeyMapPrimary.get(KeyboardAction.MOVE_EAST) == null ? "" : Main.getProperties().hotkeyMapPrimary.get(KeyboardAction.MOVE_EAST).getFullName()) + "");

								appendNPCIcon(Main.game.getActiveWorld(), x, y, unit);
								appendItemsInAreaIcon(x, y);
								appendNotVisitedLayer(Main.game.getActiveWorld(), x, y);

								// Close the tile's div:
								mapSB.append("
");

							} else {
								if(Main.game.getActiveWorld().getCell(x, y).getPlace().isDangerous()) {
									mapSB.append("
");

								} else {
									mapSB.append("
");

								}

								// Put place icon onto tile:
								if (Main.game.getActiveWorld().getCell(x, y).getPlace().getSVGString() != null) {
									if (y == playerPosition.getY() && x == playerPosition.getX()) {
										mapSB.append("
"
												+ "
"
												+ Main.game.getActiveWorld().getCell(x, y).getPlace().getSVGString() + "

");
									} else {
										mapSB.append("

" + Main.game.getActiveWorld().getCell(x, y).getPlace().getSVGString() + "

");
									}

								} else if (y == playerPosition.getY() && x == playerPosition.getX()) {
									if (Main.game.getActiveWorld().getCell(x, y).getPlace().isDangerous()) {
										mapSB.append("

" + SVGImages.SVG_IMAGE_PROVIDER.getPlayerMapDangerousIcon() + "

");
									} else {
										if(Main.game.getPlayer().getFemininityValue()<=Femininity.MASCULINE.getMaximumFemininity()) {
											mapSB.append("

" + SVGImages.SVG_IMAGE_PROVIDER.getPlayerMapIconMasculine() + "

");

										} else if(Main.game.getPlayer().getFemininityValue()<=Femininity.ANDROGYNOUS.getMaximumFemininity()) {
											mapSB.append("

" + SVGImages.SVG_IMAGE_PROVIDER.getPlayerMapIconAndrogynous() + "

");

										} else{
											mapSB.append("

" + SVGImages.SVG_IMAGE_PROVIDER.getPlayerMapIconFeminine() + "

");
										}
									}
								}

								appendNPCIcon(Main.game.getActiveWorld(), x, y, unit);
								appendItemsInAreaIcon(x, y);
								appendNotVisitedLayer(Main.game.getActiveWorld(), x, y);

								// Close the tile's div:
								mapSB.append("
");
							}

						}

					} else if(Main.game.getActiveWorld().getCell(x, y).getPlace().getPlaceType()!=PlaceType.GENERIC_IMPASSABLE) {
						mapSB.append("

");

					} else {
						mapSB.append("

");
					}

				} else {
					mapSB.append("

");
				}
			}

		}

		if(!Main.game.isInNewWorld() || Main.game.getCurrentDialogueNode().isTravelDisabled()) {
			mapSB.append("

");
			renderedDisabledMap = true;

		} else {
			if(!mapCornerGlow.isEmpty()) {
				mapSB.append(
						"
"
							+ "
"+mapCornerGlow+"
"
						+ "
");
			}
			renderedDisabledMap = false;
		}

		mapSB.append("
");

//		long t2 = System.nanoTime();
//		System.out.println("HTML map: "+(t2-t1)/1000000000f);

		return mapSB.toString();
	}

	private void appendNPCIcon(World world, int x, int y, float tileWidth) {

		List<String> mapIcons = new ArrayList<>();
		List<NPC> charactersPresent = Main.game.getCharactersPresent(world.getCell(x, y));
		List<NPC> charactersHome = Main.game.getCharactersTreatingCellAsHome(world.getCell(x, y));

		if(!charactersPresent.isEmpty() || !charactersHome.isEmpty()) {
			for(NPC gc : charactersPresent) {
				mapIcons.add(gc.getMapIcon());
			}

			for(NPC gc : charactersHome) {
				if(!charactersPresent.contains(gc) && (charactersHome.size()==1 || x!=0 || y!=0)) {
					mapIcons.add(gc.getHomeMapIcon());
				}
			}

			if(!mapIcons.isEmpty()) {
				float increment = Math.min(20, 75/mapIcons.size());
				for(int i = mapIcons.size() ; i>0 ; i--) {
					mapSB.append("
"+mapIcons.get(i-1)+"
");
				}
			}
		}
	}

	private void appendItemsInAreaIcon(int x, int y) {
		if(!Main.game.isInNewWorld()) {
			return;
		}
		if(Main.game.getActiveWorld().getCell(x, y).getInventory().getInventorySlotsTaken()>0
				|| Main.game.getActiveWorld().getCell(x, y).getInventory().getUniqueQuestWeaponCount()>0
				|| Main.game.getActiveWorld().getCell(x, y).getInventory().getUniqueQuestClothingCount()>0
				|| Main.game.getActiveWorld().getCell(x, y).getInventory().getUniqueQuestItemCount()>0
				|| Main.game.getActiveWorld().getCell(x, y).getInventory().getMoney()>0) {
			mapSB.append("
"+SVGImages.SVG_IMAGE_PROVIDER.getItemsOnFloorIcon()+"
");
		}
	}

	private void appendNotVisitedLayer(World world, int x, int y) {
		if(!world.getCell(x, y).isTravelledTo()) {
			mapSB.append("

");
		}
	}

	public void renderButtons() {
		Main.mainController.setButtonsContent(
				"
"
					+ "
"
						+ SVGImages.SVG_IMAGE_PROVIDER.getMenuIcon()
					+ "
"
				+ "
"

				+ "
"
					+ "<div class='button" + (
							(Main.mainController.isPhoneDisabled())
								?" disabled"
								:(Main.game.getPlayer().isMainQuestUpdated()
									|| Main.game.getPlayer().isSideQuestUpdated()
									|| Main.game.getPlayer().isRelationshipQuestUpdated()
									|| Main.getProperties().hasValue(PropertyValue.newWeaponDiscovered)
									|| Main.getProperties().hasValue(PropertyValue.newClothingDiscovered)
									|| Main.getProperties().hasValue(PropertyValue.newItemDiscovered)
									|| Main.getProperties().hasValue(PropertyValue.newRaceDiscovered)
									|| Main.getProperties().hasValue(PropertyValue.levelUpHightlight)
										?" highlight"
										:""))
						+ "' id='journal'>" + SVGImages.SVG_IMAGE_PROVIDER.getJournalIcon()
						+ (Main.mainController.isPhoneDisabled() ? "

" : "")
					+ "
"
				+ "
"

				+ "
"
					+ "
0 ? " highlight" : "")
					+ (Main.mainController.isInventoryDisabled() ? " disabled" : "") + "' id='inventory'>"
						+ SVGImages.SVG_IMAGE_PROVIDER.getInventoryIcon()
						+ (Main.mainController.isInventoryDisabled() ? "

" : "")
					+ "
"
				+ "
"

				+ "
"
					+ "
" + SVGImages.SVG_IMAGE_PROVIDER.getPeopleIcon()
						+ (Main.game.getCharactersPresent().isEmpty() && Main.game.getCurrentDialogueNode().getDialogueNodeType() != DialogueNodeType.CHARACTERS_PRESENT ? "

" : "")
					+ "
"
				+ "
"

				+ "
"
					+ "
"
						+ (RenderingEngine.isZoomedIn() ? SVGImages.SVG_IMAGE_PROVIDER.getZoomOutIcon() : SVGImages.SVG_IMAGE_PROVIDER.getZoomInIcon())
							+ (Main.game.getCurrentDialogueNode().isTravelDisabled() ? "

" : "")
					+ "
"
				+ "
");
	}

	public static boolean isZoomedIn() {
		return zoomedIn;
	}

	public static void setZoomedIn(boolean zoomedIn) {
		RenderingEngine.zoomedIn = zoomedIn;
	}

	public static boolean isRenderedDisabledMap() {
		return renderedDisabledMap;
	}

	public static void setRenderedDisabledMap(boolean renderedDisabledMap) {
		RenderingEngine.renderedDisabledMap = renderedDisabledMap;
	}

	private String getClassRarityIdentifier(Rarity rarity) {
		return (rarity == Rarity.COMMON ? " common" : "")
				+ (rarity == Rarity.UNCOMMON ? " uncommon" : "")
				+ (rarity == Rarity.RARE ? " rare" : "")
				+ (rarity == Rarity.EPIC ? " epic" : "")
				+ (rarity == Rarity.LEGENDARY ? " legendary" : "")
				+ (rarity == Rarity.QUEST ? " quest" : "")
				+ (rarity == Rarity.JINXED ? " jinxed" : "");
	}

	private static String getAttributeBar(String SVGImage, Colour barColour, float attributeValue, float attributeMaximum, String id) {
		return "
"
					+ "
"
						+ "
"
							+ SVGImage
						+ "
"
					+ "
"
					+ "
"
						+ "

"
					+ "
"
					+ "
"
						+ (int) Math.ceil(attributeValue)
					+ "
"
					+ "

"
				+ "
";
	}

	private static String getAttributeBarHalf(String SVGImage, Colour barColour, float attributeValue, float attributeMaximum, String id) {
		return "
"
					+ "
"
						+ "
"
							+ SVGImage
						+ "
"
					+ "
"
					+ "
"
						+ "

"
					+ "
"
					+ "
"
						+ (int) Math.ceil(attributeValue)
					+ "
"
					+ "

"
				+ "
";
	}

	private static String getAttributeBarThird(String SVGImage, Colour barColour, float attributeValue, float attributeMaximum, String id) {
		return "
"
					+ "
"
						+ "
"
							+ SVGImage
						+ "
"
					+ "
"
					+ "
"
						+ "

"
					+ "
"
					+ "
"
						+ (int) Math.ceil(attributeValue)
					+ "
"
					+ "

"
				+ "
";
	}

	private static String getCharacterPanelDiv(boolean compact, String idPrefix, GameCharacter character) {
		StringBuilder panelSB = new StringBuilder();

		panelSB.append(
				"<div class='attribute-container' style='"
						+ (Main.game.isInCombat()
								?(Combat.getTargetedCombatant(Main.game.getPlayer()).equals(character)
										?"border:2px solid "+Colour.GENERIC_COMBAT.toWebHexString()+";"
										:(Combat.getTargetedAlliedCombatant(Main.game.getPlayer()).equals(character)
												?"border:2px solid "+Colour.GENERIC_MINOR_GOOD.toWebHexString()+";"
												:"border:1px solid "+Colour.TEXT_GREY_DARK.toWebHexString()+";"))
								:"border:1px solid "+Colour.TEXT_GREY_DARK.toWebHexString()+";")
							+ "'>"
					+ "
"
						+ "
"
							+ "
"
								+ (character.isRaceConcealed()?SVGImages.SVG_IMAGE_PROVIDER.getRaceUnknown():character.getMapIcon())
							+ "
"
							+"

"
						+ "
"
						+ "
"
							+ "
"
								+ ""
									+ (character.getName(true).length() == 0
											? Util.capitaliseSentence(character.isFeminine()?character.getSubspecies().getSingularFemaleName(character):character.getSubspecies().getSingularMaleName(character))
											: (character.isPlayer()
													?character.getName(true)
													:UtilText.parse(character, "[npc.Name]")))
								+""
								+ " - Level "+ character.getLevel()
							+"
"
							+ "
"
								+ (character.getLevel() != GameCharacter.LEVEL_CAP
									? "

"
									: "

")
							+"
"
							+"

"
						+"
"
						+ (character.isPlayer()
								?"
"
									+ "
"+ UtilText.formatAsMoney(character.getMoney(), "b") +"
"
									+ "
"+ UtilText.formatAsEssences(character.getEssenceCount(TFEssence.ARCANE), "b", true) +"
"
								+"
"
								:"")
					+"
");

		if(!Main.game.isInCombat()) {
			panelSB.append("
");

			panelSB.append(
					getAttributeBarThird(PhysiqueLevel.getPhysiqueLevelFromValue(character.getAttributeValue(Attribute.MAJOR_PHYSIQUE)).getRelatedStatusEffect().getSVGString(character),
							Attribute.MAJOR_PHYSIQUE.getColour(),
							character.getAttributeValue(Attribute.MAJOR_PHYSIQUE),
							100,
							idPrefix + Attribute.MAJOR_PHYSIQUE.getName())

					+getAttributeBarThird(IntelligenceLevel.getIntelligenceLevelFromValue(character.getAttributeValue(Attribute.MAJOR_ARCANE)).getRelatedStatusEffect().getSVGString(character),
							Attribute.MAJOR_ARCANE.getColour(),
							character.getAttributeValue(Attribute.MAJOR_ARCANE),
							100,
							idPrefix + Attribute.MAJOR_ARCANE.getName())

					+getAttributeBarThird(CorruptionLevel.getCorruptionLevelFromValue(character.getAttributeValue(Attribute.MAJOR_CORRUPTION)).getRelatedStatusEffect().getSVGString(character),
							Attribute.MAJOR_CORRUPTION.getColour(),
							character.getAttributeValue(Attribute.MAJOR_CORRUPTION),
							100,
							idPrefix + Attribute.MAJOR_CORRUPTION.getName())
					);
		}

		panelSB.append("
");

		if(compact) {
			panelSB.append(
					getAttributeBarThird(Attribute.HEALTH_MAXIMUM.getSVGString(),
							Colour.ATTRIBUTE_HEALTH,
							character.getHealth(),
							character.getAttributeValue(Attribute.HEALTH_MAXIMUM),
							idPrefix + Attribute.HEALTH_MAXIMUM.getName())

					+getAttributeBarThird(Attribute.MANA_MAXIMUM.getSVGString(),
							Colour.ATTRIBUTE_MANA,
							character.getMana(),
							character.getAttributeValue(Attribute.MANA_MAXIMUM),
							idPrefix + Attribute.MANA_MAXIMUM.getName())

					+getAttributeBarThird(LustLevel.getLustLevelFromValue(character.getLust()).getRelatedStatusEffect().getSVGString(character),
							Colour.ATTRIBUTE_LUST,
							character.getLust(),
							100,
							idPrefix + Attribute.LUST.getName()));

		} else {
			panelSB.append(
					getAttributeBar(Attribute.HEALTH_MAXIMUM.getSVGString(),
							Colour.ATTRIBUTE_HEALTH,
							character.getHealth(),
							character.getAttributeValue(Attribute.HEALTH_MAXIMUM),
							idPrefix + Attribute.HEALTH_MAXIMUM.getName())

					+getAttributeBar(Attribute.MANA_MAXIMUM.getSVGString(),
							Colour.ATTRIBUTE_MANA,
							character.getMana(),
							character.getAttributeValue(Attribute.MANA_MAXIMUM),
							idPrefix + Attribute.MANA_MAXIMUM.getName())

					+getAttributeBar(LustLevel.getLustLevelFromValue(character.getLust()).getRelatedStatusEffect().getSVGString(character),
							Colour.ATTRIBUTE_LUST,
							character.getLust(),
							100,
							idPrefix + Attribute.LUST.getName()));
		}

		// Status effects:
		panelSB.append("
"
				+"
");

//		// Traits:
//		for (Perk trait : character.getTraits()) {
//			panelSB.append(
//					"
"
//							+ "
"
//								+ trait.getSVGString()
//								+ "

"
//							+ "
"
//					+ "
");
//		}

		if(!Main.game.isInCombat()) {
			// Infinite duration:
			for (StatusEffect se : character.getStatusEffects()) {
				if (!se.isCombatEffect() && character.getStatusEffectDuration(se) == -1 && se.renderInEffectsPanel())
					panelSB.append(
							"
"
									+ "
"
										+ se.getSVGString(character)
										+ "

"
									+ "
"
							+ "
");
			}
			// Timed:
			for (StatusEffect se : character.getStatusEffects()) {
				if (!se.isCombatEffect() && character.getStatusEffectDuration(se) != -1 && se.renderInEffectsPanel()) {
					int timerHeight = (int) ((character.getStatusEffectDuration(se)/(60*60*6f))*100);

					Colour timerColour = Colour.STATUS_EFFECT_TIME_HIGH;

					if(timerHeight>100) {
						timerHeight=100;
						timerColour = Colour.STATUS_EFFECT_TIME_OVERFLOW;
					} else if(timerHeight<15) {
						timerColour = Colour.STATUS_EFFECT_TIME_LOW;
					} else if (timerHeight<50) {
						timerColour = Colour.STATUS_EFFECT_TIME_MEDIUM;
					}

					panelSB.append(
							"
"
									+ "

"
									+ "
"
										+ se.getSVGString(character)
										+ "

"
									+ "
"
							+ "
");
				}
			}

			if(!character.isPlayer()) {
				for (Fetish f : character.getFetishes(true)) {
					panelSB.append(
						"
"
							+ "
"
									+ f.getSVGString(character)
									+ "

"
							+ "
"
						+ "
");
				}
			}

		} else {
			// Infinite duration:
			for (StatusEffect se : character.getStatusEffects()) {
				if (character.getStatusEffectDuration(se) == -1 && se.renderInEffectsPanel())
					panelSB.append(
							"
"
									+ "
"
										+ se.getSVGString(character)
										+ "

"
									+ "
"
							+ "
");
			}
			// Timed:
			for (StatusEffect se : character.getStatusEffects()) {
				if (character.getStatusEffectDuration(se) != -1 && se.renderInEffectsPanel() && se.isCombatEffect()) {
					int timerHeight = (int) ((character.getStatusEffectDuration(se)/(60*60*6f))*100);

					Colour timerColour = Colour.STATUS_EFFECT_TIME_HIGH;

					if(timerHeight>100) {
						timerHeight=100;
						timerColour = Colour.STATUS_EFFECT_TIME_OVERFLOW;
					} else if(timerHeight<15) {
						timerColour = Colour.STATUS_EFFECT_TIME_LOW;
					} else if (timerHeight<50) {
						timerColour = Colour.STATUS_EFFECT_TIME_MEDIUM;
					}

					panelSB.append(
							"
"
									+ "

"
									+ "
"
										+ se.getSVGString(character)
										+ "

"
									+ "
"
							+ "
");
				}
			}

			for (CombatMove combatMove : character.getAvailableMoves()) {
				int cooldown = character.getMoveCooldown(combatMove.getIdentifier());
				if (cooldown > 0) {
					int timerHeight = (int) ((Math.min(5, cooldown)/5f)*100);

					Colour timerColour = Colour.STATUS_EFFECT_TIME_MEDIUM;

					if(timerHeight>=100) {
						timerHeight=100;
						timerColour = Colour.STATUS_EFFECT_TIME_LOW;
					} else if(cooldown<2) {
						timerColour = Colour.STATUS_EFFECT_TIME_OVERFLOW;
					} else if (cooldown<4) {
						timerColour = Colour.STATUS_EFFECT_TIME_HIGH;
					}

					panelSB.append(
							"
"
									+ "

"
									+ "
"
										+ combatMove.getSVGString()
									+ "
"
//									+ "
"+SVGImages.SVG_IMAGE_PROVIDER.getStopwatch()+"
"
									+ "

"
							+ "
");

				}
			}
		}

		panelSB.append("

");

		return panelSB.toString();
	}

	private static boolean isLimitedSpectatorPanel(GameCharacter character) {
		return Sex.getSexPositionSlot(character)==SexSlotGeneric.MISC_WATCHING && !character.isPlayer();
	}

	private static String getCharacterPanelSexDiv(boolean compact, String idPrefix, GameCharacter character) {
		StringBuilder panelSB = new StringBuilder();

		panelSB.append(
				"
"
					+ "
"
						+ "
"
							+ "
"
							+ (character.isRaceConcealed()?SVGImages.SVG_IMAGE_PROVIDER.getRaceUnknown():character.getMapIcon())
							+ "
"
							+"

"
						+ "
"
						+ "
"
							+ "
"
								+ ""
									+ (character.getName(true).length() == 0
											? Util.capitaliseSentence(character.isFeminine()?character.getSubspecies().getSingularFemaleName(character):character.getSubspecies().getSingularMaleName(character))
											: (character.isPlayer()
													?character.getName(true)
													:UtilText.parse(character, "[npc.Name]")))
								+""
									+ (isLimitedSpectatorPanel(character)
										?""
										:" - "+ Util.capitaliseSentence(Sex.getSexPace(character).getName())+"")
							+"
"
							+ "
"
								+ (character.getLevel() != GameCharacter.LEVEL_CAP
									? "

"
									: "

")
							+"
"
							+"

"
						+"
"
						+(isLimitedSpectatorPanel(character)
							?""
							:"
"
								+ Util.capitaliseSentence(Sex.getSexPositionSlot(character).getName(character))
							+ "
")
					+"
");

		if(isLimitedSpectatorPanel(character)) {
			panelSB.append("
"+Util.capitaliseSentence(Sex.getSexPositionSlot(character).getName(character))+"
");

			panelSB.append("
");

			panelSB.append(getAttributeBar(ArousalLevel.getArousalLevelFromValue(character.getAttributeValue(Attribute.AROUSAL)).getRelatedStatusEffect().getSVGString(character),
						Colour.ATTRIBUTE_AROUSAL,
						character.getArousal(),
						100,
						idPrefix + Attribute.AROUSAL.getName()));

			panelSB.append("
");

		} else {
			panelSB.append("
");

			panelSB.append(
					getAttributeBarHalf(CorruptionLevel.getCorruptionLevelFromValue(character.getAttributeValue(Attribute.MAJOR_CORRUPTION)).getRelatedStatusEffect().getSVGString(character),
							Attribute.MAJOR_CORRUPTION.getColour(),
							character.getAttributeValue(Attribute.MAJOR_CORRUPTION),
							100,
							idPrefix + Attribute.MAJOR_CORRUPTION.getName())

					+getAttributeBarHalf(LustLevel.getLustLevelFromValue(character.getLust()).getRelatedStatusEffect().getSVGString(character),
							Colour.ATTRIBUTE_LUST,
							character.getLust(),
							100,
							idPrefix + Attribute.LUST.getName())

					+getAttributeBar(ArousalLevel.getArousalLevelFromValue(character.getAttributeValue(Attribute.AROUSAL)).getRelatedStatusEffect().getSVGString(character),
							Colour.ATTRIBUTE_AROUSAL,
							character.getArousal(),
							100,
							idPrefix + Attribute.AROUSAL.getName()));

			// Status effects:
			panelSB.append("
"
					+"
");

	//		// Traits:
	//		for (Perk trait : character.getTraits()) {
	//			panelSB.append(
	//					"
"
	//							+ "
"
	//								+ trait.getSVGString()
	//								+ "

"
	//							+ "
"
	//					+ "
");
	//		}

			// Infinite duration:
			for (StatusEffect se : character.getStatusEffects()) {
				boolean pointer = false;
				SexAreaInterface si = null;
				switch(se) {
					case PENIS_STATUS:
						si = SexAreaPenetration.PENIS;
						break;
					case ANUS_STATUS:
						si = SexAreaOrifice.ANUS;
						break;
					case ASS_STATUS:
						si = SexAreaOrifice.ASS;
						break;
					case MOUTH_STATUS:
						si = SexAreaOrifice.MOUTH;
						break;
					case BREAST_STATUS:
						si = SexAreaOrifice.BREAST;
						break;
					case NIPPLE_STATUS:
						si = SexAreaOrifice.NIPPLE;
						break;
					case THIGH_STATUS:
						si = SexAreaOrifice.THIGHS;
						break;
					case URETHRA_PENIS_STATUS:
						si = SexAreaOrifice.URETHRA_PENIS;
						break;
					case URETHRA_VAGINA_STATUS:
						si = SexAreaOrifice.URETHRA_VAGINA;
						break;
					case VAGINA_STATUS:
						si = SexAreaOrifice.VAGINA;
						break;
					default:
						break;
				}
				if(Main.game.isInSex() && si!=null) {
					if(!Sex.getCharactersHavingOngoingActionWith(character, si).isEmpty()) {
						pointer = true;
					}
				}

				if (se.isSexEffect() && character.getStatusEffectDuration(se) == -1 && se.renderInEffectsPanel()) {
					panelSB.append(
							"
"
									+ "
"
										+ se.getSVGString(character)
										+ "

"
									+ "
"
							+ "
");
				}
			}
			// Timed:
			for (StatusEffect se : character.getStatusEffects()) {
				if (se.isSexEffect() && character.getStatusEffectDuration(se) != -1 && se.renderInEffectsPanel()) {
					int timerHeight = (int) ((character.getStatusEffectDuration(se)/(60*60*6f))*100);

					Colour timerColour = Colour.STATUS_EFFECT_TIME_HIGH;

					if(timerHeight>100) {
						timerHeight=100;
						timerColour = Colour.STATUS_EFFECT_TIME_OVERFLOW;
					} else if(timerHeight<15) {
						timerColour = Colour.STATUS_EFFECT_TIME_LOW;
					} else if (timerHeight<50) {
						timerColour = Colour.STATUS_EFFECT_TIME_MEDIUM;
					}

					panelSB.append(
							"
"
									+ "

"
									+ "
"
										+ se.getSVGString(character)
										+ "

"
									+ "
"
							+ "
");
				}
			}

			if(!character.isPlayer()) {
				for (Fetish f : character.getFetishes(true)) {
					panelSB.append(
						"
"
							+ "
"
									+ f.getSVGString(character)
									+ "

"
							+ "
"
						+ "
");
				}
			}

			panelSB.append("

");
		}

		return panelSB.toString();
	}

	public static int getPageLeft() {
		return pageLeft;
	}

	public static void setPageLeft(int pageLeft) {
		RenderingEngine.pageLeft = pageLeft;
	}

	public static void setPage(GameCharacter charactersInventoryToRender, AbstractCoreItem item) {
		int uniqueItemCount = 0;

		for(Entry<AbstractWeapon, Integer> entry : charactersInventoryToRender.getAllWeaponsInInventory().entrySet()) {
			if(entry.getKey().getRarity()!=Rarity.QUEST || !charactersInventoryToRender.isPlayer()) {
				uniqueItemCount++;
				if(entry.getKey().equals(item)) {
					if(charactersInventoryToRender.isPlayer()) {
						setPageLeft(uniqueItemCount/ITEMS_PER_PAGE);
						return;
					} else {
						setPageRight(uniqueItemCount/ITEMS_PER_PAGE);
						return;
					}
				}
			}
		}

		for(Entry<AbstractClothing, Integer> entry : charactersInventoryToRender.getAllClothingInInventory().entrySet()) {
			if(entry.getKey().getRarity()!=Rarity.QUEST || !charactersInventoryToRender.isPlayer()) {
				uniqueItemCount++;
				if(entry.getKey().equals(item)) {
					if(charactersInventoryToRender.isPlayer()) {
						setPageLeft(uniqueItemCount/ITEMS_PER_PAGE);
						return;
					} else {
						setPageRight(uniqueItemCount/ITEMS_PER_PAGE);
						return;
					}
				}
			}
		}

		for(Entry<AbstractItem, Integer> entry : charactersInventoryToRender.getAllItemsInInventory().entrySet()) {
			if(entry.getKey().getRarity()!=Rarity.QUEST || !charactersInventoryToRender.isPlayer()) {
				uniqueItemCount++;
				if(entry.getKey().equals(item)) {
					if(charactersInventoryToRender.isPlayer()) {
						setPageLeft(uniqueItemCount/ITEMS_PER_PAGE);
						return;
					} else {
						setPageRight(uniqueItemCount/ITEMS_PER_PAGE);
						return;
					}
				}
			}
		}
	}

	public static int getPageRight() {
		return pageRight;
	}

	public static void setPageRight(int pageRight) {
		RenderingEngine.pageRight = pageRight;
	}

	public boolean isRenderingTattoosLeft() {
		return renderingTattoosLeft;
	}

	public void setRenderingTattoosLeft(boolean renderingTattoosLeft) {
		this.renderingTattoosLeft = renderingTattoosLeft;
	}

	public boolean isRenderingTattoosRight() {
		return renderingTattoosRight;
	}

	public void setRenderingTattoosRight(boolean renderingTattoosRight) {
		this.renderingTattoosRight = renderingTattoosRight;
	}

}