code:
package com.lilithsthrone.game.dialogue.companions;

import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.time.format.TextStyle;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;

import com.lilithsthrone.game.character.attributes.AffectionLevel;
import com.lilithsthrone.game.character.attributes.ObedienceLevel;
import com.lilithsthrone.game.character.npc.NPC;
import com.lilithsthrone.game.dialogue.DialogueFlagValue;
import com.lilithsthrone.game.dialogue.DialogueNode;
import com.lilithsthrone.game.dialogue.DialogueNodeType;
import com.lilithsthrone.game.dialogue.eventLog.SlaveryEventLogEntry;
import com.lilithsthrone.game.dialogue.responses.Response;
import com.lilithsthrone.game.dialogue.utils.UtilText;
import com.lilithsthrone.game.occupantManagement.SlaveJob;
import com.lilithsthrone.main.Main;
import com.lilithsthrone.rendering.SVGImages;
import com.lilithsthrone.utils.Colour;
import com.lilithsthrone.utils.Util;
import com.lilithsthrone.world.Cell;
import com.lilithsthrone.world.WorldType;
import com.lilithsthrone.world.places.GenericPlace;
import com.lilithsthrone.world.places.PlaceType;
import com.lilithsthrone.world.places.PlaceUpgrade;

/**
 * @since 0.1.8?
 * @version 0.3.5.1
 * @author Innoxia
 */
public class OccupantManagementDialogue {

	private static StringBuilder miscDialogueSB = new StringBuilder();
	private static int dayNumber = 1;
	private static DecimalFormat decimalFormat = new DecimalFormat("#0.00");

	static {
		decimalFormat.setRoundingMode(RoundingMode.HALF_EVEN);
	}

	public static NPC characterSelected() {
		return Main.game.getDialogueFlags().getManagementCompanion();
	}

	public static DialogueNode getSlaveryOverviewDialogue() {
		dayNumber = Main.game.getDayNumber();
		return OCCUPANT_OVERVIEW;
	}

	public static DialogueNode getSlaveryManagementDialogue(NPC slaveTrader) {
		Main.game.getDialogueFlags().setSlaveTrader(slaveTrader);
		return SLAVE_LIST_MANAGEMENT;
	}

	public static DialogueNode getSlaveryRoomListDialogue(NPC slaveTrader) {
		Main.game.getDialogueFlags().setSlaveTrader(slaveTrader);
		return SLAVE_LIST;
	}

	public static int getDayNumber() {
		return dayNumber;
	}

	public static void setDayNumber(int dayNumber) {
		OccupantManagementDialogue.dayNumber = Math.max(1, dayNumber);
	}

	private static Response getSlaveryResponse(int index) {
		if (index == 1) {
			return new Response("Room List", "View the management screen for all rooms.", ROOM_MANAGEMENT) {
				@Override
				public void effects() {
					Main.game.getDialogueFlags().setManagementCompanion(null);
				}
			};

		} else if (index == 2) {
			return new Response("Occupant List", "Enter the management screen for all slaves and friendly occupants.", SLAVE_LIST_MANAGEMENT) {
				@Override
				public DialogueNode getNextDialogue() {
					return OccupantManagementDialogue.getSlaveryManagementDialogue(Main.game.getDialogueFlags().getSlaveTrader());
				}
				@Override
				public void effects() {
					Main.game.getDialogueFlags().setManagementCompanion(null);
				}
			};

		} else if (index == 5) {
			if(Main.game.getOccupancyUtil().getGeneratedBalance()==0) {
				return new Response("Collect: "+UtilText.formatAsMoneyUncoloured(Main.game.getOccupancyUtil().getGeneratedBalance(), "span"), "Your current balance is 0...",  null);

			} else if(Main.game.getOccupancyUtil().getGeneratedBalance()>0) {
				return new Response("Collect: "+UtilText.formatAsMoney(Main.game.getOccupancyUtil().getGeneratedBalance(), "span"), "Collect the money that you've earned through your slaves' activities.",  OCCUPANT_OVERVIEW) {
					@Override
					public DialogueNode getNextDialogue() {
						return Main.game.getCurrentDialogueNode();
					}
					@Override
					public void effects() {
						Main.game.getOccupancyUtil().payOutBalance();
					}
				};

			} else {
				if(Main.game.getPlayer().getMoney()<Math.abs(Main.game.getOccupancyUtil().getGeneratedBalance())) {
					return new Response("Pay: "+UtilText.formatAsMoneyUncoloured(Math.abs(Main.game.getOccupancyUtil().getGeneratedBalance()), "span"),
							"You don't have enough money to pay off the accumulated debt from the upkeep of your slaves and rooms.",  null);
				}

				return new Response("Pay: "+UtilText.formatAsMoney(Math.abs(Main.game.getOccupancyUtil().getGeneratedBalance()), "span", Colour.GENERIC_BAD), "Pay off the accumulated debt from the upkeep of your slaves and rooms.",  OCCUPANT_OVERVIEW) {
					@Override
					public DialogueNode getNextDialogue() {
						return Main.game.getCurrentDialogueNode();
					}
					@Override
					public void effects() {
						Main.game.getOccupancyUtil().payOutBalance();
					}
				};
			}

		} else if (index == 0) {
			return new Response("Back", "Exit the occupancy ledger.", Main.game.getDefaultDialogue()) {
				@Override
				public void effects() {
					Main.game.getDialogueFlags().setManagementCompanion(null);
					Main.game.getDialogueFlags().setSlaveTrader(null);
				}
			};

		} else {
			return null;
		}
	}

	public static final DialogueNode OCCUPANT_OVERVIEW = new DialogueNode("Slavery Overview", ".", true) {

		@Override
		public DialogueNodeType getDialogueNodeType() {
			return DialogueNodeType.OCCUPANT_MANAGEMENT;
		}

		@Override
		public String getContent() {
			UtilText.nodeContentSB.setLength(0);

			int income = Main.game.getPlayer().getSlaveryTotalDailyIncome();
			int upkeep = Main.game.getPlayer().getSlaveryTotalDailyUpkeep();

			// Overview:
			UtilText.nodeContentSB.append(
					"
"
						+ "
Totals
"
						+ "
"
							+ "
"
								+ "Slaves"
							+ "
"
							+ "
"
								+ "Income"
							+"
"
							+ "
"
								+ "Upkeep"
							+"
"
							+ "
"
								+ "Profit"
							+"
"
							+ "
"
								+ "Funds"
							+"
"
							+ "
"
								+ "Payments"
							+"
"
							+ "
"
								+ "Balance"
							+"
"
						+ "
"
						+ "
"
							+ "
"
								+ Main.game.getPlayer().getSlavesOwned().size()
							+ "
"
							+ "
"
								+ UtilText.formatAsMoney(income)+"/day"
							+"
"
							+ "
"
								+ UtilText.formatAsMoney(upkeep, "b", Colour.GENERIC_BAD)+"/day"
							+"
"
							+ "
"
								+ UtilText.formatAsMoney(income-upkeep, "b", (income-upkeep<0?Colour.GENERIC_BAD:Colour.TEXT))+"/day"
							+"
"
							+ "
"
								+ UtilText.formatAsMoney(Main.game.getOccupancyUtil().getGeneratedIncome(), "b")
							+ "
"
							+ "
"
								+ UtilText.formatAsMoney(Main.game.getOccupancyUtil().getGeneratedUpkeep(), "b", Colour.GENERIC_BAD)
							+ "
"
							+ "
"
								+ (Main.game.getOccupancyUtil().getGeneratedBalance()<0
										? UtilText.formatAsMoney(Main.game.getOccupancyUtil().getGeneratedBalance(), "b", Colour.GENERIC_BAD)
										: UtilText.formatAsMoney(Main.game.getOccupancyUtil().getGeneratedBalance(), "b"))
							+ "
"
						+ "
"
					+"
");

			// Logs:
			UtilText.nodeContentSB.append(
					"
"
						+ "
Activity Log
");
			// Buttons:
			for(int i=6; i>=0; i--) {
				UtilText.nodeContentSB.append("
"
						+ (i==0
							?"Today"
							:(i==1
								?"Yesterday"
								:Main.game.getDateNow().minusDays(i).getDayOfWeek().getDisplayName(TextStyle.FULL, Locale.ENGLISH)))
						+ "
");
			}

			// Headers:
			UtilText.nodeContentSB.append("
"
							+ "
"
								+ "Time"
							+ "
"
							+ "
"
								+ "Slave"
							+ "
"
							+ "
"
								+ "Event"
							+"
"
							+ "
"
								+ "Description"
							+"
"
						+ "
"
						+ "
");

			int count=0;
			if(Main.game.getSlaveryEvents(dayNumber)!=null) {
				for(SlaveryEventLogEntry entry : Main.game.getSlaveryEvents(dayNumber)) {
					if(count%2==0) {
						UtilText.nodeContentSB.append("
");
					} else {
						UtilText.nodeContentSB.append("
");
					}

					UtilText.nodeContentSB.append(
								"
"
									+ String.format("%02d", entry.getTime()) + ":00
"
								+ "
"
								+ "
"
									 + entry.getSlaveName()
								+ "
"
								+ "
"
									+ entry.getName()
								+ "
"
								+ "
"
									+ entry.getDescription()
								+ "
"
								+ "
");
					count++;
				}
			}
			if(count==0) {
				UtilText.nodeContentSB.append("
[style.colourDisabled(No events for this day...)]
");
			}

			UtilText.nodeContentSB.append("
"
					+ "
");

			return UtilText.nodeContentSB.toString();
		}

		@Override
		public Response getResponse(int responseTab, int index) {
			return getSlaveryResponse(index);
		}
	};

	public static final DialogueNode ROOM_MANAGEMENT = new DialogueNode("Room Management", ".", true) {

		@Override
		public DialogueNodeType getDialogueNodeType() {
			return DialogueNodeType.OCCUPANT_MANAGEMENT;
		}

		@Override
		public String getContent() {
			UtilText.nodeContentSB.setLength(0);

			Cell cell = Main.game.getPlayerCell();
			GenericPlace place = cell.getPlace();
			List<NPC> charactersPresent = Main.game.getCharactersTreatingCellAsHome(cell);
			float affectionChange = place.getHourlyAffectionChange();
			float obedienceChange = place.getHourlyObedienceChange();
			UtilText.nodeContentSB.append(
					"
"
						+ "
Current Location
"
						+ getRoomHeader()
						+ getRoomEntry(!place.isAbleToBeUpgraded(), true, cell, charactersPresent, affectionChange, obedienceChange)
					+"
");

			// Lilaya's home:
			UtilText.nodeContentSB.append(getWorldRooms(WorldType.LILAYAS_HOUSE_GROUND_FLOOR));
			UtilText.nodeContentSB.append(getWorldRooms(WorldType.LILAYAS_HOUSE_FIRST_FLOOR));

			// Slaver alley:
			UtilText.nodeContentSB.append(getWorldRooms(WorldType.SLAVER_ALLEY));

			return UtilText.nodeContentSB.toString();
		}

		@Override
		public Response getResponse(int responseTab, int index) {
			if(index==0) {
				return new Response("Back", "Return to the previous screen.", OCCUPANT_OVERVIEW);

			} else {
				return null;
			}
		}
	};

	private static String getRoomHeader() {
		return "
"
					+ "
"
						+ "Room Name"
					+ "
"
					+ "
"
						+ "Occupants"
					+ "
"
					+ "
"
						+ "Capacity"
					+"
"
					+ "
"
						+ "Affection"
					+"
"
					+ "
"
						+ "Obedience"
					+"
"
					+ "
"
						+ "Upkeep"
					+"
"
					+ "
"
						+ "Actions"
					+"
"
				+ "
";
	}

	private static String getRoomEntry(boolean disabled, boolean currentLocation, Cell cell, List<NPC> occupants, float affectionChange, float obedienceChange) {
		miscDialogueSB.setLength(0);

		GenericPlace place = cell.getPlace();

		miscDialogueSB.append(
				"
"
						+ "
"
							+ ""+place.getName()+"
"
						+ "
"
						+ "
");

		int i=0;
		for(NPC occupant : occupants) {
			if(occupant.isSlave()) {
				miscDialogueSB.append(""+occupant.getName(true)+""+(i+1==occupants.size()?"":"
"));
				i++;
			}
		}
		if(i==0) {
			miscDialogueSB.append("Empty");
		}

		miscDialogueSB.append("
"
						+ "
"
							+ i+"/"+place.getCapacity()
						+"
"
						+ "
"
							+ "0?Colour.GENERIC_GOOD:Colour.GENERIC_BAD)).toWebHexString()+";'>"+(affectionChange>0?"+":"")
								+decimalFormat.format(affectionChange)+"/hour"
						+"
"
						+ "
"
							+ "0?Colour.GENERIC_GOOD:Colour.GENERIC_BAD)).toWebHexString()+";'>"+(obedienceChange>0?"+":"")
								+decimalFormat.format(obedienceChange)+"/hour"
						+"
"
						+ "
"
							+ (disabled
									?"[style.colourDisabled(N/A)]"
									:(place.getUpkeep()>0
										?UtilText.formatAsMoney(-place.getUpkeep(), "span", Colour.GENERIC_BAD)
										:(place.getUpkeep()==0
											?UtilText.formatAsMoney(-place.getUpkeep(), "span", Colour.TEXT_GREY)
											:UtilText.formatAsMoney(-place.getUpkeep(), "span", Colour.GENERIC_GOOD))))+"/day"
						+"
"
						+ "
"
							+ (disabled
									?"

"+SVGImages.SVG_IMAGE_PROVIDER.getSlaveInspectDisabled()+"

"
									:"

"+SVGImages.SVG_IMAGE_PROVIDER.getSlaveInspect()+"

")
						+"
"
					+ "
");

		return miscDialogueSB.toString();
	}

	private static List<Cell> importantCells = new ArrayList<>();

	public static void resetImportantCells() {
		importantCells = new ArrayList<>();
	}

	public static List<Cell> getImportantCells() {
		if(importantCells.isEmpty()) {
			WorldType[] importantWorlds = new WorldType[] {WorldType.LILAYAS_HOUSE_GROUND_FLOOR, WorldType.LILAYAS_HOUSE_FIRST_FLOOR};
			for(WorldType wt : importantWorlds) {
				Cell[][] cellGrid = Main.game.getWorlds().get(wt).getCellGrid();
				for(int i = 0; i< cellGrid.length; i++) {
					for(int j = 0; j < cellGrid[0].length; j++) {
						if(!cellGrid[i][j].getPlace().getPlaceType().equals(PlaceType.LILAYA_HOME_CORRIDOR)
								&& !cellGrid[i][j].getPlace().getPlaceType().equals(PlaceType.GENERIC_IMPASSABLE)) {
							importantCells.add(cellGrid[i][j]);
						}
					}
				}
			}
		}

		return importantCells;
	}

	private static String getWorldRooms(WorldType worldType) {
		StringBuilder worldRoomSB = new StringBuilder();

		worldRoomSB.append(
				"
"
					+ "
"+worldType.getName()+"
"
					+ getRoomHeader());

		Cell[][] cellGrid = Main.game.getWorlds().get(worldType).getCellGrid();
		List<Cell> sortingCells = new ArrayList<>();
		for(int i = 0; i< cellGrid.length; i++) {
			for(int j = 0; j < cellGrid[0].length; j++) {
				if(!cellGrid[i][j].getPlace().getPlaceUpgrades().isEmpty()) {
//					importantCells.add(cellGrid[i][j]);
					sortingCells.add(cellGrid[i][j]);
				}
			}
		}

		sortingCells.sort(Comparator.comparing(Cell::getPlaceName));

		for(Cell c : sortingCells) {
			GenericPlace place = c.getPlace();
			worldRoomSB.append(getRoomEntry(!place.isAbleToBeUpgraded(), false, c, Main.game.getCharactersTreatingCellAsHome(c), place.getHourlyAffectionChange(), place.getHourlyObedienceChange()));
		}

		worldRoomSB.append("
");

		return worldRoomSB.toString();
	}

	public static Cell cellToInspect;

	public static final DialogueNode ROOM_UPGRADES = new DialogueNode("Room Management", ".", true) {

		@Override
		public DialogueNodeType getDialogueNodeType() {
			return DialogueNodeType.OCCUPANT_MANAGEMENT;
		}

		@Override
		public String getLabel() {
			return cellToInspect.getPlace().getName()+" Management";
		}

		@Override
		public String getContent() {
			UtilText.nodeContentSB.setLength(0);

			UtilText.nodeContentSB.append(
					"
"
							+ "
Overview (Total Values for this Room)
"
							+"
"
								+ "
"
									+ "Name"
								+ "
"
								+ "
"
									+ "Occupants"
								+ "
"
								+ "
"
									+ "Capacity"
								+"
"
								+ "
"
									+ "Affection"
								+"
"
								+ "
"
									+ "Obedience"
								+"
"
								+ "
"
									+ "Upkeep"
								+"
"
							+ "
");

			GenericPlace place = cellToInspect.getPlace();
			float affectionChange = place.getHourlyAffectionChange();
			float obedienceChange = place.getHourlyObedienceChange();

			UtilText.nodeContentSB.append(
					"
"
							+ "
"
								+ "<form style='float:left; width:85%; margin:0; padding:0;'><input type='text' id='nameInput' value='"+ UtilText.parseForHTMLDisplay(cellToInspect.getPlace().getName())+ "' style='width:100%; margin:0; padding:0;'></form>"
								+ "
"
									+ "✓"
								+ "
"
							+ "
"
							+ "
");

			int i=0;
			List<NPC> occupants = Main.game.getCharactersTreatingCellAsHome(cellToInspect);
			for(NPC occupant : occupants) {
				if(occupant.isSlave()) {
					UtilText.nodeContentSB.append(""+occupant.getName(true)+""+(i+1==occupants.size()?"":"
"));
					i++;
				}
			}
			if(i==0) {
				UtilText.nodeContentSB.append("Empty");
			}

			UtilText.nodeContentSB.append(
					"
"
							+ "
"
								+ i+"/"+place.getCapacity()
							+"
"
							+ "
"
								+ "0?Colour.GENERIC_GOOD:Colour.GENERIC_BAD)).toWebHexString()+";'>"+(affectionChange>0?"+":"")
									+decimalFormat.format(affectionChange)+"/hour"
							+"
"
							+ "
"
								+ "0?Colour.GENERIC_GOOD:Colour.GENERIC_BAD)).toWebHexString()+";'>"+(obedienceChange>0?"+":"")
									+decimalFormat.format(obedienceChange)+"/hour"
							+"
"
							+ "
"
								+ (place.getUpkeep()>0
											?UtilText.formatAsMoney(-place.getUpkeep(), "span", Colour.GENERIC_BAD)
											:UtilText.formatAsMoney(-place.getUpkeep(), "span", Colour.GENERIC_GOOD))+"/day"
							+"
"
						+ "
"
						+ "
");

			// Normal upgrades:
			UtilText.nodeContentSB.append("
"
											+ "
Modifications
"
											+ getRoomUpgradeHeader());

			List<PlaceUpgrade> coreUpgrades = new ArrayList<>();
			for(PlaceUpgrade upgrade : place.getPlaceType().getAvailablePlaceUpgrades(place.getPlaceUpgrades())) {
				if(upgrade.getAvailability(cellToInspect).getKey() || (!upgrade.getAvailability(cellToInspect).getValue().isEmpty())) { // Do not display upgrades that have no explanation as to why they're banned.
					if(upgrade.isCoreRoomUpgrade()) {
						coreUpgrades.add(upgrade);
					} else {
						UtilText.nodeContentSB.append(getUpgradeEntry(cellToInspect, upgrade));
						i++;
					}
				}
			}
			if(i==0) {
				UtilText.nodeContentSB.append(
						"
"
								+ "No Modifications Available"
						+ "
");
			}

			UtilText.nodeContentSB.append("
");

			// Core upgrades:
			UtilText.nodeContentSB.append("
"
					+ "
Core Modifications
"
					+"
Purchasing a [style.boldArcane(core modification)] will remove [style.boldBad(all)] other modifications in this room!
"
					+ getRoomUpgradeHeader());

//			for (PlaceUpgrade upgrade : place.getPlaceUpgrades()) {
//				if(upgrade.isCoreRoomUpgrade()) {
//					UtilText.nodeContentSB.append(getUpgradeEntry(cellToInspect, upgrade));
//				}
//			}

			i = 0;
			for (PlaceUpgrade upgrade : coreUpgrades) {
				UtilText.nodeContentSB.append(getUpgradeEntry(cellToInspect, upgrade));
				i++;
			}
			if(i==0) {
				UtilText.nodeContentSB.append(
						"
"
								+ "No Core Modifications Available"
						+ "
");
			}

			UtilText.nodeContentSB.append("
"
					+ "

");

			return UtilText.nodeContentSB.toString();
		}

		@Override
		public Response getResponse(int responseTab, int index) {
			if (index == 5) {
				if(Main.game.getOccupancyUtil().getGeneratedBalance()==0) {
					return new Response("Collect: "+UtilText.formatAsMoneyUncoloured(Main.game.getOccupancyUtil().getGeneratedBalance(), "span"), "Your current balance is 0...",  null);

				} else if(Main.game.getOccupancyUtil().getGeneratedBalance()>0) {
					return new Response("Collect: "+UtilText.formatAsMoney(Main.game.getOccupancyUtil().getGeneratedBalance(), "span"),
							"Collect the money that you've earned through your slaves' activities.",  ROOM_UPGRADES) {
						@Override
						public DialogueNode getNextDialogue() {
							return Main.game.getCurrentDialogueNode();
						}
						@Override
						public void effects() {
							Main.game.getOccupancyUtil().payOutBalance();
						}
					};

				} else {
					if(Main.game.getPlayer().getMoney()<Math.abs(Main.game.getOccupancyUtil().getGeneratedBalance())) {
						return new Response("Pay: "+UtilText.formatAsMoneyUncoloured(Math.abs(Main.game.getOccupancyUtil().getGeneratedBalance()), "span"),
								"You don't have enough money to pay off the accumulated debt from the upkeep of your slaves and rooms.",  null);
					}

					return new Response("Pay: "+UtilText.formatAsMoney(Math.abs(Main.game.getOccupancyUtil().getGeneratedBalance()), "span", Colour.GENERIC_BAD),
							"Pay off the accumulated debt from the upkeep of your slaves and rooms.",  ROOM_UPGRADES) {
						@Override
						public DialogueNode getNextDialogue() {
							return Main.game.getCurrentDialogueNode();
						}
						@Override
						public void effects() {
							Main.game.getOccupancyUtil().payOutBalance();
						}
					};
				}

			} else if(index==0) {
				return new Response("Back", "Return to the previous screen.", ROOM_UPGRADES) {
					@Override
					public DialogueNode getNextDialogue() {
						return Main.game.getDefaultDialogueNoEncounter();
					}
				};
			} else {
				return null;
			}
		}
	};

	public static final DialogueNode ROOM_UPGRADES_MANAGEMENT = new DialogueNode("Room Management", ".", true) {

		@Override
		public DialogueNodeType getDialogueNodeType() {
			return DialogueNodeType.OCCUPANT_MANAGEMENT;
		}

		@Override
		public String getLabel() {
			return cellToInspect.getPlace().getName()+" Management";
		}

		@Override
		public String getContent() {
			return ROOM_UPGRADES.getContent();
		}

		@Override
		public Response getResponse(int responseTab, int index) {
			if (index == 5) {
				if(Main.game.getOccupancyUtil().getGeneratedBalance()==0) {
					return new Response("Collect: "+UtilText.formatAsMoneyUncoloured(Main.game.getOccupancyUtil().getGeneratedBalance(), "span"), "Your current balance is 0...",  null);

				} else if(Main.game.getOccupancyUtil().getGeneratedBalance()>0) {
					return new Response("Collect: "+UtilText.formatAsMoney(Main.game.getOccupancyUtil().getGeneratedBalance(), "span"),
							"Collect the money that you've earned through your slaves' activities.",  ROOM_UPGRADES_MANAGEMENT) {
						@Override
						public DialogueNode getNextDialogue() {
							return Main.game.getCurrentDialogueNode();
						}
						@Override
						public void effects() {
							Main.game.getOccupancyUtil().payOutBalance();
						}
					};

				} else {
					if(Main.game.getPlayer().getMoney()<Math.abs(Main.game.getOccupancyUtil().getGeneratedBalance())) {
						return new Response("Pay: "+UtilText.formatAsMoneyUncoloured(Math.abs(Main.game.getOccupancyUtil().getGeneratedBalance()), "span"),
								"You don't have enough money to pay off the accumulated debt from the upkeep of your slaves and rooms.",  null);
					}

					return new Response("Pay: "+UtilText.formatAsMoney(Math.abs(Main.game.getOccupancyUtil().getGeneratedBalance()), "span", Colour.GENERIC_BAD),
							"Pay off the accumulated debt from the upkeep of your slaves and rooms.",  ROOM_UPGRADES_MANAGEMENT) {
						@Override
						public DialogueNode getNextDialogue() {
							return Main.game.getCurrentDialogueNode();
						}
						@Override
						public void effects() {
							Main.game.getOccupancyUtil().payOutBalance();
						}
					};
				}

			} else if(index==0) {
				return new Response("Back", "Return to the previous screen.", ROOM_MANAGEMENT);
			} else {
				return null;
			}
		}
	};

	private static String getRoomUpgradeHeader() {
		return "
"
					+ "
"
						+ "Upgrade"
					+ "
"
					+ "
"
						+ "Capacity"
					+"
"
					+ "
"
						+ "Affection"
					+"
"
					+ "
"
						+ "Obedience"
					+"
"
					+ "
"
						+ "Upkeep"
					+"
"
					+ "
"
						+ "Cost"
					+"
"
					+ "
"
						+ "Actions"
					+"
"
				+ "
";
	}

	private static String getUpgradeEntry(Cell cell, PlaceUpgrade upgrade) {
		miscDialogueSB.setLength(0);
		GenericPlace place = cell.getPlace();
		float affectionChange = upgrade.getHourlyAffectionGain();
		float obedienceChange = upgrade.getHourlyObedienceGain();
		boolean owned = place.getPlaceUpgrades().contains(upgrade);
		boolean availableForPurchase = upgrade.isPrerequisitesMet(place) && upgrade.getAvailability(cell).getKey() && (owned?Main.game.getPlayer().getMoney()>=upgrade.getRemovalCost():Main.game.getPlayer().getMoney()>=upgrade.getInstallCost());
		boolean canBuy = availableForPurchase;

		miscDialogueSB.append(
				"
"
						+ "
"
							+ "
"+SVGImages.SVG_IMAGE_PROVIDER.getInformationIcon()+"
"
						+ "
"
						+ "
"
							+ (owned
									?""+Util.capitaliseSentence(upgrade.getName())+""
									:(!availableForPurchase
											?""+Util.capitaliseSentence(upgrade.getName())+""
											:""+Util.capitaliseSentence(upgrade.getName())+""))
//							+ "
"+SVGImages.SVG_IMAGE_PROVIDER.getInformationIcon()+"
"
//							+"

"
						+ "
"
						+ "
"
							+ (upgrade.getCapacity()>0
									?"+"+upgrade.getCapacity()+""
									:(upgrade.getCapacity()<0
											?""+upgrade.getCapacity()+""
											:"[style.colourDisabled(0)]"))
						+ "
"
						+ "
"
							+ (affectionChange>0
									?"+"+decimalFormat.format(affectionChange)+ "/hour"
									:(affectionChange<0
											?""+decimalFormat.format(affectionChange)+ "/hour"
											:"[style.colourDisabled(0)]/hour"))
						+"
"
						+ "
"
							+ (obedienceChange>0
									?"+"+decimalFormat.format(obedienceChange)+ "/hour"
									:(obedienceChange<0
											?""+decimalFormat.format(obedienceChange)+ "/hour"
											:"[style.colourDisabled(0)]/hour"))
						+"
"
						+ "
"
							+ (upgrade.getUpkeep()>0
									?UtilText.formatAsMoney(upgrade.getUpkeep(), "b", Colour.GENERIC_BAD)
									:UtilText.formatAsMoney(upgrade.getUpkeep(), "b", Colour.GENERIC_GOOD))+"/day"
						+"
"
						+ "
"
							+ (owned
									?(upgrade.getRemovalCost()<0
											?UtilText.formatAsMoney(upgrade.getRemovalCost(), "b", Colour.GENERIC_GOOD)
											:(upgrade.getRemovalCost() < Main.game.getPlayer().getMoney()
													?UtilText.formatAsMoney(upgrade.getRemovalCost(), "b")
													:UtilText.formatAsMoney(upgrade.getRemovalCost(), "b", Colour.GENERIC_BAD)))
									:(upgrade.getInstallCost()<0
											?UtilText.formatAsMoney(upgrade.getInstallCost(), "b", Colour.GENERIC_GOOD)
											:(upgrade.getInstallCost() < Main.game.getPlayer().getMoney()
													?UtilText.formatAsMoney(upgrade.getInstallCost(), "b")
													:UtilText.formatAsMoney(upgrade.getInstallCost(), "b", Colour.GENERIC_BAD))))
						+"
"
						+ "
");

		if(owned) {
			if(Main.game.getPlayer().getMoney()<upgrade.getRemovalCost() || upgrade.isCoreRoomUpgrade()) {
				miscDialogueSB.append("

"+SVGImages.SVG_IMAGE_PROVIDER.getTransactionSellDisabled()+"

");
			} else {
				miscDialogueSB.append("

"+SVGImages.SVG_IMAGE_PROVIDER.getTransactionSell()+"

");
			}

		} else {
			if(Main.game.getPlayer().getMoney()<upgrade.getInstallCost() || Main.game.getOccupancyUtil().getGeneratedBalance()<0) {
				canBuy = false;
			}
			if(canBuy) {
				if(!upgrade.getPrerequisites().isEmpty()) {
					for(PlaceUpgrade prereq : upgrade.getPrerequisites()) {
						if(!place.getPlaceUpgrades().contains(prereq)) {
							canBuy = false;
							break;
						}
					}
				}
			}

			if(canBuy) {
				miscDialogueSB.append("

"+SVGImages.SVG_IMAGE_PROVIDER.getTransactionBuy()+"

");
			} else {
				miscDialogueSB.append("

"+SVGImages.SVG_IMAGE_PROVIDER.getTransactionBuyDisabled()+"

");
			}
		}

		miscDialogueSB.append(
				"
"
//					+ "
"
//						+ ""
//							+(!owned
//								?"[style.colourDisabled("+upgrade.getDescriptionForPurchase()+")]"
//								:upgrade.getDescriptionAfterPurchase())
//						+""
//					+ "
"
//					+  (upgrade.isCoreRoomUpgrade() && !owned
//							?"
This is a [style.boldArcane(core modification)], and will [style.boldBad(remove all other modifications in this room when purchased)].
"
//							:"")
					);

		if(!canBuy) {
			miscDialogueSB.append("
"
				+ ""
				+ "[style.colourBad("+ getPurchaseAvailabilityTooltipText(OccupantManagementDialogue.cellToInspect, upgrade)+")]"
				+""
			+ "
");
		}

		miscDialogueSB.append("
");

		return miscDialogueSB.toString();
	}

	private static StringBuilder purchaseAvailability = new StringBuilder();
	public static String getPurchaseAvailabilityTooltipText(Cell cell, PlaceUpgrade upgrade) {
		GenericPlace place = cell.getPlace();
		boolean owned = place.getPlaceUpgrades().contains(upgrade);

		purchaseAvailability.setLength(0);

		if(owned) {
			if(Main.game.getPlayer().getMoney()<upgrade.getRemovalCost()) {
				purchaseAvailability.append("You cannot afford to remove this modification.");
			}

		} else {
			if(Main.game.getOccupancyUtil().getGeneratedBalance()<0) {
				purchaseAvailability.append("You cannot purchase any modifications while your slavery balance is negative.");
			}

			if(Main.game.getPlayer().getMoney()<upgrade.getInstallCost()) {
				purchaseAvailability.append("You cannot afford this modification.");
			}

			if(!upgrade.getPrerequisites().isEmpty()) {
				purchaseAvailability.append("You need to purchase the following first:");
				for(PlaceUpgrade prereq : upgrade.getPrerequisites()) {
					if(place.getPlaceUpgrades().contains(prereq)) {
						purchaseAvailability.append("
"+prereq.getName()+"");
					} else {
						purchaseAvailability.append("
"+prereq.getName()+"");
					}
				}
			}
		}

		String availabilityDescription = upgrade.getAvailability(OccupantManagementDialogue.cellToInspect).getValue();
		if(availabilityDescription!=null && availabilityDescription.length()>0) {
			purchaseAvailability.append("
"+availabilityDescription+"");
		}

		return purchaseAvailability.toString();
	}

	public static final DialogueNode SLAVE_LIST = new DialogueNode("Slave & Occupant Management", ".", true) {

		@Override
		public DialogueNodeType getDialogueNodeType() {
			return DialogueNodeType.OCCUPANT_MANAGEMENT;
		}

		@Override
		public String getContent() {
			UtilText.nodeContentSB.setLength(0);

			if(Main.game.getDialogueFlags().getSlaveTrader()!=null) {
				// Append for sale first:
				UtilText.nodeContentSB.append("
"
						+ "
Slaves For Sale
"

						+ getSlaveryHeader());
				int i=0;
				List<NPC> npcsPresent = new ArrayList<>(Main.game.getCharactersTreatingCellAsHome(Main.game.getPlayerCell()));

				npcsPresent.removeIf((npc) -> !npc.isSlave());

				for(NPC slave : npcsPresent) {
					if(!slave.getOwner().isPlayer()) {
						AffectionLevel affection = AffectionLevel.getAffectionLevelFromValue(slave.getAffection(Main.game.getPlayer()));
						ObedienceLevel obedience = ObedienceLevel.getObedienceLevelFromValue(slave.getObedienceValue());
						float affectionChange = slave.getDailyAffectionChange();
						float obedienceChange = slave.getDailyObedienceChange();
						GenericPlace place = Main.game.getPlayerCell().getPlace();

						UtilText.nodeContentSB.append(getSlaveryEntry(false, place, slave, affection, affectionChange, obedience, obedienceChange, i%2==0));
						i++;
					}
				}
				if(i==0) {
					UtilText.nodeContentSB.append("

No slaves for sale!

");
				}
				UtilText.nodeContentSB.append("
");

			} else { // Don't show occupants if trading slaves.
				// Friendly occupants:
				UtilText.nodeContentSB.append("
"
						+ "
Friendly Occupants
"

						+ getOccupantHeader());

				if(Main.game.getPlayer().getFriendlyOccupants().isEmpty()) {
					UtilText.nodeContentSB.append(
							"
"
									+"
You do not have anyone living with you...
"
							+ "
");

				} else {
					int i = 0;
					for(String id : Main.game.getPlayer().getFriendlyOccupants()) {
						try {
							NPC occupant = (NPC) Main.game.getNPCById(id);
							if(occupant.getHomeWorldLocation()!=WorldType.DOMINION) {
								AffectionLevel affection = AffectionLevel.getAffectionLevelFromValue(occupant.getAffection(Main.game.getPlayer()));
								ObedienceLevel obedience = ObedienceLevel.getObedienceLevelFromValue(occupant.getObedienceValue());
								float affectionChange = occupant.getDailyAffectionChange();
								float obedienceChange = occupant.getDailyObedienceChange();
								GenericPlace place = Main.game.getPlayerCell().getPlace();

								UtilText.nodeContentSB.append(getOccupantEntry(place, occupant, affection, affectionChange, obedience, obedienceChange, i%2==0));
								i++;
							}
						} catch (Exception e) {
							Util.logGetNpcByIdError("SLAVE_LIST.getResponse()", id);
						}
					}
				}

				UtilText.nodeContentSB.append(
						"
");
			}

			// Your slaves:
			UtilText.nodeContentSB.append("
"
					+ "
Slaves Owned
"

					+ getSlaveryHeader());

			if(Main.game.getPlayer().getSlavesOwned().isEmpty()) {
				UtilText.nodeContentSB.append(
						"
"
								+"
You do not own any slaves...
"
						+ "
");

			} else {
				int i = 0;
				for(String id : Main.game.getPlayer().getSlavesOwned()) {
					try {
						NPC slave = (NPC) Main.game.getNPCById(id);
						AffectionLevel affection = AffectionLevel.getAffectionLevelFromValue(slave.getAffection(Main.game.getPlayer()));
						ObedienceLevel obedience = ObedienceLevel.getObedienceLevelFromValue(slave.getObedienceValue());
						float affectionChange = slave.getDailyAffectionChange();
						float obedienceChange = slave.getDailyObedienceChange();
						GenericPlace place = Main.game.getPlayerCell().getPlace();

						UtilText.nodeContentSB.append(getSlaveryEntry(true, place, slave, affection, affectionChange, obedience, obedienceChange, i%2==0));
						i++;
					} catch (Exception e) {
						System.err.println("Main.game.getNPCById("+id+") returning null 2nd instance in method: SLAVE_LIST.getResponse()");
					}
				}
			}

			UtilText.nodeContentSB.append(
					"
");

			return UtilText.nodeContentSB.toString();
		}

		@Override
		public Response getResponse(int responseTab, int index) {
			return CompanionManagement.getManagementResponses(index);
		}
	};

	public static final DialogueNode SLAVE_LIST_MANAGEMENT = new DialogueNode("Slave Management", ".", true) {

		@Override
		public DialogueNodeType getDialogueNodeType() {
			return DialogueNodeType.OCCUPANT_MANAGEMENT;
		}

		@Override
		public String getContent() {
			return SLAVE_LIST.getContent();
		}

		@Override
		public Response getResponse(int responseTab, int index) {
			if(index == 0) {
				return new Response("Back", "Exit the slave management screen.", OCCUPANT_OVERVIEW);

			} else {
				return SLAVE_LIST.getResponse(responseTab, index);
			}
		}
	};

	private static String getSlaveryHeader() {
		return "
"
					+ "
"
					+ "Slave"
				+ "
"
				+ "
"
					+ "Location"
				+ "
"
				+ "
"
					+ "Affection"
				+"
"
				+ "
"
					+ "Obedience"
				+"
"
				+ "
"
					+ "Value"
				+"
"
				+ "
"
					+ "Actions"
				+"
"
			+ "
";
	}

	private static String getOccupantHeader() {
		return "
"
					+ "
"
					+ "Occupant"
				+ "
"
				+ "
"
					+ "Location"
				+ "
"
				+ "
"
					+ "Affection"
				+"
"
				+ "
"
					+ "Obedience"
				+"
"
				+ "
"
					+ "Value"
				+"
"
				+ "
"
					+ "Actions"
				+"
"
			+ "
";
	}

	private static String getSlaveryEntry(boolean slaveOwned, GenericPlace place, NPC slave, AffectionLevel affection, float affectionChange, ObedienceLevel obedience, float obedienceChange, boolean alternateBackground) {
		miscDialogueSB.setLength(0);

		miscDialogueSB.append(
				"
"
						+ "
"
							+ ""+slave.getName(true)+"
"
							+ ""
								+Util.capitaliseSentence((slave.isFeminine()?slave.getSubspecies().getSingularFemaleName(slave):slave.getSubspecies().getSingularMaleName(slave)))+"
"
							+ ""+Util.capitaliseSentence(slave.getGender().getName())+""
						+ "
"
						+ "
"
							+ ""+slave.getLocationPlace().getName()+""
							+",
"
							+ ""+slave.getWorldLocation().getName()+""
						+ "
"
						+ "
"
							+ ""+slave.getAffection(Main.game.getPlayer())+ ""
							+ "
0?Colour.GENERIC_GOOD:Colour.GENERIC_BAD)).toWebHexString()+";'>"+(affectionChange>0?"+":"")
								+decimalFormat.format(affectionChange)+"/day"
							+ "
"
							+ ""+Util.capitaliseSentence(affection.getName())+""
						+"
"
						+ "
"
							+ ""+slave.getObedienceValue()+ ""
							+ "
0?Colour.GENERIC_GOOD:Colour.GENERIC_BAD)).toWebHexString()+";'>"+(obedienceChange>0?"+":"")
								+decimalFormat.format(obedienceChange)+"/day"
							+ "
"
							+ ""+Util.capitaliseSentence(obedience.getName())+""
						+"
"
						+ "
"
							+ (Main.game.getDialogueFlags().getSlaveTrader()!=null
								?(slaveOwned
										?UtilText.formatAsMoney((int) (slave.getValueAsSlave(true)*Main.game.getDialogueFlags().getSlaveTrader().getBuyModifier()), "b", Colour.GENERIC_ARCANE)
										:UtilText.formatAsMoney((int) (slave.getValueAsSlave(true)*Main.game.getDialogueFlags().getSlaveTrader().getSellModifier()), "b", Colour.GENERIC_ARCANE))
								:UtilText.formatAsMoney(slave.getValueAsSlave(true)))+"
"
							+ ""+Util.capitaliseSentence(slave.getSlaveJob(Main.game.getHourOfDay()).getName(slave))+" (now)
"
							+ UtilText.formatAsMoney(SlaveJob.getFinalDailyIncomeAfterModifiers(slave))+"/day"
						+"
");

		if(slaveOwned) {
			miscDialogueSB.append("
"
					+ "

"+SVGImages.SVG_IMAGE_PROVIDER.getSlaveInspect()+"

"

					+ "

"+SVGImages.SVG_IMAGE_PROVIDER.getSlaveJob()+"

"

					+ "

"+SVGImages.SVG_IMAGE_PROVIDER.getSlavePermissions()+"

"

					+"

"+SVGImages.SVG_IMAGE_PROVIDER.getInventoryIcon()+"

"

					+ "<div "+((place.getCapacity()<=Main.game.getCharactersTreatingCellAsHome(Main.game.getPlayerCell()).size())
								|| !place.isSlaveCell()
								|| (slave.getLocation().equals(Main.game.getPlayer().getLocation()) && slave.getWorldLocation().equals(Main.game.getPlayer().getWorldLocation()))
										?" id='"+slave.getId()+"_TRANSFER_DISABLED' class='square-button big disabled'>
"+SVGImages.SVG_IMAGE_PROVIDER.getSlaveTransferDisabled()+"

"
										:" id='"+slave.getId()+"_TRANSFER' class='square-button big'>
"+SVGImages.SVG_IMAGE_PROVIDER.getSlaveTransfer()+"

"));

			if(Main.game.getDialogueFlags().getSlaveTrader()==null) {
				miscDialogueSB.append("

"+SVGImages.SVG_IMAGE_PROVIDER.getTransactionSellDisabled()+"

");
			} else {
				miscDialogueSB.append("

"+SVGImages.SVG_IMAGE_PROVIDER.getTransactionSell()+"

");
			}

			if(Main.game.getDialogueFlags().hasFlag(DialogueFlagValue.kateIntroduced)) {
				miscDialogueSB.append("

"+SVGImages.SVG_IMAGE_PROVIDER.getSlaveCosmetics()+"

");
			} else {
				miscDialogueSB.append("

"+SVGImages.SVG_IMAGE_PROVIDER.getSlaveCosmeticsDisabled()+"

");
			}

		} else { // Slave trader's slave:
			miscDialogueSB.append("
"
					+ "

"+SVGImages.SVG_IMAGE_PROVIDER.getSlaveInspect()+"

"

					+ "

"+SVGImages.SVG_IMAGE_PROVIDER.getSlaveJobDisabled()+"

"

					+ "

"+SVGImages.SVG_IMAGE_PROVIDER.getSlavePermissionsDisabled()+"

"

					+"

"+SVGImages.SVG_IMAGE_PROVIDER.getInventoryIconDisabled()+"

"

					+ "

"+SVGImages.SVG_IMAGE_PROVIDER.getSlaveTransferDisabled()+"

");

			if(Main.game.getPlayer().getMoney() < ((int) (slave.getValueAsSlave(true)*Main.game.getDialogueFlags().getSlaveTrader().getSellModifier()))) {
				miscDialogueSB.append("

"+SVGImages.SVG_IMAGE_PROVIDER.getTransactionBuyDisabled()+"

");
			} else {
				miscDialogueSB.append("

"+SVGImages.SVG_IMAGE_PROVIDER.getTransactionBuy()+"

");
			}

			miscDialogueSB.append("

"+SVGImages.SVG_IMAGE_PROVIDER.getSlaveCosmeticsDisabled()+"

");
		}

		miscDialogueSB.append("

");

		return miscDialogueSB.toString();
	}

	private static String getOccupantEntry(GenericPlace place, NPC occupant, AffectionLevel affection, float affectionChange, ObedienceLevel obedience, float obedienceChange, boolean alternateBackground) {
		miscDialogueSB.setLength(0);

		miscDialogueSB.append(
				"
"
						+ "
"
							+ ""+occupant.getName(true)+"
"
							+ ""
								+Util.capitaliseSentence((occupant.isFeminine()?occupant.getSubspecies().getSingularFemaleName(occupant):occupant.getSubspecies().getSingularMaleName(occupant)))+"
"
							+ ""+Util.capitaliseSentence(occupant.getGender().getName())+""
						+ "
"
						+ "
"
							+ (occupant.getWorldLocation()==WorldType.EMPTY
								?"At Work"
										+",
"
										+ ""+WorldType.DOMINION.getName()+""
								:""+occupant.getLocationPlace().getName()+""
									+",
"
									+ ""+occupant.getWorldLocation().getName()+"")
						+ "
"
						+ "
"
							+ ""+occupant.getAffection(Main.game.getPlayer())+ ""
							+ "
0?Colour.GENERIC_GOOD:Colour.GENERIC_BAD)).toWebHexString()+";'>"+(affectionChange>0?"+":"")
								+decimalFormat.format(affectionChange)+"/day"
							+ "
"
							+ ""+Util.capitaliseSentence(affection.getName())+""
						+"
"
						+ "
"
							+ ""+occupant.getObedienceValue()+ ""
							+ "
0?Colour.GENERIC_GOOD:Colour.GENERIC_BAD)).toWebHexString()+";'>"+(obedienceChange>0?"+":"")
								+decimalFormat.format(obedienceChange)+"/day"
							+ "
"
							+ ""+Util.capitaliseSentence(obedience.getName())+""
						+"
"
						+ "
"
							+ ""+Util.capitaliseSentence(occupant.getHistory().getName())+"
"
							+ "[style.boldDisabled(N/A)]"
						+"
"

				+ "
"

				+ "

"+SVGImages.SVG_IMAGE_PROVIDER.getSlaveInspect()+"

"

				+ "

"+SVGImages.SVG_IMAGE_PROVIDER.getSlaveJobDisabled()+"

"

				+ "

"+SVGImages.SVG_IMAGE_PROVIDER.getSlavePermissionsDisabled()+"

"

				+"

"+SVGImages.SVG_IMAGE_PROVIDER.getInventoryIcon()+"

"

				+ "<div "+((place.getCapacity()<=Main.game.getCharactersTreatingCellAsHome(Main.game.getPlayerCell()).size())
							|| place.isSlaveCell()
							|| occupant.getHomeWorldLocation()==WorldType.DOMINION
							|| (occupant.getLocation().equals(Main.game.getPlayer().getLocation()) && occupant.getWorldLocation().equals(Main.game.getPlayer().getWorldLocation()))
									?" id='"+occupant.getId()+"_TRANSFER_DISABLED' class='square-button big disabled'>
"+SVGImages.SVG_IMAGE_PROVIDER.getSlaveTransferDisabled()+"

"
									:" id='"+occupant.getId()+"_TRANSFER' class='square-button big'>
"+SVGImages.SVG_IMAGE_PROVIDER.getSlaveTransfer()+"

"));

		if(Main.game.getDialogueFlags().hasFlag(DialogueFlagValue.kateIntroduced)) {
			miscDialogueSB.append("

"+SVGImages.SVG_IMAGE_PROVIDER.getSlaveCosmetics()+"

");
		} else {
			miscDialogueSB.append("

"+SVGImages.SVG_IMAGE_PROVIDER.getSlaveCosmeticsDisabled()+"

");
		}

		miscDialogueSB.append("

");

		return miscDialogueSB.toString();
	}

}

repo_name: klorpa/Pedo

license: unknown